init
This commit is contained in:
125
src/Obj/Analysis/CutFill/CreatePolygon.js
Normal file
125
src/Obj/Analysis/CutFill/CreatePolygon.js
Normal file
@ -0,0 +1,125 @@
|
||||
class CreatePolygon {
|
||||
constructor(viewer) {
|
||||
if (!viewer) throw new Error("no viewer object!");
|
||||
this.activePoints = [];
|
||||
this.viewer = viewer;
|
||||
this.handler = undefined;
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
this.activeShapePoints = [];
|
||||
this.floatingPoint = undefined;
|
||||
this.activeShape = undefined;
|
||||
this.activePoints.forEach((element) => {
|
||||
this.viewer.entities.remove(element);
|
||||
});
|
||||
this.activePoints = [];
|
||||
this.initHandler();
|
||||
}
|
||||
start(callback) {
|
||||
const $this = this;
|
||||
$this.keyDownStatus(true);
|
||||
$this.init();
|
||||
$this.handler = new Cesium.ScreenSpaceEventHandler($this.viewer.canvas);
|
||||
$this.handler.setInputAction(function (event) {
|
||||
let earthPosition = $this.viewer.scene.pickPosition(event.position);
|
||||
if (Cesium.defined(earthPosition)) {
|
||||
if ($this.activeShapePoints.length === 0) {
|
||||
$this.floatingPoint = $this.createPoint(earthPosition);
|
||||
$this.activeShapePoints.push(earthPosition);
|
||||
let dynamicPositions = new Cesium.CallbackProperty(function () {
|
||||
return new Cesium.PolygonHierarchy($this.activeShapePoints);
|
||||
}, false);
|
||||
$this.activeShape = $this.drawShape(dynamicPositions); //绘制动态图
|
||||
}
|
||||
$this.activeShapePoints.push(earthPosition);
|
||||
$this.createPoint(earthPosition);
|
||||
}
|
||||
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||||
$this.handler.setInputAction(function (event) {
|
||||
if (Cesium.defined($this.floatingPoint)) {
|
||||
let newPosition = $this.viewer.scene.pickPosition(event.endPosition);
|
||||
if (Cesium.defined(newPosition)) {
|
||||
$this.floatingPoint.position.setValue(newPosition);
|
||||
$this.activeShapePoints.pop();
|
||||
$this.activeShapePoints.push(newPosition);
|
||||
}
|
||||
}
|
||||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||||
$this.handler.setInputAction(function () {
|
||||
$this.activeShapePoints.pop(); //去除最后一个动态点
|
||||
if ($this.activeShapePoints.length) {
|
||||
$this.polygon = $this.drawShape($this.activeShapePoints); //绘制最终图
|
||||
}
|
||||
$this.viewer.entities.remove($this.floatingPoint); //去除动态点图形(当前鼠标点)
|
||||
$this.viewer.entities.remove($this.activeShape); //去除动态图形
|
||||
$this.activePoints.forEach((element) => {
|
||||
$this.viewer.entities.remove(element);
|
||||
});
|
||||
$this.handler.destroy();
|
||||
setTimeout(() => {
|
||||
if (typeof callback == "function") callback();
|
||||
}, 1000);
|
||||
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
|
||||
}
|
||||
initHandler() {
|
||||
if (this.handler) {
|
||||
this.handler.destroy();
|
||||
this.handler = undefined;
|
||||
}
|
||||
}
|
||||
createPoint(worldPosition) {
|
||||
let point = this.viewer.entities.add({
|
||||
position: worldPosition,
|
||||
point: {
|
||||
color: Cesium.Color.SKYBLUE,
|
||||
pixelSize: 5,
|
||||
},
|
||||
});
|
||||
this.activePoints.push(point);
|
||||
return point;
|
||||
}
|
||||
drawShape(positionData) {
|
||||
let shape = this.viewer.entities.add({
|
||||
polygon: {
|
||||
hierarchy: positionData,
|
||||
material: new Cesium.ColorMaterialProperty(
|
||||
Cesium.Color.BLUE.withAlpha(0.4)
|
||||
),
|
||||
zIndex: 99999999
|
||||
},
|
||||
});
|
||||
return shape;
|
||||
}
|
||||
//快捷键//Ctrl + Z
|
||||
keyDownStatus(bool) {
|
||||
const $this = this;
|
||||
document.onkeydown = function (event) {
|
||||
if (event.ctrlKey && window.event.keyCode == 90) {
|
||||
if (!bool) {
|
||||
return false;
|
||||
}
|
||||
$this.activeShapePoints.pop();
|
||||
$this.viewer.entities.remove(
|
||||
$this.activePoints[$this.activePoints.length - 1]
|
||||
);
|
||||
$this.activePoints.pop();
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Cesium中世界坐标系(笛卡尔)转经纬度
|
||||
* @param {*} cartesian3
|
||||
* @returns 经纬度
|
||||
*/
|
||||
Cartesian3ToDgrees(cartesian3) {
|
||||
let cartographic =
|
||||
window.viewer.scene.globe.ellipsoid.cartesianToCartographic(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 };
|
||||
}
|
||||
}
|
||||
|
||||
export default CreatePolygon;
|
75
src/Obj/Analysis/CutFill/_element.js
Normal file
75
src/Obj/Analysis/CutFill/_element.js
Normal file
@ -0,0 +1,75 @@
|
||||
function html() {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 70px;">绘制分析区域</span>
|
||||
<button class="draw-btn"><svg class="icon-edit"><use xlink:href="#yj-icon-edit"></use></svg>开始绘制</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">基准高度</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input class="input" type="number" title="" min="-999999" max="999999" name="height">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">精度</span>
|
||||
<div class="input-number input-number-unit">
|
||||
<input class="input" type="number" title="" min="1" max="1250" name="precision">
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 74px;">总分析面积:</span>
|
||||
<span class="text-number" name="allArea">0</span>
|
||||
<span class="unit text-number">m²</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 90px;">无须填挖面积:</span>
|
||||
<span class="text-number" name="noArea">0</span>
|
||||
<span class="unit text-number">m²</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 74px;">填方面积:</span>
|
||||
<span class="text-number" name="fillArea">0</span>
|
||||
<span class="unit text-number">m²</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 90px;">挖方面积:</span>
|
||||
<span class="text-number" name="cutArea">0</span>
|
||||
<span class="unit text-number">m²</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 74px;">填方体积:</span>
|
||||
<span class="text-number" name="fillVolume">0</span>
|
||||
<span class="unit text-number">m³</span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 90px;">挖方体积:</span>
|
||||
<span class="text-number" name="cutVolume">0</span>
|
||||
<span class="unit text-number">m³</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
354
src/Obj/Analysis/CutFill/index.js
Normal file
354
src/Obj/Analysis/CutFill/index.js
Normal file
@ -0,0 +1,354 @@
|
||||
import Dialog from '../../../BaseDialog';
|
||||
import { html } from "./_element";
|
||||
// import CreatePolygon from "./CreatePolygon";
|
||||
import DrawPolygon from "../../../Draw/drawPolygon"
|
||||
|
||||
class CutFillAnalysis {
|
||||
/**
|
||||
* @constructor 填挖方分析
|
||||
* @param sdk
|
||||
* **/
|
||||
constructor(sdk, options = {}, _Dialog = {}) {
|
||||
this.sdk = sdk;
|
||||
this.viewer = sdk.viewer;
|
||||
// if (!positions) throw new Error("no positions object!");
|
||||
// this.positions = positions;
|
||||
this.height = options.height || 70
|
||||
this.maxHeigh = -1000000;
|
||||
this.precision = options.precision || 125
|
||||
this.Dialog = _Dialog
|
||||
this.result = {
|
||||
allArea: "",
|
||||
cutArea: "",
|
||||
cutVolume: "",
|
||||
fillArea: "",
|
||||
fillVolume: "",
|
||||
noArea: "",
|
||||
}
|
||||
this.entities = []
|
||||
this.Draw = new DrawPolygon(this.sdk)
|
||||
YJ.Analysis.AnalysesResults.push(this)
|
||||
CutFillAnalysis.EditBox(this)
|
||||
}
|
||||
|
||||
create() {
|
||||
this.clean()
|
||||
this.Draw.start((a, positions) => {
|
||||
if(!positions || positions.length<3) {
|
||||
let _error = '最少需要三个坐标!'
|
||||
console.warn(_error)
|
||||
window.ELEMENT && window.ELEMENT.Message({
|
||||
message: _error,
|
||||
type: 'warning',
|
||||
duration: 1500
|
||||
});
|
||||
return
|
||||
}
|
||||
let fromDegreesArray = []
|
||||
for (let i = 0; i < positions.length; i++) {
|
||||
fromDegreesArray.push(positions[i].lng, positions[i].lat, positions[i].alt)
|
||||
}
|
||||
this.positions = Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray)
|
||||
this.createPolygonGeo(this.positions);
|
||||
this.result = this.VolumeAnalysis();
|
||||
this.viewer.scene.screenSpaceCameraController.enableCollisionDetection = false; //允许相机进入地下
|
||||
})
|
||||
// const $this = this;
|
||||
// if (!this.cp) {
|
||||
// this.cp = new CreatePolygon(this.viewer)
|
||||
// }
|
||||
// this.cp.start(function () {
|
||||
// console.log($this.cp.activeShapePoints)
|
||||
// $this.positions = $this.cp.activeShapePoints;
|
||||
// $this.createPolygonGeo($this.positions);
|
||||
// $this.result = $this.VolumeAnalysis();
|
||||
// $this.viewer.entities.remove($this.cp.polygon);
|
||||
// $this.viewer.scene.screenSpaceCameraController.enableCollisionDetection = false; //允许相机进入地下
|
||||
|
||||
// });
|
||||
}
|
||||
createPolygonGeo(points) {
|
||||
//计算网格粒度-精度
|
||||
let granularity = Math.PI / Math.pow(2, 11);
|
||||
granularity = granularity / this.precision;
|
||||
let polygonGeometry = new Cesium.PolygonGeometry.fromPositions({
|
||||
positions: points,
|
||||
vertexFormat: Cesium.PerInstanceColorAppearance.FLAT_VERTEX_FORMAT,
|
||||
granularity: granularity,
|
||||
});
|
||||
//创建自定义平面几何体
|
||||
this.geom = new Cesium.PolygonGeometry.createGeometry(polygonGeometry);
|
||||
}
|
||||
VolumeAnalysis() {
|
||||
let cutArea = 0,
|
||||
cutVolume = 0,
|
||||
fillArea = 0,
|
||||
fillVolume = 0,
|
||||
noArea = 0;
|
||||
const indices = this.geom.indices; //获取顶点索引数据
|
||||
if (!this.geom || !this.geom.attributes || !this.geom.attributes.position) {
|
||||
return;
|
||||
}
|
||||
const positions = this.geom.attributes.position.values;
|
||||
for (let index = 0; index < indices.length; index += 3) {
|
||||
const pos0 = this.returnPosition(positions, indices[index]);
|
||||
const pos1 = this.returnPosition(positions, indices[index + 1]);
|
||||
const pos2 = this.returnPosition(positions, indices[index + 2]);
|
||||
let entity = this.viewer.entities.add({
|
||||
name: "三角面",
|
||||
polygon: {
|
||||
hierarchy: [pos0.heightPos, pos1.heightPos, pos2.heightPos],
|
||||
perPositionHeight: true,
|
||||
material: Cesium.Color.fromRandom(),
|
||||
extrudedHeight: this.height,
|
||||
outline: true,
|
||||
outlineColor: Cesium.Color.BLACK,
|
||||
},
|
||||
});
|
||||
this.entities.push(entity)
|
||||
//水平状态下三角形面积
|
||||
const area = this.computeArea4Triangle(
|
||||
pos0.noHeightPos,
|
||||
pos1.noHeightPos,
|
||||
pos2.noHeightPos
|
||||
);
|
||||
//计算三个点的均高
|
||||
const height = (pos0.height + pos1.height + pos2.height) / 3;
|
||||
if (height < this.height) {
|
||||
// 需要填方的部分
|
||||
fillArea += area;
|
||||
const volume = area * (this.height - height);
|
||||
fillVolume += volume;
|
||||
} else if (height == this.height) {
|
||||
noArea += area;
|
||||
} else {
|
||||
// 需要挖方的部分
|
||||
cutArea += area;
|
||||
const volume = area * (height - this.height);
|
||||
cutVolume += volume;
|
||||
}
|
||||
}
|
||||
const allArea = cutArea + fillArea + noArea;
|
||||
// this.result = {
|
||||
// allArea,
|
||||
// cutArea,
|
||||
// cutVolume,
|
||||
// fillArea,
|
||||
// fillVolume,
|
||||
// noArea,
|
||||
// };
|
||||
this.result.allArea = allArea
|
||||
this.result.cutArea = cutArea
|
||||
this.result.cutVolume = cutVolume
|
||||
this.result.fillArea = fillArea
|
||||
this.result.fillVolume = fillVolume
|
||||
this.result.noArea = noArea
|
||||
return this.result;
|
||||
}
|
||||
computeCentroid4Polygon(positions) {
|
||||
let x = [],
|
||||
y = [];
|
||||
let allX = 0,
|
||||
allY = 0;
|
||||
for (let i = 0; i < positions.length; i++) {
|
||||
let cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
|
||||
allX += cartographic.longitude;
|
||||
allY += cartographic.latitude;
|
||||
x.push(cartographic.longitude);
|
||||
y.push(cartographic.latitude);
|
||||
}
|
||||
let centroidx = allX / positions.length;
|
||||
let centroidy = allY / positions.length;
|
||||
const Cartographic = new Cesium.Cartographic(centroidx, centroidy);
|
||||
return Cesium.Cartesian3.fromRadians(
|
||||
Cartographic.longitude,
|
||||
Cartographic.latitude,
|
||||
this.maxHeigh + 30
|
||||
);
|
||||
}
|
||||
/**
|
||||
* 海伦公式求取三角形面积
|
||||
* @param {*} pos1
|
||||
* @param {*} pos2
|
||||
* @param {*} pos3
|
||||
* @returns 三角形面积㎡
|
||||
*/
|
||||
computeArea4Triangle(pos1, pos2, pos3) {
|
||||
let a = Cesium.Cartesian3.distance(pos1, pos2);
|
||||
let b = Cesium.Cartesian3.distance(pos2, pos3);
|
||||
let c = Cesium.Cartesian3.distance(pos3, pos1);
|
||||
let S = (a + b + c) / 2;
|
||||
return Math.sqrt(S * (S - a) * (S - b) * (S - c));
|
||||
}
|
||||
returnPosition(positions, index) {
|
||||
let cartesian = new Cesium.Cartesian3(
|
||||
positions[index * 3],
|
||||
positions[index * 3 + 1],
|
||||
positions[index * 3 + 2]
|
||||
);
|
||||
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
|
||||
let height = this.viewer.scene.sampleHeightSupported
|
||||
? this.viewer.scene.sampleHeight(cartographic)
|
||||
: this.viewer.scene.globe.getHeight(cartographic);
|
||||
if (height > this.maxHeigh) {
|
||||
this.maxHeigh = height;
|
||||
}
|
||||
return {
|
||||
heightPos: Cesium.Cartesian3.fromRadians(
|
||||
cartographic.longitude,
|
||||
cartographic.latitude,
|
||||
height
|
||||
),
|
||||
noHeightPos: Cesium.Cartesian3.fromRadians(
|
||||
cartographic.longitude,
|
||||
cartographic.latitude,
|
||||
0
|
||||
),
|
||||
height: height,
|
||||
};
|
||||
}
|
||||
|
||||
static async EditBox(that) {
|
||||
if (that._DialogObject && that._DialogObject.close) {
|
||||
that._DialogObject.close()
|
||||
that._DialogObject = null
|
||||
}
|
||||
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
|
||||
title: '土方分析', left: '180px', top: '100px',
|
||||
closeCallBack: () => {
|
||||
that.clean()
|
||||
that.Dialog.closeCallBack && that.Dialog.closeCallBack()
|
||||
},
|
||||
})
|
||||
await that._DialogObject.init()
|
||||
let contentElm = document.createElement('div');
|
||||
contentElm.innerHTML = html()
|
||||
that._DialogObject.contentAppChild(contentElm)
|
||||
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' cut-fill'
|
||||
|
||||
// 高度值
|
||||
let e_height = contentElm.querySelector("input[name='height']")
|
||||
e_height.value = that.height
|
||||
e_height.addEventListener('blur', (e) => {
|
||||
let value = e.target.value
|
||||
if (e.data != '.' && (e.data != '-' || e.target.value)) {
|
||||
value = Number(value)
|
||||
if ((e.target.max) && value > Number(e.target.max)) {
|
||||
value = Number(e.target.max)
|
||||
}
|
||||
if ((e.target.min) && value < Number(e.target.min)) {
|
||||
value = Number(e.target.min)
|
||||
}
|
||||
e_height.value = value
|
||||
that.height = e_height.value;
|
||||
}
|
||||
});
|
||||
|
||||
// 精度值
|
||||
let e_precision = contentElm.querySelector("input[name='precision']")
|
||||
e_precision.value = that.precision
|
||||
e_precision.addEventListener('blur', (e) => {
|
||||
let value = Number(e.target.value)
|
||||
if ((e.target.max) && value > Number(e.target.max)) {
|
||||
value = Number(e.target.max)
|
||||
}
|
||||
if ((e.target.min) && value < Number(e.target.min)) {
|
||||
value = Number(e.target.min)
|
||||
}
|
||||
e_precision.value = value
|
||||
that.precision = e_precision.value;
|
||||
});
|
||||
|
||||
// 总分析面积
|
||||
let e_allArea = contentElm.querySelector("span[name='allArea']")
|
||||
e_allArea.innerHTML = that.result.allArea || 0
|
||||
Object.defineProperty(that.result, 'allArea', {
|
||||
get() {
|
||||
return e_allArea.innerHTML
|
||||
},
|
||||
set(value) {
|
||||
e_allArea.innerHTML = Number(value.toFixed(4))
|
||||
}
|
||||
})
|
||||
// 填方面积
|
||||
let e_fillArea = contentElm.querySelector("span[name='fillArea']")
|
||||
e_fillArea.innerHTML = that.result.fillArea || 0
|
||||
Object.defineProperty(that.result, 'fillArea', {
|
||||
get() {
|
||||
return e_fillArea.innerHTML
|
||||
},
|
||||
set(value) {
|
||||
e_fillArea.innerHTML = Number(value.toFixed(4))
|
||||
}
|
||||
})
|
||||
|
||||
// 填方体积
|
||||
let e_fillVolume = contentElm.querySelector("span[name='fillVolume']")
|
||||
e_fillVolume.innerHTML = that.result.fillVolume || 0
|
||||
Object.defineProperty(that.result, 'fillVolume', {
|
||||
get() {
|
||||
return e_fillVolume.innerHTML
|
||||
},
|
||||
set(value) {
|
||||
e_fillVolume.innerHTML = Number(value.toFixed(4))
|
||||
}
|
||||
})
|
||||
|
||||
// 挖方面积
|
||||
let e_cutArea = contentElm.querySelector("span[name='cutArea']")
|
||||
e_cutArea.innerHTML = that.result.cutArea || 0
|
||||
Object.defineProperty(that.result, 'cutArea', {
|
||||
get() {
|
||||
return e_cutArea.innerHTML
|
||||
},
|
||||
set(value) {
|
||||
e_cutArea.innerHTML = Number(value.toFixed(4))
|
||||
}
|
||||
})
|
||||
|
||||
// 挖方体积
|
||||
let e_cutVolume = contentElm.querySelector("span[name='cutVolume']")
|
||||
e_cutVolume.innerHTML = that.result.cutVolume || 0
|
||||
Object.defineProperty(that.result, 'cutVolume', {
|
||||
get() {
|
||||
return e_cutVolume.innerHTML
|
||||
},
|
||||
set(value) {
|
||||
e_cutVolume.innerHTML = Number(value.toFixed(4))
|
||||
}
|
||||
})
|
||||
|
||||
// 无须填挖面积
|
||||
let e_noArea = contentElm.querySelector("span[name='noArea']")
|
||||
e_noArea.innerHTML = that.result.noArea || 0
|
||||
Object.defineProperty(that.result, 'noArea', {
|
||||
get() {
|
||||
return e_noArea.innerHTML
|
||||
},
|
||||
set(value) {
|
||||
e_noArea.innerHTML = Number(value.toFixed(4))
|
||||
}
|
||||
})
|
||||
|
||||
let newDivBtn = contentElm.getElementsByClassName('draw-btn')[0];
|
||||
newDivBtn.addEventListener('click', () => {
|
||||
that.create()
|
||||
});
|
||||
}
|
||||
|
||||
clean() {
|
||||
this.Draw && this.Draw.end()
|
||||
for (let i = 0; i < this.entities.length; i++) {
|
||||
this.viewer.entities.remove(this.entities[i])
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.clean()
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
}
|
||||
}
|
||||
export default CutFillAnalysis;
|
Reference in New Issue
Block a user