Men的博客

欢迎光临!

0%

Cesium淹没分析

功能描述:
计算绘制多边形的最高点,最低点、平均高度等,
定时器设置多边形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;