/* 九、绘制弓形面 */ class DrawBowPlane { constructor(arg) { this.viewer = arg.viewer; this.Cesium = arg.Cesium; this.tt = 0.4; this.floatingPoint = null;//标识点 this.drawHandler = null;//画事件 this.DrawBowPlane = null;//弓形 this._DrawBowPlaneLast = null; //最后一个弓形 this._positions = [];//活动点 this._entities_point = [];//脏数据 this._entities_PincerArrow = [];//脏数据 this._DrawBowPlaneData = null; //用于构造弓形 this.DrawStartEvent = new Cesium.Event(); //开始绘制事件 this.DrawEndEvent = new Cesium.Event(); //结束绘制事件 /* 通用参数集合 */ this._param = { id: "DrawStraightArrow", polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色 outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色 outlineWidth: 1, //边框宽度 } /* 创建面材质 */ this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor); /* 创建线材质 */ // this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线 // dashLength: 16, // color: Cesium.Color.fromCssColorString(this._param.outlineColor) // }); this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor); } //返回弓形 get PincerArrow() { return this._DrawBowPlaneLast; } //返回弓形数据用于加载弓形 getData() { return this._DrawBowPlaneData; } // 修改编辑调用计算 computePosition(data) { var $this = this; if (data.length < 3) { return; } var DrawBowPlane = []; let positions = []; for (var i = 0; i < data.length; i++) { positions.push($this.cartesianToLatlng(data[i])); var cart3 =$this.lonLatToMercator($this.cartesianToLatlng(data[i])); DrawBowPlane.push(cart3); } let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowPlane[0], DrawBowPlane[2], DrawBowPlane[1], null, null]; let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3) let radius = $this.MathDistance(pnt1, center) let angle1 = $this.getAzimuth(pnt1, center) let angle2 = $this.getAzimuth(pnt2, center) if ($this.isClockWise(pnt1, pnt2, pnt3)) { startAngle = angle2 endAngle = angle1 } else { startAngle = angle1 endAngle = angle2 } let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle); let pHierarchy = []; for (var l = 0; l < getArcPoint.length; l++) { var cart3 =$this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l])); pHierarchy.push(cart3); } pHierarchy.push(pHierarchy[0]) $this._DrawBowPlaneData = positions return new $this.Cesium.PolygonHierarchy(pHierarchy) } //加载 addload(data) { var $this = this; if (data.length < 3) { return; } var DrawBowPlane = []; for (var i = 0; i < data.length; i++) { var cart3 =$this.lonLatToMercator(data[i]); DrawBowPlane.push(cart3); } let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowPlane[0], DrawBowPlane[2], DrawBowPlane[1], null, null]; let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3) let radius = $this.MathDistance(pnt1, center) let angle1 = $this.getAzimuth(pnt1, center) let angle2 = $this.getAzimuth(pnt2, center) if ($this.isClockWise(pnt1, pnt2, pnt3)) { startAngle = angle2 endAngle = angle1 } else { startAngle = angle1 endAngle = angle2 } let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle); let pHierarchy = []; for (var l = 0; l < getArcPoint.length; l++) { var cart3 =$this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l])); pHierarchy.push(cart3); } pHierarchy.push(pHierarchy[0]) var arrowEntity = $this.viewer.entities.add({ Type: 'DrawBowPlane', Position: data, id: data.id || $this.objId, polygon: { hierarchy: new $this.Cesium.PolygonHierarchy(pHierarchy), show: true, material: $this.Cesium.Color.YELLOW, width: 3, clampToGround: true, outlineWidth:3, outline: true, outlineColor: Cesium.Color.MAGENTA, } } ) return arrowEntity } // 开始创建 startCreate(drawType) { this.drawType = drawType var $this = this; this.handler = new $this.Cesium.ScreenSpaceEventHandler($this.viewer.scene.canvas); this.handler.setInputAction(function (event) { //屏幕坐标转世界坐标 var position = event.position; if (!$this.Cesium.defined(position)) { return; } var ray = $this.viewer.camera.getPickRay(position); if (!$this.Cesium.defined(ray)) { return; } var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene); if (!$this.Cesium.defined(cartesian)) { return; } if ($this._positions.length == 0) { $this._positions.push(cartesian.clone()); $this.floatingPoint = $this.createPoint(cartesian); } if ($this._positions.length <= 2) { $this.createPoint(cartesian); // 绘制点 $this._positions.push(cartesian); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); this.handler.setInputAction(function (event) { //移动时绘制面 //console.log("_positions",_positions); if ($this._positions.length < 2) { return; } //屏幕坐标转世界坐标 var position = event.endPosition; if (!$this.Cesium.defined(position)) { return; } var ray = $this.viewer.camera.getPickRay(position); if (!$this.Cesium.defined(ray)) { return; } var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene); if (!$this.Cesium.defined(cartesian)) { return; } //console.log("点击地图移动采集的点:",cartesian); if (!$this.Cesium.defined($this.DrawBowPlane)) { $this.DrawBowPlane = $this.createDrawBowPlane(); } $this.floatingPoint.position.setValue(cartesian); if ($this.DrawBowPlane) { //替换最后一个点 // _positions.pop(); // _positions.push(cartesian); //替换中间点 if ($this._positions.length == 3) { $this._positions[1] = cartesian; } else { $this._positions.pop(); $this._positions.push(cartesian); } } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); //右击停止采集 this.handler.setInputAction(function (movement) { if ($this._positions.length >= 3) { $this._DrawBowPlaneData = $this._positions.concat(); $this.viewer.entities.remove($this.DrawBowPlane); //移除 $this.DrawBowPlane = null; var lnglatArr = []; for (var i = 0; i < $this._DrawBowPlaneData.length; i++) { var lnglat = $this.cartesianToLatlng($this._DrawBowPlaneData[i]); lnglatArr.push(lnglat) } $this._DrawBowPlaneData = lnglatArr; var pincerArrow = $this.addload(lnglatArr); //加载 $this._entities_PincerArrow.push(pincerArrow); $this._DrawBowPlaneLast = pincerArrow; $this.viewer.entities.remove($this.floatingPoint); $this.floatingPoint = null; //删除关键点 $this.clearPoint(); $this.destroy() } }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); } //创建弓形 createDrawBowPlane() { let $this = this var DrawBowPlaneEntity = $this.viewer.entities.add({ polygon: { hierarchy: new $this.Cesium.CallbackProperty(function () { if ($this._positions.length < 3) { return; } var DrawBowPlane = []; for (var i = 0; i < $this._positions.length; i++) { var cart3 =$this.lonLatToMercator($this.cartesianToLatlng($this._positions[i])); DrawBowPlane.push(cart3); } let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowPlane[0], DrawBowPlane[2], DrawBowPlane[1], null, null]; let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3) let radius = $this.MathDistance(pnt1, center) let angle1 = $this.getAzimuth(pnt1, center) let angle2 = $this.getAzimuth(pnt2, center) if ($this.isClockWise(pnt1, pnt2, pnt3)) { startAngle = angle2 endAngle = angle1 } else { startAngle = angle1 endAngle = angle2 } let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle); let pHierarchy = []; for (var l = 0; l < getArcPoint.length; l++) { var cart3 =$this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l])); pHierarchy.push(cart3); } pHierarchy.push(pHierarchy[0]) return new $this.Cesium.PolygonHierarchy(pHierarchy) }, false), show: true, material: $this.Cesium.Color.YELLOW, clampToGround: true } } ) $this._entities_PincerArrow.push(DrawBowPlaneEntity); return DrawBowPlaneEntity } //创建点 createPoint(cartesian) { var $this = this; var point = this.viewer.entities.add({ position: cartesian, point: { pixelSize: 10, color: $this.Cesium.Color.RED, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, } }); $this._entities_point.push(point); return point; } cartesianToLatlng(cartesian) { let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian); let lat = this.Cesium.Math.toDegrees(cartographic.latitude); let lng = this.Cesium.Math.toDegrees(cartographic.longitude); let alt = cartographic.height; return [lng, lat]; } //销毁 destroy() { if (this.handler) { this.handler.destroy(); this.handler = null; } } clearPoint() { this.DrawEndEvent.raiseEvent(this._DrawBowPlaneLast, this._DrawBowPlaneData, this.drawType); for (var i = 0; i < this._entities_point.length; i++) { this.viewer.entities.remove(this._entities_point[i]); } this._entities_point = []; //脏数据 } //清空实体对象 clear() { for (var i = 0; i < this._entities_point.length; i++) { this.viewer.entities.remove(this._entities_point[i]); } for (var i = 0; i < this._entities_PincerArrow.length; i++) { this.viewer.entities.remove(this._entities_PincerArrow[i]); } this.floatingPoint = null;//标识点 this._PincerArrow = null; //活动弓形 this._PincerArrowLast = null; //最后一个弓形 this._positions = []; //活动点 this._entities_point = []; //脏数据 this._entities_PincerArrow = []; //脏数据 this._PincerArrowData = null; //用于构造弓形数据 } getCatesian3FromPX(px) { var cartesian; var ray = this.viewer.camera.getPickRay(px); if (!ray) return null; cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene); return cartesian; } _computeTempPositions() { var _this = this; var pnts = [].concat(_this._positions); var num = pnts.length; var first = pnts[0]; var last = pnts[num - 1]; if (_this._isSimpleXYZ(first, last) == false) { pnts.push(first); num += 1; } _this.tempPositions = []; for (var i = 1; i < num; i++) { var p1 = pnts[i - 1]; var p2 = pnts[i]; var cp = _this._computeCenterPotition(p1, p2); _this.tempPositions.push(p1); _this.tempPositions.push(cp); } } _isSimpleXYZ(p1, p2) { if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) { return true; } return false; } _computeCenterPotition(p1, p2) { var _this = this; var c1 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p1); var c2 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p2); var cm = new _this.Cesium.EllipsoidGeodesic(c1, c2).interpolateUsingFraction(0.5); var cp = _this.viewer.scene.globe.ellipsoid.cartographicToCartesian(cm); return cp; } /** * 笛卡尔坐标转经纬度坐标 */ getLonLat(cartesian) { var cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian); cartographic.height = this.viewer.scene.globe.getHeight(cartographic); var pos = { lon: cartographic.longitude, lat: cartographic.latitude, alt: cartographic.height }; pos.lon = this.Cesium.Math.toDegrees(pos.lon); pos.lat = this.Cesium.Math.toDegrees(pos.lat); return pos; } LatlngTocartesian(latlng) { let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]); return cartesian3 } /** * 经纬度坐标转墨卡托坐标 */ // 墨卡托坐标系:展开地球,赤道作为x轴,向东为x轴正方,本初子午线作为y轴,向北为y轴正方向。 // 数字20037508.34是地球赤道周长的一半:地球半径6378137米,赤道周长2*PI*r = 2 * 20037508.3427892,墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892] lonLatToMercator(Latlng) { var E = Latlng[0]; var N = Latlng[1]; var x = E * 20037508.34 / 180; var y = Math.log(Math.tan((90 + N) * Math.PI / 360)) / (Math.PI / 180); y = y * 20037508.34 / 180; return [x, y] } /** * 墨卡托坐标转经纬度坐标转 */ WebMercator2lonLat(mercator) { let x = mercator[0] / 20037508.34 * 180; let ly = mercator[1] / 20037508.34 * 180; let y = 180 / Math.PI * (2 * Math.atan(Math.exp(ly * Math.PI / 180)) - Math.PI / 2) return [x, y]; } ////////////////////////////////////////弓形///////////////////////////////////////////////////// /** * 通过三个点确定一个圆的中心点 * @param point1 * @param point2 * @param point3 */ getCircleCenterOfThreePoints(point1, point2, point3) { let pntA = [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2] let pntB = [pntA[0] - point1[1] + point2[1], pntA[1] + point1[0] - point2[0]] let pntC = [(point1[0] + point3[0]) / 2, (point1[1] + point3[1]) / 2] let pntD = [pntC[0] - point1[1] + point3[1], pntC[1] + point1[0] - point3[0]] return this.getIntersectPoint(pntA, pntB, pntC, pntD) } /** * 获取交集的点 * @param pntA * @param pntB * @param pntC * @param pntD * @returns {[*,*]} */ getIntersectPoint(pntA, pntB, pntC, pntD) { if (pntA[1] === pntB[1]) { let f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1]) let x = f * (pntA[1] - pntC[1]) + pntC[0] let y = pntA[1] return [x, y] } if (pntC[1] === pntD[1]) { let e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1]) let x = e * (pntC[1] - pntA[1]) + pntA[0] let y = pntC[1] return [x, y] } let e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1]) let f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1]) let y = (e * pntA[1] - pntA[0] - f * pntC[1] + pntC[0]) / (e - f) let x = e * y - e * pntA[1] + pntA[0] return [x, y] } /** * 计算两个坐标之间的距离 * @ignore * @param pnt1 * @param pnt2 * @returns {number} * @constructor */ MathDistance(pnt1, pnt2) { return (Math.sqrt(Math.pow((pnt1[0] - pnt2[0]), 2) + Math.pow((pnt1[1] - pnt2[1]), 2))) } /** * 获取方位角(地平经度) * @param startPoint * @param endPoint * @returns {*} */ getAzimuth(startPoint, endPoint) { let azimuth let angle = Math.asin(Math.abs(endPoint[1] - startPoint[1]) / (this.MathDistance(startPoint, endPoint))) if (endPoint[1] >= startPoint[1] && endPoint[0] >= startPoint[0]) { azimuth = angle + Math.PI } else if (endPoint[1] >= startPoint[1] && endPoint[0] < startPoint[0]) { azimuth = Math.PI * 2 - angle } else if (endPoint[1] < startPoint[1] && endPoint[0] < startPoint[0]) { azimuth = angle } else if (endPoint[1] < startPoint[1] && endPoint[0] >= startPoint[0]) { azimuth = Math.PI - angle } return azimuth } /** * 判断是否是顺时针 * @param pnt1 * @param pnt2 * @param pnt3 * @returns {boolean} */ isClockWise (pnt1, pnt2, pnt3) { return ((pnt3[1] - pnt1[1]) * (pnt2[0] - pnt1[0]) > (pnt2[1] - pnt1[1]) * (pnt3[0] - pnt1[0])) } /** * 插值弓形线段点 * @param center * @param radius * @param startAngle * @param endAngle * @returns {null} */ getArcPoints(center, radius, startAngle, endAngle) { let [x, y, pnts, angleDiff] = [null, null, [], (endAngle - startAngle)] angleDiff = ((angleDiff < 0) ? (angleDiff + (Math.PI * 2)) : angleDiff) for (let i = 0; i <= 100; i++) { let angle = startAngle + angleDiff * i / 100 x = center[0] + radius * Math.cos(angle) y = center[1] + radius * Math.sin(angle) pnts.push([x, y]) } return pnts } } export default DrawBowPlane