浏览代码

fix: 解析shape的prj文件,初始化默认位置,测了三个文件

xzw 7 月之前
父节点
当前提交
c02069db0f
共有 2 个文件被更改,包括 330 次插入21 次删除
  1. 329 20
      public/lib/potree/potree.js
  2. 1 1
      public/lib/potree/potree.js.map

+ 329 - 20
public/lib/potree/potree.js

@@ -22078,18 +22078,17 @@
 	          //移动过后使用移动后的坐标
 	          model.position.copy(prop.position);
 	        } else {
-	          if (!model.isPointcloud && prop.raw.wgs84) {
+	          if (!model.isPointcloud && prop.raw.wgs84 || model.fileType == 'shp') {
 	            //有经纬度  
-	            var locationLonLat = prop.raw.wgs84.split(',').map(e => parseFloat(e));
-	            var location = viewer.transform.lonlatToLocal.forward(locationLonLat);
-	            MergeEditor.moveBoundCenterTo(model, new Vector3().fromArray(location));
-	            model.hasLonLat = true;
-	            model.lonLatPos = model.position.clone();
-	          } else if (model.fileType == 'shp') {
+	            if (prop.raw.wgs84) {
+	              var locationLonLat = prop.raw.wgs84.split(',').map(e => parseFloat(e));
+	              var location = viewer.transform.lonlatToLocal.forward(locationLonLat);
+	              MergeEditor.moveBoundCenterTo(model, new Vector3().fromArray(location));
+	            }
 	            model.hasLonLat = true;
 	            model.lonLatPos = model.position.clone();
 	          }
-	          MergeEditor.setModelBtmHeight(model, 0); // 离地高度为0 (因为不想在地图下方所以高程不管了,都在地面上即可)
+	          MergeEditor.setModelBtmHeight(model, 0.1); // 离地高度为0 (因为不想在地图下方所以高程不管了,都在地面上即可)
 	        }
 	      }
 	      if (prop.rotation && (prop.rotation.x != 0 || prop.rotation.y != 0 || prop.rotation.z != 0)) {
@@ -38916,6 +38915,15 @@
 	}
 	;
 
+	/*  proj4.defs("CGCS2000","+proj=tmerc +lat_0=0 +lon_0=114 +k=1 +x_0=500000 +y_0=0 +ellps=WGS84 +units=m +no_defs")
+	 
+	function transformCGCS2000ToWGS84([lng, lat]) {  
+	  // Define the CGCS2000 and WGS84 coordinate systems   
+	    const transformed = proj4("CGCS2000", "LOCAL", [lng, lat]);  
+	    return  transformed 
+	}  
+	 */
+
 	class ShapefileLoader {
 	  constructor() {
 	    //this.transform = null;
@@ -38929,12 +38937,15 @@
 	      dashed: false
 	    });
 	    var features = await this.loadShapefileFeatures(path);
-	    var node = new Object3D();
 	    if (!features) {
-	      console.error('no features');
+	      console.error('no features', path);
 	      return;
 	    }
-	    var transform = this.analyseTransform(features, path);
+	    var node = new Object3D();
+	    var transform = await this.loadProj(path);
+	    if (!transform) {
+	      transform = this.analyseTransform(features, path);
+	    }
 	    var jump = 0;
 	    for (var feature of features) {
 	      //5是碎的
@@ -38958,7 +38969,7 @@
 	    if (viewer.transform) {
 	      var count = 0,
 	        maxCount = 100;
-	      var notLonLat, transform;
+	      var notLonLat, _transform;
 	      var judge = coord => {
 	        if (!(coord[0] >= -180 && coord[0] <= 180 && coord[1] >= -90 && coord[1] <= 90)) {
 	          //如果超出经纬度范围,那就不是经纬度
@@ -38981,18 +38992,21 @@
 	        }
 	      }
 	      if (notLonLat) {
-	        transform = v => {
+	        _transform = v => {
 	          var a = viewer.transform.lonlatTo4550.inverse(v); //这种类型和不使用transform很接近
 	          return viewer.transform.lonlatToLocal.forward(a);
 	        };
-	        console.log('该shape使用大地坐标', path.split('/').pop());
+	        //transform = transformCGCS2000ToWGS84 
+	        console.log('该shape使用4550大地坐标', path.split('/').pop());
 	      } else {
-	        transform = viewer.transform.lonlatToLocal.forward;
+	        _transform = viewer.transform.lonlatToLocal.forward;
 	        console.log('该shape使用经纬度', path.split('/').pop());
 	      }
-	      return transform;
+	      return _transform;
 
 	      //loaders.shapeLoader.transform = viewer.transform.lonlatToLocal.forward;
+	    } else {
+	      console.log('该shape没用任何transform 因为场景没有设置经纬度', path.split('/').pop());
 	    }
 	  }
 	  featureToSceneNode(feature, matLine, transform) {
@@ -39126,8 +39140,293 @@
 	      });
 	    }
 	  }
+	  async loadProj(path) {
+	    var a = path.split('/');
+	    var name = a.pop().split('.')[0];
+	    path = a.join('/') + '/' + name + '.prj';
+	    return new Promise((resolve, reject) => {
+	      Potree.loadFile(path, {
+	        returnText: true
+	      }, e => {
+	        name += '_proj';
+	        var projDef = parsePrjToProj4(e);
+	        proj4.defs(name, projDef);
+	        console.log('loadedProj:', name, '解析得def:  ', projDef, '原:', e);
+	        try {
+	          var proj = proj4(name, "LOCAL");
+	          var _transform2 = _ref => {
+	            var [lng, lat] = _ref;
+	            return proj.forward([lng, lat]);
+	          };
+	          resolve(_transform2);
+	        } catch (e) {
+	          console.log(e, 'build proj4 failed', name);
+	          resolve();
+	        }
+	      }, () => {
+	        resolve();
+	        console.log('prj load failed', name);
+	      });
+	    });
+
+	    //let transformed = c.forward([lng, lat])
+	    return transform;
+	  }
 	}
 	;
+	function parsePrjToProj4(prjString) {
+	  var def = '';
+	  var json = prjToJson(prjString);
+	  var projectionType;
+	  var datum = '';
+	  var ellipsoid = '';
+	  var centralMeridian = '';
+	  var scaleFactor = '1';
+	  var falseEasting = '0';
+	  var falseNorthing = '0';
+	  var latitudeOfOrigin = '0';
+	  if (json.projection == 'Transverse_Mercator') {
+	    projectionType = 'tmerc';
+	  } else if (!json.projection) {
+	    projectionType = 'lonlat';
+	  } else {
+	    projectionType = projection;
+	    console.log('unknown projection:', json.projection);
+	  }
+	  if (json.parameters) {
+	    falseEasting = json.parameters.false_easting;
+	    falseNorthing = json.parameters.false_northing;
+	    centralMeridian = json.parameters.central_meridian;
+	    latitudeOfOrigin = json.parameters.latitude_of_origin;
+	    scaleFactor = json.parameters.scale_factor;
+	  }
+	  if (json.spheroid) {
+	    if (json.spheroid.name.toLowerCase().includes('wgs84')) ellipsoid = 'WGS84';
+	  }
+	  def += "+proj=".concat(projectionType);
+	  def += "+lat_0=".concat(latitudeOfOrigin, " ");
+	  def += "+lon_0=".concat(centralMeridian, " ");
+	  def += "+k=".concat(scaleFactor, " ");
+	  def += "+x_0=".concat(falseEasting, " ");
+	  def += "+y_0=".concat(falseNorthing, " ");
+	  return def;
+	}
+	function prjToJson(prjString) {
+	  var result = {};
+
+	  // 提取 PROJCS 和 GEOGCS 信息
+	  var projcsMatch = prjString.match(/PROJCS\["([^"]+)",(.*)\]/);
+	  if (projcsMatch) {
+	    result.projcsName = projcsMatch[1];
+	    var geoPart = projcsMatch[2];
+
+	    // 解析 GEOGCS 部分
+	    var geoMatch = geoPart.match(/GEOGCS\["([^"]+)",DATUM\["([^"]+)",SPHEROID\["([^"]+)",([0-9.]+),([0-9.]+)\]\],PRIMEM\["([^"]+)",([0-9.]+)\],UNIT\["([^"]+)",([0-9.]+)\]/);
+	    if (geoMatch) {
+	      result.geogcs = {
+	        name: geoMatch[1],
+	        datum: geoMatch[2],
+	        spheroid: {
+	          name: geoMatch[3],
+	          semiMajorAxis: parseFloat(geoMatch[4]),
+	          inverseFlattening: parseFloat(geoMatch[5])
+	        },
+	        primeMeridian: {
+	          name: geoMatch[6],
+	          value: parseFloat(geoMatch[7])
+	        },
+	        unit: {
+	          name: geoMatch[8],
+	          conversionFactor: parseFloat(geoMatch[9])
+	        }
+	      };
+	    }
+
+	    // 解析 PROJECTION 部分
+	    var projMatch = geoPart.match(/PROJECTION\["([^"]+)"\]/);
+	    if (projMatch) {
+	      result.projection = projMatch[1];
+	    }
+
+	    // 解析 PARAMETER 部分
+	    var parameters = {};
+	    var paramMatches = geoPart.matchAll(/PARAMETER\["([^"]+)",([-\d.]+)\]/g);
+	    for (var match of paramMatches) {
+	      parameters[match[1]] = parseFloat(match[2]);
+	    }
+	    result.parameters = parameters;
+
+	    // 解析 UNIT 部分
+	    var unitMatch = geoPart.match(/UNIT\["([^"]+)",([-\d.]+)\]/);
+	    if (unitMatch) {
+	      result.unit = {
+	        name: unitMatch[1],
+	        conversionFactor: parseFloat(unitMatch[2])
+	      };
+	    }
+	  } else {
+	    // 如果没有 PROJCS,则尝试解析 GEOGCS
+	    var _geoMatch = prjString.match(/GEOGCS\["([^"]+)",DATUM\["([^"]+)",SPHEROID\["([^"]+)",([0-9.]+),([0-9.]+)\]\],PRIMEM\["([^"]+)",([0-9.]+)\],UNIT\["([^"]+)",([0-9.]+)\]/);
+	    if (_geoMatch) {
+	      result.geogcs = {
+	        name: _geoMatch[1],
+	        datum: _geoMatch[2],
+	        spheroid: {
+	          name: _geoMatch[3],
+	          semiMajorAxis: parseFloat(_geoMatch[4]),
+	          inverseFlattening: parseFloat(_geoMatch[5])
+	        },
+	        primeMeridian: {
+	          name: _geoMatch[6],
+	          value: parseFloat(_geoMatch[7])
+	        },
+	        unit: {
+	          name: _geoMatch[8],
+	          conversionFactor: parseFloat(_geoMatch[9])
+	        }
+	      };
+	    }
+	  }
+	  return result;
+	}
+
+	/* 
+	  
+	function parsePrjToProj4(prjString) {
+	    // 初始化 Proj4 字符串的部分
+	    let proj4Def = ''
+
+	    // 提取关键信息
+	    const prjParts = prjString.match(/(\w+)\[(.*?)\]/g);
+	     
+	    let projectionType = '';
+	    let datum = '';
+	    let ellipsoid = '';
+	    let centralMeridian = '';
+	    let scaleFactor = '1';
+	    let falseEasting = '0';
+	    let falseNorthing = '0';
+	    let latitudeOfOrigin = '0';
+
+	    prjParts.forEach(part => {
+	        if (part.includes('PROJECTION')) {
+	            projectionType = part.match(/"([^"]+)"/)[1].toLowerCase().replace('_', ''); 
+	            //xzw:
+	            if(projectionType == 'transversemercator') projectionType = 'tmerc'
+	             
+	        }else if (part.includes('DATUM')) {
+	            datum = part.match(/"([^"]+)"/)[1];
+	        } else if (part.includes('SPHEROID')) {
+	            ellipsoid = part.match(/"([^"]+)"/)[1].toLowerCase();
+	        } else if (part.includes('PARAMETER')) {
+	            let paramName = part.match(/"([^"]+)"/)[1].toLowerCase().replace(/ /g, '_');
+	            let paramValue = part.match(/(-?\d+\.?\d*)/)[1];
+	            switch (paramName) {
+	                case 'central_meridian':
+	                    centralMeridian = paramValue;
+	                    break;
+	                case 'scale_factor':
+	                    scaleFactor = paramValue;
+	                    break;
+	                case 'false_easting':
+	                    falseEasting = paramValue;
+	                    break;
+	                case 'false_northing':
+	                    falseNorthing = paramValue;
+	                    break;
+	                case 'latitude_of_origin':
+	                    latitudeOfOrigin = paramValue;
+	                    break;
+	            }
+	        }
+	    });
+
+	    // 构建完整的 Proj4 定义字符串
+	    if(!projectionType && prjString.includes('GCS_WGS_1984')) projectionType = 'longlat'
+	    
+	    
+	    projectionType && (proj4Def += `+proj=${projectionType} `) 
+	    proj4Def += `+lat_0=${latitudeOfOrigin} `;
+	    proj4Def += `+lon_0=${centralMeridian} `;
+	    proj4Def += `+k=${scaleFactor} `;
+	    proj4Def += `+x_0=${falseEasting} `;
+	    proj4Def += `+y_0=${falseNorthing} `;
+	    ellipsoid && (proj4Def += `+ellps=${ellipsoid} `);
+	    proj4Def += '+units=m +no_defs';
+
+	    return proj4Def;
+	}
+	 */
+
+	/* 
+	function parsePrjToProj4(prjString) {
+	   // 初始化 Proj4 参数对象
+	   let proj4Params = {};
+	   
+	   // 提取 PROJCS 和 GEOGCS 部分
+	   const projcsMatch = prjString.match(/PROJCS\["([^"]+)",(.*)\]/);
+	   if (projcsMatch){ 
+	   
+	   const projcsName = projcsMatch[1];
+	   const geoPart = projcsMatch[2];
+
+	   // 解析 GEOGCS 部分
+	   const datumMatch = geoPart.match(/DATUM\["([^"]+)",SPHEROID\["([^"]+)",([0-9.]+),([0-9.]+)\]\]/);
+	   if (datumMatch) {
+	       proj4Params.datum = datumMatch[1].toLowerCase();
+	       proj4Params.ellps = datumMatch[2].toLowerCase();
+	       proj4Params.a = parseFloat(datumMatch[3]); // Semi-major axis
+	       proj4Params.rf = parseFloat(datumMatch[4]); // Inverse flattening
+	   }
+
+	   // 解析 PROJECTION 部分
+	   const projMatch = geoPart.match(/PROJECTION\["([^"]+)"\]/);
+	   if (projMatch) {
+	       proj4Params.proj = projMatch[1].toLowerCase().replace(/_/g, '');
+	   }
+
+	   // 解析 PARAMETER 部分
+	   const paramMatches = geoPart.matchAll(/PARAMETER\["([^"]+)",([-\d.]+)\]/g);
+	   for (const match of paramMatches) {
+	       const paramName = match[1].toLowerCase().replace(/ /g, '_');
+	       const paramValue = parseFloat(match[2]);
+	       switch (paramName) {
+	           case 'false_easting':
+	               proj4Params.x_0 = paramValue;
+	               break;
+	           case 'false_northing':
+	               proj4Params.y_0 = paramValue;
+	               break;
+	           case 'central_meridian':
+	               proj4Params.lon_0 = paramValue;
+	               break;
+	           case 'scale_factor':
+	               proj4Params.k = paramValue;
+	               break;
+	           case 'latitude_of_origin':
+	               proj4Params.lat_0 = paramValue;
+	               break;
+	       }
+	   }
+
+	   // 设置单位
+	   proj4Params.units = "m"; // 默认米
+	   proj4Params.no_defs = true;
+
+	   // 构建 Proj4 字符串
+	   let proj4Def = '+proj=' + proj4Params.proj;
+	   proj4Def += ' +lat_0=' + proj4Params.lat_0;
+	   proj4Def += ' +lon_0=' + proj4Params.lon_0;
+	   proj4Def += ' +k=' + proj4Params.k;
+	   proj4Def += ' +x_0=' + proj4Params.x_0;
+	   proj4Def += ' +y_0=' + proj4Params.y_0;
+	   proj4Def += ' +ellps=' + proj4Params.ellps;
+	   proj4Def += ' +units=' + proj4Params.units;
+	   proj4Def += ' +no_defs';
+
+	   return proj4Def;
+	}
+	*/
 
 	var defaultColors = {
 	  "landuse": [0.5, 0.5, 0.5],
@@ -78696,6 +78995,7 @@
 	    this.panDelta.set(0, 0);
 	  }
 	  zoomToLocation(mouse) {
+	    var _viewer$modules$Merge;
 	    var I = viewer.inputHandler.intersect;
 	    var object;
 	    if (I) {
@@ -78711,10 +79011,15 @@
 	    }
 	    var dis = this.currentViewport.view.position.distanceTo(I);
 	    var distance;
-	    if (object) {
-	      distance = this.updateRadiusByModel(object, dis);
-	    } else {
-	      distance = Math.min(dis, 50); //方便从高空回到地面
+	    var object_ = object || ((_viewer$modules$Merge = viewer.modules.MergeEditor) === null || _viewer$modules$Merge === void 0 ? void 0 : _viewer$modules$Merge.selected);
+	    if (object_) {
+	      distance = this.updateRadiusByModel(object_, dis);
+	    }
+	    if (!object) {
+	      if (!distance || distance < 50) {
+	        //方便从高空回到地面
+	        distance = Math.min(dis, 50);
+	      }
 	      this.updateRadius('focus');
 	    }
 	    viewer.focusOnObject({
@@ -87214,6 +87519,10 @@
 	        }).catch(onError);
 	      } else {
 	        var response = await fetch(path, info);
+	        if (!response.ok) {
+	          console.log('loadFile失败', path);
+	          return onError && onError();
+	        }
 	        var text = await response.text();
 	        var data = params.returnText ? text : JSON.parse(text);
 	        if (data.data) data = data.data;

文件差异内容过多而无法显示
+ 1 - 1
public/lib/potree/potree.js.map