功能描述:
计算绘制多边形的最高点,最低点、平均高度等,
定时器设置多边形extrudedHeight高度,动态实现淹没效果
class SubmergeAnalysis {
constructor(option) {
this._viewer = option.viewer;
this.eventBus = {};
this.setTime = null;
this._extrudedHeight = 1;
this.minHeight = option.minHeight ?option.minHeight : 1;
this.maxHeight = option.maxHeight ? option.maxHeight : 1500;
this.currentMinHeight = 0;
this.currentMaxHeight = 800;
this.speed = option.speed ? option.speed : 1;
this.activeShapePoints = [];
this.activeShape = null;
this.floatingPoint = null;
this.drawingMode = “polygon”; //多边形
this.timer = null;
this.tempPoints = [];
this.area = 0;
this.volue = 0;
this.handler = null
this.boarder = null
this.totalTime = null;
this.heightData = [];
}
getCurrentMaxHeight() {
return this.currentMaxHeight;
}
getCurrentMinHeight() {
return this.currentMinHeight;
}
setMinHeight(minHeight) {
this.minHeight = minHeight;
}
setMaxHeight(maxHeight) {
this.maxHeight = maxHeight;
}
setSpeed(speed) {
this.speed = speed;
}
setTotalTime(time) {
this.totalTime = time;
}
//计算面积
getArea(points) {
var res = 0;
var that = this
//拆分三角曲面
for (var i = 0; i < points.length - 2; i++) {
var j = (i + 1) % points.length;
var k = (i + 2) % points.length;
var totalAngle = that.Angle(points[i], points[j], points[k]);
var dis_temp1 = that.distance(positions[i], positions[j]);
var dis_temp2 = that.distance(positions[j], positions[k]);
res += dis_temp1 * dis_temp2 * Math.abs(Math.sin(totalAngle));
}
return (res / 1000000.0).toFixed(4);
}
/角度/
Angle(p1, p2, p3) {
var that = this
var bearing21 = that.Bearing(p2, p1);
var bearing23 = that.Bearing(p2, p3);
var angle = bearing21 - bearing23;
if (angle < 0) {
angle += 360;
}
return angle;
}
/方向/
Bearing(from, to) {
var radiansPerDegree = Math.PI / 180.0;//角度转化为弧度(rad)
var degreesPerRadian = 180.0 / Math.PI;//弧度转化为角度
var lat1 = from.lat * radiansPerDegree;
var lon1 = from.lon * radiansPerDegree;
var lat2 = to.lat * radiansPerDegree;
var lon2 = to.lon * radiansPerDegree;
var angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
if (angle < 0) {
angle += Math.PI * 2.0;
}
angle = angle * degreesPerRadian;//角度
return angle;
}
distance(point1, point2) {
var point1cartographic = Cesium.Cartographic.fromCartesian(point1);
var point2cartographic = Cesium.Cartographic.fromCartesian(point2);
/**根据经纬度计算出距离**/
var geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
var s = geodesic.surfaceDistance;
//返回两点之间的距离
s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2));
return s;
}
//计算体积
getVolume() {}
//开始分析
start() {
if (this.maxHeight == 1500) {
this.maxHeight == this.currentMaxHeight;
}
var that = this;
if (this.totalTime) {
this.speed = this.totalTime / (this.maxHeight - this.minHeight);
}
this.timer = setInterval(() => {
that._extrudedHeight += that.speed / 100;
if (that._extrudedHeight > that.maxHeight) {
that._extrudedHeight = that.maxHeight;
clearInterval(that.timer);
}
let len = that.heightData.length;
var submergeArea = 0;
if (len > 0) {
var count = 0;
for (var i = 0; i < len; i++) {
if (that._extrudedHeight > that.heightData[i]) {
count += 1;
}
}
submergeArea = count / len * that.area;
}
that.$emit("observe", {
extrudedHeight: that._extrudedHeight,
maxHeight: that.maxHeight,
minHeight: that.minHeight,
speed: that.speed,
submergeArea:submergeArea
});
}, 10);
}
//暂停
pause() {
clearInterval(this.timer);
}
//清除
clear() {
this._viewer.entities.remove(this.boarder); //去除动态点图形(当前鼠标点)
this.boarder = undefined;
this._viewer.entities.remove(this.floatingPoint); //去除动态点图形(当前鼠标点)
this._viewer.entities.remove(this.activeShape); //去除动态图形
this.floatingPoint = undefined;
this.activeShape = undefined;
this.activeShapePoints = [];
clearInterval(this.timer);
this._extrudedHeight = 1;
this.speed = 1;
this._viewer.entities.removeAll();
this.eventBus = {};
}
//绑定事件
_bindEvent() {
let that = this;
that.handler = new Cesium.ScreenSpaceEventHandler(that._viewer.canvas);
//双击鼠标左键清除默认事件
that._viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
);
that.handler.setInputAction(function(event) {
// We use `viewer.scene.pickPosition` here instead of `viewer.camera.pickEllipsoid` so that
// we get the correct point when mousing over terrain.
// scene.pickPosition只有在开启地形深度检测,且不使用默认地形时是准确的。
var earthPosition = that._viewer.scene.pickPosition(event.position);
// `earthPosition` will be undefined if our mouse is not over the globe.
if (Cesium.defined(earthPosition)) {
if (that.activeShapePoints.length === 0) {
that.floatingPoint = that.createPoint(earthPosition);
that.activeShapePoints.push(earthPosition);
var dynamicPositions = new Cesium.CallbackProperty(function() {
if (that.drawingMode === "polygon") {
return new Cesium.PolygonHierarchy(that.activeShapePoints);
}
return that.activeShapePoints;
}, false);
that.activeShape = that.drawShape(dynamicPositions); //绘制动态图
}
that.activeShapePoints.push(earthPosition);
that.createPoint(earthPosition);
let len = that.activeShapePoints.length
var cartographic = Cesium.Cartographic.fromCartesian(that.activeShapePoints[len - 1]);
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
var heightString = cartographic.height;
that.tempPoints.push({ lon: longitudeString, lat: latitudeString, hei: heightString });
if (len > 1) {
if (!that.boarder) {
that.boarder = that._viewer.entities.add({
polyline: {
positions: that.activeShapePoints,
clampToGround: true,
width: 2,
material :new Cesium.PolylineOutlineMaterialProperty({
color:new Cesium.Color.fromBytes(0, 191, 255, 100),
outlineWidth: 2,
outlineColor: new Cesium.Color.fromBytes(0, 191, 255, 100),
})
},
});
}else{
that.boarder.polyline.positions = that.activeShapePoints;
}
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
//鼠标移动
that.handler.setInputAction(function(event) {
if (Cesium.defined(that.floatingPoint)) {
var newPosition = that._viewer.scene.pickPosition(event.endPosition);
if (Cesium.defined(newPosition)) {
that.floatingPoint.position.setValue(newPosition);
that.activeShapePoints.pop();
that.activeShapePoints.push(newPosition);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
that.handler.setInputAction(function(event) {
let newArr = [];
if(that.activeShapePoints.length > 0){
that.activeShapePoints.forEach(item=>{
var cartographic=Cesium.Cartographic.fromCartesian(item);
newArr.push(cartographic)
})
}
//计算淹没面积
// that.area = that.getArea(that.tempPoints) || 0;
var promise = Cesium.sampleTerrainMostDetailed(that._viewer.terrainProvider, newArr);
Cesium.when(promise, function(updatedPositions) {
// positions[0].height and positions[1].height have been updated.
// updatedPositions is just a reference to positions.
let heightArr = updatedPositions.map(item=> item.height);
// console.log('heightArr',heightArr);
that.currentMaxHeight = Math.ceil(Math.max(...heightArr) + 20 + Math.ceil(Math.random() * 50));
that.currentMinHeight = Math.ceil(Math.min(...heightArr) + 20 + Math.ceil(Math.random() * 50));
//console.log('that.currentMaxHeight', that.currentMaxHeight);
});
that.terminateShape();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
//绘制点
createPoint(worldPosition) {
var point = this._viewer.entities.add({
position: worldPosition,
point: {
color: Cesium.Color.GREENYELLOW,
pixelSize: 9,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
});
return point;
}
//绘制图形
drawShape(positionData) {
var that = this;
var shape;
if (that.drawingMode === “line”) {
shape = that._viewer.entities.add({
polyline: {
positions: positionData,
clampToGround: true,
width: 3,
},
});
} else if (that.drawingMode === “polygon”) {
shape = that._viewer.entities.add({
polygon: {
hierarchy: positionData,
perPositionHeight: false,
extrudedHeight: new Cesium.CallbackProperty(function() {
return that._extrudedHeight;
}, false),
//new Cesium.Color.fromBytes(0,191,255,100),
//new Cesium.ColorMaterialProperty(Cesium.Color.AQUA.withAlpha(0.3))
material: new Cesium.Color.fromBytes(0, 191, 255, 100),
},
});
} else if (that.drawingMode === “circle”) {
//当positionData为数组时绘制最终图,如果为function则绘制动态图
var value =
typeof positionData.getValue === “function”
? positionData.getValue(0)
: positionData;
//var start = activeShapePoints[0];
//var end = activeShapePoints[activeShapePoints.length - 1];
//var r = Math.sqrt(Math.pow(start.x - end.x, 2) + Math.pow(start.y - end.y, 2));
//r = r ? r : r + 1;
shape = that._viewer.entities.add({
position: that.activeShapePoints[0],
name: “Blue translucent, rotated, and extruded ellipse with outline”,
type: “Selection tool”,
ellipse: {
semiMinorAxis: new Cesium.CallbackProperty(function() {
//半径 两点间距离
var r = Math.sqrt(
Math.pow(value[0].x - value[value.length - 1].x, 2) +
Math.pow(value[0].y - value[value.length - 1].y, 2)
);
return r ? r : r + 1;
}, false),
semiMajorAxis: new Cesium.CallbackProperty(function() {
var r = Math.sqrt(
Math.pow(value[0].x - value[value.length - 1].x, 2) +
Math.pow(value[0].y - value[value.length - 1].y, 2)
);
return r ? r : r + 1;
}, false),
material: Cesium.Color.BLUE.withAlpha(0.5),
outline: true,
},
});
} else if (that.drawingMode === “rectangle”) {
//当positionData为数组时绘制最终图,如果为function则绘制动态图
var arr =
typeof positionData.getValue === “function”
? positionData.getValue(0)
: positionData;
shape = that._viewer.entities.add({
name: “Blue translucent, rotated, and extruded ellipse with outline”,
rectangle: {
coordinates: new Cesium.CallbackProperty(function() {
var obj = Cesium.Rectangle.fromCartesianArray(arr);
//if(obj.west==obj.east){ obj.east+=0.000001};
//if(obj.south==obj.north){obj.north+=0.000001};
return obj;
}, false),
material: Cesium.Color.RED.withAlpha(0.5),
},
});
}
return shape;
}
terminateShape() {
this.activeShapePoints.pop(); //去除最后一个动态点
this.computePolygonHeightRange(this.activeShapePoints);
this.area = this.computeSignedArea(this.activeShapePoints);
if (this.activeShapePoints.length) {
this.drawShape(this.activeShapePoints); //绘制最终图
var tmp = this.activeShapePoints;
tmp.push(this.activeShapePoints[0]);
// console.log(tmp);
this.boarder.polyline.positions = tmp;
}
this._viewer.entities.remove(this.floatingPoint); //去除动态点图形(当前鼠标点)
//this._viewer.entities.remove(this.activeShape); //去除动态图形
this.floatingPoint = undefined;
//this.activeShape = undefined;
this.activeShapePoints = [];
}
computePolygonHeightRange(e) {
var t = []
for (var i = 0; i < e.length; i++) t.push(e[i].clone());
var a, n, r, o, s, u, l, h = 0,
g = 9999,
c = Math.PI / Math.pow(2, 11) / 64,
m = new Cesium.PolygonGeometry.fromPositions({
positions: t,
vertexFormat: Cesium.PerInstanceColorAppearance.FLAT_VERTEX_FORMAT,
granularity: c
}),
d = new Cesium.PolygonGeometry.createGeometry(m);
var sum = [];
for (i = 0; i < d.indices.length; i += 3) a = d.indices[i],
n = d.indices[i + 1],
r = d.indices[i + 2],
l = new Cesium.Cartesian3(d.attributes.position.values[3 * a], d.attributes.position.values[3 * a + 1], d.attributes.position.values[3 * a + 2]),
(o = this._viewer.scene.globe.getHeight(Cesium.Cartographic.fromCartesian(l))) < g && (g = o),
h < o && (h = o),
l = new Cesium.Cartesian3(d.attributes.position.values[3 * n], d.attributes.position.values[3 * n + 1], d.attributes.position.values[3 * n + 2]),
(s = this._viewer.scene.globe.getHeight(Cesium.Cartographic.fromCartesian(l))) < g && (g = s),
h < s && (h = s),
l = new Cesium.Cartesian3(d.attributes.position.values[3 * r], d.attributes.position.values[3 * r + 1], d.attributes.position.values[3 * r + 2]),
(u = this._viewer.scene.globe.getHeight(Cesium.Cartographic.fromCartesian(l))) < g && (g = u),
h < u && (h = u),
sum.push(Math.max(Math.max(o,s),u));
this.currentMaxHeight = h;
this.currentMinHeight = g;
this.maxHeight = h;
this.minHeight = g;
this._extrudedHeight = g;
this.heightData = sum;
this.$emit("height", {
maxHeight: this.maxHeight,
minHeight: this.minHeight,
speed: this.speed,
});
}
computeSignedArea(tmppath) {
var path = [];
for (var i = 0; i < tmppath.length; i++) {
var cartographic = Cesium.Cartographic.fromCartesian(tmppath[i]);
var longitude = Cesium.Math.toDegrees(cartographic.longitude);
var latitude = Cesium.Math.toDegrees(cartographic.latitude);
path.push({lng:longitude,lat:latitude });
}
let radius= 6371009
let len = path.length;
if (len < 3) return 0;
let total = 0;
let prev = path[len - 1];
let prevTanLat = Math.tan(((Math.PI / 2 - prev.lat/180*Math.PI) / 2));
let prevLng = (prev.lng)/180*Math.PI;
for (let i in path) {
let tanLat = Math.tan((Math.PI / 2 -
(path[i].lat)/180*Math.PI) / 2);
let lng = (path[i].lng)/180*Math.PI;
total += this.polarTriangleArea(tanLat, lng, prevTanLat, prevLng);
prevTanLat = tanLat;
prevLng = lng;
}
return Math.abs(total * (radius * radius)) / 1000;
}
polarTriangleArea(tan1,lng1,tan2,lng2) {
let deltaLng = lng1 - lng2;
let t = tan1 * tan2;
return 2 * Math.atan2(t * Math.sin(deltaLng), 1 + t * Math.cos(deltaLng));
}
$on(event, cb) {
if (!this.eventBus[event]) {
this.eventBus[event] = new Set();
}
this.eventBus[event].add(cb);
}
$emit(event, …args) {
if (this.eventBus[event]) {
Array.from(this.eventBus[event]).forEach((handle) => {
handle.call(this, args);
});
}
}
$off(event, cb) {
if (this.eventBus[event]) {
this.eventBus[event].delete(cb);
}
}
}
export default SubmergeAnalysis;