DrawBowLine.js 15 KB

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