Three.js , leaflet coordinates projection problem

62 Views Asked by At

I'm developing an angular app in which i upload svg image to leaflet and place it/scale it/rotate it using (distortable image overlay) .

After that i Draw polygons inside that image as zones.

Those two are working perfectly fine .

The problem is that i have a function that will take that svg image and make it as a plane and then project the coordinates of the drawn polygons inside threejs, I tried everything but the result is always shifted.

Those are the screenshots

This screenshot after drawing polygon in leaflet - tilelayer is hidden here-

This when i try to make it 3d using threejs

This how i display the svg and the plane

private async createFloorFromSvg(svgUrl: string,corners: number[][]): Promise<void>  {

  const floorTopLeft = new THREE.Vector3(corners[0][0], 0, corners[0][1]);
    const floorTopRight = new THREE.Vector3(corners[1][0], 0, corners[1][1]);
   const middle= new THREE.Vector3((corners[1][0]+corners[0][0])/2,0,(corners[2][1]+corners[0][1])/2)
    const floorBottomLeft = new THREE.Vector3(corners[2][0], 0, corners[2][1]);
  const response = await fetch(svgUrl);
    const svgContent = await response.text();

    const tempSvg = new DOMParser().parseFromString(svgContent, 'image/svg+xml');
    const svgWidth = parseFloat(tempSvg.documentElement.getAttribute('width'))  // Default width if not specified
    const svgHeight = parseFloat(tempSvg.documentElement.getAttribute('height')) // Default height if not specified

  const loader = new SVGLoader();
   const group = new THREE.Group();
  loader.load(svgUrl,function (data)  {
    const paths = data.paths;
 
    let renderOrder = 0;

    for ( const path of data.paths ) {
      const fillColor = path.userData.style.fill;
        const material = new THREE.MeshBasicMaterial( {
      
          side: THREE.DoubleSide,
          depthWrite: false, 
        } );
        const shapes = SVGLoader.createShapes( path );
        for ( const shape of shapes ) {
          const geometry = new THREE.ShapeGeometry( shape );
          const mesh = new THREE.Mesh( geometry, material );
          mesh.renderOrder = renderOrder ++;
          group.add( mesh );
        }
        const material2 = new THREE.MeshBasicMaterial( {
      
          transparent: true,
          side: THREE.DoubleSide,
          depthWrite: false 
        } );
        for ( const subPath of path.subPaths ) {
          const geometry = SVGLoader.pointsToStroke( subPath.getPoints(), path.userData.style );
          if ( geometry ) {
            const mesh = new THREE.Mesh( geometry, material2 );
            mesh.renderOrder = renderOrder ++;
            group.add( mesh );
          }
        }
    }
  
    const planeGeometry = new THREE.PlaneGeometry(svgWidth, svgHeight, 1, 1);
    const planeMaterial = new THREE.MeshBasicMaterial({
      color: 0x000000,
      side: THREE.DoubleSide,
      depthWrite: false,
      transparent: true,
      opacity: 0.5,
      depthTest:false
    });
    const plane = new  THREE.Mesh(planeGeometry, planeMaterial);
 group.position.copy(new THREE.Vector3((svgWidth/2),(svgHeight/2),0));
  plane.position.copy(new THREE.Vector3((svgWidth/2),(svgHeight/2),0));
 
  
 
group.rotation.z = Math.PI ;
  group.add(plane);
  });

 this.scene.add(group);
}

This how i try to display the polygons

private  convertPolygonToImageCoordinates(polygonCoordinates: number[][], svgCorners: number[][], svgWidth: any, svgHeight: any): THREE.Vector3[] {
  const localCoordinates: THREE.Vector3[] = [];

  this.calculateRotationAngle(svgCorners)
 
  const svgTopLeft = new THREE.Vector3(svgCorners[0][0], 0, svgCorners[0][1]);
  const svgTopRight = new THREE.Vector3(svgCorners[1][0], 0, svgCorners[1][1]);
  const svgBottomLeft = new THREE.Vector3(svgCorners[2][0], 0, svgCorners[2][1]);
  const svgBottomRight = new THREE.Vector3(svgCorners[3][0], 0, svgCorners[3][1]);

  const scaleX = svgBottomLeft.distanceTo(svgBottomRight) / svgWidth;
  const scaleZ = svgTopLeft.distanceTo(svgBottomLeft) / svgHeight;
 
   const transformationMatrix = new THREE.Matrix4();
  transformationMatrix.scale(new THREE.Vector3(scaleX, 1, scaleZ));
  const translateX = (svgTopLeft.x ) ;
  const translateY = 0;
  const translateZ = (svgTopLeft.z ) ;
 
const directionVector = svgTopLeft.clone().sub(svgTopRight);
 const rotationAngle = Math.atan2(directionVector.z, directionVector.x);
  for (const [longitude, latitude] of polygonCoordinates) {
   
    const x = (longitude - translateX) / scaleX;
    console.log('longitude - translateX/s',x)
    const y = translateY;  
    const z = (latitude - translateZ) / scaleZ;
    console.log('latitude - translateZ/s',z)
    localCoordinates.push(new THREE.Vector3(x, y, z));
  }
  const rotationMatrix = new THREE.Matrix4().makeRotationY(rotationAngle);
  localCoordinates.forEach(point => {
    point.applyMatrix4(rotationMatrix);
  }); 
  this.createPolygon(localCoordinates,svgWidth,svgHeight); 
  return localCoordinates;
}
private createPolygon(coordinates: THREE.Vector3[],svgWidth: number,svgHeight: number): void {
 
  const shapePoints = coordinates.map(coord => new THREE.Vector2(coord.x, coord.z));

 
  const shape = new THREE.Shape(shapePoints);
 
  const extrudeSettings = {
    depth: 50, 
   bevelEnabled: false,
 
  };
  const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings  );
  const material =new THREE.MeshStandardMaterial({
    color: 0x778899,
    roughness: 0
  })  
  const polygon = new THREE.Mesh(geometry, material);
  var position = new THREE.Vector3();
  polygon.getWorldPosition( position );
  this.camera.lookAt( position );
  polygon.position.copy(new THREE.Vector3((svgWidth/2),(svgHeight/2),0));
  this.scene.add(polygon);
}

I want to fix those misplaced polygons

0

There are 0 best solutions below