init
This commit is contained in:
74
src/Obj/Analysis/ViewShed2/_element.js
Normal file
74
src/Obj/Analysis/ViewShed2/_element.js
Normal file
@ -0,0 +1,74 @@
|
||||
function html() {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">位置拾取(起点、终点)</span>
|
||||
<button class="edit"><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 subtitle-box">
|
||||
<span class="subtitle">视域夹角</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="range-box">
|
||||
<div class="range-bg">
|
||||
<div class="range-process-box">
|
||||
<div class="range-process"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-node-box">
|
||||
<span class="range-node-text">0°</span>
|
||||
<span class="range-node-text">45°</span>
|
||||
<span class="range-node-text">90°</span>
|
||||
<span class="range-node-text">135°</span>
|
||||
<span class="range-node-text">180°</span>
|
||||
<div class="range-node-active"><span class="range-node-active-text">0°</span></div>
|
||||
</div>
|
||||
<input type="range" max="180" min="0" step="1" name="horizontalViewAngle">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">经度:</span>
|
||||
<span class="text-number" name="lng"></span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">偏航角:</span>
|
||||
<span class="text-number" name="viewHeading"></span>
|
||||
<span class="unit">°</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">纬度:</span>
|
||||
<span class="text-number" name="lat"></span>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">俯仰角:</span>
|
||||
<span class="text-number" name="viewPitch"></span>
|
||||
<span class="unit">°</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">高度:</span>
|
||||
<span class="text-number" name="alt"></span>
|
||||
<span class="unit text-number" style="margin-left: 5px;">m</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
512
src/Obj/Analysis/ViewShed2/_index.js
Normal file
512
src/Obj/Analysis/ViewShed2/_index.js
Normal file
@ -0,0 +1,512 @@
|
||||
/*
|
||||
* @Author: Wang jianLei
|
||||
* @Date: 2022-05-17 21:49:28
|
||||
* @Last Modified by: Wang JianLei
|
||||
* @Last Modified time: 2022-05-19 22:08:14
|
||||
*/
|
||||
|
||||
let ViewShed = function (sdk, canvasEleId) {
|
||||
if (!sdk.viewer) throw new Error("no viewer object!");
|
||||
alert(canvasEleId)
|
||||
let canvasEle = document.getElementById(canvasEleId);
|
||||
if (!canvasEle) throw new Error("the canvas element is not exist");
|
||||
this.canvasEle = canvasEle;
|
||||
this.viewer = sdk.viewer;
|
||||
this.handler = undefined;
|
||||
this.lightCamera;
|
||||
this.pyramid;
|
||||
this.frustumPrimitive;
|
||||
this.viewershedPolygon;
|
||||
};
|
||||
ViewShed.prototype = {
|
||||
/**
|
||||
* 初始化handler
|
||||
*/
|
||||
initHandler() {
|
||||
if (this.handler) {
|
||||
this.handler.destroy();
|
||||
this.handler = undefined;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 开始执行视域分析
|
||||
* @param {number} precision 精度,值越大创建耗时越长,建议在10~20之间
|
||||
*/
|
||||
createViewshed: function (precision) {
|
||||
let $this = this;
|
||||
let scene = $this.viewer.scene;
|
||||
$this.initHandler();
|
||||
$this.clearAll();
|
||||
$this.handler = new Cesium.ScreenSpaceEventHandler($this.viewer.canvas);
|
||||
$this.handler.setInputAction((event) => {
|
||||
// 禁止地球旋转和缩放,地球的旋转会对鼠标移动监听有影响,所以需要禁止
|
||||
scene.screenSpaceCameraController.enableRotate = false;
|
||||
scene.screenSpaceCameraController.enableZoom = false;
|
||||
scene.globe.depthTestAgainstTerrain = true;
|
||||
let earthPosition = scene.pickPosition(event.position);
|
||||
let pos = $this.cartesian3ToDegree(earthPosition);
|
||||
$this.handler.setInputAction(function (event) {
|
||||
let newPosition = scene.pickPosition(event.endPosition);
|
||||
if (Cesium.defined(newPosition)) {
|
||||
let pos1 = $this.cartesian3ToDegree(newPosition);
|
||||
let distance = Cesium.Cartesian3.distance(newPosition, earthPosition);
|
||||
let angle = $this.getAngle(pos[0], pos[1], pos1[0], pos1[1]);
|
||||
let pitch = $this.getPitch(earthPosition, newPosition);
|
||||
$this.ViewShedOptions = {
|
||||
viewPosition: earthPosition, //观测点 笛卡尔坐标
|
||||
endPosition: newPosition, //目标点 笛卡尔坐标
|
||||
direction: angle, //观测方位角 默认为`0`,范围`0~360`
|
||||
pitch: pitch, //俯仰角,radius,默认为`0`
|
||||
horizontalViewAngle: 90, //可视域水平夹角,默认为 `90`,范围`0~360`
|
||||
verticalViewAngle: 60, //可视域垂直夹角,默认为`60`,范围`0~180`
|
||||
visibleAreaColor: Cesium.Color.GREEN, //可视区域颜色,默认为`green`
|
||||
invisibleAreaColor: Cesium.Color.RED, //不可见区域颜色,默认为`red`
|
||||
visualRange: distance, //距离,单位`米`
|
||||
};
|
||||
$this.updateViewShed();
|
||||
}
|
||||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||||
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
|
||||
|
||||
$this.handler.setInputAction(() => {
|
||||
$this.initHandler();
|
||||
// 开启地球旋转和缩放
|
||||
scene.screenSpaceCameraController.enableRotate = true;
|
||||
scene.screenSpaceCameraController.enableZoom = true;
|
||||
$this.drawViewershed(precision);
|
||||
}, Cesium.ScreenSpaceEventType.LEFT_UP);
|
||||
},
|
||||
|
||||
ReturnDistance(pos0, pos1) {
|
||||
let distance = 0;
|
||||
let point1cartographic = Cesium.Cartographic.fromCartesian(pos0);
|
||||
let point2cartographic = Cesium.Cartographic.fromCartesian(pos1);
|
||||
/**根据经纬度计算出距离**/
|
||||
let geodesic = new Cesium.EllipsoidGeodesic();
|
||||
geodesic.setEndPoints(point1cartographic, point2cartographic);
|
||||
let s = geodesic.surfaceDistance;
|
||||
return s;
|
||||
},
|
||||
getHeight(x, y, objectsToExclude) {
|
||||
let endCartographic = Cesium.Cartographic.fromDegrees(x, y);
|
||||
let endHeight = this.viewer.scene.sampleHeight(
|
||||
endCartographic,
|
||||
objectsToExclude
|
||||
);
|
||||
return endHeight;
|
||||
},
|
||||
|
||||
cartesian3ToDegree: function (Cartesian3) {
|
||||
let _ellipsoid = this.viewer.scene.globe.ellipsoid;
|
||||
let _cartographic = _ellipsoid.cartesianToCartographic(Cartesian3);
|
||||
let _lat = Cesium.Math.toDegrees(_cartographic.latitude);
|
||||
let _lng = Cesium.Math.toDegrees(_cartographic.longitude);
|
||||
let _alt = _cartographic.height;
|
||||
return [_lng, _lat, _alt];
|
||||
},
|
||||
getAngle: function (lng1, lat1, lng2, lat2) {
|
||||
let dRotateAngle = Math.atan2(Math.abs(lng1 - lng2), Math.abs(lat1 - lat2));
|
||||
if (lng2 >= lng1) {
|
||||
dRotateAngle = lat2 < lat1 ? Math.PI - dRotateAngle : dRotateAngle;
|
||||
} else {
|
||||
dRotateAngle =
|
||||
lat2 >= lat1 ? 2 * Math.PI - dRotateAngle : Math.PI + dRotateAngle;
|
||||
}
|
||||
dRotateAngle = (dRotateAngle * 180) / Math.PI;
|
||||
return dRotateAngle;
|
||||
},
|
||||
|
||||
getPitch(pointA, pointB) {
|
||||
let transfrom = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
|
||||
const vector = Cesium.Cartesian3.subtract(
|
||||
pointB,
|
||||
pointA,
|
||||
new Cesium.Cartesian3()
|
||||
);
|
||||
let direction = Cesium.Matrix4.multiplyByPointAsVector(
|
||||
Cesium.Matrix4.inverse(transfrom, transfrom),
|
||||
vector,
|
||||
vector
|
||||
);
|
||||
Cesium.Cartesian3.normalize(direction, direction);
|
||||
return Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z);
|
||||
},
|
||||
|
||||
updateViewShed: function () {
|
||||
this.clear();
|
||||
this.setLightCamera();
|
||||
this.addVisualPyramid();
|
||||
this.createFrustum();
|
||||
},
|
||||
clear: function () {
|
||||
if (this.pyramid) {
|
||||
this.viewer.entities.removeById(this.pyramid.id);
|
||||
this.pyramid = undefined;
|
||||
}
|
||||
if (this.frustumPrimitive) {
|
||||
this.viewer.scene.primitives.remove(this.frustumPrimitive);
|
||||
this.frustumPrimitive = undefined;
|
||||
}
|
||||
if (this.debugModelMatrixPrimitive) {
|
||||
this.viewer.scene.primitives.remove(this.debugModelMatrixPrimitive);
|
||||
this.debugModelMatrixPrimitive = undefined;
|
||||
}
|
||||
},
|
||||
clearAll: function () {
|
||||
this.clear();
|
||||
if (this.viewershedPolygon) {
|
||||
this.viewer.scene.primitives.remove(this.viewershedPolygon);
|
||||
this.viewershedPolygon = undefined;
|
||||
}
|
||||
},
|
||||
addVisualPyramid: function () {
|
||||
let options = this.ViewShedOptions;
|
||||
let position = options.viewPosition;
|
||||
let visualRange = Number(options.visualRange);
|
||||
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
|
||||
this.debugModelMatrixPrimitive = this.viewer.scene.primitives.add(
|
||||
new Cesium.DebugModelMatrixPrimitive({
|
||||
modelMatrix: transform,
|
||||
length: 5.0,
|
||||
})
|
||||
);
|
||||
const halfClock = options.horizontalViewAngle / 2;
|
||||
const halfCone = options.verticalViewAngle / 2;
|
||||
const pitch = Cesium.Math.toDegrees(options.pitch);
|
||||
const ellipsoid = new Cesium.EllipsoidGraphics({
|
||||
radii: new Cesium.Cartesian3(visualRange, visualRange, visualRange),
|
||||
minimumClock: Cesium.Math.toRadians(90 - options.direction - halfClock),
|
||||
maximumClock: Cesium.Math.toRadians(90 - options.direction + halfClock),
|
||||
minimumCone: Cesium.Math.toRadians(90 - pitch - halfCone),
|
||||
maximumCone: Cesium.Math.toRadians(90 - pitch + halfCone),
|
||||
fill: false,
|
||||
outline: true,
|
||||
subdivisions: 256,
|
||||
stackPartitions: 64,
|
||||
slicePartitions: 64,
|
||||
outlineColor: Cesium.Color.YELLOWGREEN.withAlpha(0.5),
|
||||
});
|
||||
const pyramidEntity = new Cesium.Entity({
|
||||
position: position,
|
||||
ellipsoid,
|
||||
});
|
||||
this.pyramid = this.viewer.entities.add(pyramidEntity);
|
||||
},
|
||||
setLightCamera: function () {
|
||||
if (!this.lightCamera) {
|
||||
this.lightCamera = new Cesium.Camera(this.viewer.scene);
|
||||
}
|
||||
let options = this.ViewShedOptions;
|
||||
let visualRange = Number(options.visualRange);
|
||||
this.lightCamera.position = options.viewPosition;
|
||||
this.lightCamera.frustum.near = 0.1;
|
||||
this.lightCamera.frustum.far = visualRange;
|
||||
const hr = Cesium.Math.toRadians(options.horizontalViewAngle);
|
||||
const vr = Cesium.Math.toRadians(options.verticalViewAngle);
|
||||
this.lightCamera.frustum.aspectRatio =
|
||||
(visualRange * Math.tan(hr / 2) * 2) /
|
||||
(visualRange * Math.tan(vr / 2) * 2);
|
||||
this.lightCamera.frustum.fov = hr > vr ? hr : vr;
|
||||
this.lightCamera.setView({
|
||||
destination: options.viewPosition,
|
||||
orientation: {
|
||||
heading: Cesium.Math.toRadians(options.direction || 0),
|
||||
pitch: options.pitch || 0,
|
||||
roll: 0,
|
||||
},
|
||||
});
|
||||
},
|
||||
createFrustum: function () {
|
||||
const scratchRight = new Cesium.Cartesian3();
|
||||
const scratchRotation = new Cesium.Matrix3();
|
||||
const scratchOrientation = new Cesium.Quaternion();
|
||||
const direction = this.lightCamera.directionWC;
|
||||
const up = this.lightCamera.upWC;
|
||||
let right = this.lightCamera.rightWC;
|
||||
right = Cesium.Cartesian3.negate(right, scratchRight);
|
||||
let rotation = scratchRotation;
|
||||
Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
|
||||
Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
|
||||
Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
|
||||
let orientation = Cesium.Quaternion.fromRotationMatrix(
|
||||
rotation,
|
||||
scratchOrientation
|
||||
);
|
||||
let instanceOutline = new Cesium.GeometryInstance({
|
||||
geometry: new Cesium.FrustumOutlineGeometry({
|
||||
frustum: this.lightCamera.frustum,
|
||||
origin: this.ViewShedOptions.viewPosition,
|
||||
orientation: orientation,
|
||||
}),
|
||||
id: "视椎体轮廓线" + Math.random().toString(36).substr(2),
|
||||
attributes: {
|
||||
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
||||
new Cesium.Color(0.0, 1.0, 0.0, 1.0)
|
||||
),
|
||||
show: new Cesium.ShowGeometryInstanceAttribute(true),
|
||||
},
|
||||
});
|
||||
this.frustumPrimitive = this.viewer.scene.primitives.add(
|
||||
new Cesium.Primitive({
|
||||
geometryInstances: instanceOutline,
|
||||
appearance: new Cesium.PerInstanceColorAppearance({
|
||||
flat: true,
|
||||
translucent: false,
|
||||
closed: true,
|
||||
}),
|
||||
})
|
||||
);
|
||||
},
|
||||
createPoint: function (firstPos, secondPos) {
|
||||
let entity4FirstPos = new Cesium.Entity({
|
||||
name: "firstPos",
|
||||
show: true,
|
||||
position: firstPos,
|
||||
point: {
|
||||
show: true,
|
||||
pixelSize: 20,
|
||||
color: Cesium.Color.RED,
|
||||
outlineColor: Cesium.Color.YELLOW,
|
||||
outlineWidth: 5,
|
||||
},
|
||||
description: `
|
||||
<p>这是绘制的视椎体起点</p>`,
|
||||
});
|
||||
this.viewer.entities.add(entity4FirstPos);
|
||||
let entity4SecondPos = new Cesium.Entity({
|
||||
name: "secondPos",
|
||||
show: true,
|
||||
position: secondPos,
|
||||
point: {
|
||||
show: true,
|
||||
pixelSize: 30,
|
||||
color: Cesium.Color.YELLOW,
|
||||
outlineColor: Cesium.Color.RED,
|
||||
outlineWidth: 8,
|
||||
},
|
||||
description: `
|
||||
<p>这是绘制的视椎体视角终点</p>`,
|
||||
});
|
||||
this.viewer.entities.add(entity4SecondPos);
|
||||
},
|
||||
|
||||
//绘制可视域
|
||||
add(positionArr) {
|
||||
let polygon = new Cesium.PolygonGeometry({
|
||||
polygonHierarchy: new Cesium.PolygonHierarchy(
|
||||
Cesium.Cartesian3.fromDegreesArray(positionArr)
|
||||
),
|
||||
height: 0.0,
|
||||
extrudedHeight: 0.0,
|
||||
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
|
||||
stRotation: 0.0, // 纹理的旋转坐标(以弧度为单位),正旋转是逆时针方向
|
||||
ellipsoid: Cesium.Ellipsoid.WGS84,
|
||||
granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数
|
||||
perPositionHeight: false, // 每个位置点使用的高度
|
||||
closeTop: true,
|
||||
closeBottom: true,
|
||||
// NONE 与椭圆表面不符的直线;GEODESIC 遵循测地路径;RHUMB 遵循大黄蜂或恶魔般的道路。
|
||||
arcType: Cesium.ArcType.GEODESIC, // 多边形边缘线型
|
||||
});
|
||||
|
||||
let polygonInstance = new Cesium.GeometryInstance({
|
||||
geometry: polygon,
|
||||
name: "ViewershedPolygon",
|
||||
attributes: {
|
||||
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
||||
Cesium.Color.BLUE.withAlpha(0.6)
|
||||
),
|
||||
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
|
||||
},
|
||||
});
|
||||
this.viewershedPolygon = this.viewer.scene.primitives.add(
|
||||
new Cesium.GroundPrimitive({
|
||||
geometryInstances: polygonInstance,
|
||||
appearance: new Cesium.EllipsoidSurfaceAppearance({
|
||||
aboveGround: true,
|
||||
material: new Cesium.Material({
|
||||
fabric: {
|
||||
type: "Image",
|
||||
uniforms: {
|
||||
image: this.returnImgae(),
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
})
|
||||
);
|
||||
},
|
||||
drawViewershed(precision) {
|
||||
const pos = this.cartesian3ToDegree(this.ViewShedOptions.viewPosition);
|
||||
const radius = this.ViewShedOptions.visualRange;
|
||||
const direction = this.ViewShedOptions.direction;
|
||||
let boundary = this.computeBoundaryOptions(pos, radius, direction);
|
||||
const bbox = boundary.bbox;
|
||||
let mask = turf.polygon([boundary.boundaryPoints]);
|
||||
const dis = this.ViewShedOptions.visualRange / (precision * 1000);
|
||||
let gridPoints = turf.pointGrid(bbox, dis, { mask: mask });
|
||||
|
||||
let pointsResult = this.createTargetPoints(gridPoints, dis, pos);
|
||||
let variogram = kriging.train(
|
||||
pointsResult.values,
|
||||
pointsResult.lngs,
|
||||
pointsResult.lats,
|
||||
"exponential",
|
||||
0,
|
||||
100
|
||||
);
|
||||
let grid = kriging.grid([boundary.boundaryPoints], variogram, dis / 1000);
|
||||
const colors = [
|
||||
"#ff000080",
|
||||
"#ff000080",
|
||||
"#ff000080",
|
||||
"#ff000080",
|
||||
"#ff000080",
|
||||
"#ff000080",
|
||||
"#00ff0080",
|
||||
"#00ff0080",
|
||||
"#00ff0080",
|
||||
"#00ff0080",
|
||||
"#00ff0080",
|
||||
"#00ff0080",
|
||||
];
|
||||
|
||||
this.canvasEle.width = 3840;
|
||||
this.canvasEle.height = 2160;
|
||||
kriging.plot(
|
||||
this.canvasEle,
|
||||
grid,
|
||||
[bbox[0], bbox[2]],
|
||||
[bbox[1], bbox[3]],
|
||||
colors
|
||||
);
|
||||
this.add(boundary.positionArr);
|
||||
},
|
||||
computeBoundaryOptions(pos, radius, angle) {
|
||||
let Ea = 6378137; // 赤道半径
|
||||
let Eb = 6356725; // 极半径
|
||||
const lng = pos[0],
|
||||
lat = pos[1];
|
||||
const bbox = [lng, lat, lng, lat]; //[minX, minY, maxX, maxY]
|
||||
let positionArr = [];
|
||||
let boundaryPoints = [];
|
||||
positionArr.push(lng, lat);
|
||||
boundaryPoints.push([lng, lat]);
|
||||
//正北是0°
|
||||
let start = angle + 45 > 360 ? angle - 45 - 360 : angle - 45;
|
||||
let end = start + 90;
|
||||
for (let i = start; i <= end; i++) {
|
||||
let dx = radius * Math.sin((i * Math.PI) / 180.0);
|
||||
let dy = radius * Math.cos((i * Math.PI) / 180.0);
|
||||
let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0;
|
||||
let ed = ec * Math.cos((lat * Math.PI) / 180);
|
||||
let BJD = lng + ((dx / ed) * 180.0) / Math.PI;
|
||||
let BWD = lat + ((dy / ec) * 180.0) / Math.PI;
|
||||
positionArr.push(BJD, BWD);
|
||||
boundaryPoints.push([BJD, BWD]);
|
||||
this.refreshBBox(bbox, BJD, BWD);
|
||||
}
|
||||
boundaryPoints.push([lng, lat]);
|
||||
return {
|
||||
positionArr,
|
||||
boundaryPoints,
|
||||
bbox,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* 更新外围矩形 Bbox
|
||||
* @param {Array} result 外围矩形Bbox-[minX, minY, maxX, maxY]
|
||||
* @param {Number} x 经度
|
||||
* @param {Number} y 纬度
|
||||
*/
|
||||
refreshBBox(result, x, y) {
|
||||
result[0] = x < result[0] ? x : result[0];
|
||||
result[1] = y < result[1] ? y : result[1];
|
||||
result[2] = x > result[2] ? x : result[2];
|
||||
result[3] = y > result[3] ? y : result[3];
|
||||
},
|
||||
/**
|
||||
* 插值点用射线判断通视性
|
||||
* @param {*} gridPoints 网格点
|
||||
* @param {*} step 步长,可以理解成是精度
|
||||
* @param {*} sourcePos 视域分析起点
|
||||
* @returns kriging插值所需的参数对象{ values:[], lngs:[], lats:[]}
|
||||
*/
|
||||
createTargetPoints(gridPoints, step, sourcePos) {
|
||||
let positionArr = [];
|
||||
let objectsToExclude = [
|
||||
this.frustumPrimitive,
|
||||
this.pyramid,
|
||||
this.debugModelMatrixPrimitive,
|
||||
];
|
||||
let values = [],
|
||||
lngs = [],
|
||||
lats = [];
|
||||
let height = this.getHeight(sourcePos[0], sourcePos[1], objectsToExclude);
|
||||
positionArr.push({
|
||||
x: sourcePos[0],
|
||||
y: sourcePos[1],
|
||||
z: height,
|
||||
});
|
||||
let viewPoint = this.ViewShedOptions.viewPosition;
|
||||
for (let index = 0; index < gridPoints.features.length; index++) {
|
||||
const feature = gridPoints.features[index];
|
||||
const coords = feature.geometry.coordinates;
|
||||
const x = coords[0],
|
||||
y = coords[1];
|
||||
let h = this.getHeight(x, y, objectsToExclude);
|
||||
let endPoint = Cesium.Cartesian3.fromDegrees(x, y, h);
|
||||
let direction = Cesium.Cartesian3.normalize(
|
||||
Cesium.Cartesian3.subtract(
|
||||
endPoint,
|
||||
viewPoint,
|
||||
new Cesium.Cartesian3()
|
||||
),
|
||||
new Cesium.Cartesian3()
|
||||
);
|
||||
// 建立射线
|
||||
let ray = new Cesium.Ray(viewPoint, direction);
|
||||
let result = this.viewer.scene.pickFromRay(ray, objectsToExclude); // 计算交互点,返回第一个
|
||||
if (result) {
|
||||
let buffer = this.ReturnDistance(endPoint, result.position);
|
||||
// let M_color = Cesium.Color.GREEN;
|
||||
if (buffer > step) {
|
||||
// M_color = Cesium.Color.RED;
|
||||
values.push(0);
|
||||
} else {
|
||||
values.push(1);
|
||||
}
|
||||
lngs.push(x);
|
||||
lats.push(y);
|
||||
// this.viewer.entities.add(
|
||||
// new Cesium.Entity({
|
||||
// name: "插值点哦",
|
||||
// show: true,
|
||||
// position: endPoint,
|
||||
// point: {
|
||||
// show: true,
|
||||
// pixelSize: 10,
|
||||
// color: M_color,
|
||||
// outlineWidth: 2,
|
||||
// outlineColor: Cesium.Color.YELLOW,
|
||||
// },
|
||||
// })
|
||||
// );
|
||||
}
|
||||
}
|
||||
return {
|
||||
values,
|
||||
lngs,
|
||||
lats,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* canvas转image图片
|
||||
* @returns base64图片
|
||||
*/
|
||||
returnImgae() {
|
||||
return this.canvasEle.toDataURL("image/png");
|
||||
},
|
||||
};
|
||||
|
||||
export default ViewShed;
|
131
src/Obj/Analysis/ViewShed2/glsl.js
Normal file
131
src/Obj/Analysis/ViewShed2/glsl.js
Normal file
@ -0,0 +1,131 @@
|
||||
export default `
|
||||
#define USE_CUBE_MAP_SHADOW true
|
||||
uniform sampler2D colorTexture;
|
||||
uniform sampler2D depthTexture;
|
||||
varying vec2 v_textureCoordinates;
|
||||
uniform mat4 camera_projection_matrix;
|
||||
uniform mat4 camera_view_matrix;
|
||||
uniform samplerCube shadowMap_textureCube;
|
||||
uniform mat4 shadowMap_matrix;
|
||||
uniform vec4 shadowMap_lightPositionEC;
|
||||
uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
|
||||
uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
|
||||
uniform float helsing_viewDistance;
|
||||
uniform vec4 helsing_visibleAreaColor;
|
||||
uniform vec4 helsing_invisibleAreaColor;
|
||||
|
||||
struct zx_shadowParameters
|
||||
{
|
||||
vec3 texCoords;
|
||||
float depthBias;
|
||||
float depth;
|
||||
float nDotL;
|
||||
vec2 texelStepSize;
|
||||
float normalShadingSmooth;
|
||||
float darkness;
|
||||
};
|
||||
|
||||
float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
|
||||
{
|
||||
float depthBias = shadowParameters.depthBias;
|
||||
float depth = shadowParameters.depth;
|
||||
float nDotL = shadowParameters.nDotL;
|
||||
float normalShadingSmooth = shadowParameters.normalShadingSmooth;
|
||||
float darkness = shadowParameters.darkness;
|
||||
vec3 uvw = shadowParameters.texCoords;
|
||||
depth -= depthBias;
|
||||
float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
|
||||
return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
|
||||
}
|
||||
|
||||
vec4 getPositionEC(){
|
||||
return czm_windowToEyeCoordinates(gl_FragCoord);
|
||||
}
|
||||
|
||||
vec3 getNormalEC(){
|
||||
return vec3(1.);
|
||||
}
|
||||
|
||||
vec4 toEye(in vec2 uv,in float depth){
|
||||
vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
|
||||
vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
|
||||
posInCamera=posInCamera/posInCamera.w;
|
||||
return posInCamera;
|
||||
}
|
||||
|
||||
vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
|
||||
vec3 v01=point-planeOrigin;
|
||||
float d=dot(planeNormal,v01);
|
||||
return(point-planeNormal*d);
|
||||
}
|
||||
|
||||
float getDepth(in vec4 depth){
|
||||
float z_window=czm_unpackDepth(depth);
|
||||
z_window=czm_reverseLogDepth(z_window);
|
||||
float n_range=czm_depthRange.near;
|
||||
float f_range=czm_depthRange.far;
|
||||
return(2.*z_window-n_range-f_range)/(f_range-n_range);
|
||||
}
|
||||
|
||||
float shadow(in vec4 positionEC){
|
||||
vec3 normalEC=getNormalEC();
|
||||
zx_shadowParameters shadowParameters;
|
||||
shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
|
||||
shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
|
||||
shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
|
||||
shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
|
||||
vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
|
||||
float distance=length(directionEC);
|
||||
directionEC=normalize(directionEC);
|
||||
float radius=shadowMap_lightPositionEC.w;
|
||||
if(distance>radius)
|
||||
{
|
||||
return 2.0;
|
||||
}
|
||||
vec3 directionWC=czm_inverseViewRotation*directionEC;
|
||||
shadowParameters.depth=distance/radius-0.0003;
|
||||
shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
|
||||
shadowParameters.texCoords=directionWC;
|
||||
float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
|
||||
return visibility;
|
||||
}
|
||||
|
||||
bool visible(in vec4 result)
|
||||
{
|
||||
result.x/=result.w;
|
||||
result.y/=result.w;
|
||||
result.z/=result.w;
|
||||
return result.x>=-1.&&result.x<=1.
|
||||
&&result.y>=-1.&&result.y<=1.
|
||||
&&result.z>=-1.&&result.z<=1.;
|
||||
}
|
||||
|
||||
void main(){
|
||||
// 釉色 = 结构二维(颜色纹理, 纹理坐标)
|
||||
gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
|
||||
// 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
|
||||
float depth = getDepth(texture2D(depthTexture, v_textureCoordinates));
|
||||
// 视角 = (纹理坐标, 深度)
|
||||
vec4 viewPos = toEye(v_textureCoordinates, depth);
|
||||
// 世界坐标
|
||||
vec4 wordPos = czm_inverseView * viewPos;
|
||||
// 虚拟相机中坐标
|
||||
vec4 vcPos = camera_view_matrix * wordPos;
|
||||
float near = .001 * helsing_viewDistance;
|
||||
float dis = length(vcPos.xyz);
|
||||
if(dis > near && dis < helsing_viewDistance){
|
||||
// 透视投影
|
||||
vec4 posInEye = camera_projection_matrix * vcPos;
|
||||
// 可视区颜色
|
||||
// vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
|
||||
// vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
|
||||
if(visible(posInEye)){
|
||||
float vis = shadow(viewPos);
|
||||
if(vis > 0.3){
|
||||
gl_FragColor = mix(gl_FragColor,helsing_visibleAreaColor,.5);
|
||||
} else {
|
||||
gl_FragColor = mix(gl_FragColor,helsing_invisibleAreaColor,.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
721
src/Obj/Analysis/ViewShed2/index.js
Normal file
721
src/Obj/Analysis/ViewShed2/index.js
Normal file
@ -0,0 +1,721 @@
|
||||
// ViewShed.js
|
||||
import glsl from './glsl'
|
||||
import Event from "../../../Event";
|
||||
import MouseTip from "../../../MouseTip";
|
||||
import Tools from "../../../Tools";
|
||||
import Controller from "../../../Controller";
|
||||
import Dialog from '../../../BaseDialog';
|
||||
import { html } from "./_element";
|
||||
/**
|
||||
* @constructor
|
||||
* @description 可视域分析(测试中)
|
||||
* @param sdk
|
||||
* @param {Object} options 选项。
|
||||
* @param {Cesium.Cartesian3} options.viewPosition 观测点位置。
|
||||
* @param {Cesium.Cartesian3} options.viewPositionEnd 最远观测点位置(如果设置了观测距离,这个属性可以不设置)。
|
||||
* @param {Number} options.viewDistance 观测距离(单位`米`)。
|
||||
* @param {Number} options.viewHeading 航向角(单位`度`)。
|
||||
* @param {Number} options.viewPitch 俯仰角(单位`度`)。
|
||||
* @param {Number} options.horizontalViewAngle=90 可视域水平夹角(单位`度`)。
|
||||
* @param {Number} options.verticalViewAngle=60 可视域垂直夹角(单位`度`)。
|
||||
* @param {String} options.visibleAreaColor=#008000 可视区域颜色(默认值`绿色`)。
|
||||
* @param {String} options.invisibleAreaColor=#FF0000 不可视区域颜色(默认值`红色`)。
|
||||
*/
|
||||
class ViewShedStage extends Tools {
|
||||
|
||||
constructor(sdk, options = {}, _Dialog = {}) {
|
||||
super(sdk, options)
|
||||
|
||||
// if (Object.hasOwn(options.viewPosition, 'lng') && Object.hasOwn(options.viewPosition, 'lat') && Object.hasOwn(options.viewPosition, 'alt')) {
|
||||
// this.error = '请提供观测点位置!'
|
||||
// window.ELEMENT && window.ELEMENT.Message({
|
||||
// message: '请提供观测点位置!',
|
||||
// type: 'warning',
|
||||
// duration: 1500
|
||||
// });
|
||||
// return
|
||||
// }
|
||||
|
||||
this.viewer = sdk.viewer;
|
||||
this.options = {}
|
||||
this.options.viewPosition = options.viewPosition;
|
||||
this.options.viewPositionEnd = options.viewPositionEnd;
|
||||
this.options.horizontalViewAngle = (options.horizontalViewAngle || options.horizontalViewAngle === 0) ? options.horizontalViewAngle : 90.0;
|
||||
this.options.verticalViewAngle = (options.verticalViewAngle || options.verticalViewAngle === 0) ? options.verticalViewAngle : 60.0;
|
||||
this.options.visibleAreaColor = options.visibleAreaColor || '#008000';
|
||||
this.options.invisibleAreaColor = options.invisibleAreaColor || '#FF0000';
|
||||
// this.enabled = (typeof options.enabled === "boolean") ? options.enabled : true;
|
||||
// this.softShadows = (typeof options.softShadows === "boolean") ? options.softShadows : true;
|
||||
// this.size = options.size || 10240; // 2048
|
||||
this.ids = []
|
||||
this.Dialog = _Dialog
|
||||
this.html = null
|
||||
YJ.Analysis.AnalysesResults.push(this)
|
||||
ViewShedStage.create(this)
|
||||
// ViewShedStage.edit(this)
|
||||
// this.update();
|
||||
}
|
||||
|
||||
get viewPosition() {
|
||||
return this.options.viewPosition
|
||||
}
|
||||
|
||||
set viewPosition(v) {
|
||||
this.options.viewPosition = v
|
||||
this.ids[0] && (this.viewer.entities.getById(this.ids[0]).position = new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt))
|
||||
this.update()
|
||||
// let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt)
|
||||
}
|
||||
|
||||
get viewPositionEnd() {
|
||||
return this.options.viewPositionEnd
|
||||
}
|
||||
|
||||
set viewPositionEnd(v) {
|
||||
this.options.viewPositionEnd = v
|
||||
this.ids[1] && (this.viewer.entities.getById(this.ids[1]).position = new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt))
|
||||
this.update()
|
||||
// let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
|
||||
// this.viewDistance = this.viewPositionEnd ? Cesium.Cartesian3.distance(this.viewPosition, this.viewPositionEnd) : (options.viewDistance || 100.0);
|
||||
}
|
||||
|
||||
get horizontalViewAngle() {
|
||||
return this.options.horizontalViewAngle
|
||||
}
|
||||
|
||||
set horizontalViewAngle(v) {
|
||||
this.options.horizontalViewAngle = v
|
||||
if (this._DialogObject && this._DialogObject._element && this._DialogObject._element.content) {
|
||||
let contentElm = this._DialogObject._element.content
|
||||
let e_horizontalViewAngle = contentElm.querySelector("input[name='horizontalViewAngle']")
|
||||
e_horizontalViewAngle.value = v
|
||||
let rangeNodeActive = contentElm.getElementsByClassName('range-node-active')[0]
|
||||
let rangeNodeActiveText = rangeNodeActive.getElementsByClassName('range-node-active-text')[0]
|
||||
rangeNodeActiveText.innerHTML = v + '°';
|
||||
let rangeProcess = contentElm.getElementsByClassName('range-process')[0]
|
||||
rangeProcess.style.width = v / 180 * 100 + '%'
|
||||
}
|
||||
this.update()
|
||||
}
|
||||
|
||||
get visibleAreaColor() {
|
||||
return this.options.visibleAreaColor
|
||||
}
|
||||
|
||||
set visibleAreaColor(v) {
|
||||
this.options.visibleAreaColor = v
|
||||
this.update()
|
||||
}
|
||||
|
||||
get invisibleAreaColor() {
|
||||
return this.options.invisibleAreaColor
|
||||
}
|
||||
|
||||
set invisibleAreaColor(v) {
|
||||
this.options.invisibleAreaColor = v
|
||||
this.update()
|
||||
}
|
||||
|
||||
get verticalViewAngle() {
|
||||
return this.options.verticalViewAngle
|
||||
}
|
||||
|
||||
set verticalViewAngle(v) {
|
||||
this.options.verticalViewAngle = v
|
||||
this.update()
|
||||
}
|
||||
|
||||
get viewDistance() {
|
||||
let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt)
|
||||
let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
|
||||
let distance = Cesium.Cartesian3.distance(viewPosition3, viewPositionEnd3)
|
||||
return distance
|
||||
}
|
||||
|
||||
get viewHeading() {
|
||||
let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt)
|
||||
let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
|
||||
let heading = getHeading(viewPosition3, viewPositionEnd3)
|
||||
if (this.html) {
|
||||
let e_viewHeading = this.html.querySelector("span[name='viewHeading']")
|
||||
e_viewHeading.innerHTML = Number(heading.toFixed(8))
|
||||
}
|
||||
return heading
|
||||
}
|
||||
|
||||
get viewPitch() {
|
||||
let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt)
|
||||
let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
|
||||
let pitch = getPitch(viewPosition3, viewPositionEnd3)
|
||||
if (this.html) {
|
||||
let e_viewPitch = this.html.querySelector("span[name='viewPitch']")
|
||||
e_viewPitch.innerHTML = Number(pitch.toFixed(8))
|
||||
}
|
||||
return pitch
|
||||
}
|
||||
|
||||
static create(that) {
|
||||
let count = 0;
|
||||
if (!YJ.Measure.GetMeasureStatus()) {
|
||||
that.event = new Event(that.sdk)
|
||||
that.tip = new MouseTip('左键选择观测点位置,右键取消', that.sdk)
|
||||
YJ.Measure.SetMeasureStatus(true)
|
||||
that.event.mouse_left((movement, cartesian) => {
|
||||
if (!that.viewPosition) {
|
||||
that.options.viewPosition = that.cartesian3Towgs84(cartesian, that.viewer)
|
||||
that.ids.push(ViewShedStage.create_point(that, cartesian))
|
||||
that.tip.set_text("左键选择最远观测点位置,右键取消")
|
||||
}
|
||||
count++
|
||||
if (count === 2) {
|
||||
that.options.viewPositionEnd = that.cartesian3Towgs84(cartesian, that.viewer)
|
||||
that.ids.push(ViewShedStage.create_point(that, cartesian))
|
||||
end()
|
||||
that.update()
|
||||
}
|
||||
})
|
||||
that.event.mouse_move((movement, cartesian) => {
|
||||
that.tip.setPosition(cartesian, movement.endPosition.x, movement.endPosition.y)
|
||||
})
|
||||
that.event.mouse_right((movement, cartesian) => {
|
||||
that.ids.forEach(id => {
|
||||
that.viewer.entities.removeById(id)
|
||||
})
|
||||
that.ids = []
|
||||
end()
|
||||
})
|
||||
that.event.gesture_pinck_start((movement, cartesian) => {
|
||||
let startTime = new Date()
|
||||
that.event.gesture_pinck_end(() => {
|
||||
let endTime = new Date()
|
||||
if (endTime - startTime >= 500) {
|
||||
that.ids.forEach(id => {
|
||||
that.viewer.entities.removeById(id)
|
||||
})
|
||||
that.ids = []
|
||||
end()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
else {
|
||||
console.log('上一次测量未结束')
|
||||
}
|
||||
|
||||
function end() {
|
||||
that.ids.forEach(id => {
|
||||
let entity = that.viewer.entities.getById(id)
|
||||
entity.show = false
|
||||
})
|
||||
YJ.Measure.SetMeasureStatus(false)
|
||||
that.tip.destroy()
|
||||
that.event.destroy()
|
||||
that.tip = null
|
||||
that.event = null
|
||||
if (count === 2) {
|
||||
ViewShedStage.edit(that)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static create_point(that, cartesian) {
|
||||
let id = that.randomString()
|
||||
let p = that.cartesian3Towgs84(cartesian, that.viewer)
|
||||
let params = {
|
||||
id: id,
|
||||
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt),
|
||||
billboard: {
|
||||
image: that.getSourceRootPath() + '/img/point.png',
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
||||
color: Cesium.Color.WHITE.withAlpha(0.99)
|
||||
}
|
||||
}
|
||||
that.viewer.entities.add(
|
||||
new Cesium.Entity(params)
|
||||
)
|
||||
return id
|
||||
}
|
||||
|
||||
|
||||
add() {
|
||||
this.createLightCamera();
|
||||
this.createShadowMap();
|
||||
this.createPostStage();
|
||||
this.drawFrustumOutline();
|
||||
this.drawSketch();
|
||||
}
|
||||
|
||||
update() {
|
||||
this.clear();
|
||||
this.add();
|
||||
}
|
||||
|
||||
static async edit(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.Dialog.closeCallBack && that.Dialog.closeCallBack()
|
||||
YJ.Measure.SetMeasureStatus(false)
|
||||
that.editevent && that.editevent.destroy()
|
||||
that.ControllerObject && that.ControllerObject.destroy()
|
||||
that.ids.forEach(id => {
|
||||
that.viewer.entities.removeById(id)
|
||||
})
|
||||
},
|
||||
})
|
||||
await that._DialogObject.init()
|
||||
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' view-shed'
|
||||
let contentElm = document.createElement('div');
|
||||
contentElm.innerHTML = html()
|
||||
that._DialogObject.contentAppChild(contentElm)
|
||||
let resetBtn = that._DialogObject._element.body.getElementsByClassName('edit')[0];
|
||||
resetBtn.addEventListener('click', () => {
|
||||
that.nodeEdit()
|
||||
})
|
||||
that.html = contentElm
|
||||
//经度值
|
||||
let e_lng = contentElm.querySelector("span[name='lng']")
|
||||
e_lng.innerHTML = Number(that.options.viewPosition.lng.toFixed(8))
|
||||
|
||||
//纬度值
|
||||
let e_lat = contentElm.querySelector("span[name='lat']")
|
||||
e_lat.innerHTML = Number(that.options.viewPosition.lat.toFixed(8))
|
||||
|
||||
//高度值
|
||||
let e_alt = contentElm.querySelector("span[name='alt']")
|
||||
e_alt.innerHTML = Number(that.options.viewPosition.alt.toFixed(8))
|
||||
|
||||
//偏航角
|
||||
let e_viewHeading = contentElm.querySelector("span[name='viewHeading']")
|
||||
e_viewHeading.innerHTML = Number(that.viewHeading.toFixed(8))
|
||||
|
||||
//俯仰角
|
||||
let e_viewPitch = contentElm.querySelector("span[name='viewPitch']")
|
||||
e_viewPitch.innerHTML = Number(that.viewPitch.toFixed(8))
|
||||
|
||||
//视域夹角
|
||||
let e_horizontalViewAngle = contentElm.querySelector("input[name='horizontalViewAngle']")
|
||||
e_horizontalViewAngle.value = that.options.horizontalViewAngle
|
||||
let rangeNodeActive = contentElm.getElementsByClassName('range-node-active')[0]
|
||||
let rangeNodeActiveText = rangeNodeActive.getElementsByClassName('range-node-active-text')[0]
|
||||
let rangeProcess = contentElm.getElementsByClassName('range-process')[0]
|
||||
let percentage = that.horizontalViewAngle / 180 * 100
|
||||
rangeNodeActive.style.left = percentage + '%';
|
||||
rangeProcess.style.width = percentage + '%'
|
||||
rangeNodeActiveText.innerHTML = that.horizontalViewAngle + '°';
|
||||
let timeout
|
||||
e_horizontalViewAngle.addEventListener('input', () => {
|
||||
let percentage = e_horizontalViewAngle.value / 180 * 100
|
||||
rangeNodeActive.style.left = percentage + '%';
|
||||
rangeProcess.style.width = percentage + '%';
|
||||
rangeNodeActiveText.innerHTML = e_horizontalViewAngle.value + '°';
|
||||
})
|
||||
e_horizontalViewAngle.addEventListener('change', () => {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => {
|
||||
that.horizontalViewAngle = e_horizontalViewAngle.value;
|
||||
}, 300);
|
||||
});
|
||||
}
|
||||
|
||||
clear() {
|
||||
YJ.Measure.SetMeasureStatus(false)
|
||||
this.tip && this.tip.destroy()
|
||||
this.event && this.event.destroy()
|
||||
this.tip = null
|
||||
this.event = null
|
||||
if (this.sketch) {
|
||||
this.viewer.entities.removeById(this.sketch.id);
|
||||
this.sketch = null;
|
||||
}
|
||||
if (this.frustumOutline) {
|
||||
this.frustumOutline.destroy();
|
||||
this.frustumOutline = null;
|
||||
}
|
||||
if (this.FrustumBottomSurface) {
|
||||
this.FrustumBottomSurface.destroy();
|
||||
this.FrustumBottomSurface = null;
|
||||
}
|
||||
if (this.postStage) {
|
||||
this.viewer.scene.postProcessStages.remove(this.postStage);
|
||||
this.postStage = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.clear()
|
||||
this.editevent && this.editevent.destroy()
|
||||
this.ControllerObject && this.ControllerObject.destroy()
|
||||
this.ids.forEach(id => {
|
||||
this.viewer.entities.removeById(id)
|
||||
})
|
||||
YJ.Measure.SetMeasureStatus(false)
|
||||
}
|
||||
|
||||
nodeEdit() {
|
||||
if (YJ.Measure.GetMeasureStatus()) {
|
||||
console.log('上一次测量未结束')
|
||||
}
|
||||
else {
|
||||
this.editevent && this.editevent.destroy()
|
||||
this.ids.forEach(id => {
|
||||
let entity = this.viewer.entities.getById(id)
|
||||
entity.show = true
|
||||
})
|
||||
let selectPoint
|
||||
YJ.Measure.SetMeasureStatus(true)
|
||||
// this.tip = new MouseTip('左键选择要操作的观测点,右键取消', this.sdk)
|
||||
this.editevent = new Event(this.sdk)
|
||||
this.editevent.mouse_left((movement, cartesian) => {
|
||||
let pick = this.viewer.scene.pick(movement.position);
|
||||
if (pick && pick.id && pick.id.id && this.ids.indexOf(pick.id.id) != -1 && (!selectPoint || selectPoint.id != pick.id.id)) {
|
||||
selectPoint = pick.id
|
||||
// this.event.destroy()
|
||||
// this.tip.destroy()
|
||||
this.viewer.entities.getById(this.ids[0]).position = new Cesium.Cartesian3.fromDegrees(this.viewPosition.lng, this.viewPosition.lat, this.viewPosition.alt)
|
||||
this.viewer.entities.getById(this.ids[1]).position = new Cesium.Cartesian3.fromDegrees(this.viewPositionEnd.lng, this.viewPositionEnd.lat, this.viewPositionEnd.alt)
|
||||
this.viewPosition
|
||||
this.ControllerObject && this.ControllerObject.destroy()
|
||||
console.log(this.cartesian3Towgs84(selectPoint.position._value, this.sdk.viewer))
|
||||
this.ControllerObject = new Controller(this.sdk, { position: { ...this.cartesian3Towgs84(selectPoint.position._value, this.sdk.viewer) } })
|
||||
this.ControllerObject.controllerCallBack = (params, status) => {
|
||||
if (params.position.alt < 0) {
|
||||
params.position.alt = 0
|
||||
}
|
||||
selectPoint.position = new Cesium.Cartesian3.fromDegrees(params.position.lng, params.position.lat, params.position.alt)
|
||||
if (status) {
|
||||
if (this.ids.indexOf(pick.id.id) == 0) {
|
||||
this.viewPosition = params.position
|
||||
}
|
||||
else {
|
||||
this.viewPositionEnd = params.position
|
||||
}
|
||||
YJ.Measure.SetMeasureStatus(true)
|
||||
}
|
||||
}
|
||||
this.ControllerObject.editTranslational()
|
||||
}
|
||||
})
|
||||
this.editevent.mouse_right((movement, cartesian) => {
|
||||
YJ.Measure.SetMeasureStatus(false)
|
||||
this.editevent && this.editevent.destroy()
|
||||
this.ControllerObject && this.ControllerObject.destroy()
|
||||
this.ids.forEach(id => {
|
||||
let entity = this.viewer.entities.getById(id)
|
||||
entity.show = false
|
||||
})
|
||||
selectPoint = null
|
||||
})
|
||||
this.editevent.mouse_move((movement, cartesian) => {
|
||||
// this.tip.setPosition(
|
||||
// cartesian,
|
||||
// movement.endPosition.x,
|
||||
// movement.endPosition.y
|
||||
// )
|
||||
})
|
||||
|
||||
this.editevent.gesture_pinck_start((movement, cartesian) => {
|
||||
let startTime = new Date()
|
||||
this.editevent.gesture_pinck_end(() => {
|
||||
let endTime = new Date()
|
||||
if (endTime - startTime >= 500) {
|
||||
YJ.Measure.SetMeasureStatus(false)
|
||||
this.editevent && this.editevent.destroy()
|
||||
this.ControllerObject && this.ControllerObject.destroy()
|
||||
this.ids.forEach(id => {
|
||||
let entity = this.viewer.entities.getById(id)
|
||||
entity.show = false
|
||||
})
|
||||
selectPoint = null
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
createLightCamera() {
|
||||
let _this = this
|
||||
this.lightCamera = new Cesium.Camera(this.viewer.scene);
|
||||
this.lightCamera.position = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt);
|
||||
// if (this.viewPositionEnd) {
|
||||
// let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.viewPositionEnd, this.viewPosition, new Cesium.Cartesian3()), new Cesium.Cartesian3());
|
||||
// this.lightCamera.direction = direction; // direction是相机面向的方向
|
||||
// }
|
||||
this.lightCamera.frustum.near = this.viewDistance * 0.001;
|
||||
this.lightCamera.frustum.far = this.viewDistance;
|
||||
const hr = Cesium.Math.toRadians(this.horizontalViewAngle);
|
||||
const vr = Cesium.Math.toRadians(this.verticalViewAngle);
|
||||
const aspectRatio =
|
||||
(this.viewDistance * Math.tan(hr / 2) * 2) /
|
||||
(this.viewDistance * Math.tan(vr / 2) * 2);
|
||||
this.lightCamera.frustum.aspectRatio = aspectRatio;
|
||||
if (hr > vr) {
|
||||
this.lightCamera.frustum.fov = hr;
|
||||
} else {
|
||||
this.lightCamera.frustum.fov = vr;
|
||||
}
|
||||
this.lightCamera.setView({
|
||||
destination: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
|
||||
orientation: {
|
||||
heading: Cesium.Math.toRadians(this.viewHeading || 0),
|
||||
pitch: Cesium.Math.toRadians(this.viewPitch || 0),
|
||||
roll: 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createShadowMap() {
|
||||
this.shadowMap = new Cesium.ShadowMap({
|
||||
context: (this.viewer.scene).context,
|
||||
lightCamera: this.lightCamera,
|
||||
enabled: true,
|
||||
isPointLight: true,
|
||||
pointLightRadius: this.viewDistance,
|
||||
cascadesEnabled: false,
|
||||
size: 2048, // 2048
|
||||
softShadows: true,
|
||||
normalOffset: false,
|
||||
fromLightSource: false
|
||||
});
|
||||
this.viewer.scene.shadowMap = this.shadowMap;
|
||||
}
|
||||
|
||||
createPostStage() {
|
||||
const fs = glsl
|
||||
const postStage = new Cesium.PostProcessStage({
|
||||
fragmentShader: fs,
|
||||
uniforms: {
|
||||
shadowMap_textureCube: () => {
|
||||
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
|
||||
return Reflect.get(this.shadowMap, "_shadowMapTexture");
|
||||
},
|
||||
shadowMap_matrix: () => {
|
||||
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
|
||||
return Reflect.get(this.shadowMap, "_shadowMapMatrix");
|
||||
},
|
||||
shadowMap_lightPositionEC: () => {
|
||||
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
|
||||
return Reflect.get(this.shadowMap, "_lightPositionEC");
|
||||
},
|
||||
shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: () => {
|
||||
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
|
||||
const bias = this.shadowMap._pointBias;
|
||||
return Cesium.Cartesian4.fromElements(
|
||||
bias.normalOffsetScale,
|
||||
this.shadowMap._distance,
|
||||
this.shadowMap.maximumDistance,
|
||||
0.0,
|
||||
new Cesium.Cartesian4()
|
||||
);
|
||||
},
|
||||
shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: () => {
|
||||
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
|
||||
const bias = this.shadowMap._pointBias;
|
||||
const scratchTexelStepSize = new Cesium.Cartesian2();
|
||||
const texelStepSize = scratchTexelStepSize;
|
||||
texelStepSize.x = 1.0 / this.shadowMap._textureSize.x;
|
||||
texelStepSize.y = 1.0 / this.shadowMap._textureSize.y;
|
||||
|
||||
return Cesium.Cartesian4.fromElements(
|
||||
texelStepSize.x,
|
||||
texelStepSize.y,
|
||||
bias.depthBias,
|
||||
bias.normalShadingSmooth,
|
||||
new Cesium.Cartesian4()
|
||||
);
|
||||
},
|
||||
camera_projection_matrix: this.lightCamera.frustum.projectionMatrix,
|
||||
camera_view_matrix: this.lightCamera.viewMatrix,
|
||||
helsing_viewDistance: () => {
|
||||
return this.viewDistance;
|
||||
},
|
||||
helsing_visibleAreaColor: Cesium.Color.fromCssColorString(this.visibleAreaColor),
|
||||
helsing_invisibleAreaColor: Cesium.Color.fromCssColorString(this.invisibleAreaColor),
|
||||
shadowMap: this.shadowMap,
|
||||
far: () => {
|
||||
return this.viewDistance;
|
||||
},
|
||||
}
|
||||
});
|
||||
this.postStage = this.viewer.scene.postProcessStages.add(postStage);
|
||||
}
|
||||
|
||||
drawFrustumOutline() {
|
||||
const scratchRight = new Cesium.Cartesian3();
|
||||
const scratchRotation = new Cesium.Matrix3();
|
||||
const scratchOrientation = new Cesium.Quaternion();
|
||||
const position = this.lightCamera.positionWC;
|
||||
const direction = this.lightCamera.directionWC;
|
||||
const up = this.lightCamera.upWC;
|
||||
let right = this.lightCamera.rightWC;
|
||||
right = Cesium.Cartesian3.negate(right, scratchRight);
|
||||
let rotation = scratchRotation;
|
||||
Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
|
||||
Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
|
||||
Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
|
||||
let orientation = Cesium.Quaternion.fromRotationMatrix(rotation, scratchOrientation);
|
||||
|
||||
let instance = new Cesium.GeometryInstance({
|
||||
geometry: new Cesium.FrustumOutlineGeometry({
|
||||
frustum: this.lightCamera.frustum,
|
||||
origin: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
|
||||
orientation: orientation
|
||||
}),
|
||||
id: Math.random().toString(36).substr(2),
|
||||
attributes: {
|
||||
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
||||
Cesium.Color.YELLOWGREEN//new Cesium.Color(0.0, 1.0, 0.0, 1.0)
|
||||
),
|
||||
show: new Cesium.ShowGeometryInstanceAttribute(true)
|
||||
}
|
||||
});
|
||||
|
||||
let frustum = this.lightCamera.frustum.clone()
|
||||
frustum.near = frustum.far - 100
|
||||
let instance2 = new Cesium.GeometryInstance({
|
||||
geometry: new Cesium.FrustumGeometry({
|
||||
frustum: frustum,
|
||||
origin: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
|
||||
orientation: orientation,
|
||||
vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
|
||||
}),
|
||||
id: Math.random().toString(36).substr(2),
|
||||
attributes: {
|
||||
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
||||
Cesium.Color.YELLOWGREEN//new Cesium.Color(0.0, 1.0, 0.0, 1.0)
|
||||
),
|
||||
show: new Cesium.ShowGeometryInstanceAttribute(true)
|
||||
}
|
||||
});
|
||||
|
||||
this.frustumOutline = this.viewer.scene.primitives.add(
|
||||
new Cesium.Primitive({
|
||||
geometryInstances: [instance],
|
||||
appearance: new Cesium.PerInstanceColorAppearance({
|
||||
flat: true,
|
||||
translucent: false
|
||||
})
|
||||
})
|
||||
);
|
||||
|
||||
const radius = this.viewDistance;
|
||||
const angle = this.viewHeading;
|
||||
|
||||
let Ea = 6378137; // 赤道半径
|
||||
let Eb = 6356725; // 极半径
|
||||
const lng = this.options.viewPosition.lng,
|
||||
lat = this.options.viewPosition.lat;
|
||||
let positionArr = [];
|
||||
let boundaryPoints = [];
|
||||
positionArr.push(lng, lat);
|
||||
boundaryPoints.push([lng, lat]);
|
||||
//正北是0°
|
||||
let start = angle + 45 > 360 ? angle - 45 - 360 : angle - 45;
|
||||
let end = start + 90;
|
||||
for (let i = start; i <= end; i++) {
|
||||
let dx = radius * Math.sin((i * Math.PI) / 180.0);
|
||||
let dy = radius * Math.cos((i * Math.PI) / 180.0);
|
||||
let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0;
|
||||
let ed = ec * Math.cos((lat * Math.PI) / 180);
|
||||
let BJD = lng + ((dx / ed) * 180.0) / Math.PI;
|
||||
let BWD = lat + ((dy / ec) * 180.0) / Math.PI;
|
||||
positionArr.push(BJD, BWD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
let polygon = new Cesium.PolygonGeometry({
|
||||
polygonHierarchy: new Cesium.PolygonHierarchy(
|
||||
Cesium.Cartesian3.fromDegreesArray(positionArr)
|
||||
),
|
||||
height: 0.0,
|
||||
extrudedHeight: 0.0,
|
||||
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
|
||||
stRotation: 0.0, // 纹理的旋转坐标(以弧度为单位),正旋转是逆时针方向
|
||||
ellipsoid: Cesium.Ellipsoid.WGS84,
|
||||
granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数
|
||||
perPositionHeight: false, // 每个位置点使用的高度
|
||||
closeTop: true,
|
||||
closeBottom: true,
|
||||
// NONE 与椭圆表面不符的直线;GEODESIC 遵循测地路径;RHUMB 遵循大黄蜂或恶魔般的道路。
|
||||
arcType: Cesium.ArcType.GEODESIC, // 多边形边缘线型
|
||||
});
|
||||
let polygonInstance = new Cesium.GeometryInstance({
|
||||
geometry: polygon,
|
||||
name: "ViewershedPolygon",
|
||||
attributes: {
|
||||
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
||||
Cesium.Color.BLUE
|
||||
),
|
||||
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
|
||||
},
|
||||
});
|
||||
// this.FrustumBottomSurface = this.viewer.scene.primitives.add(
|
||||
// new Cesium.GroundPrimitive({
|
||||
// geometryInstances: polygonInstance,
|
||||
// appearance: new Cesium.PerInstanceColorAppearance({
|
||||
// translucent: true, //false时透明度无效
|
||||
// closed: false,
|
||||
// }),
|
||||
// })
|
||||
// );
|
||||
}
|
||||
|
||||
drawSketch() {
|
||||
this.sketch = this.viewer.entities.add({
|
||||
name: 'sketch',
|
||||
position: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
|
||||
orientation: Cesium.Transforms.headingPitchRollQuaternion(
|
||||
Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
|
||||
Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - 90, this.viewPitch, 0.0)
|
||||
),
|
||||
ellipsoid: {
|
||||
radii: new Cesium.Cartesian3(
|
||||
this.viewDistance,
|
||||
this.viewDistance,
|
||||
this.viewDistance
|
||||
),
|
||||
// innerRadii: new Cesium.Cartesian3(2.0, 2.0, 2.0),
|
||||
minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
|
||||
maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
|
||||
minimumCone: Cesium.Math.toRadians(this.verticalViewAngle + 7.75),
|
||||
maximumCone: Cesium.Math.toRadians(180 - this.verticalViewAngle - 7.75),
|
||||
fill: false,
|
||||
outline: true,
|
||||
subdivisions: 256,
|
||||
stackPartitions: 64,
|
||||
slicePartitions: 64,
|
||||
outlineColor: Cesium.Color.YELLOWGREEN
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getHeading(fromPosition, toPosition) {
|
||||
let finalPosition = new Cesium.Cartesian3();
|
||||
let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
|
||||
Cesium.Matrix4.inverse(matrix4, matrix4);
|
||||
Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
|
||||
Cesium.Cartesian3.normalize(finalPosition, finalPosition);
|
||||
return Cesium.Math.toDegrees(Math.atan2(finalPosition.x, finalPosition.y));
|
||||
}
|
||||
|
||||
function getPitch(fromPosition, toPosition) {
|
||||
let finalPosition = new Cesium.Cartesian3();
|
||||
let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
|
||||
Cesium.Matrix4.inverse(matrix4, matrix4);
|
||||
Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
|
||||
Cesium.Cartesian3.normalize(finalPosition, finalPosition);
|
||||
return Cesium.Math.toDegrees(Math.asin(finalPosition.z));
|
||||
}
|
||||
|
||||
export default ViewShedStage;
|
Reference in New Issue
Block a user