|
@@ -0,0 +1,80 @@
|
|
|
+import proj4 from "proj4";
|
|
|
+
|
|
|
+// 屏幕点和真实点通用对象
|
|
|
+type Pos = [number, number, number];
|
|
|
+type Conversion = {
|
|
|
+ scale: number;
|
|
|
+ rotation: number;
|
|
|
+ translate: number[];
|
|
|
+ startAltitude: number[];
|
|
|
+ altitude: number;
|
|
|
+};
|
|
|
+
|
|
|
+// 获取角度
|
|
|
+const getAngle = (p1: Pos, p2: Pos) => Math.atan2(p2[0] - p1[0], p2[1] - p1[1]);
|
|
|
+// 获取长度
|
|
|
+const getLength = (p1: Pos, p2: Pos) =>
|
|
|
+ Math.sqrt(Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2));
|
|
|
+
|
|
|
+// 获取本地与魔卡托的映射关系
|
|
|
+const getConversion2D = ([p1, p2]: Pos[], [b1, b2]: Pos[]) => {
|
|
|
+ const rotation = getAngle(p1, p2) - getAngle(b1, b2);
|
|
|
+ const scale = getLength(b1, b2) / getLength(p1, p2);
|
|
|
+ const translate = [
|
|
|
+ b1[0] - scale * (p1[0] * Math.cos(rotation) - p1[1] * Math.sin(rotation)),
|
|
|
+ b1[1] - scale * (p1[0] * Math.sin(rotation) + p1[1] * Math.cos(rotation)),
|
|
|
+ ];
|
|
|
+ const altitude = (b2[2] - b1[2]) / (p2[2] - p1[2]);
|
|
|
+ const startAltitude = [p1[2], b1[2]];
|
|
|
+
|
|
|
+ return {
|
|
|
+ rotation,
|
|
|
+ scale,
|
|
|
+ translate,
|
|
|
+ startAltitude,
|
|
|
+ altitude,
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+const transform = (point: Pos, cover: Conversion): Pos => {
|
|
|
+ const ctrla = cover.scale * Math.cos(cover.rotation);
|
|
|
+ const ctrlb = cover.scale * Math.sin(cover.rotation);
|
|
|
+ return [
|
|
|
+ ctrla * point[0] - ctrlb * point[1] + cover.translate[0],
|
|
|
+ ctrlb * point[0] + ctrla * point[1] + cover.translate[1],
|
|
|
+ cover.altitude * (point[2] - cover.startAltitude[0]) +
|
|
|
+ cover.startAltitude[1],
|
|
|
+ ];
|
|
|
+};
|
|
|
+
|
|
|
+const wCoordType = "EPSG:4326";
|
|
|
+const tCoordType = "EPSG:3857";
|
|
|
+
|
|
|
+proj4.defs(wCoordType, "+proj=longlat +ellps=GRS80 +no_defs");
|
|
|
+proj4.defs(
|
|
|
+ tCoordType,
|
|
|
+ "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crs"
|
|
|
+);
|
|
|
+
|
|
|
+// 传入本地坐标与控制点的关系
|
|
|
+export const conversionFactory = (locals: [Pos, Pos], gpss: [Pos, Pos]) => {
|
|
|
+ const maps = gpss.map((pos) => proj4(wCoordType, tCoordType, pos));
|
|
|
+ const coverLocalToWeb = getConversion2D(locals, maps);
|
|
|
+ const coverWebToLocal = getConversion2D(maps, locals);
|
|
|
+
|
|
|
+ return {
|
|
|
+ toLocal(pos: Pos): Pos {
|
|
|
+ const tPos = transform(
|
|
|
+ proj4(wCoordType, tCoordType, [...pos]),
|
|
|
+ coverWebToLocal
|
|
|
+ );
|
|
|
+ return tPos;
|
|
|
+ },
|
|
|
+ toWGS84(pos: Pos): Pos {
|
|
|
+ const tPos = transform(pos, coverLocalToWeb);
|
|
|
+ const wPos = proj4(tCoordType, wCoordType, [...tPos]);
|
|
|
+
|
|
|
+ return [wPos[0], wPos[1], tPos[2]];
|
|
|
+ },
|
|
|
+ };
|
|
|
+};
|