/* eslint-disable no-unused-vars */
/**
* 距离(米)转换为经度 一米对应的经度与所在有关纬度
* @param meter 距离
* @param lat 所在纬度
* @returns {number}
*/
export const meter2Lng = (meter, lat) => {
let pi = Math.PI;
let latInMeter = (Math.cos((lat * pi) / 180) * 6371 * 2 * pi) / 360;
return meter / latInMeter / 1000;
};
/**
* 距离(米)转换为纬度 一米对应的纬度为定值
* @param meter 距离多少米
* @returns {number}
*/
export const meter2Lat = (meter) => {
let pi = Math.PI;
let lngInMeter = (6371 * 2 * pi) / 360;
return meter / lngInMeter / 1000;
};
/**
* 判断该点是否是经纬度或者笛卡尔坐标
* @param point
*/
export const isDegreesOrCartesian = (point) => {
if (!point) {
throw "参数错误!";
}
if (
"number" === typeof point.x &&
"number" === typeof point.y &&
"number" === typeof point.z
) {
return true;
}
if ("number" === typeof point.lng && "number" === typeof point.lat) {
return true;
}
return false;
};
/**
* 笛卡尔坐标转WGS84
* @param Cartesian3 单个点或点数组
*/
export const Cartesian3ToWGS84 = ({ Cesium, viewer }, Cartesian3) => {
if (!Cesium || !viewer) {
return;
}
if (!Cartesian3 || !Cartesian3.x) {
throw "Error in parameters";
}
let _cartesian3 = new Cesium.Cartesian3(
Cartesian3.x,
Cartesian3.y,
Cartesian3.z
);
let _cartographic = Cesium.Cartographic.fromCartesian(_cartesian3);
let _lat = Cesium.Math.toDegrees(_cartographic.latitude);
let _lng = Cesium.Math.toDegrees(_cartographic.longitude);
let _alt = _cartographic.height;
return { lng: _lng, lat: _lat, alt: _alt };
};
/**
* 世界坐标系转屏幕坐标
* @param point
* @param viewer
*/
export const toWindowCoordinates = ({ Cesium, viewer }, point) => {
if (!Cesium || !viewer) {
return;
}
if (viewer && point && point.x && point.y && point.z) {
return Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, point);
} else if (viewer && point.lng && point.lat && point.alt) {
return Cesium.SceneTransforms.wgs84ToWindowCoordinates(
viewer.scene,
toCartesianFromDegrees({ Cesium, viewer }, point)
);
} else {
throw "参数错误!";
}
};
/**
* 笛卡尔坐标转世界坐标
* @param point
*/
export const toDegreesFromCartesian = ({ Cesium, viewer }, point) => {
if (!Cesium || !viewer) {
return;
}
if (point.x && point.y && point.z) {
let cartesian33 = new Cesium.Cartesian3(point.x, point.y, point.z);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian33);
return {
lng: parseFloat(
Cesium.Math.toDegrees(cartographic.longitude).toFixed(10)
),
lat: parseFloat(Cesium.Math.toDegrees(cartographic.latitude).toFixed(10)),
alt: parseFloat(cartographic.height.toFixed(5)),
};
} else {
throw "参数错误!";
}
};
/**
* 世界坐标转笛卡尔坐标
* @param point
*/
export const toCartesianFromDegrees = ({ Cesium, viewer }, point) => {
if (!Cesium || !viewer) {
return;
}
if (point.lng && point.lat) {
return Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.alt || 0);
} else {
throw "参数错误!";
}
};
/**
* 转化成经纬度
* @param point
*/
export const toDegrees = ({ Cesium, viewer }, point) => {
if (!Cesium || !viewer) {
return;
}
if (isDegreesOrCartesian(point)) {
if (point.x && point.y && point.z) {
point = toDegreesFromCartesian({ Cesium, viewer }, point);
}
return point;
} else {
throw "参数错误!";
}
};
/**
* 转化成笛卡尔坐标
* @param point
*/
export const toCartesian = ({ Cesium, viewer }, point) => {
if (!Cesium || !viewer) {
return;
}
if (isDegreesOrCartesian(point)) {
if (point.lng && point.lat) {
point = toCartesianFromDegrees({ Cesium, viewer }, point);
}
return point;
} else {
throw "参数错误!";
}
};
/**
* tile 保留range区域
* @param {*} range 多边形区域
* @param {*} model 操作的模型
* @returns
*/
export const tileClippingPlanes = ({ Cesium, viewer }, range, model) => {
if (!range || !model || range.length < 4) {
return;
}
function getInverseTransform(tileSet) {
let transform = undefined;
let tmp = tileSet.root.transform;
if ((tmp && tmp.equals(Cesium.Matrix4.IDENTITY)) || !tmp) {
// 如果root.transform不存在,则3DTiles的原点变成了boundingSphere.center
transform = Cesium.Transforms.eastNorthUpToFixedFrame(
tileSet.boundingSphere.center
);
} else {
transform = Cesium.Matrix4.fromArray(tileSet.root.transform);
}
return Cesium.Matrix4.inverseTransformation(
transform,
new Cesium.Matrix4()
);
}
function getOriginCoordinateSystemPoint(point, inverseTransform) {
return Cesium.Matrix4.multiplyByPoint(
inverseTransform,
point,
new Cesium.Cartesian3()
);
}
function createPlane(p1, p2, inverseTransform) {
let p1C3 = getOriginCoordinateSystemPoint(p1, inverseTransform);
let p2C3 = getOriginCoordinateSystemPoint(p2, inverseTransform);
// 定义一个垂直向上的向量up
let up = new Cesium.Cartesian3(0, 0, 10);
// right 实际上就是由p1指向p2的向量
let right = Cesium.Cartesian3.subtract(p2C3, p1C3, new Cesium.Cartesian3());
// 计算normal, right叉乘up,得到平面法向量,这个法向量指向right的右侧
let normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3());
normal = Cesium.Cartesian3.normalize(normal, normal);
//由于已经获得了法向量和过平面的一点,因此可以直接构造Plane,并进一步构造ClippingPlane
let planeTmp = Cesium.Plane.fromPointNormal(p2C3, normal);
return Cesium.ClippingPlane.fromPlane(planeTmp);
}
let inverseTransform;
if (model) {
inverseTransform = getInverseTransform(model);
} else {
inverseTransform = Cesium.Matrix4.IDENTITY;
}
// let inverseTransform = getInverseTransform(model);
let clippingPlanes = [];
//判断是顺时针还是逆时针多边形 顺时针为负值 逆时针为正值
let temp =
(range[1].x - range[0].x) * (range[2].y - range[0].y) -
(range[1].y - range[0].y) * (range[2].x - range[0].x);
let rangeLength = range.length;
for (let i = 0; i < range.length; i++) {
let nextIndex;
if (temp <= 0) {
nextIndex = (i + 1) % rangeLength;
} else {
if (i === 0) {
nextIndex = rangeLength - 1;
} else {
nextIndex = i - 1;
}
}
clippingPlanes.push(
createPlane(range[i], range[nextIndex], inverseTransform)
);
}
return new Cesium.ClippingPlaneCollection({
planes: clippingPlanes,
unionClippingRegions: true,
edgeWidth: 0.4,
edgeColor: Cesium.Color.RED.withAlpha(0.1),
enabled: true,
});
};
/**
* tile或者globe 扣一个洞
* @param {*} points 多边形区域
* @param {*} primitive 需要挖洞的模型或者地球
* @returns
*/
export const getClippingPlanes = ({ Cesium, viewer }, points, primitive) => {
let modelMatrix = null;
if (primitive) {
modelMatrix = getInverseTransform(primitive);
} else {
modelMatrix = Cesium.Matrix4.IDENTITY;
}
function getInverseTransform(tileSet) {
let transform = undefined;
let tmp = tileSet.root.transform;
if ((tmp && tmp.equals(Cesium.Matrix4.IDENTITY)) || !tmp) {
// 如果root.transform不存在,则3DTiles的原点变成了boundingSphere.center
transform = Cesium.Transforms.eastNorthUpToFixedFrame(
tileSet.boundingSphere.center
);
} else {
transform = Cesium.Matrix4.fromArray(tileSet.root.transform);
}
return Cesium.Matrix4.inverseTransformation(
transform,
new Cesium.Matrix4()
);
}
let pointsLength = points.length;
let clippingPlanes = []; // 存储ClippingPlane集合
//判断是顺时针还是逆时针多边形 顺时针为负值 逆时针为正值
let temp =
(points[1].x - points[0].x) * (points[2].y - points[0].y) -
(points[1].y - points[0].y) * (points[2].x - points[0].x);
for (let i = 0; i < pointsLength; i++) {
let nextIndex;
if (temp > 0) {
nextIndex = (i + 1) % pointsLength;
} else {
if (i === 0) {
nextIndex = pointsLength - 1;
} else {
nextIndex = i - 1;
}
}
let midpoint = Cesium.Cartesian3.add(
points[i],
points[nextIndex],
new Cesium.Cartesian3()
);
midpoint = Cesium.Cartesian3.multiplyByScalar(midpoint, 0.5, midpoint);
let up = Cesium.Cartesian3.normalize(midpoint, new Cesium.Cartesian3());
let right = Cesium.Cartesian3.subtract(
points[nextIndex],
midpoint,
new Cesium.Cartesian3()
);
right = Cesium.Cartesian3.normalize(right, right);
let normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3());
normal = Cesium.Cartesian3.normalize(normal, normal);
let originCenteredPlane = new Cesium.Plane(normal, 0.0);
let distance = Cesium.Plane.getPointDistance(originCenteredPlane, midpoint);
clippingPlanes.push(new Cesium.ClippingPlane(normal, distance));
}
return new Cesium.ClippingPlaneCollection({
modelMatrix: modelMatrix,
planes: clippingPlanes,
// unionClippingRegions: true,
edgeWidth: 0.4,
edgeColor: Cesium.Color.RED.withAlpha(0.1),
enabled: true,
});
};
/**
* 获取两点之间的距离
* @param p1
* @param p2
* @returns {*}
*/
export const getDistance = ({ Cesium, viewer }, p1, p2) => {
p1 = toCartesian({ Cesium, viewer }, p1);
p2 = toCartesian({ Cesium, viewer }, p2);
return Math.sqrt(
Math.pow(p1.x - p2.x, 2) +
Math.pow(p1.y - p2.y, 2) +
Math.pow(p1.z - p2.z, 2)
);
};
/**
* 点到线段的最短距离
* @param a 线段上一点
* @param b 线段上另一个点
* @param s 该点到ab的最短距离
* @returns {number}
*/
export const point2LineMinDistance = ({ Cesium, viewer }, a, b, s) => {
a = toCartesian({ Cesium, viewer }, a);
b = toCartesian({ Cesium, viewer }, b);
s = toCartesian({ Cesium, viewer }, s);
let ab = Math.sqrt(
Math.pow(a.x - b.x, 2.0) +
Math.pow(a.y - b.y, 2.0) +
Math.pow(a.z - b.z, 2.0)
);
let as = Math.sqrt(
Math.pow(a.x - s.x, 2.0) +
Math.pow(a.y - s.y, 2.0) +
Math.pow(a.z - s.z, 2.0)
);
let bs = Math.sqrt(
Math.pow(s.x - b.x, 2.0) +
Math.pow(s.y - b.y, 2.0) +
Math.pow(s.z - b.z, 2.0)
);
let cos_A =
(Math.pow(as, 2.0) + Math.pow(ab, 2.0) - Math.pow(bs, 2.0)) / (2 * ab * as);
let sin_A = Math.sqrt(1 - Math.pow(cos_A, 2.0));
let t =
((a.x - s.x) * (a.x - b.x) +
(a.y - s.y) * (a.y - b.y) +
(a.z - s.z) * (a.z - b.z)) /
(Math.pow(a.x - b.x, 2.0) +
Math.pow(a.y - b.y, 2.0) +
Math.pow(a.z - b.z, 2.0));
if (t < 0) {
return as;
} else if (t <= 1 && t >= 0) {
return as * sin_A;
} else if (t > 1) {
return bs;
}
};
/**
* 求三角形面积;返回-1为不能组成三角形;
* @param a
* @param b
* @param c
* @returns {*}
*/
export const countTriangleArea = ({ Cesium, viewer }, a, b, c) => {
a = toCartesian({ Cesium, viewer }, a);
b = toCartesian({ Cesium, viewer }, b);
c = toCartesian({ Cesium, viewer }, c);
let area = -1;
let side = []; //存储三条边的长度;
side[0] = Math.sqrt(
Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2) + Math.pow(a.z - b.z, 2)
);
side[1] = Math.sqrt(
Math.pow(a.x - c.x, 2) + Math.pow(a.y - c.y, 2) + Math.pow(a.z - c.z, 2)
);
side[2] = Math.sqrt(
Math.pow(c.x - b.x, 2) + Math.pow(c.y - b.y, 2) + Math.pow(c.z - b.z, 2)
);
//不能构成三角形;
if (
side[0] + side[1] <= side[2] ||
side[0] + side[2] <= side[1] ||
side[1] + side[2] <= side[0]
) {
return area;
}
//利用海伦公式。area =sqr(p*(p-a)(p-b)(p-c));
let p = (side[0] + side[1] + side[2]) / 2; //半周长;
area = Math.sqrt(p * (p - side[0]) * (p - side[1]) * (p - side[2]));
return area;
};
/**
* 获取多边形的中心(根据经纬度,不包括高程)
* @param path 数组 [{lng:123,lat:32},...]
* @returns {{lng: number, lat: number}}
*/
export const getPolygonCenterByDegree = (path) => {
if (!path || path.length < 3 || !path[0].lng) {
throw "Error in parameters";
}
let x = 0.0;
let y = 0.0;
for (let i = 0; i < path.length; i++) {
x = x + parseFloat(path[i].lng);
y = y + parseFloat(path[i].lat);
}
x = x / path.length;
y = y / path.length;
return {
lng: x,
lat: y,
};
};
/**
* 求多边形的面积
* @param arr
* @returns {*}
*/
export const countArea = ({ Cesium, viewer }, arr) => {
if (!arr || arr.length < 3) {
throw "参数错误!";
} else {
let area = 0;
for (let i = 0; i < arr.length; i++) {
let j = (i + 1) % arr.length;
let p1 = arr[i],
p2 = arr[j];
p1 = toCartesian({ Cesium, viewer }, p1);
p2 = toCartesian({ Cesium, viewer }, p2);
area += p1.x * p2.y;
area -= p1.y * p2.x;
}
area /= 2;
return Math.abs(area);
}
};
Cesium 坐标转换、模型裁剪、面积计算
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- Unity3D - Shader - 模型、世界、观察、裁剪空间坐标转换 一个顶点要经过多个坐标空间的转换才能够被...
- 1. Cesium中的常用坐标系(Transform) Cesium的坐标系统,可以认为在常用的三维坐标系统上,增...
- 之前整理过:《透析矩阵,由浅入深娓娓道来—高数-线性代数-矩阵》、《三维旋转笔记:欧拉角/四元数/旋转矩阵/轴角-...