fanvanzh / 3dtiles

The fastest tools for 3dtiles convert in the world!
Apache License 2.0
1.94k stars 591 forks source link

倾斜摄影OSGB是基于CGCS2000的,如何转换成GCJ02 的3dtiles #200

Open yangchao2015 opened 3 years ago

yangchao2015 commented 3 years ago

你好,麻烦问下,倾斜摄影OSGB是基于CGCS2000的,如何转换成GCJ02 的3dtiles

fanvanzh commented 3 years ago

不明白你的意思, CGCS2000、GCJ02 应该都是说的基准点坐标。 3dtile 都是 单位是米的 投影数据

yangchao2015 commented 3 years ago

对倾斜摄影不太了解,第三方机构提供的是基于CGCS2000的,通过3dtiles 转换成 3dtiles 文件,需要在高德地图进行加载,空间参考填写 高德的经纬度坐标点?我尝试过,转换过之后是无法正常加载的

yangchao2015 commented 3 years ago

OSGB 倾斜摄影 数据其中的 metadata.xml内容如下: 1628219113(1)

fanvanzh commented 3 years ago

高德地图支持加载 3dtiles 了? 你这个 metadata.xml 是 高斯3度带的投影, EPSG=4549

这个项目只支持 EPSG: 4549 这种写法的解析。

fanvanzh commented 3 years ago

你注意下 3dtile.exe 执行时的输出里,有没有打印 x -> {}, y -> {} 的日志。 这个坐标就是经纬度坐标。

yangchao2015 commented 3 years ago

1628302675(1) 是的,现在我转换出来直接使用 Cesium 可以加载出来,但是使用高德加载,无法显示,查看得到的titleCenter 坐标 是 {lng: -23.40701687715633, lat: 39.141703930756044},应该是坐标系的问题,导致的显示的问题,不知道如何去进行处理和显示,希望能得到如何去处理的方式,或者可以处理的工具,感谢 1628302714

yangchao2015 commented 3 years ago

输出的 坐标是 118.788434239726, 32.057578129300

fanvanzh commented 3 years ago

那你高德地图经纬度填写这个坐标试试呢? 118.788434239726, 32.057578129300

没用过 高德这个功能, 3dtile 里 b3dm 里是不涉及坐标系的, 只有 tileset.json/transform 和坐标有关

liaozd commented 2 years ago

问题最后怎么解决的?我们也有同样的3Dtile需要展示在高德地图上

yangchao2015 commented 2 years ago

您好,您的邮件已收到,谢谢!

ibandeng commented 1 year ago

你好,麻烦问下,倾斜摄影OSGB是基于CGCS2000的,如何转换成GCJ02 的3dtiles

你好,请问问题最后怎么解决的?

yangchao2015 commented 1 year ago

您好,您的邮件已收到,谢谢!

lianzhao commented 1 year ago

谈一些我的经验,抛砖引玉。我经历了两套b3dm要转为gcj-02坐标系。

(PS,我的b3dm文件不是通过本项目生成的,而是从别的软件导出的。所以如果是跟本项目相关的特定问题,那下面的描述帮不到您)

Case 1

这套文件,有多个树状结构的tileset.json,每个文件有两种方式决定对应模型所在的位置

Case 1.1

有些文件通过boundingVolume.box来决定,结构为

"boundingVolume": {
  "box": [
    0,   0,   10,
    100, 0,   0,
    0,   100, 0,
    0,   0,   10
  ]
}

根据文档,前三个值就是中心点坐标。使用类似如下的代码来变更box前三个值

import { Ellipsoid } from '@math.gl/geospatial';

const updateBox = boundingVolume => {
  const center = Ellipsoid.WGS84.cartesianToCartographic(boundingVolume.box.slice(0, 3));
  const { lng, lat } = toGCJ02(center[0], center[1]);
  const transformed = Ellipsoid.WGS84.cartographicToCartesian([lng, lat, center[2]]);
  boundingVolume.box[0] = transformed[0];
  boundingVolume.box[1] = transformed[1];
  boundingVolume.box[2] = transformed[2];
}

Case 1.2

有些文件通过transform来决定相对父元素的transform。解决方法是:

Case 2

这是我拿到的另一套b3dm文件。这次关键的位置信息在b3dm文件的FeatureTable里,而非tileset.json中。使用类似如下的代码来变更b3dm文件

import { promises as fs } from "fs";
import path from "path";
import { Ellipsoid } from '@math.gl/geospatial';

const handleFile = async (file) => {
  const fullPath = path.resolve(file);
  const content = (await fs.readFile(fullPath));
  const jsonStart = 28; // 按照协议,feature table从28开始
  const jsonLength = content[12]; // 按照协议,这里是json的长度
  const jsonObj = JSON.parse(content.slice(jsonStart, jsonStart + jsonLength));
  const center = Ellipsoid.WGS84.cartesianToCartographic(jsonObj.RTC_CENTER);
  const { lng, lat } = toGCJ02(center[0], center[1]);
  const transformed = Ellipsoid.WGS84.cartographicToCartesian([lng, lat, center[2]]);
  const buffer = Buffer.alloc(jsonLength, 32); // 结果中需要保持jsonLength的长度不变,如果长度不足,用'32'填充(不知道为什么,但原数据就是这样)
  Buffer.from(`{"BATCH_LENGTH":1,"RTC_CENTER":[${transformed.map(val => val.toFixed(6)).join()}]}`).copy(buffer);
  for (let i = 0; i < jsonLength; i++) {
    content[jsonStart + i] = buffer[i];
  }
  await fs.writeFile(fullPath, content);
}

上述代码是处理一个b3dm文件的过程。你需要按照你的目录结构遍历所有b3dm文件。

fanvanzh commented 1 year ago

@lianzhao 需要您这样有分享精神的人

lianzhao commented 1 year ago

@lianzhao 需要您这样有分享精神的人

像您学习😁

顺便再分享下处理boundingVolume.region的方法,根据文档,region里的经纬度是“角度”,因此先把角度转化为经纬度,再转gcj-02,再转回角度就行了。处理一个tileset.json的代码大概是这样的

import { promises as fs } from "fs";
import path from "path";
import { degrees, radians } from '@math.gl/core';

const updateRegion = boundingVolume => {
  const [west, south, east, north, minHeight, maxHeight] = boundingVolume.region;
  const northWest = toGCJ02(degrees(west), degrees(north));
  const southEast = toGCJ02(degrees(east), degrees(south));
  boundingVolume.region[0] = radians(northWest.lng);
  boundingVolume.region[1] = radians(southEast.lat);
  boundingVolume.region[2] = radians(southEast.lng);
  boundingVolume.region[3] = radians(northWest.lat);
  // console.log(west, south, east, north);
  // console.log(boundingVolume.region.slice(0, 4));
}

const handleObject = obj => {
  updateRegion(obj.boundingVolume);
  obj.children?.forEach(handleObject);
}

const handleFile = async file => {
  const fullPath = path.resolve(file);
  const obj = JSON.parse(await fs.readFile(fullPath));
  handleObject(obj.root);
  await fs.writeFile(fullPath, JSON.stringify(obj));
};