three-tile
three-tile copied to clipboard
【插件】增加了单个 tif dem 地形数据 loader
发现 fork 提不上来,补充在这里,给用需要的人(用于局部地形加载)
需要先安装两个库 geotiff 用以解析 tif dem数据,geotiff-tile 这个库是前者的补丁,用以处理经纬度范围裁剪数据,这个库的 ts 类型声明有 bug,有需要的可以自己下载重新编译,也可以 @ts-ignore
plugin
|-singleTifDEMLoader
|--index.ts
|--TifDEMLoader.ts
|--TifDEMSource.ts
index.ts
export * from "./TifDEMLoader";
export * from "./TifDEMSource";
import { registerDEMLoader } from "../..";
import { TifDEMLoder } from "./TifDEMLoader";
registerDEMLoader(new TifDEMLoder());
TifDEMSource.ts
import { TileSource } from "../..";
export class TifDemSource extends TileSource {
public dataType = "tif-dem";
public data?: any;
public author= "c3d"
}
TifDEMLoader.ts
import { BufferGeometry } from "three";
import { ITileGeometryLoader, TileSourceLoadParamsType, ISource, TileGeometry, ITileLoaderInfo} from '../..'
import { fromUrl } from 'geotiff'
// @ts-ignore 由于 geotiff-tile 包的类型声明问题,暂时忽略类型检查
import createTile from "geotiff-tile";
const EarthRad = 6378.137;
export class TifDEMLoder implements ITileGeometryLoader {
public dataType: string = "tif-dem";
public name: string = "tif loader";
public author?: string = 'chaoxl';
public lon0: number = 0;
public info: ITileLoaderInfo = { version: '0.0.1' };
public mapWidth = 2 * Math.PI * EarthRad; //E-W scacle Earth's circumference(km)
public mapHeight = this.mapWidth; //S-N scacle Earth's circumference(km)
public mapDepth = 1; //Height scale
public tiffData: any = null;
async load(params: TileSourceLoadParamsType<ISource & { url: string }>): Promise<BufferGeometry> {
const { source: _source, x: _x, y: _y, z: _z,} = params;
if( !this.tiffData ) await this.getTiffData(_source.url)
const tilebounds = this.getLonLatBoundsFromXYZ(_x, _y, _z);
const tileOpts: any = {
geotiff: this.tiffData,
bbox: tilebounds,
method: "bilinear",
tile_height: 20,
tile_width: 20
};
const { tile } = await createTile(tileOpts);
const geometry = new TileGeometry()
geometry.setData(new Float32Array( tile[0].map((i: any) => i ? i : null ) ))
return geometry
}
public async getTiffData(url: string) {
this.tiffData = await fromUrl(url)
}
public getProjBoundsFromXYZ(x: number, y: number, z: number): [number, number, number, number] {
const p1 = this.getTileXYZproj(x, y, z);
const p2 = this.getTileXYZproj(x + 1, y + 1, z);
return [Math.min(p1.x, p2.x), Math.min(p1.y, p2.y), Math.max(p1.x, p2.x), Math.max(p1.y, p2.y)];
}
public getLonLatBoundsFromXYZ(x: number, y: number, z: number): [number, number, number, number] {
const projectBounds = this.getProjBoundsFromXYZ(x, y, z);
const p1 = this.unProject(projectBounds[0], projectBounds[1]);
const p2 = this.unProject(projectBounds[2], projectBounds[3]);
return [p1.lon, p1.lat, p2.lon, p2.lat];
}
public unProject(x: number, y: number) {
let lon = (x / EarthRad) * (180 / Math.PI) + this.lon0; // 考虑中心经度偏移
if (lon > 180) lon -= 360;
const latRad = 2 * Math.atan(Math.exp(y / EarthRad)) - Math.PI / 2;
const lat = latRad * (180 / Math.PI);
return { lat, lon };
}
public getTileXYZproj(x: number, y: number, z: number): { x: number, y: number } {
const w = this.mapWidth;
const h = this.mapHeight / 2;
const px = (x / Math.pow(2, z)) * w - w / 2;
const py = h - (y / Math.pow(2, z)) * h * 2;
return { x: px, y: py };
}
}
非常好,下一版合并进项目!!!