easy-three-utils 0.0.346 → 0.0.348
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cesium/index.ts +10 -2
- package/cesium/utils/index.ts +2 -0
- package/cesium/utils/lib/CreatePolygonOnGround.js +195 -0
- package/cesium/utils/lib/ReminderTip.js +71 -0
- package/cesium/utils/useCustomCollection.ts +14 -1
- package/cesium/utils/useMeasure.ts +531 -15
- package/cesium/utils/useSlope.ts +300 -0
- package/package.json +1 -1
package/cesium/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ type TCesiumUtilsType = {
|
|
|
13
13
|
clipping: ReturnType<typeof hooks.useClipping>;
|
|
14
14
|
weather: ReturnType<typeof hooks.useWeather>;
|
|
15
15
|
measure: ReturnType<typeof hooks.useMeasure>;
|
|
16
|
+
slope: ReturnType<typeof hooks.useSlope>;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
let config;
|
|
@@ -87,7 +88,13 @@ const useCesium = () => {
|
|
|
87
88
|
const clipping = hooks.useClipping(viewer)
|
|
88
89
|
const weather = hooks.useWeather(viewer)
|
|
89
90
|
const measure = hooks.useMeasure(viewer, {
|
|
90
|
-
distanceCollection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.MEASURE_DISTANCE)
|
|
91
|
+
distanceCollection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.MEASURE_DISTANCE),
|
|
92
|
+
heightCollection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.MEASURE_HEIGHT),
|
|
93
|
+
areaCollection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.MEASURE_AREA),
|
|
94
|
+
altitudeCollection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.MEASURE_ALTITUDE)
|
|
95
|
+
})
|
|
96
|
+
const slope = hooks.useSlope(viewer, {
|
|
97
|
+
collection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.SLOPE)
|
|
91
98
|
})
|
|
92
99
|
|
|
93
100
|
if (config.controllerStyle === cesiumConfigDict.EControllerStyle.THREE) {
|
|
@@ -100,7 +107,8 @@ const useCesium = () => {
|
|
|
100
107
|
drawPolygon,
|
|
101
108
|
clipping,
|
|
102
109
|
weather,
|
|
103
|
-
measure
|
|
110
|
+
measure,
|
|
111
|
+
slope
|
|
104
112
|
})
|
|
105
113
|
|
|
106
114
|
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
package/cesium/utils/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { useDrawPolygon } from './useDrawPolygon'
|
|
|
3
3
|
import { useClipping } from './useClipping'
|
|
4
4
|
import { useWeather, EWeatherType } from './useWeather'
|
|
5
5
|
import { useMeasure } from './useMeasure'
|
|
6
|
+
import { useSlope } from './useSlope'
|
|
6
7
|
|
|
7
8
|
const dict = {
|
|
8
9
|
ECollectionWhiteListNames,
|
|
@@ -15,6 +16,7 @@ export {
|
|
|
15
16
|
useClipping,
|
|
16
17
|
useWeather,
|
|
17
18
|
useMeasure,
|
|
19
|
+
useSlope,
|
|
18
20
|
|
|
19
21
|
dict
|
|
20
22
|
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// import CreateRemindertip from "./ReminderTip";
|
|
2
|
+
import * as Cesium from 'cesium'
|
|
3
|
+
|
|
4
|
+
const CreatePolygonOnGround = function ({ viewer, collection }, resultList, options, callback, cb) {
|
|
5
|
+
if (!viewer) throw new Error("no viewer object!");
|
|
6
|
+
options = options || {};
|
|
7
|
+
let id = options.id || setSessionid(); //Polygon的id
|
|
8
|
+
if (collection.entities.getById(id))
|
|
9
|
+
throw new Error("the id parameter is an unique value");
|
|
10
|
+
let color = options.color || Cesium.Color.RED; //Polygon的填充色
|
|
11
|
+
let outlineColor = options.outlineColor || color.withAlpha(1); //Polygon的轮廓线颜色
|
|
12
|
+
let outlineWidth = options.outlineWidth || 2; //Polygon的轮廓线宽度
|
|
13
|
+
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
|
|
14
|
+
cb && cb(handler)
|
|
15
|
+
let toolTip = "左键点击开始绘制";
|
|
16
|
+
let anchorpoints = [];
|
|
17
|
+
let polygon = undefined;
|
|
18
|
+
let drawStatus = true;
|
|
19
|
+
handler.setInputAction(function (event) {
|
|
20
|
+
let pixPos = event.position;
|
|
21
|
+
let cartesian = getCatesian3FromPX(viewer, pixPos);
|
|
22
|
+
if (anchorpoints.length == 0) {
|
|
23
|
+
toolTip = "左键添加第二个点";
|
|
24
|
+
anchorpoints.push(cartesian);
|
|
25
|
+
let linePoints = new Cesium.CallbackProperty(function () {
|
|
26
|
+
let verPoints = anchorpoints.concat([anchorpoints[0]]);
|
|
27
|
+
return verPoints;
|
|
28
|
+
}, false);
|
|
29
|
+
let dynamicPositions = new Cesium.CallbackProperty(function () {
|
|
30
|
+
return new Cesium.PolygonHierarchy(anchorpoints);
|
|
31
|
+
}, false);
|
|
32
|
+
polygon = collection.entities.add({
|
|
33
|
+
name: "Polygon",
|
|
34
|
+
id: id,
|
|
35
|
+
polyline: {
|
|
36
|
+
positions: linePoints,
|
|
37
|
+
width: outlineWidth,
|
|
38
|
+
material: outlineColor,
|
|
39
|
+
clampToGround: true,
|
|
40
|
+
},
|
|
41
|
+
polygon: {
|
|
42
|
+
heightReference: Cesium.HeightReference.None,
|
|
43
|
+
hierarchy: dynamicPositions,
|
|
44
|
+
material: color,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
polygon.GeoType = "Polygon";
|
|
48
|
+
} else {
|
|
49
|
+
toolTip = "左键添加点,Ctrl+Z回退,右键完成绘制";
|
|
50
|
+
}
|
|
51
|
+
anchorpoints.push(cartesian);
|
|
52
|
+
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
|
53
|
+
|
|
54
|
+
handler.setInputAction(function (movement) {
|
|
55
|
+
let endPos = movement.endPosition;
|
|
56
|
+
// CreateRemindertip(toolTip, endPos, true);
|
|
57
|
+
if (Cesium.defined(polygon)) {
|
|
58
|
+
anchorpoints.pop();
|
|
59
|
+
let cartesian = getCatesian3FromPX(viewer, endPos);
|
|
60
|
+
anchorpoints.push(cartesian);
|
|
61
|
+
}
|
|
62
|
+
if (anchorpoints.length === 3) {
|
|
63
|
+
polygon.polygon.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
|
|
64
|
+
}
|
|
65
|
+
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
|
66
|
+
|
|
67
|
+
handler.setInputAction(function (event) {
|
|
68
|
+
anchorpoints.pop();
|
|
69
|
+
polygon.pottingPoint = anchorpoints;
|
|
70
|
+
resultList.push(polygon);
|
|
71
|
+
handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_DOWN)
|
|
72
|
+
handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
73
|
+
handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
74
|
+
handler.destroy();
|
|
75
|
+
handler = null
|
|
76
|
+
// CreateRemindertip(toolTip, event.position, false);
|
|
77
|
+
drawStatus = false;
|
|
78
|
+
if (typeof callback == "function") callback(polygon);
|
|
79
|
+
}, Cesium.ScreenSpaceEventType.RIGHT_DOWN);
|
|
80
|
+
|
|
81
|
+
//Ctrl + Z回退
|
|
82
|
+
document.onkeydown = function (event) {
|
|
83
|
+
if (event.ctrlKey && window.event.keyCode == 90) {
|
|
84
|
+
if (!drawStatus) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
anchorpoints.pop();
|
|
88
|
+
if (anchorpoints.length == 2) {
|
|
89
|
+
toolTip = "左键添加第二个点";
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
function getCatesian3FromPX(viewer, px) {
|
|
95
|
+
let picks = viewer.scene.drillPick(px);
|
|
96
|
+
let cartesian = null;
|
|
97
|
+
let isOn3dtiles = false,
|
|
98
|
+
isOnTerrain = false;
|
|
99
|
+
// drillPick
|
|
100
|
+
for (let i in picks) {
|
|
101
|
+
let pick = picks[i];
|
|
102
|
+
if (
|
|
103
|
+
(pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) ||
|
|
104
|
+
(pick && pick.primitive instanceof Cesium.Cesium3DTileset) ||
|
|
105
|
+
(pick && pick.primitive instanceof Cesium.Model)
|
|
106
|
+
) {
|
|
107
|
+
//模型上拾取
|
|
108
|
+
isOn3dtiles = true;
|
|
109
|
+
}
|
|
110
|
+
// 3dtilset
|
|
111
|
+
if (isOn3dtiles) {
|
|
112
|
+
viewer.scene.pick(px);
|
|
113
|
+
cartesian = viewer.scene.pickPosition(px);
|
|
114
|
+
if (cartesian) {
|
|
115
|
+
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
|
|
116
|
+
if (cartographic.height < 0) cartographic.height = 0;
|
|
117
|
+
let lon = Cesium.Math.toDegrees(cartographic.longitude),
|
|
118
|
+
lat = Cesium.Math.toDegrees(cartographic.latitude),
|
|
119
|
+
height = cartographic.height;
|
|
120
|
+
cartesian = transformWGS84ToCartesian(viewer, {
|
|
121
|
+
lng: lon,
|
|
122
|
+
lat: lat,
|
|
123
|
+
alt: height,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// 地形
|
|
129
|
+
let boolTerrain =
|
|
130
|
+
viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider;
|
|
131
|
+
// Terrain
|
|
132
|
+
if (!isOn3dtiles && !boolTerrain) {
|
|
133
|
+
let ray = viewer.scene.camera.getPickRay(px);
|
|
134
|
+
if (!ray) return null;
|
|
135
|
+
cartesian = viewer.scene.globe.pick(ray, viewer.scene);
|
|
136
|
+
isOnTerrain = true;
|
|
137
|
+
}
|
|
138
|
+
// 地球
|
|
139
|
+
if (!isOn3dtiles && !isOnTerrain && boolTerrain) {
|
|
140
|
+
cartesian = viewer.scene.camera.pickEllipsoid(
|
|
141
|
+
px,
|
|
142
|
+
viewer.scene.globe.ellipsoid
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
if (cartesian) {
|
|
146
|
+
let position = transformCartesianToWGS84(viewer, cartesian);
|
|
147
|
+
if (position.alt < 0) {
|
|
148
|
+
cartesian = transformWGS84ToCartesian(viewer, position, 0.1);
|
|
149
|
+
}
|
|
150
|
+
return cartesian;
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/***
|
|
156
|
+
* 坐标转换 84转笛卡尔
|
|
157
|
+
* @param {Object} {lng,lat,alt} 地理坐标
|
|
158
|
+
* @return {Object} Cartesian3 三维位置坐标
|
|
159
|
+
*/
|
|
160
|
+
function transformWGS84ToCartesian(viewer, position, alt) {
|
|
161
|
+
return position
|
|
162
|
+
? Cesium.Cartesian3.fromDegrees(
|
|
163
|
+
position.lng || position.lon,
|
|
164
|
+
position.lat,
|
|
165
|
+
(position.alt = alt || position.alt),
|
|
166
|
+
Cesium.Ellipsoid.WGS84
|
|
167
|
+
)
|
|
168
|
+
: Cesium.Cartesian3.ZERO;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/***
|
|
172
|
+
* 坐标转换 笛卡尔转84
|
|
173
|
+
* @param {Object} Cartesian3 三维位置坐标
|
|
174
|
+
* @return {Object} {lng,lat,alt} 地理坐标
|
|
175
|
+
*/
|
|
176
|
+
function transformCartesianToWGS84(viewer, cartesian) {
|
|
177
|
+
let ellipsoid = Cesium.Ellipsoid.WGS84;
|
|
178
|
+
let cartographic = ellipsoid.cartesianToCartographic(cartesian);
|
|
179
|
+
return {
|
|
180
|
+
lng: Cesium.Math.toDegrees(cartographic.longitude),
|
|
181
|
+
lat: Cesium.Math.toDegrees(cartographic.latitude),
|
|
182
|
+
alt: cartographic.height,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function setSessionid(num) {
|
|
186
|
+
let len = num || 32;
|
|
187
|
+
let chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
|
|
188
|
+
let maxPos = chars.length;
|
|
189
|
+
let pwd = "";
|
|
190
|
+
for (let i = 0; i < len; i++) {
|
|
191
|
+
pwd += chars.charAt(Math.floor(Math.random() * maxPos));
|
|
192
|
+
}
|
|
193
|
+
return pwd;
|
|
194
|
+
}
|
|
195
|
+
export default CreatePolygonOnGround;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const CreateRemindertip = function (arr, position, show) {
|
|
2
|
+
let tooltip = document.getElementById("toolTip");
|
|
3
|
+
let style, _x, _y, _color;
|
|
4
|
+
if (arr && typeof arr === "object") {
|
|
5
|
+
style = arr;
|
|
6
|
+
}
|
|
7
|
+
if (style && style.origin) {
|
|
8
|
+
style.origin === "center" && ((_x = 15), (_y = -12));
|
|
9
|
+
style.origin === "top" && ((_x = 15), (_y = -44));
|
|
10
|
+
style.origin === "bottom" && ((_x = 15), (_y = 20));
|
|
11
|
+
} else {
|
|
12
|
+
(_x = 15), (_y = 20);
|
|
13
|
+
}
|
|
14
|
+
if (style && style.color) {
|
|
15
|
+
style.color === "white" &&
|
|
16
|
+
(_color = "background: rgba(255, 255, 255, 0.8);color: black;");
|
|
17
|
+
style.color === "black" &&
|
|
18
|
+
(_color = "background: rgba(0, 0, 0, 0.5);color: white;");
|
|
19
|
+
style.color === "yellow" &&
|
|
20
|
+
(_color =
|
|
21
|
+
"color: black;background-color: #ffcc33;border: 1px solid white;");
|
|
22
|
+
} else {
|
|
23
|
+
_color = "background: rgba(0, 0, 0, 0.5);color: white;";
|
|
24
|
+
}
|
|
25
|
+
if (!tooltip) {
|
|
26
|
+
const viewerDom = document.getElementsByClassName("cesium-viewer")[0];
|
|
27
|
+
let elementbottom = document.createElement("div");
|
|
28
|
+
viewerDom.append(elementbottom);
|
|
29
|
+
let html =
|
|
30
|
+
'<div id="toolTip" style="display: none;pointer-events: none;position: absolute;z-index: 1000;opacity: 0.8;border-radius: 4px;padding: 4px 8px;white-space: nowrap;font-family:黑体;color:white;font-weight: bolder;font-size: 14px;' +
|
|
31
|
+
_color +
|
|
32
|
+
'"></div>';
|
|
33
|
+
viewerDom.insertAdjacentHTML("beforeend", html);
|
|
34
|
+
tooltip = document.getElementById("toolTip");
|
|
35
|
+
}
|
|
36
|
+
if (show) {
|
|
37
|
+
tooltip.innerHTML = arr;
|
|
38
|
+
tooltip.style.left = position.x + _x + "px";
|
|
39
|
+
tooltip.style.top = position.y + _y + "px";
|
|
40
|
+
tooltip.style.display = "block";
|
|
41
|
+
} else {
|
|
42
|
+
tooltip.style.display = "none";
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
tooltip: tooltip,
|
|
46
|
+
style: style,
|
|
47
|
+
showAt: function (position, text) {
|
|
48
|
+
this.tooltip.innerHTML = text;
|
|
49
|
+
if (this.style && this.style.origin) {
|
|
50
|
+
this.style.origin === "center" &&
|
|
51
|
+
((_x = 15), (_y = -this.tooltip.offsetHeight / 2));
|
|
52
|
+
this.style.origin === "top" &&
|
|
53
|
+
((_x = 15), (_y = -this.tooltip.offsetHeight - 20));
|
|
54
|
+
this.style.origin === "bottom" && ((_x = 15), (_y = 20));
|
|
55
|
+
} else {
|
|
56
|
+
(_x = 15), (_y = -this.tooltip.offsetHeight / 2);
|
|
57
|
+
}
|
|
58
|
+
this.tooltip.style.left = position.x + _x + "px";
|
|
59
|
+
this.tooltip.style.top = position.y + _y + "px";
|
|
60
|
+
this.tooltip.style.display = "block";
|
|
61
|
+
},
|
|
62
|
+
show: function (show) {
|
|
63
|
+
if (show) {
|
|
64
|
+
this.tooltip.style.display = "block";
|
|
65
|
+
} else {
|
|
66
|
+
this.tooltip.style.display = "none";
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export default CreateRemindertip;
|
|
@@ -5,12 +5,25 @@ enum ECollectionWhiteListNames {
|
|
|
5
5
|
POLYGON = 'polygon',
|
|
6
6
|
|
|
7
7
|
MEASURE_DISTANCE = 'measure_distance',
|
|
8
|
+
MEASURE_HEIGHT = 'measure_height',
|
|
9
|
+
MEASURE_AREA = 'measure_area',
|
|
10
|
+
MEASURE_ALTITUDE = 'measure_altitude',
|
|
11
|
+
|
|
12
|
+
SLOPE = 'slope'
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
const useCustomCollection = (viewer: Cesium.Viewer) => {
|
|
11
16
|
|
|
12
17
|
let collectionNames: string[] = ([])
|
|
13
|
-
let whiteList: string[] = [
|
|
18
|
+
let whiteList: string[] = [
|
|
19
|
+
'polygon',
|
|
20
|
+
'polygon_node',
|
|
21
|
+
'measure_distance',
|
|
22
|
+
'measure_height',
|
|
23
|
+
'measure_area',
|
|
24
|
+
'measure_altitude',
|
|
25
|
+
'slope'
|
|
26
|
+
]
|
|
14
27
|
|
|
15
28
|
const addCollection = (name: string) => {
|
|
16
29
|
const index = collectionNames.findIndex(item => item === name)
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import * as Cesium from 'cesium'
|
|
2
|
+
import * as turf from "@turf/turf"
|
|
2
3
|
|
|
3
4
|
const useMeasure = (viewer: Cesium.Viewer, options: {
|
|
4
|
-
distanceCollection: Cesium.CustomDataSource
|
|
5
|
+
distanceCollection: Cesium.CustomDataSource,
|
|
6
|
+
heightCollection: Cesium.CustomDataSource,
|
|
7
|
+
areaCollection: Cesium.CustomDataSource,
|
|
8
|
+
altitudeCollection: Cesium.CustomDataSource
|
|
5
9
|
}) => {
|
|
6
10
|
|
|
7
|
-
const point = {
|
|
8
|
-
color: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
|
|
9
|
-
outlineColor: Cesium.Color.WHITE,
|
|
10
|
-
outlineWidth: 2,
|
|
11
|
-
pixelSize: 10,
|
|
12
|
-
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
|
13
|
-
}
|
|
14
|
-
|
|
15
11
|
const angleMeasurement = () => {
|
|
16
12
|
let anglePoints = []
|
|
17
13
|
let angleEntities = []
|
|
@@ -66,7 +62,7 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
|
|
|
66
62
|
}
|
|
67
63
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
68
64
|
|
|
69
|
-
angleMeasurementHandler.setInputAction(
|
|
65
|
+
angleMeasurementHandler.setInputAction((movement) => {
|
|
70
66
|
if (anglePoints.length > 0 && anglePoints.length < 3) {
|
|
71
67
|
const ray = viewer.camera.getPickRay(movement.endPosition)
|
|
72
68
|
const cartesian = viewer.scene.globe.pick(ray, viewer.scene)
|
|
@@ -112,7 +108,7 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
|
|
|
112
108
|
position: p2,
|
|
113
109
|
label: {
|
|
114
110
|
text: angleDeg.toFixed(2) + '°',
|
|
115
|
-
font: 'normal
|
|
111
|
+
font: 'normal 28px MicroSoft YaHei',
|
|
116
112
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
117
113
|
fillColor: Cesium.Color.WHITE,
|
|
118
114
|
verticalOrigin: Cesium.VerticalOrigin.CENTER,
|
|
@@ -154,11 +150,20 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
|
|
|
154
150
|
const distanceMeasurement = () => {
|
|
155
151
|
let positions = []
|
|
156
152
|
let tempPositions = []
|
|
153
|
+
let currentLineEntity: Cesium.Entity
|
|
157
154
|
let handler = null
|
|
158
155
|
|
|
156
|
+
const point = {
|
|
157
|
+
color: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
|
|
158
|
+
outlineColor: Cesium.Color.WHITE,
|
|
159
|
+
outlineWidth: 2,
|
|
160
|
+
pixelSize: 10,
|
|
161
|
+
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
|
162
|
+
}
|
|
163
|
+
|
|
159
164
|
const draw = () => {
|
|
160
165
|
if (handler) {
|
|
161
|
-
console.log('
|
|
166
|
+
console.log('请使用右键结束上次测量!')
|
|
162
167
|
return
|
|
163
168
|
}
|
|
164
169
|
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
@@ -168,6 +173,10 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
|
|
|
168
173
|
}
|
|
169
174
|
|
|
170
175
|
const stopDraw = () => {
|
|
176
|
+
if (currentLineEntity) {
|
|
177
|
+
options.distanceCollection.entities.remove(currentLineEntity)
|
|
178
|
+
}
|
|
179
|
+
|
|
171
180
|
if (handler) {
|
|
172
181
|
handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
173
182
|
handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
@@ -181,11 +190,12 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
|
|
|
181
190
|
}
|
|
182
191
|
|
|
183
192
|
const removeAll = () => {
|
|
193
|
+
stopDraw()
|
|
184
194
|
options.distanceCollection.entities.removeAll()
|
|
185
195
|
}
|
|
186
196
|
|
|
187
197
|
const createLine = () => {
|
|
188
|
-
options.distanceCollection.entities.add({
|
|
198
|
+
currentLineEntity = options.distanceCollection.entities.add({
|
|
189
199
|
polyline: {
|
|
190
200
|
positions: new Cesium.CallbackProperty(() => tempPositions, false),
|
|
191
201
|
material: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
|
|
@@ -232,7 +242,14 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
|
|
|
232
242
|
}
|
|
233
243
|
|
|
234
244
|
const leftClickEvent = () => {
|
|
245
|
+
let lastClickTime = 0
|
|
246
|
+
const MIN_INTERVAL = 250
|
|
247
|
+
|
|
235
248
|
handler.setInputAction(event => {
|
|
249
|
+
const now = Date.now()
|
|
250
|
+
if (now - lastClickTime < MIN_INTERVAL) return
|
|
251
|
+
lastClickTime = now
|
|
252
|
+
|
|
236
253
|
let position = viewer.scene.pickPosition(event.position)
|
|
237
254
|
if (!position)
|
|
238
255
|
position = viewer.scene.camera.pickEllipsoid(event.position, viewer.scene.globe.ellipsoid)
|
|
@@ -266,7 +283,7 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
|
|
|
266
283
|
|
|
267
284
|
const rightClickEvent = () => {
|
|
268
285
|
handler.setInputAction(() => {
|
|
269
|
-
if (positions.length
|
|
286
|
+
if (positions.length <= 1) {
|
|
270
287
|
removeAll()
|
|
271
288
|
stopDraw()
|
|
272
289
|
} else {
|
|
@@ -290,15 +307,514 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
|
|
|
290
307
|
}
|
|
291
308
|
|
|
292
309
|
const heightMeasurement = () => {
|
|
310
|
+
let positions = []
|
|
311
|
+
let currentLineEntity: Cesium.Entity
|
|
312
|
+
let currentPointEntities: Cesium.Entity[] = []
|
|
313
|
+
let currentLabelEntity: Cesium.Entity
|
|
314
|
+
let handler = null
|
|
315
|
+
|
|
316
|
+
const cartesian3Point3 = (pos) => {
|
|
317
|
+
const ellipsoid = viewer.scene.globe.ellipsoid
|
|
318
|
+
const cartographic = ellipsoid.cartesianToCartographic(pos)
|
|
319
|
+
return [
|
|
320
|
+
Cesium.Math.toDegrees(cartographic.longitude),
|
|
321
|
+
Cesium.Math.toDegrees(cartographic.latitude),
|
|
322
|
+
cartographic.height
|
|
323
|
+
]
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const draw = () => {
|
|
327
|
+
if (handler) {
|
|
328
|
+
console.log('请先结束上次测量!')
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
332
|
+
leftClickEvent()
|
|
333
|
+
mouseMoveEvent()
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const createLine = () => {
|
|
337
|
+
currentLineEntity = options.heightCollection.entities.add({
|
|
338
|
+
polyline: {
|
|
339
|
+
positions: new Cesium.CallbackProperty(() => positions, false),
|
|
340
|
+
width: 2,
|
|
341
|
+
material: Cesium.Color.fromCssColorString("rgb(249,157,11)")
|
|
342
|
+
}
|
|
343
|
+
})
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const createPoint = (index) => {
|
|
347
|
+
const entity = options.heightCollection.entities.add({
|
|
348
|
+
position: new Cesium.CallbackProperty(() => positions[index], false) as Cesium.CallbackPositionProperty,
|
|
349
|
+
point: {
|
|
350
|
+
color: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
|
|
351
|
+
outlineColor: Cesium.Color.WHITE,
|
|
352
|
+
outlineWidth: 2,
|
|
353
|
+
pixelSize: 10
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
currentPointEntities.push(entity)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const createLabel = () => {
|
|
361
|
+
currentLabelEntity = options.heightCollection.entities.add({
|
|
362
|
+
position: new Cesium.CallbackProperty(() => positions[1], false) as Cesium.CallbackPositionProperty,
|
|
363
|
+
label: {
|
|
364
|
+
text: "",
|
|
365
|
+
scale: 0.5,
|
|
366
|
+
font: "normal 28px MicroSoft YaHei",
|
|
367
|
+
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
368
|
+
pixelOffset: new Cesium.Cartesian2(0, -30),
|
|
369
|
+
outlineWidth: 9,
|
|
370
|
+
outlineColor: Cesium.Color.WHITE
|
|
371
|
+
}
|
|
372
|
+
})
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const leftClickEvent = () => {
|
|
376
|
+
let lastClickTime = 0
|
|
377
|
+
const MIN_INTERVAL = 250
|
|
378
|
+
|
|
379
|
+
handler.setInputAction(e => {
|
|
380
|
+
const now = Date.now()
|
|
381
|
+
if (now - lastClickTime < MIN_INTERVAL) return
|
|
382
|
+
lastClickTime = now
|
|
383
|
+
|
|
384
|
+
let position = viewer.scene.pickPosition(e.position)
|
|
385
|
+
if (!position) position = viewer.scene.camera.pickEllipsoid(e.position, viewer.scene.globe.ellipsoid)
|
|
386
|
+
if (!position) return
|
|
387
|
+
|
|
388
|
+
if (positions.length === 0) {
|
|
389
|
+
positions.push(position)
|
|
390
|
+
createPoint(0)
|
|
391
|
+
createLine()
|
|
392
|
+
createLabel()
|
|
393
|
+
} else if (positions.length > 2) {
|
|
394
|
+
options.heightCollection.entities.add({
|
|
395
|
+
polyline: {
|
|
396
|
+
positions: positions,
|
|
397
|
+
width: 2,
|
|
398
|
+
material: Cesium.Color.fromCssColorString("rgb(249,157,11)")
|
|
399
|
+
}
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
positions.forEach(pos => {
|
|
403
|
+
options.heightCollection.entities.add({
|
|
404
|
+
position: pos,
|
|
405
|
+
point: {
|
|
406
|
+
color: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
|
|
407
|
+
outlineColor: Cesium.Color.WHITE,
|
|
408
|
+
outlineWidth: 2,
|
|
409
|
+
pixelSize: 10
|
|
410
|
+
}
|
|
411
|
+
})
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
options.heightCollection.entities.add({
|
|
415
|
+
position: positions[1],
|
|
416
|
+
label: {
|
|
417
|
+
text: currentLabelEntity.label.text,
|
|
418
|
+
scale: 0.5,
|
|
419
|
+
font: "normal 28px MicroSoft YaHei",
|
|
420
|
+
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
421
|
+
pixelOffset: new Cesium.Cartesian2(0, -30),
|
|
422
|
+
outlineWidth: 9,
|
|
423
|
+
outlineColor: Cesium.Color.WHITE
|
|
424
|
+
}
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
stopDraw()
|
|
428
|
+
}
|
|
429
|
+
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const mouseMoveEvent = () => {
|
|
433
|
+
handler.setInputAction(e => {
|
|
434
|
+
let position = viewer.scene.pickPosition(e.endPosition)
|
|
435
|
+
if (!position) position = viewer.scene.camera.pickEllipsoid(e.startPosition, viewer.scene.globe.ellipsoid)
|
|
436
|
+
if (!position) return
|
|
437
|
+
|
|
438
|
+
handleMove(position)
|
|
439
|
+
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const handleMove = (position) => {
|
|
443
|
+
if (positions.length < 1) return
|
|
444
|
+
const first = cartesian3Point3(positions[0])
|
|
445
|
+
const move = cartesian3Point3(position)
|
|
446
|
+
|
|
447
|
+
const h = move[2] - first[2]
|
|
448
|
+
first[2] = move[2]
|
|
449
|
+
const twoPos = Cesium.Cartesian3.fromDegrees(first[0], first[1], move[2])
|
|
450
|
+
|
|
451
|
+
if (positions.length < 2) {
|
|
452
|
+
positions.push(twoPos, position)
|
|
453
|
+
createPoint(1)
|
|
454
|
+
createPoint(2)
|
|
455
|
+
} else {
|
|
456
|
+
positions[1] = twoPos
|
|
457
|
+
positions[2] = position
|
|
458
|
+
if (currentLabelEntity) {
|
|
459
|
+
(currentLabelEntity.label.text as any) = `高度:${h.toFixed(3)} 米`
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const stopDraw = () => {
|
|
465
|
+
if (handler) {
|
|
466
|
+
handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
467
|
+
handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
|
|
468
|
+
handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
469
|
+
handler.destroy()
|
|
470
|
+
handler = null
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (currentLineEntity) {
|
|
474
|
+
options.heightCollection.entities.remove(currentLineEntity)
|
|
475
|
+
currentLineEntity = null
|
|
476
|
+
}
|
|
477
|
+
if (currentLabelEntity) {
|
|
478
|
+
options.heightCollection.entities.remove(currentLabelEntity)
|
|
479
|
+
currentLabelEntity = null
|
|
480
|
+
}
|
|
481
|
+
if (currentPointEntities.length) {
|
|
482
|
+
currentPointEntities.forEach(entity => options.heightCollection.entities.remove(entity))
|
|
483
|
+
currentPointEntities = []
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
positions = []
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const removeAll = () => {
|
|
490
|
+
stopDraw()
|
|
491
|
+
options.heightCollection.entities.removeAll()
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return {
|
|
495
|
+
draw,
|
|
496
|
+
removeAll
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const areaMeasurement = () => {
|
|
501
|
+
let handler = null
|
|
502
|
+
let currentPolygonEntity = null
|
|
503
|
+
let currentLabelEntity = null
|
|
504
|
+
let positions = []
|
|
505
|
+
let tempPositions = []
|
|
506
|
+
let height = undefined
|
|
507
|
+
|
|
508
|
+
const draw = () => {
|
|
509
|
+
if (handler) {
|
|
510
|
+
console.log('请使用右键结束上次测量!')
|
|
511
|
+
return
|
|
512
|
+
}
|
|
513
|
+
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
514
|
+
leftClickEvent()
|
|
515
|
+
mouseMoveEvent()
|
|
516
|
+
rightClickEvent()
|
|
517
|
+
}
|
|
293
518
|
|
|
519
|
+
const stopDraw = () => {
|
|
520
|
+
if (handler) {
|
|
521
|
+
handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
|
|
522
|
+
handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
523
|
+
handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
524
|
+
handler.destroy()
|
|
525
|
+
handler = null
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
tempPositions = []
|
|
529
|
+
positions = []
|
|
530
|
+
currentPolygonEntity = null
|
|
531
|
+
currentLabelEntity = null
|
|
532
|
+
height = undefined
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const removeAll = () => {
|
|
536
|
+
stopDraw()
|
|
537
|
+
options.areaCollection.entities.removeAll()
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const createPolygon = () => {
|
|
541
|
+
currentPolygonEntity = options.areaCollection.entities.add({
|
|
542
|
+
polygon: {
|
|
543
|
+
hierarchy: new Cesium.CallbackProperty(() => {
|
|
544
|
+
return new Cesium.PolygonHierarchy(tempPositions)
|
|
545
|
+
}, false),
|
|
546
|
+
material: Cesium.Color.fromCssColorString("rgb(249, 157, 11,.6)")
|
|
547
|
+
},
|
|
548
|
+
polyline: {
|
|
549
|
+
clampToGround: true,
|
|
550
|
+
positions: new Cesium.CallbackProperty(() => {
|
|
551
|
+
return tempPositions.concat(tempPositions[0])
|
|
552
|
+
}, false),
|
|
553
|
+
width: 1,
|
|
554
|
+
material: new Cesium.PolylineOutlineMaterialProperty({
|
|
555
|
+
outlineWidth: 2,
|
|
556
|
+
outlineColor: Cesium.Color.WHITE
|
|
557
|
+
})
|
|
558
|
+
}
|
|
559
|
+
})
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const createPoint = () => {
|
|
563
|
+
options.areaCollection.entities.add({
|
|
564
|
+
position: positions[positions.length - 1],
|
|
565
|
+
point: {
|
|
566
|
+
color: Cesium.Color.fromCssColorString("rgb(249, 157, 11)"),
|
|
567
|
+
outlineColor: Cesium.Color.WHITE,
|
|
568
|
+
outlineWidth: 2,
|
|
569
|
+
pixelSize: 10,
|
|
570
|
+
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
|
571
|
+
}
|
|
572
|
+
})
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const createLabel = () => {
|
|
576
|
+
currentLabelEntity = options.areaCollection.entities.add({
|
|
577
|
+
position: new Cesium.CallbackProperty(() => getCenterPosition(), false) as Cesium.CallbackPositionProperty,
|
|
578
|
+
label: {
|
|
579
|
+
text: new Cesium.CallbackProperty(() => {
|
|
580
|
+
return "面积 " + computeArea(tempPositions)
|
|
581
|
+
}, false),
|
|
582
|
+
scale: 0.5,
|
|
583
|
+
font: "normal 28px MicroSoft YaHei",
|
|
584
|
+
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
585
|
+
pixelOffset: new Cesium.Cartesian2(0, -30),
|
|
586
|
+
outlineWidth: 9,
|
|
587
|
+
outlineColor: Cesium.Color.WHITE,
|
|
588
|
+
disableDepthTestDistance: Number.POSITIVE_INFINITY
|
|
589
|
+
}
|
|
590
|
+
})
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
const getCenterPosition = () => {
|
|
594
|
+
if (tempPositions.length < 3) return tempPositions[0]
|
|
595
|
+
const points = tempPositions.map(p => {
|
|
596
|
+
const c = cartesian3ToPoint3D(p)
|
|
597
|
+
return [c.x, c.y]
|
|
598
|
+
})
|
|
599
|
+
const geo = turf.lineString(points)
|
|
600
|
+
const bbox = turf.bbox(geo)
|
|
601
|
+
const bboxPolygon = turf.bboxPolygon(bbox)
|
|
602
|
+
const center = turf.center(bboxPolygon)
|
|
603
|
+
const [lon, lat] = center.geometry.coordinates
|
|
604
|
+
return Cesium.Cartesian3.fromDegrees(lon, lat, height + 0.3)
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const leftClickEvent = () => {
|
|
608
|
+
let lastClickTime = 0
|
|
609
|
+
const MIN_INTERVAL = 250
|
|
610
|
+
|
|
611
|
+
handler.setInputAction(e => {
|
|
612
|
+
const now = Date.now()
|
|
613
|
+
if (now - lastClickTime < MIN_INTERVAL) return
|
|
614
|
+
lastClickTime = now
|
|
615
|
+
|
|
616
|
+
let position = viewer.scene.pickPosition(e.position)
|
|
617
|
+
if (!position) {
|
|
618
|
+
const ellipsoid = viewer.scene.globe.ellipsoid
|
|
619
|
+
position = viewer.scene.camera.pickEllipsoid(e.position, ellipsoid)
|
|
620
|
+
}
|
|
621
|
+
if (!position) return
|
|
622
|
+
|
|
623
|
+
positions.push(position)
|
|
624
|
+
height = unifiedHeight(positions, height)
|
|
625
|
+
if (positions.length === 1) {
|
|
626
|
+
createPolygon()
|
|
627
|
+
}
|
|
628
|
+
createPoint()
|
|
629
|
+
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const mouseMoveEvent = () => {
|
|
633
|
+
handler.setInputAction(e => {
|
|
634
|
+
let position = viewer.scene.pickPosition(e.endPosition)
|
|
635
|
+
if (!position)
|
|
636
|
+
position = viewer.scene.camera.pickEllipsoid(
|
|
637
|
+
e.startPosition,
|
|
638
|
+
viewer.scene.globe.ellipsoid
|
|
639
|
+
)
|
|
640
|
+
if (!position) return
|
|
641
|
+
handleMoveEvent(position)
|
|
642
|
+
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const rightClickEvent = () => {
|
|
646
|
+
handler.setInputAction(e => {
|
|
647
|
+
if (positions.length < 3) {
|
|
648
|
+
stopDraw()
|
|
649
|
+
removeAll()
|
|
650
|
+
} else {
|
|
651
|
+
tempPositions = [...positions]
|
|
652
|
+
currentPolygonEntity.polygon.hierarchy = new Cesium.PolygonHierarchy(tempPositions)
|
|
653
|
+
currentLabelEntity.position = getCenterPosition()
|
|
654
|
+
currentLabelEntity.label.text = "总面积为 " + computeArea(positions)
|
|
655
|
+
stopDraw()
|
|
656
|
+
}
|
|
657
|
+
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
const handleMoveEvent = (position) => {
|
|
661
|
+
if (positions.length < 1) return
|
|
662
|
+
height = unifiedHeight(positions, height)
|
|
663
|
+
tempPositions = positions.concat(position)
|
|
664
|
+
if (tempPositions.length >= 3 && !currentLabelEntity) createLabel()
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const unifiedHeight = (positions, height) => {
|
|
668
|
+
if (!height) height = getPositionHeight(positions[0])
|
|
669
|
+
for (let i = 0; i < positions.length; i++) {
|
|
670
|
+
const p = cartesian3ToPoint3D(positions[i])
|
|
671
|
+
positions[i] = Cesium.Cartesian3.fromDegrees(p.x, p.y, height)
|
|
672
|
+
}
|
|
673
|
+
return height
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const computeArea = (points) => {
|
|
677
|
+
let res = 0
|
|
678
|
+
for (let i = 0; i < points.length - 2; i++) {
|
|
679
|
+
const j = (i + 1) % points.length
|
|
680
|
+
const k = (i + 2) % points.length
|
|
681
|
+
const angle = Angle(points[i], points[j], points[k])
|
|
682
|
+
const dis1 = distance(points[j], points[0])
|
|
683
|
+
const dis2 = distance(points[k], points[0])
|
|
684
|
+
res += (dis1 * dis2 * Math.sin(angle)) / 2
|
|
685
|
+
}
|
|
686
|
+
return res < 1000000
|
|
687
|
+
? Math.abs(res).toFixed(4) + " 平方米"
|
|
688
|
+
: Math.abs(res / 1000000).toFixed(4) + " 平方公里"
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
const Bearing = (from, to) => {
|
|
692
|
+
from = Cesium.Cartographic.fromCartesian(from)
|
|
693
|
+
to = Cesium.Cartographic.fromCartesian(to)
|
|
694
|
+
const lat1 = from.latitude, lon1 = from.longitude
|
|
695
|
+
const lat2 = to.latitude, lon2 = to.longitude
|
|
696
|
+
let angle = -Math.atan2(
|
|
697
|
+
Math.sin(lon1 - lon2) * Math.cos(lat2),
|
|
698
|
+
Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2)
|
|
699
|
+
)
|
|
700
|
+
if (angle < 0) angle += Math.PI * 2.0
|
|
701
|
+
return (angle * 180.0) / Math.PI
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const Angle = (p1, p2, p3) => {
|
|
705
|
+
const b21 = Bearing(p2, p1)
|
|
706
|
+
const b23 = Bearing(p2, p3)
|
|
707
|
+
let angle = b21 - b23
|
|
708
|
+
if (angle < 0) angle += 360
|
|
709
|
+
return angle
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
const distance = (p1, p2) => {
|
|
713
|
+
const c1 = Cesium.Cartographic.fromCartesian(p1)
|
|
714
|
+
const c2 = Cesium.Cartographic.fromCartesian(p2)
|
|
715
|
+
const geodesic = new Cesium.EllipsoidGeodesic()
|
|
716
|
+
geodesic.setEndPoints(c1, c2)
|
|
717
|
+
let s = geodesic.surfaceDistance
|
|
718
|
+
return Math.sqrt(s * s + Math.pow(c2.height - c1.height, 2))
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
const getPositionHeight = (p) => {
|
|
722
|
+
const c = Cesium.Cartographic.fromCartesian(p)
|
|
723
|
+
return c.height
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const cartesian3ToPoint3D = (p) => {
|
|
727
|
+
const c = Cesium.Cartographic.fromCartesian(p)
|
|
728
|
+
return {
|
|
729
|
+
x: Cesium.Math.toDegrees(c.longitude),
|
|
730
|
+
y: Cesium.Math.toDegrees(c.latitude),
|
|
731
|
+
z: c.height
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
return {
|
|
736
|
+
draw,
|
|
737
|
+
removeAll
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const altitudeMeasurement = () => {
|
|
742
|
+
let handler = null
|
|
743
|
+
|
|
744
|
+
const enable = () => {
|
|
745
|
+
disable();
|
|
746
|
+
|
|
747
|
+
(viewer.container as HTMLElement).style.cursor = "crosshair"
|
|
748
|
+
|
|
749
|
+
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
750
|
+
handler.setInputAction(async (event) => {
|
|
751
|
+
const cartesian = viewer.scene.pickPosition(event.position)
|
|
752
|
+
if (!cartesian) return
|
|
753
|
+
|
|
754
|
+
const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
|
|
755
|
+
const lon = Cesium.Math.toDegrees(cartographic.longitude)
|
|
756
|
+
const lat = Cesium.Math.toDegrees(cartographic.latitude)
|
|
757
|
+
const height = await getHeightFromLonLat(lon, lat)
|
|
758
|
+
|
|
759
|
+
options.altitudeCollection.entities.add({
|
|
760
|
+
position: Cesium.Cartesian3.fromDegrees(lon, lat, height + 2),
|
|
761
|
+
point: {
|
|
762
|
+
color: Cesium.Color.fromCssColorString("rgb(249, 157, 11)"),
|
|
763
|
+
outlineColor: Cesium.Color.WHITE,
|
|
764
|
+
outlineWidth: 2,
|
|
765
|
+
pixelSize: 10,
|
|
766
|
+
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
|
|
767
|
+
},
|
|
768
|
+
label: {
|
|
769
|
+
text: `${height.toFixed(2)} m`,
|
|
770
|
+
scale: 0.5,
|
|
771
|
+
font: "normal 28px MicroSoft YaHei",
|
|
772
|
+
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
773
|
+
pixelOffset: new Cesium.Cartesian2(0, -30),
|
|
774
|
+
outlineWidth: 9,
|
|
775
|
+
outlineColor: Cesium.Color.WHITE
|
|
776
|
+
},
|
|
777
|
+
})
|
|
778
|
+
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const getHeightFromLonLat = async (lon, lat) => {
|
|
782
|
+
const positions = [Cesium.Cartographic.fromDegrees(lon, lat)]
|
|
783
|
+
const updated = await Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, positions)
|
|
784
|
+
return updated[0].height || 0
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
const disable = () => {
|
|
788
|
+
if (handler) {
|
|
789
|
+
handler.destroy()
|
|
790
|
+
handler = null
|
|
791
|
+
}
|
|
792
|
+
(viewer.container as HTMLElement).style.cursor = "default"
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const removeAll = () => {
|
|
796
|
+
options.altitudeCollection.entities.removeAll()
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
return {
|
|
800
|
+
enable,
|
|
801
|
+
disable,
|
|
802
|
+
removeAll
|
|
803
|
+
}
|
|
294
804
|
}
|
|
295
805
|
|
|
296
806
|
const angle = angleMeasurement()
|
|
297
807
|
const distance = distanceMeasurement()
|
|
808
|
+
const height = heightMeasurement()
|
|
809
|
+
const area = areaMeasurement()
|
|
810
|
+
const altitude = altitudeMeasurement()
|
|
298
811
|
|
|
299
812
|
return {
|
|
300
813
|
angle,
|
|
301
|
-
distance
|
|
814
|
+
distance,
|
|
815
|
+
height,
|
|
816
|
+
area,
|
|
817
|
+
altitude
|
|
302
818
|
}
|
|
303
819
|
}
|
|
304
820
|
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import * as Cesium from "cesium"
|
|
2
|
+
import * as turf from "@turf/turf"
|
|
3
|
+
import CreatePolygonOnGround from "./lib/CreatePolygonOnGround"
|
|
4
|
+
// import CreateRemindertip from "./lib/ReminderTip"
|
|
5
|
+
|
|
6
|
+
const useSlope = (viewer: Cesium.Viewer, options: {
|
|
7
|
+
collection: Cesium.CustomDataSource
|
|
8
|
+
}) => {
|
|
9
|
+
|
|
10
|
+
let result = []
|
|
11
|
+
// let handler = null
|
|
12
|
+
// let toolTip = ""
|
|
13
|
+
let arrowWidth = 20
|
|
14
|
+
|
|
15
|
+
const Cartesian3ListToWGS84 = (cartesianList) => {
|
|
16
|
+
const ellipsoid = Cesium.Ellipsoid.WGS84
|
|
17
|
+
return cartesianList.map((cartesian) => {
|
|
18
|
+
const cartographic = ellipsoid.cartesianToCartographic(cartesian)
|
|
19
|
+
return {
|
|
20
|
+
lng: Cesium.Math.toDegrees(cartographic.longitude),
|
|
21
|
+
lat: Cesium.Math.toDegrees(cartographic.latitude),
|
|
22
|
+
alt: cartographic.height,
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const calculateSlopeColor = (value, alpha) => {
|
|
28
|
+
if (value < 0.0087) return `rgba(85,182,43,${alpha})`
|
|
29
|
+
if (value < 0.0349) return `rgba(135,211,43,${alpha})`
|
|
30
|
+
if (value < 0.0874) return `rgba(204,244,44,${alpha})`
|
|
31
|
+
if (value < 0.2679) return `rgba(245,233,44,${alpha})`
|
|
32
|
+
if (value < 0.7002) return `rgba(255,138,43,${alpha})`
|
|
33
|
+
if (value < 1.4281) return `rgba(255,84,43,${alpha})`
|
|
34
|
+
return `rgba(255,32,43,${alpha})`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// const openTip = () => {
|
|
38
|
+
// handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
39
|
+
// handler.setInputAction((movement) => {
|
|
40
|
+
// const pick = viewer.scene.pick(movement.endPosition)
|
|
41
|
+
// if (pick && pick.id && pick.id.type === "SlopeAspect") {
|
|
42
|
+
// toolTip = pick.id.value.toFixed(2)
|
|
43
|
+
// CreateRemindertip(toolTip, movement.endPosition, true)
|
|
44
|
+
// } else {
|
|
45
|
+
// toolTip = ""
|
|
46
|
+
// CreateRemindertip(toolTip, movement.endPosition, false)
|
|
47
|
+
// }
|
|
48
|
+
// }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
49
|
+
// }
|
|
50
|
+
|
|
51
|
+
// const closeTip = () => {
|
|
52
|
+
// if (handler) {
|
|
53
|
+
// handler.destroy()
|
|
54
|
+
// handler = null
|
|
55
|
+
// }
|
|
56
|
+
// }
|
|
57
|
+
|
|
58
|
+
const drawByDistance = (distance = 0.1, onDrawStart?: (ev: () => void) => void, onComplete?: () => void) => {
|
|
59
|
+
const width = distance * 200 > 35 ? 35 : distance * 200
|
|
60
|
+
arrowWidth = width < 15 ? 15 : width
|
|
61
|
+
|
|
62
|
+
CreatePolygonOnGround({
|
|
63
|
+
viewer,
|
|
64
|
+
collection: options.collection
|
|
65
|
+
}, [],
|
|
66
|
+
{
|
|
67
|
+
color: Cesium.Color.RED.withAlpha(0.1),
|
|
68
|
+
outlineColor: Cesium.Color.YELLOW,
|
|
69
|
+
outlineWidth: 2,
|
|
70
|
+
},
|
|
71
|
+
(polygon) => {
|
|
72
|
+
const degrees = Cartesian3ListToWGS84(polygon.pottingPoint)
|
|
73
|
+
options.collection.entities.remove(polygon)
|
|
74
|
+
|
|
75
|
+
const boundary = degrees.map((p) => [p.lng, p.lat])
|
|
76
|
+
const bbox = turf.bbox(turf.polygon([boundary.concat([boundary[0]])]))
|
|
77
|
+
const mask = turf.polygon([boundary.concat([boundary[0]])])
|
|
78
|
+
const gridSquare = turf.squareGrid(bbox, distance, { mask })
|
|
79
|
+
createEllipse(gridSquare)
|
|
80
|
+
|
|
81
|
+
onComplete && onComplete()
|
|
82
|
+
},
|
|
83
|
+
(drawHandler: () => void) => onDrawStart && onDrawStart(drawHandler)
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const drawByNum = (num = 10, onDrawStart?: (ev: () => void) => void, onComplete?: () => void) => {
|
|
88
|
+
CreatePolygonOnGround({
|
|
89
|
+
viewer,
|
|
90
|
+
collection: options.collection
|
|
91
|
+
}, [],
|
|
92
|
+
{
|
|
93
|
+
color: Cesium.Color.RED.withAlpha(0.1),
|
|
94
|
+
outlineColor: Cesium.Color.YELLOW,
|
|
95
|
+
outlineWidth: 2,
|
|
96
|
+
},
|
|
97
|
+
(polygon) => {
|
|
98
|
+
const degrees = Cartesian3ListToWGS84(polygon.pottingPoint)
|
|
99
|
+
options.collection.entities.remove(polygon)
|
|
100
|
+
|
|
101
|
+
const boundary = degrees.map((p) => [p.lng, p.lat])
|
|
102
|
+
const bbox = turf.bbox(turf.polygon([boundary.concat([boundary[0]])]))
|
|
103
|
+
|
|
104
|
+
const [minX, minY, maxX, maxY] = bbox
|
|
105
|
+
const step = Math.max(maxX - minX, maxY - minY) / num
|
|
106
|
+
|
|
107
|
+
const width = step * 2000 > 35 ? 35 : step * 2000
|
|
108
|
+
arrowWidth = width < 15 ? 15 : width
|
|
109
|
+
|
|
110
|
+
const mask = turf.polygon([boundary.concat([boundary[0]])])
|
|
111
|
+
const gridSquare = turf.squareGrid(bbox, step, {
|
|
112
|
+
units: "degrees",
|
|
113
|
+
mask,
|
|
114
|
+
})
|
|
115
|
+
createEllipse(gridSquare)
|
|
116
|
+
|
|
117
|
+
onComplete && onComplete()
|
|
118
|
+
},
|
|
119
|
+
(drawHandler: () => void) => { onDrawStart && onDrawStart(drawHandler) }
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const createEllipse = (gridSquare) => {
|
|
124
|
+
const boxResults = []
|
|
125
|
+
|
|
126
|
+
for (const feature of gridSquare.features) {
|
|
127
|
+
const coordinates = feature.geometry.coordinates[0]
|
|
128
|
+
const centerdegree = [
|
|
129
|
+
(coordinates[0][0] + coordinates[2][0]) / 2,
|
|
130
|
+
(coordinates[0][1] + coordinates[2][1]) / 2,
|
|
131
|
+
]
|
|
132
|
+
const centerCarto = Cesium.Cartographic.fromDegrees(
|
|
133
|
+
centerdegree[0],
|
|
134
|
+
centerdegree[1]
|
|
135
|
+
)
|
|
136
|
+
boxResults.push(centerCarto)
|
|
137
|
+
|
|
138
|
+
for (let i = 0; i < coordinates.length; i++) {
|
|
139
|
+
const coord = coordinates[i]
|
|
140
|
+
const carto = Cesium.Cartographic.fromDegrees(coord[0], coord[1])
|
|
141
|
+
boxResults.push(carto)
|
|
142
|
+
|
|
143
|
+
const next = coordinates[i + 1]
|
|
144
|
+
if (next) {
|
|
145
|
+
const mid = Cesium.Cartographic.fromDegrees(
|
|
146
|
+
(coord[0] + next[0]) / 2,
|
|
147
|
+
(coord[1] + next[1]) / 2
|
|
148
|
+
)
|
|
149
|
+
boxResults.push(mid)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Cesium.sampleTerrainMostDetailed(viewer.scene.terrainProvider, boxResults)
|
|
155
|
+
.then((updatePositions) => {
|
|
156
|
+
const group = []
|
|
157
|
+
for (let i = 0; i < updatePositions.length; i += 10) {
|
|
158
|
+
const slice = updatePositions.slice(i, i + 10)
|
|
159
|
+
if (slice.length) group.push(slice)
|
|
160
|
+
}
|
|
161
|
+
calculateSlope(group)
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const createPolygonInstance = (points, color) => {
|
|
166
|
+
const positions = points
|
|
167
|
+
.slice(1, -1)
|
|
168
|
+
.map((p) => Cesium.Cartographic.toCartesian(p))
|
|
169
|
+
const polygon = new Cesium.PolygonGeometry({
|
|
170
|
+
polygonHierarchy: new Cesium.PolygonHierarchy(positions),
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
return new Cesium.GeometryInstance({
|
|
174
|
+
geometry: polygon,
|
|
175
|
+
attributes: {
|
|
176
|
+
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
|
177
|
+
Cesium.Color.fromCssColorString(color)
|
|
178
|
+
),
|
|
179
|
+
show: new Cesium.ShowGeometryInstanceAttribute(true),
|
|
180
|
+
},
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const createArrowInstance = (target, center, diagonal, heightDiff, slope) => {
|
|
185
|
+
const mid0 = new Cesium.Cartographic(
|
|
186
|
+
(target.longitude + center.longitude) / 2,
|
|
187
|
+
(target.latitude + center.latitude) / 2,
|
|
188
|
+
(target.height + center.height) / 2
|
|
189
|
+
)
|
|
190
|
+
const mid1 = new Cesium.Cartographic(
|
|
191
|
+
(diagonal.longitude + center.longitude) / 2,
|
|
192
|
+
(diagonal.latitude + center.latitude) / 2,
|
|
193
|
+
(diagonal.height + center.height) / 2
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
const positions =
|
|
197
|
+
heightDiff > 0
|
|
198
|
+
? [
|
|
199
|
+
Cesium.Cartographic.toCartesian(mid0),
|
|
200
|
+
Cesium.Cartographic.toCartesian(mid1),
|
|
201
|
+
]
|
|
202
|
+
: [
|
|
203
|
+
Cesium.Cartographic.toCartesian(mid1),
|
|
204
|
+
Cesium.Cartographic.toCartesian(mid0),
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
return new Cesium.GeometryInstance({
|
|
208
|
+
id: { type: "SlopeAspect", value: slope },
|
|
209
|
+
geometry: new Cesium.GroundPolylineGeometry({
|
|
210
|
+
positions,
|
|
211
|
+
width: arrowWidth,
|
|
212
|
+
}),
|
|
213
|
+
attributes: {
|
|
214
|
+
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
|
215
|
+
Cesium.Color.BLUE.withAlpha(0.6)
|
|
216
|
+
),
|
|
217
|
+
show: new Cesium.ShowGeometryInstanceAttribute(true),
|
|
218
|
+
},
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const calculateSlope = (groups) => {
|
|
223
|
+
const polygons = []
|
|
224
|
+
const arrows = []
|
|
225
|
+
|
|
226
|
+
for (const ellipse of groups) {
|
|
227
|
+
const center = ellipse[0]
|
|
228
|
+
let maxHD = 0
|
|
229
|
+
let maxIndex = 0
|
|
230
|
+
|
|
231
|
+
for (let i = 1; i < ellipse.length; i++) {
|
|
232
|
+
const hd = ellipse[i].height - center.height
|
|
233
|
+
if (Math.abs(hd) > Math.abs(maxHD)) {
|
|
234
|
+
maxHD = hd
|
|
235
|
+
maxIndex = i
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const p0 = new Cesium.Cartographic(center.longitude, center.latitude, 0)
|
|
240
|
+
const p1 = new Cesium.Cartographic(
|
|
241
|
+
ellipse[maxIndex].longitude,
|
|
242
|
+
ellipse[maxIndex].latitude,
|
|
243
|
+
0
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
const dist = Cesium.Cartesian3.distance(
|
|
247
|
+
Cesium.Cartographic.toCartesian(p0),
|
|
248
|
+
Cesium.Cartographic.toCartesian(p1)
|
|
249
|
+
)
|
|
250
|
+
const slope = Math.abs(maxHD / dist)
|
|
251
|
+
const color = calculateSlopeColor(slope, 0.4)
|
|
252
|
+
|
|
253
|
+
polygons.push(createPolygonInstance(ellipse, color))
|
|
254
|
+
|
|
255
|
+
const diag = ellipse[maxIndex > 4 ? maxIndex - 4 : maxIndex + 4]
|
|
256
|
+
arrows.push(createArrowInstance(ellipse[maxIndex], center, diag, maxHD, slope))
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const polyPrimitive = viewer.scene.primitives.add(
|
|
260
|
+
new Cesium.GroundPrimitive({
|
|
261
|
+
geometryInstances: polygons,
|
|
262
|
+
appearance: new Cesium.PerInstanceColorAppearance({
|
|
263
|
+
translucent: true,
|
|
264
|
+
closed: false,
|
|
265
|
+
}),
|
|
266
|
+
})
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
const arrowPrimitive = viewer.scene.primitives.add(
|
|
270
|
+
new Cesium.GroundPolylinePrimitive({
|
|
271
|
+
geometryInstances: arrows,
|
|
272
|
+
appearance: new Cesium.PolylineMaterialAppearance({
|
|
273
|
+
material: new Cesium.Material({
|
|
274
|
+
fabric: {
|
|
275
|
+
type: "PolylineArrow",
|
|
276
|
+
uniforms: { color: new Cesium.Color(1, 1, 0, 0.8) },
|
|
277
|
+
},
|
|
278
|
+
}),
|
|
279
|
+
}),
|
|
280
|
+
})
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
result.push(polyPrimitive, arrowPrimitive)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const removeAll = () => {
|
|
287
|
+
result.forEach((p) => viewer.scene.primitives.remove(p))
|
|
288
|
+
result = []
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
drawByDistance,
|
|
293
|
+
drawByNum,
|
|
294
|
+
removeAll
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export {
|
|
299
|
+
useSlope
|
|
300
|
+
}
|