DrawBowPlane.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. 九、绘制弓形面
  3. */
  4. class DrawBowPlane {
  5. constructor(arg) {
  6. this.viewer = arg.viewer;
  7. this.Cesium = arg.Cesium;
  8. this.tt = 0.4;
  9. this.floatingPoint = null;//标识点
  10. this.drawHandler = null;//画事件
  11. this.DrawBowPlane = null;//弓形
  12. this._DrawBowPlaneLast = null; //最后一个弓形
  13. this._positions = [];//活动点
  14. this._entities_point = [];//脏数据
  15. this._entities_PincerArrow = [];//脏数据
  16. this._DrawBowPlaneData = null; //用于构造弓形
  17. this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
  18. this.DrawEndEvent = new Cesium.Event(); //结束绘制事件
  19. /* 通用参数集合 */
  20. this._param = {
  21. id: "DrawStraightArrow",
  22. polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
  23. outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
  24. outlineWidth: 1, //边框宽度
  25. }
  26. /* 创建面材质 */
  27. this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
  28. /* 创建线材质 */
  29. // this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
  30. // dashLength: 16,
  31. // color: Cesium.Color.fromCssColorString(this._param.outlineColor)
  32. // });
  33. this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
  34. }
  35. //返回弓形
  36. get PincerArrow() {
  37. return this._DrawBowPlaneLast;
  38. }
  39. //返回弓形数据用于加载弓形
  40. getData() {
  41. return this._DrawBowPlaneData;
  42. }
  43. // 修改编辑调用计算
  44. computePosition(data) {
  45. var $this = this;
  46. if (data.length < 3) {
  47. return;
  48. }
  49. var DrawBowPlane = [];
  50. let positions = [];
  51. for (var i = 0; i < data.length; i++) {
  52. positions.push($this.cartesianToLatlng(data[i]));
  53. var cart3 =$this.lonLatToMercator($this.cartesianToLatlng(data[i]));
  54. DrawBowPlane.push(cart3);
  55. }
  56. let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowPlane[0], DrawBowPlane[2], DrawBowPlane[1], null, null];
  57. let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3)
  58. let radius = $this.MathDistance(pnt1, center)
  59. let angle1 = $this.getAzimuth(pnt1, center)
  60. let angle2 = $this.getAzimuth(pnt2, center)
  61. if ($this.isClockWise(pnt1, pnt2, pnt3)) {
  62. startAngle = angle2
  63. endAngle = angle1
  64. } else {
  65. startAngle = angle1
  66. endAngle = angle2
  67. }
  68. let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle);
  69. let pHierarchy = [];
  70. for (var l = 0; l < getArcPoint.length; l++) {
  71. var cart3 =$this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l]));
  72. pHierarchy.push(cart3);
  73. }
  74. pHierarchy.push(pHierarchy[0])
  75. $this._DrawBowPlaneData = positions
  76. return new $this.Cesium.PolygonHierarchy(pHierarchy)
  77. }
  78. //加载
  79. addload(data) {
  80. var $this = this;
  81. if (data.length < 3) {
  82. return;
  83. }
  84. var DrawBowPlane = [];
  85. for (var i = 0; i < data.length; i++) {
  86. var cart3 =$this.lonLatToMercator(data[i]);
  87. DrawBowPlane.push(cart3);
  88. }
  89. let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowPlane[0], DrawBowPlane[2], DrawBowPlane[1], null, null];
  90. let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3)
  91. let radius = $this.MathDistance(pnt1, center)
  92. let angle1 = $this.getAzimuth(pnt1, center)
  93. let angle2 = $this.getAzimuth(pnt2, center)
  94. if ($this.isClockWise(pnt1, pnt2, pnt3)) {
  95. startAngle = angle2
  96. endAngle = angle1
  97. } else {
  98. startAngle = angle1
  99. endAngle = angle2
  100. }
  101. let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle);
  102. let pHierarchy = [];
  103. for (var l = 0; l < getArcPoint.length; l++) {
  104. var cart3 =$this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l]));
  105. pHierarchy.push(cart3);
  106. }
  107. pHierarchy.push(pHierarchy[0])
  108. var arrowEntity = $this.viewer.entities.add({
  109. Type: 'DrawBowPlane',
  110. Position: data,
  111. id: data.id || $this.objId,
  112. polygon: {
  113. hierarchy: new $this.Cesium.PolygonHierarchy(pHierarchy),
  114. show: true,
  115. material: $this.Cesium.Color.YELLOW,
  116. width: 3,
  117. clampToGround: true,
  118. outlineWidth:3,
  119. outline: true,
  120. outlineColor: Cesium.Color.MAGENTA,
  121. }
  122. }
  123. )
  124. return arrowEntity
  125. }
  126. // 开始创建
  127. startCreate(drawType) {
  128. this.drawType = drawType
  129. var $this = this;
  130. this.handler = new $this.Cesium.ScreenSpaceEventHandler($this.viewer.scene.canvas);
  131. this.handler.setInputAction(function (event) {
  132. //屏幕坐标转世界坐标
  133. var position = event.position;
  134. if (!$this.Cesium.defined(position)) {
  135. return;
  136. }
  137. var ray = $this.viewer.camera.getPickRay(position);
  138. if (!$this.Cesium.defined(ray)) {
  139. return;
  140. }
  141. var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene);
  142. if (!$this.Cesium.defined(cartesian)) {
  143. return;
  144. }
  145. if ($this._positions.length == 0) {
  146. $this._positions.push(cartesian.clone());
  147. $this.floatingPoint = $this.createPoint(cartesian);
  148. }
  149. if ($this._positions.length <= 2) {
  150. $this.createPoint(cartesian); // 绘制点
  151. $this._positions.push(cartesian);
  152. }
  153. }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  154. this.handler.setInputAction(function (event) { //移动时绘制面
  155. //console.log("_positions",_positions);
  156. if ($this._positions.length < 2) {
  157. return;
  158. }
  159. //屏幕坐标转世界坐标
  160. var position = event.endPosition;
  161. if (!$this.Cesium.defined(position)) {
  162. return;
  163. }
  164. var ray = $this.viewer.camera.getPickRay(position);
  165. if (!$this.Cesium.defined(ray)) {
  166. return;
  167. }
  168. var cartesian = $this.viewer.scene.globe.pick(ray, $this.viewer.scene);
  169. if (!$this.Cesium.defined(cartesian)) {
  170. return;
  171. }
  172. //console.log("点击地图移动采集的点:",cartesian);
  173. if (!$this.Cesium.defined($this.DrawBowPlane)) {
  174. $this.DrawBowPlane = $this.createDrawBowPlane();
  175. }
  176. $this.floatingPoint.position.setValue(cartesian);
  177. if ($this.DrawBowPlane) {
  178. //替换最后一个点
  179. // _positions.pop();
  180. // _positions.push(cartesian);
  181. //替换中间点
  182. if ($this._positions.length == 3) {
  183. $this._positions[1] = cartesian;
  184. } else {
  185. $this._positions.pop();
  186. $this._positions.push(cartesian);
  187. }
  188. }
  189. }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  190. //右击停止采集
  191. this.handler.setInputAction(function (movement) {
  192. if ($this._positions.length >= 3) {
  193. $this._DrawBowPlaneData = $this._positions.concat();
  194. $this.viewer.entities.remove($this.DrawBowPlane); //移除
  195. $this.DrawBowPlane = null;
  196. var lnglatArr = [];
  197. for (var i = 0; i < $this._DrawBowPlaneData.length; i++) {
  198. var lnglat = $this.cartesianToLatlng($this._DrawBowPlaneData[i]);
  199. lnglatArr.push(lnglat)
  200. }
  201. $this._DrawBowPlaneData = lnglatArr;
  202. var pincerArrow = $this.addload(lnglatArr); //加载
  203. $this._entities_PincerArrow.push(pincerArrow);
  204. $this._DrawBowPlaneLast = pincerArrow;
  205. $this.viewer.entities.remove($this.floatingPoint);
  206. $this.floatingPoint = null;
  207. //删除关键点
  208. $this.clearPoint();
  209. $this.destroy()
  210. }
  211. }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  212. }
  213. //创建弓形
  214. createDrawBowPlane() {
  215. let $this = this
  216. var DrawBowPlaneEntity = $this.viewer.entities.add({
  217. polygon: {
  218. hierarchy: new $this.Cesium.CallbackProperty(function () {
  219. if ($this._positions.length < 3) {
  220. return;
  221. }
  222. var DrawBowPlane = [];
  223. for (var i = 0; i < $this._positions.length; i++) {
  224. var cart3 =$this.lonLatToMercator($this.cartesianToLatlng($this._positions[i]));
  225. DrawBowPlane.push(cart3);
  226. }
  227. let [pnt1, pnt2, pnt3, startAngle, endAngle] = [DrawBowPlane[0], DrawBowPlane[2], DrawBowPlane[1], null, null];
  228. let center = $this.getCircleCenterOfThreePoints(pnt1, pnt2, pnt3)
  229. let radius = $this.MathDistance(pnt1, center)
  230. let angle1 = $this.getAzimuth(pnt1, center)
  231. let angle2 = $this.getAzimuth(pnt2, center)
  232. if ($this.isClockWise(pnt1, pnt2, pnt3)) {
  233. startAngle = angle2
  234. endAngle = angle1
  235. } else {
  236. startAngle = angle1
  237. endAngle = angle2
  238. }
  239. let getArcPoint = $this.getArcPoints(center, radius, startAngle, endAngle);
  240. let pHierarchy = [];
  241. for (var l = 0; l < getArcPoint.length; l++) {
  242. var cart3 =$this.LatlngTocartesian($this.WebMercator2lonLat(getArcPoint[l]));
  243. pHierarchy.push(cart3);
  244. }
  245. pHierarchy.push(pHierarchy[0])
  246. return new $this.Cesium.PolygonHierarchy(pHierarchy)
  247. }, false),
  248. show: true,
  249. material: $this.Cesium.Color.YELLOW,
  250. clampToGround: true
  251. }
  252. }
  253. )
  254. $this._entities_PincerArrow.push(DrawBowPlaneEntity);
  255. return DrawBowPlaneEntity
  256. }
  257. //创建点
  258. createPoint(cartesian) {
  259. var $this = this;
  260. var point = this.viewer.entities.add({
  261. position: cartesian,
  262. point: {
  263. pixelSize: 10,
  264. color: $this.Cesium.Color.RED,
  265. heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
  266. }
  267. });
  268. $this._entities_point.push(point);
  269. return point;
  270. }
  271. cartesianToLatlng(cartesian) {
  272. let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
  273. let lat = this.Cesium.Math.toDegrees(cartographic.latitude);
  274. let lng = this.Cesium.Math.toDegrees(cartographic.longitude);
  275. let alt = cartographic.height;
  276. return [lng, lat];
  277. }
  278. //销毁
  279. destroy() {
  280. if (this.handler) {
  281. this.handler.destroy();
  282. this.handler = null;
  283. }
  284. }
  285. clearPoint() {
  286. this.DrawEndEvent.raiseEvent(this._DrawBowPlaneLast, this._DrawBowPlaneData, this.drawType);
  287. for (var i = 0; i < this._entities_point.length; i++) {
  288. this.viewer.entities.remove(this._entities_point[i]);
  289. }
  290. this._entities_point = []; //脏数据
  291. }
  292. //清空实体对象
  293. clear() {
  294. for (var i = 0; i < this._entities_point.length; i++) {
  295. this.viewer.entities.remove(this._entities_point[i]);
  296. }
  297. for (var i = 0; i < this._entities_PincerArrow.length; i++) {
  298. this.viewer.entities.remove(this._entities_PincerArrow[i]);
  299. }
  300. this.floatingPoint = null;//标识点
  301. this._PincerArrow = null; //活动弓形
  302. this._PincerArrowLast = null; //最后一个弓形
  303. this._positions = []; //活动点
  304. this._entities_point = []; //脏数据
  305. this._entities_PincerArrow = []; //脏数据
  306. this._PincerArrowData = null; //用于构造弓形数据
  307. }
  308. getCatesian3FromPX(px) {
  309. var cartesian;
  310. var ray = this.viewer.camera.getPickRay(px);
  311. if (!ray) return null;
  312. cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
  313. return cartesian;
  314. }
  315. _computeTempPositions() {
  316. var _this = this;
  317. var pnts = [].concat(_this._positions);
  318. var num = pnts.length;
  319. var first = pnts[0];
  320. var last = pnts[num - 1];
  321. if (_this._isSimpleXYZ(first, last) == false) {
  322. pnts.push(first);
  323. num += 1;
  324. }
  325. _this.tempPositions = [];
  326. for (var i = 1; i < num; i++) {
  327. var p1 = pnts[i - 1];
  328. var p2 = pnts[i];
  329. var cp = _this._computeCenterPotition(p1, p2);
  330. _this.tempPositions.push(p1);
  331. _this.tempPositions.push(cp);
  332. }
  333. }
  334. _isSimpleXYZ(p1, p2) {
  335. if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) {
  336. return true;
  337. }
  338. return false;
  339. }
  340. _computeCenterPotition(p1, p2) {
  341. var _this = this;
  342. var c1 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p1);
  343. var c2 = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(p2);
  344. var cm = new _this.Cesium.EllipsoidGeodesic(c1, c2).interpolateUsingFraction(0.5);
  345. var cp = _this.viewer.scene.globe.ellipsoid.cartographicToCartesian(cm);
  346. return cp;
  347. }
  348. /**
  349. * 笛卡尔坐标转经纬度坐标
  350. */
  351. getLonLat(cartesian) {
  352. var cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
  353. cartographic.height = this.viewer.scene.globe.getHeight(cartographic);
  354. var pos = {
  355. lon: cartographic.longitude,
  356. lat: cartographic.latitude,
  357. alt: cartographic.height
  358. };
  359. pos.lon = this.Cesium.Math.toDegrees(pos.lon);
  360. pos.lat = this.Cesium.Math.toDegrees(pos.lat);
  361. return pos;
  362. }
  363. LatlngTocartesian(latlng) {
  364. let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
  365. return cartesian3
  366. }
  367. /**
  368. * 经纬度坐标转墨卡托坐标
  369. */
  370. // 墨卡托坐标系:展开地球,赤道作为x轴,向东为x轴正方,本初子午线作为y轴,向北为y轴正方向。
  371. // 数字20037508.34是地球赤道周长的一半:地球半径6378137米,赤道周长2*PI*r = 2 * 20037508.3427892,墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892]
  372. lonLatToMercator(Latlng) {
  373. var E = Latlng[0];
  374. var N = Latlng[1];
  375. var x = E * 20037508.34 / 180;
  376. var y = Math.log(Math.tan((90 + N) * Math.PI / 360)) / (Math.PI / 180);
  377. y = y * 20037508.34 / 180;
  378. return [x, y]
  379. }
  380. /**
  381. * 墨卡托坐标转经纬度坐标转
  382. */
  383. WebMercator2lonLat(mercator) {
  384. let x = mercator[0] / 20037508.34 * 180;
  385. let ly = mercator[1] / 20037508.34 * 180;
  386. let y = 180 / Math.PI * (2 * Math.atan(Math.exp(ly * Math.PI / 180)) - Math.PI / 2)
  387. return [x, y];
  388. }
  389. ////////////////////////////////////////弓形/////////////////////////////////////////////////////
  390. /**
  391. * 通过三个点确定一个圆的中心点
  392. * @param point1
  393. * @param point2
  394. * @param point3
  395. */
  396. getCircleCenterOfThreePoints(point1, point2, point3) {
  397. let pntA = [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2]
  398. let pntB = [pntA[0] - point1[1] + point2[1], pntA[1] + point1[0] - point2[0]]
  399. let pntC = [(point1[0] + point3[0]) / 2, (point1[1] + point3[1]) / 2]
  400. let pntD = [pntC[0] - point1[1] + point3[1], pntC[1] + point1[0] - point3[0]]
  401. return this.getIntersectPoint(pntA, pntB, pntC, pntD)
  402. }
  403. /**
  404. * 获取交集的点
  405. * @param pntA
  406. * @param pntB
  407. * @param pntC
  408. * @param pntD
  409. * @returns {[*,*]}
  410. */
  411. getIntersectPoint(pntA, pntB, pntC, pntD) {
  412. if (pntA[1] === pntB[1]) {
  413. let f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1])
  414. let x = f * (pntA[1] - pntC[1]) + pntC[0]
  415. let y = pntA[1]
  416. return [x, y]
  417. }
  418. if (pntC[1] === pntD[1]) {
  419. let e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1])
  420. let x = e * (pntC[1] - pntA[1]) + pntA[0]
  421. let y = pntC[1]
  422. return [x, y]
  423. }
  424. let e = (pntB[0] - pntA[0]) / (pntB[1] - pntA[1])
  425. let f = (pntD[0] - pntC[0]) / (pntD[1] - pntC[1])
  426. let y = (e * pntA[1] - pntA[0] - f * pntC[1] + pntC[0]) / (e - f)
  427. let x = e * y - e * pntA[1] + pntA[0]
  428. return [x, y]
  429. }
  430. /**
  431. * 计算两个坐标之间的距离
  432. * @ignore
  433. * @param pnt1
  434. * @param pnt2
  435. * @returns {number}
  436. * @constructor
  437. */
  438. MathDistance(pnt1, pnt2) {
  439. return (Math.sqrt(Math.pow((pnt1[0] - pnt2[0]), 2) + Math.pow((pnt1[1] - pnt2[1]), 2)))
  440. }
  441. /**
  442. * 获取方位角(地平经度)
  443. * @param startPoint
  444. * @param endPoint
  445. * @returns {*}
  446. */
  447. getAzimuth(startPoint, endPoint) {
  448. let azimuth
  449. let angle = Math.asin(Math.abs(endPoint[1] - startPoint[1]) / (this.MathDistance(startPoint, endPoint)))
  450. if (endPoint[1] >= startPoint[1] && endPoint[0] >= startPoint[0]) {
  451. azimuth = angle + Math.PI
  452. } else if (endPoint[1] >= startPoint[1] && endPoint[0] < startPoint[0]) {
  453. azimuth = Math.PI * 2 - angle
  454. } else if (endPoint[1] < startPoint[1] && endPoint[0] < startPoint[0]) {
  455. azimuth = angle
  456. } else if (endPoint[1] < startPoint[1] && endPoint[0] >= startPoint[0]) {
  457. azimuth = Math.PI - angle
  458. }
  459. return azimuth
  460. }
  461. /**
  462. * 判断是否是顺时针
  463. * @param pnt1
  464. * @param pnt2
  465. * @param pnt3
  466. * @returns {boolean}
  467. */
  468. isClockWise (pnt1, pnt2, pnt3) {
  469. return ((pnt3[1] - pnt1[1]) * (pnt2[0] - pnt1[0]) > (pnt2[1] - pnt1[1]) * (pnt3[0] - pnt1[0]))
  470. }
  471. /**
  472. * 插值弓形线段点
  473. * @param center
  474. * @param radius
  475. * @param startAngle
  476. * @param endAngle
  477. * @returns {null}
  478. */
  479. getArcPoints(center, radius, startAngle, endAngle) {
  480. let [x, y, pnts, angleDiff] = [null, null, [], (endAngle - startAngle)]
  481. angleDiff = ((angleDiff < 0) ? (angleDiff + (Math.PI * 2)) : angleDiff)
  482. for (let i = 0; i <= 100; i++) {
  483. let angle = startAngle + angleDiff * i / 100
  484. x = center[0] + radius * Math.cos(angle)
  485. y = center[1] + radius * Math.sin(angle)
  486. pnts.push([x, y])
  487. }
  488. return pnts
  489. }
  490. }
  491. export default DrawBowPlane