Cesium-Examples/examples/cesiumEx/measureVolume.js
2025-03-11 17:51:04 +08:00

456 lines
18 KiB
JavaScript

/**
* @class DEUGlobe.Analysis.measureVolume
* @category 分析
* @classdesc 方量分析直接调用new DEUGlobe.Analysis.measureVolume()即可,左键画线,右键停止
* @param {Object} viewer - Cesium.viewer。
* @param {Object} options - 参数。
* @param {Boolean} options.terrainLevel - terrainLevel。 查询当前地形级别(默认 13)
*/
class MeasureVolume{
constructor(viewer,options){
var _this = this;
this.viewer = viewer;
this.optS = options ||{};
this.handler = null;
this.polygon = null;
this.wall = null;
this.initHeight = 0;
this.minHeight = 0;
this.maxHeight =0;
this.volumn = 0;
this.label = null;
this.cartesian = null;
this.poly = null;
this.area = null;
this.cellsize = null;
this.centroid = null;
this.planeHeight = 0;
this.positions = [];
this.Cartesian2Array = [];
this.floatingPointLis = [];
viewer.scene.globe.depthTestAgainstTerrain = true;
this.data = [];
this.PolygonPrimitive = (function () {
function _(positions) {
this.options = {
name: '多边形',
polygon: {
show: true,
perPositionHeight: true,
material: Cesium.Color.CHARTREUSE.withAlpha(0.5),
}
};
this.hierarchy = positions;
this._init();
}
_.prototype._init = function () {
var _self = this;
var _update = function () {
return new Cesium.PolygonHierarchy(_self.hierarchy);
};
//实时更新polygon.positions
this.options.polygon.hierarchy = new Cesium.CallbackProperty(_update, false);
_this.polygon = _this.viewer.entities.add(this.options);
};
return _;
})();
var tooltip = document.createElement('div');
tooltip.setAttribute('class','roamWidget_tooltip')
var tooltipArrow = document.createElement('div');
tooltipArrow.setAttribute('class','roamWidget_tooltip_arrow')
tooltip.appendChild(tooltipArrow);
var tooltipInner = document.createElement('div');
tooltipInner.setAttribute('class','roamWidget_tooltip_inner')
tooltip.appendChild(tooltipInner);
tooltipInner.innerHTML = "单击 开始绘制";
this.tooltip = tooltip;
this.tooltipInner = tooltipInner;
}
/**
* @classdesc 方量分析
* @param {function} callback - 绘制完成回调
*/
initMeasureVolume(callback){
var _this = this;
_this.positions = []
_this.Cartesian2Array = []
_this.handler = new Cesium.ScreenSpaceEventHandler(_this.viewer.scene._imageryLayerCollection);
_this.tooltip.style.left = "-100000px";
_this.tooltip.style.top = "-100000px";
document.getElementsByTagName('body')[0].appendChild(_this.tooltip);
_this.viewer.scene.canvas.style.cursor='crosshair';
_this.handler.setInputAction(function (movement) {
var ray = _this.viewer.camera.getPickRay(movement.endPosition);
_this.cartesian = _this.viewer.scene.globe.pick(ray,_this.viewer.scene);
if (_this.positions.length >= 2) {
if (!Cesium.defined(_this.poly)) {
_this.poly = new _this.PolygonPrimitive(_this.positions);
} else {
if(_this.cartesian != null){
_this.positions.pop();
_this.cartesian.y += (1 + Math.random());
_this.positions.push(_this.cartesian);
}
}
};
_this.tooltip.style.left = movement.endPosition.x + 20 + "px";
_this.tooltip.style.top = movement.endPosition.y - 10 + "px";
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
_this.handler.setInputAction(function (movement) {
var ray = _this.viewer.camera.getPickRay(movement.position);
_this.cartesian = _this.viewer.scene.globe.pick(ray,_this.viewer.scene);
if (_this.positions.length == 0) {
_this.positions.push(_this.cartesian.clone());
}
// console.log(_this.positions)
_this.positions.push(_this.cartesian);
_this.tooltipInner.innerHTML = "单击增加点,右键结束";
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
_this.handler.setInputAction(function (movement) {
_this.viewer.entities.remove(_this.polygon);
document.getElementsByTagName('body')[0].removeChild(_this.tooltip);
_this.viewer.scene.canvas.style.cursor=''
_this.handler.destroy();//关闭事件句柄
_this.positions.pop();//最后一个点无效
var ellipsoid = _this.viewer.scene.globe.ellipsoid;
_this.positions.forEach(element => {
var cartographic=ellipsoid.cartesianToCartographic(element);
var lat=Cesium.Math.toDegrees(cartographic.latitude);
var lng=Cesium.Math.toDegrees(cartographic.longitude);
_this.Cartesian2Array.push([lng,lat])
});
_this.Cartesian2Array.push(_this.Cartesian2Array[0]);
let polygon = turf.polygon([ _this.Cartesian2Array]);
_this.cellsize = Math.sqrt(turf.area(polygon) / 10000);
let enveloped = turf.envelope(polygon);
_this.area = turf.area(polygon);
_this.centroid = turf.centroid(polygon);
let bbox = turf.bbox(enveloped);
let grid = turf.pointGrid(bbox, _this.cellsize, { units: 'meters' });
let ptsWithin = turf.pointsWithinPolygon(grid, polygon);
let lonlats = [];
let features = ptsWithin.features;
for (let i = 0; i < features.length; i++) {
lonlats.push({
lon: features[i].geometry.coordinates[0],
lat: features[i].geometry.coordinates[1]
})
}
TerrainToolCopy.LonlatPointsTerrainData( _this.viewer.terrainProvider, lonlats, _this.optS.terrainLevel, (positions) => {
_this.getVolumn(positions);
callback({
planeHeight:_this.minHeight,
wallMinHeight:_this.minHeight,
wallMaxHeight:_this.maxHeight
})
})
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
};
initMeasure(positions) {
var _this = this;
_this.positions = []
_this.Cartesian2Array = []
_this.tooltip.style.left = "-100000px";
_this.tooltip.style.top = "-100000px";
var ellipsoid = _this.viewer.scene.globe.ellipsoid;
_this.positions = positions
_this.positions.forEach(element => {
var cartographic=ellipsoid.cartesianToCartographic(element);
var lat=Cesium.Math.toDegrees(cartographic.latitude);
var lng=Cesium.Math.toDegrees(cartographic.longitude);
_this.Cartesian2Array.push([lng,lat])
});
_this.Cartesian2Array.push(_this.Cartesian2Array[0]);
_this.minHeight = 3000;
_this.initHeight = 4000;
_this.maxHeight = 5000;
let polygon = turf.polygon([ _this.Cartesian2Array]);
_this.cellsize = Math.sqrt(turf.area(polygon) / 10000);
let enveloped = turf.envelope(polygon);
_this.area = turf.area(polygon);
_this.centroid = turf.centroid(polygon);
let bbox = turf.bbox(enveloped);
let grid = turf.pointGrid(bbox, _this.cellsize, { units: 'meters' });
let ptsWithin = turf.pointsWithinPolygon(grid, polygon);
let lonlats = [];
let features = ptsWithin.features;
for (let i = 0; i < features.length; i++) {
lonlats.push({
lon: features[i].geometry.coordinates[0],
lat: features[i].geometry.coordinates[1]
})
}
TerrainToolCopy.LonlatPointsTerrainData( _this.viewer.terrainProvider, lonlats, _this.optS.terrainLevel, (positions) => {
_this.getVolumn(positions,true);
callback({
planeHeight:_this.minHeight,
wallMinHeight:_this.minHeight,
wallMaxHeight:_this.maxHeight
})
})
};
getVolumn(data,flag) {
var _this = this;
_this.data = data;
let positions = [];
var ellipsoid=_this.viewer.scene.globe.ellipsoid;
_this.positions.forEach(element => {
var cartographic=ellipsoid.cartesianToCartographic(element);
let haiba = _this.viewer.scene.globe.getHeight(cartographic);
positions.push(haiba)
_this.floatingPoint = _this.viewer.entities.add({
position: element,
label: {
text: "海拔:" + haiba.toFixed(2) + "米",
font: '19px sans-serif',
fillColor: Cesium.Color.GOLD,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
pixelOffset: new Cesium.Cartesian2(0.0, -20)
}
});
_this.floatingPointLis.push(_this.floatingPoint);
});
if (!flag) {
_this.minHeight = findMinHeight(positions);
_this.initHeight = _this.planeHeight = _this.minHeight;
_this.maxHeight = findMaxHeight(positions);
}
_this.volumn = 0;
let a1 = 0,a2 = 0;
for (let i = 0; i < data.length; i++) {
_this.volumn += (data[i]['height'] - _this.minHeight) * _this.cellsize * _this.cellsize;
}
let Cartesian3Array = [];
let minimumHeights = [];
let maximumHeights = [];
_this.Cartesian2Array.forEach(element => {
console.log(element)
element.forEach((element1,index) => {
Cartesian3Array.push(element1);
if(index==1){
Cartesian3Array.push(0);
}
})
minimumHeights.push(_this.minHeight);
maximumHeights.push(_this.maxHeight);
});
_this.wall = _this.viewer.entities.add({
wall: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights(Cartesian3Array),
minimumHeights:minimumHeights,
maximumHeights:maximumHeights,
outline:true,
outlineColor: Cesium.Color.WHITE.withAlpha(0.7),
material: Cesium.Color.CYAN.withAlpha(0.7),
},
});
_this.polygon = _this.viewer.entities.add({
polygon: {
show: true,
hierarchy:new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights(Cartesian3Array)),
height:_this.minHeight,
material: Cesium.Color.CHARTREUSE.withAlpha(0.5),
}
});
let volumn = 0;
let area = 0;
if( _this.volumn/10000 > 0.01){
volumn = ( _this.volumn/10000).toFixed(2) +'万立方米';
}else{
volumn = _this.volumn.toFixed(2) +'立方米';
}
if( _this.area/10000 > 0.01){
area = ( _this.area/10000).toFixed(2) +'万平方米';
}else{
area = _this.area.toFixed(2) +'平方米';
}
_this.label = _this.viewer.entities.add({
name: "飞机",
position: Cesium.Cartesian3.fromDegrees(_this.centroid.geometry.coordinates[0], _this.centroid.geometry.coordinates[1], _this.maxHeight),
label: {
text:"挖方体积:" + volumn +'\n'+ "横切面积:" + area,
font: '18px sans-serif',
showBackground: true,
fillColor: Cesium.Color.WHITE,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
pixelOffset: new Cesium.Cartesian2(0.0, -80)
}
});
}
/**
* @classdesc 设置参数
* @param {Object} options - 参数。
* @param {function} callback - 绘制完成回调
*/
setParameters(opt,callback){
this.planeHeight = opt.planeHeight == undefined ? this.planeHeight : opt.planeHeight;
this.minHeight = opt.wallMinHeight == undefined ? this.minHeight : opt.wallMinHeight;
this.maxHeight = opt.wallMaxHeight == undefined ? this.maxHeight : opt.wallMaxHeight;
if(this.planeHeight < this.minHeight){
this.minHeight = this.planeHeight;
}
if(this.planeHeight > this.maxHeight){
this.maxHeight = this.planeHeight;
}
if (Cesium.defined(this.polygon)){
this.polygon.polygon.height.setValue(this.planeHeight);
}
if (Cesium.defined(this.wall)){
let minimumHeights = [];
for (let index = 0; index < this.wall.wall.minimumHeights.getValue().length; index++) {
minimumHeights.push(this.minHeight)
}
this.wall.wall.minimumHeights.setValue(minimumHeights);
let maximumHeights = [];
for (let index = 0; index < this.wall.wall.maximumHeights.getValue().length; index++) {
maximumHeights.push(this.maxHeight)
}
this.wall.wall.maximumHeights.setValue(maximumHeights);
}
this.calculateBulk();
callback({
planeHeight:this.planeHeight,
wallMinHeight:this.minHeight,
wallMaxHeight:this.maxHeight
});
}
//计算体积
calculateBulk(){
//基准面下的体积
let planeBulk = this.area * (this.planeHeight - this.minHeight);
//挖方体积
let volumn = 0;
this.volumn = 0;
for (let i = 0; i < this.data.length; i++) {
this.volumn += (this.data[i]['height'] - this.minHeight) * this.cellsize * this.cellsize;
if(this.data[i]['height'] > this.planeHeight){
volumn += (this.data[i]['height'] - this.planeHeight) * this.cellsize * this.cellsize;
}
}
let fillInBulk = 0;
if(this.initHeight <= this.planeHeight){
//填方体积
fillInBulk = planeBulk - (this.volumn - volumn);
}
if(fillInBulk > 0){
if( fillInBulk/10000 > 0.01){
fillInBulk = ( fillInBulk/10000).toFixed(2) +'万立方米';
}else{
fillInBulk = fillInBulk.toFixed(2) +'立方米';
}
fillInBulk = "填方体积:"+ fillInBulk+'\n';
}else{
fillInBulk ='';
}
if(volumn >0){
if( volumn/10000 > 0.01){
volumn = ( volumn/10000).toFixed(2) +'万立方米';
}else{
volumn = volumn.toFixed(2) +'立方米';
}
volumn = "挖方体积:"+ volumn +'\n';
}else{
volumn ='';
}
let area = this.area
if( area/10000 > 0.01){
area = ( area/10000).toFixed(2) +'万平方米';
}else{
area = area.toFixed(2) +'平方米';
}
this.label.label.text.setValue(fillInBulk+volumn+"横切面积:"+area)
}
//清除
clear(){
if(this.floatingPointLis.length>0){
this.floatingPointLis.forEach(element => {
this.viewer.entities.remove(element);
});
}
if(Cesium.defined(this.wall)){
this.viewer.entities.remove(this.wall);
}
if(Cesium.defined(this.polygon)){
this.viewer.entities.remove(this.polygon);
}
if(Cesium.defined(this.label)){
this.viewer.entities.remove(this.label);
}
}
}
function findMinHeight(e) {
e = e.sort((a, b) => a - b);
// let minHeight = 0;
// let minPoint = null;
// for (let i = 0; i < e.length; i++) {
// let height = e[i];
// if (height < minHeight) {
// minHeight = height;
// }
// }
return e[0];
}
function findMaxHeight(e) {
e = e.sort((a, b) => b - a);
return e[0];
}
//获取高程
var TerrainToolCopy = (
function () {
function _() {
}
//传入lonlat数组 角度制的lon lat
_.LonlatPointsTerrainData = function (terrainProvider,lonlats, terrainLevel = 13, callback) {
var pointArrInput = [];
for (var i = 0; i < lonlats.length; i++) {
pointArrInput.push(Cesium.Cartographic.fromDegrees(lonlats[i].lon, lonlats[i].lat));
}
// var promise = Cesium.sampleTerrain(terrainProvider, terrainLevel, pointArrInput);//pointArrInput
// Cesium.when(promise, function (updatedPositions) {
// callback(updatedPositions);
// });
var p1 = Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, pointArrInput)
Promise.all([p1]).then((samples) => {
callback(samples[0]);
})
};
//传入Cartographic类型数组 弧度制经纬度
_.CartographicPointsTerrainData = function (terrainProvider,Cartographics, callback) {
if (Cartographics.length && Cartographics.length > 0) { } else { return; }
// var promise = Cesium.sampleTerrain(terrainProvider, terrainLevel, Cartographics);//pointArrInput
// Cesium.when(promise, function (updatedPositions) {
// callback(updatedPositions);
// });
var p1 = Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, Cartographics)
Promise.all([p1]).then((samples) => {
callback(samples[0]);
})
};
return _;
}
)();