DrawAttackArrow.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. import {
  2. createTooltip
  3. } from "../../../common/common.js";
  4. import {
  5. isRuntimeApp,
  6. isRuntimeWeb,
  7. createOperationMainDom,
  8. showTooltipMessage
  9. } from "../../../common/RuntimeEnvironment.js";
  10. /*
  11. 七、绘制攻击箭头
  12. */
  13. class DrawAttackArrow {
  14. constructor(arg) {
  15. //设置唯一id 备用
  16. this.objId = Number((new Date()).getTime() + "" + Number(Math.random() * 1000).toFixed(0));
  17. this.viewer = arg.viewer;
  18. this.Cesium = arg.Cesium;
  19. // this.callback=arg.callback;
  20. this.floatingPoint = null; //标识点
  21. this._AttackArrow = null; //活动箭头
  22. this._AttackArrowLast = null; //最后一个箭头
  23. this._positions = []; //活动点
  24. this._entities_point = []; //脏数据
  25. this._entities_AttackArrow = []; //脏数据
  26. this._AttackArrowData = null; //用于构造箭头数据
  27. this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
  28. this.DrawEndEvent = new Cesium.Event(); //结束绘制事件
  29. this._tooltip = createTooltip(this.viewer.container);
  30. /* 通用参数集合 */
  31. this._param = {
  32. id: "DrawStraightArrow",
  33. polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
  34. outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
  35. outlineWidth: 1, //边框宽度
  36. }
  37. /* 创建面材质 */
  38. this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
  39. /* 创建线材质 */
  40. // this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
  41. // dashLength: 16,
  42. // color: Cesium.Color.fromCssColorString(this._param.outlineColor)
  43. // });
  44. this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
  45. }
  46. //返回箭头
  47. get AttackArrow() {
  48. return this._AttackArrowLast;
  49. }
  50. //返回箭头数据用于加载箭头
  51. getData() {
  52. return this._AttackArrowData;
  53. }
  54. //加载箭头
  55. addload(data) {
  56. var $this = this;
  57. if (data.length < 3) {
  58. return null;
  59. }
  60. var res = $this.fineArrow(data);
  61. var returnData = res.polygonalPoint;
  62. var arrowEntity = $this.viewer.entities.add({
  63. Type: 'DrawAttackArrow',
  64. Position: data,
  65. id: data.id || $this.objId,
  66. polygon: {
  67. hierarchy: new $this.Cesium.PolygonHierarchy(returnData),
  68. show: true,
  69. fill: true,
  70. clampToGround: true,
  71. material: $this.polygonMaterial
  72. }
  73. });
  74. return arrowEntity
  75. }
  76. // 修改编辑调用计算
  77. computePosition(data) {
  78. //计算面
  79. let $this = this
  80. var lnglatArr = [];
  81. for (var i = 0; i < data.length; i++) {
  82. var lnglat = $this.cartesianToLatlng(data[i]);
  83. lnglatArr.push(lnglat)
  84. }
  85. $this._AttackArrowData = lnglatArr;
  86. var res = $this.fineArrow(lnglatArr);
  87. var returnData = res.polygonalPoint;
  88. return new $this.Cesium.PolygonHierarchy(returnData)
  89. }
  90. //开始创建
  91. startCreate(drawType) {
  92. if (isRuntimeApp()) {
  93. showTooltipMessage("点击开始绘制");
  94. }
  95. var $this = this;
  96. this.drawType = drawType;
  97. this.handler = new $this.Cesium.ScreenSpaceEventHandler($this.viewer.scene.canvas);
  98. //单击开始绘制
  99. this.handler.setInputAction(function(evt) {
  100. if (isRuntimeApp()) {
  101. //屏幕坐标转地形上坐标
  102. var cartesian = $this.getCatesian3FromPX(evt.position);
  103. if (!cartesian) {
  104. return;
  105. }
  106. $this.createPoint(cartesian); // 绘制点
  107. $this._positions.push(cartesian);
  108. if ($this._positions.length <= 2) {
  109. showTooltipMessage("点击添加点");
  110. } else {
  111. showTooltipMessage("点击添加点,点击完成按钮,结束绘制");
  112. if ($this._positions.length === 3) {
  113. if (!$this.Cesium.defined($this._AttackArrow)) {
  114. $this._AttackArrow = $this.createAttackArrow();
  115. //创建按钮
  116. createOperationMainDom();
  117. //隐藏回退按钮
  118. document.getElementById("btnDrawBackout").style.display = 'none';
  119. //完成绘制
  120. document.getElementById("btnDrawComplete").onclick = () => {
  121. $this._AttackArrowData = $this._positions.concat();
  122. $this.viewer.entities.remove($this._AttackArrow); //移除
  123. $this._AttackArrow = null;
  124. $this._positions = [];
  125. let lnglatArr = [];
  126. for (var i = 0; i < $this._AttackArrowData.length; i++) {
  127. var lnglat = $this.cartesianToLatlng($this._AttackArrowData[i]);
  128. lnglatArr.push(lnglat)
  129. }
  130. $this._AttackArrowData = lnglatArr;
  131. var straightArrow = $this.addload(lnglatArr); //加载
  132. $this._entities_AttackArrow.push(straightArrow);
  133. $this._AttackArrowLast = straightArrow;
  134. $this.clearPoint();
  135. $this.destroy();
  136. let buttonDiv = document.getElementById("drawButtonDiv");
  137. if (buttonDiv) {
  138. //从页面移除
  139. document.body.removeChild(buttonDiv);
  140. }
  141. }
  142. }
  143. }
  144. }
  145. } else {
  146. console.log('监听鼠标事件', '单击')
  147. /* 锁定点击事件 以免和双击事件冲突 */
  148. clearTimeout($this._timer);
  149. $this._timer = setTimeout(function() {
  150. //屏幕坐标转地形上坐标
  151. var cartesian = $this.getCatesian3FromPX(evt.position);
  152. if (!cartesian) {
  153. return;
  154. }
  155. if ($this._positions.length == 0) {
  156. // $this._positions.push(cartesian.clone());
  157. $this.floatingPoint = $this.createPoint(cartesian);
  158. $this.createPoint(cartesian); // 绘制点
  159. }
  160. if ($this._positions.length == 1) {
  161. $this._positions.push(cartesian.clone());
  162. $this.createPoint(cartesian); // 绘制点
  163. }
  164. $this._positions.push(cartesian);
  165. }, 200);
  166. }
  167. }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
  168. //移动时绘制面
  169. this.handler.setInputAction(function(evt) {
  170. /* 如果运行环境是App 则禁止使用鼠标移动事件 */
  171. if (isRuntimeApp()) return;
  172. // console.log('监听鼠标事件', '移动')
  173. if ($this._positions.length == 0) {
  174. $this._tooltip.showAt(evt.endPosition, "点击开始绘制");
  175. } else {
  176. $this._tooltip.showAt(evt.endPosition, "点击添加点");
  177. }
  178. if ($this._positions.length < 3) return;
  179. // $this._tooltip.showAt(evt.endPosition, "点击添加点,右键删除点,双击结束绘制");
  180. $this._tooltip.showAt(evt.endPosition, "点击添加点,双击结束绘制");
  181. if (!$this.Cesium.defined($this._AttackArrow)) {
  182. $this._AttackArrow = $this.createAttackArrow();
  183. }
  184. var cartesian = $this.getCatesian3FromPX(evt.endPosition);
  185. if (!cartesian) {
  186. return;
  187. }
  188. $this.floatingPoint.position.setValue(cartesian);
  189. if ($this._AttackArrow) {
  190. $this._positions.pop();
  191. $this._positions.push(cartesian);
  192. }
  193. }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  194. //右键结束改为双击结束
  195. this.handler.setInputAction(function(evt) {
  196. // var cartesian = $this.getCatesian3FromPX(evt.position);
  197. // $this._positions.pop();
  198. // // $this._positions.push(cartesian);
  199. // $this._AttackArrowData = $this._positions.concat();
  200. // $this.viewer.entities.remove($this._AttackArrow); //移除
  201. // $this._AttackArrow = null;
  202. // $this._positions = [];
  203. // $this.floatingPoint.position.setValue(cartesian);
  204. // let lnglatArr = [];
  205. // for (var i = 0; i < $this._AttackArrowData.length; i++) {
  206. // var lnglat = $this.cartesianToLatlng($this._AttackArrowData[i]);
  207. // lnglatArr.push(lnglat)
  208. // }
  209. // $this._AttackArrowData = lnglatArr;
  210. // var straightArrow = $this.addload(lnglatArr); //加载
  211. // $this._entities_AttackArrow.push(straightArrow);
  212. // $this._AttackArrowLast = straightArrow;
  213. // $this.clearPoint();
  214. // $this.destroy()
  215. }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  216. //双击结束
  217. this.handler.setInputAction(function(evt) {
  218. /* 如果运行环境是App 则禁止使用鼠标双击事件 */
  219. if (isRuntimeApp()) return;
  220. console.log('监听鼠标事件', '双击')
  221. /* 解除锁定 */
  222. clearTimeout($this._timer);
  223. var cartesian = $this.getCatesian3FromPX(evt.position);
  224. $this._positions.pop();
  225. $this._positions.push(cartesian);
  226. $this._AttackArrowData = $this._positions.concat();
  227. $this.viewer.entities.remove($this._AttackArrow); //移除
  228. $this._AttackArrow = null;
  229. $this._positions = [];
  230. $this.floatingPoint.position.setValue(cartesian);
  231. let lnglatArr = [];
  232. for (var i = 0; i < $this._AttackArrowData.length; i++) {
  233. var lnglat = $this.cartesianToLatlng($this._AttackArrowData[i]);
  234. lnglatArr.push(lnglat)
  235. }
  236. $this._AttackArrowData = lnglatArr;
  237. var straightArrow = $this.addload(lnglatArr); //加载
  238. $this._entities_AttackArrow.push(straightArrow);
  239. $this._AttackArrowLast = straightArrow;
  240. $this.clearPoint();
  241. $this.destroy();
  242. $this._tooltip.setVisible(false);
  243. }, $this.Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
  244. }
  245. //创建攻击箭头
  246. createAttackArrow() {
  247. var $this = this;
  248. var arrowEntity = $this.viewer.entities.add({
  249. polygon: {
  250. hierarchy: new $this.Cesium.CallbackProperty(
  251. function() {
  252. //计算面
  253. var lnglatArr = [];
  254. for (var i = 0; i < $this._positions.length; i++) {
  255. var lnglat = $this.cartesianToLatlng($this._positions[i]);
  256. lnglatArr.push(lnglat)
  257. }
  258. var res = $this.fineArrow(lnglatArr);
  259. var returnData = res.polygonalPoint;
  260. return new $this.Cesium.PolygonHierarchy(returnData);
  261. }, false),
  262. show: true,
  263. fill: true,
  264. clampToGround: true,
  265. material: $this.polygonMaterial
  266. }
  267. })
  268. $this._entities_AttackArrow.push(arrowEntity);
  269. return arrowEntity
  270. }
  271. //创建点
  272. createPoint(cartesian) {
  273. var $this = this;
  274. var point = this.viewer.entities.add({
  275. position: cartesian,
  276. point: {
  277. pixelSize: 10,
  278. color: $this.Cesium.Color.RED,
  279. heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
  280. }
  281. });
  282. point.objId = this.objId;
  283. $this._entities_point.push(point);
  284. return point;
  285. }
  286. cartesianToLatlng(cartesian) {
  287. let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
  288. let lat = this.Cesium.Math.toDegrees(cartographic.latitude);
  289. let lng = this.Cesium.Math.toDegrees(cartographic.longitude);
  290. let alt = cartographic.height;
  291. return [lng, lat, alt];
  292. }
  293. //销毁
  294. destroy() {
  295. if (this.handler) {
  296. this.handler.destroy();
  297. this.handler = null;
  298. }
  299. }
  300. clearPoint() {
  301. this.DrawEndEvent.raiseEvent(this._AttackArrowLast, this._AttackArrowData, this.drawType);
  302. for (var i = 0; i < this._entities_point.length; i++) {
  303. this.viewer.entities.remove(this._entities_point[i]);
  304. }
  305. this._entities_point = []; //脏数据
  306. }
  307. //清空实体对象
  308. clear() {
  309. for (var i = 0; i < this._entities_point.length; i++) {
  310. this.viewer.entities.remove(this._entities_point[i]);
  311. }
  312. for (var i = 0; i < this._entities_AttackArrow.length; i++) {
  313. this.viewer.entities.remove(this._entities_AttackArrow[i]);
  314. }
  315. this.floatingPoint = null; //标识点
  316. this._AttackArrow = null; //活动箭头
  317. this._AttackArrowLast = null; //最后一个箭头
  318. this._positions = []; //活动点
  319. this._entities_point = []; //脏数据
  320. this._entities_AttackArrow = []; //脏数据
  321. this._AttackArrowData = null; //用于构造箭头数据
  322. }
  323. getCatesian3FromPX(px) {
  324. var cartesian;
  325. var ray = this.viewer.camera.getPickRay(px);
  326. if (!ray) return null;
  327. cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
  328. return cartesian;
  329. }
  330. ////////////////////////////////////////求取箭头坐标函数/////////////////////////////////////////////////////
  331. //箭头配置函数
  332. fineArrowDefualParam() {
  333. return {
  334. headHeightFactor: .18,
  335. headWidthFactor: .3,
  336. neckHeightFactor: .85,
  337. neckWidthFactor: .15,
  338. tailWidthFactor: .1,
  339. headTailFactor: .8,
  340. swallowTailFactor: 1
  341. }
  342. }
  343. fineArrow(inputPoint) {
  344. var $this = this;
  345. inputPoint = $this.dereplication(inputPoint);
  346. let tailWidthFactor = $this.fineArrowDefualParam().tailWidthFactor;
  347. let swallowTailFactor = $this.fineArrowDefualParam().swallowTailFactor;
  348. let swallowTailPnt = $this.fineArrowDefualParam().swallowTailPnt;
  349. //控制点
  350. var result = {
  351. controlPoint: null,
  352. polygonalPoint: null
  353. };
  354. result.controlPoint = inputPoint;
  355. var t = inputPoint.length;
  356. if (!(2 > t)) {
  357. if (2 == inputPoint.length) {
  358. result.polygonalPoint = inputPoint;
  359. return result;
  360. }
  361. var o = inputPoint,
  362. e = o[0],
  363. r = o[1];
  364. $this.isClockWise(o[0], o[1], o[2]) && (e = o[1], r = o[0]);
  365. var n = $this.mid(e, r),
  366. g = [n].concat(o.slice(2)),
  367. i = $this.getAttackArrowHeadPoints(g, e, r, $this.fineArrowDefualParam()),
  368. s = i[0],
  369. a = i[4],
  370. l = $this.distance(e, r),
  371. u = $this.getBaseLength(g),
  372. c = u * tailWidthFactor * swallowTailFactor;
  373. swallowTailPnt = $this.getThirdPoint(g[1], g[0], 0, c, !0);
  374. var p = l / u,
  375. h = $this.getAttackArrowBodyPoints(g, s, a, p),
  376. t = h.length,
  377. d = [e].concat(h.slice(0, t / 2));
  378. d.push(s);
  379. var f = [r].concat(h.slice(t / 2, t));
  380. var newArray = [];
  381. f.push(a),
  382. d = $this.getQBSplinePoints(d),
  383. f = $this.getQBSplinePoints(f),
  384. newArray = $this.array2Dto1D(d.concat(i, f.reverse(), [swallowTailPnt, d[0]]));
  385. result.polygonalPoint = $this.Cesium.Cartesian3.fromDegreesArray(newArray);
  386. }
  387. return result;
  388. }
  389. getArrowBodyPoints(t, o, e, r) {
  390. var $this = this;
  391. for (var n = $this.wholeDistance(t), g = $this.getBaseLength(t), i = g * r, s = $this.distance(o, e), a = (i - s) / 2, l = 0, u = [], c = [], p = 1; p < t.length - 1; p++) {
  392. var h = $this.getAngleOfThreePoints(t[p - 1], t[p], t[p + 1]) / 2;
  393. l += $this.distance(t[p - 1], t[p]);
  394. var d = (i / 2 - l / n * a) / Math.sin(h),
  395. f = $this.getThirdPoint(t[p - 1], t[p], Math.PI - h, d, !0),
  396. E = $this.getThirdPoint(t[p - 1], t[p], h, d, !1);
  397. u.push(f),
  398. c.push(E)
  399. }
  400. return u.concat(c)
  401. }
  402. getAttackArrowHeadPoints(t, o, e, defaultParam) {
  403. var $this = this;
  404. let headHeightFactor = defaultParam.headHeightFactor;
  405. let headTailFactor = defaultParam.headTailFactor;
  406. let headWidthFactor = defaultParam.headWidthFactor;
  407. let neckWidthFactor = defaultParam.neckWidthFactor;
  408. let neckHeightFactor = defaultParam.neckHeightFactor;
  409. var r = $this.getBaseLength(t),
  410. n = r * headHeightFactor,
  411. g = t[t.length - 1];
  412. r = $this.distance(g, t[t.length - 2]);
  413. var i = $this.distance(o, e);
  414. n > i * headTailFactor && (n = i * headTailFactor);
  415. var s = n * headWidthFactor,
  416. a = n * neckWidthFactor;
  417. n = n > r ? r : n;
  418. var l = n * neckHeightFactor,
  419. u = $this.getThirdPoint(t[t.length - 2], g, 0, n, !0),
  420. c = $this.getThirdPoint(t[t.length - 2], g, 0, l, !0),
  421. p = $this.getThirdPoint(g, u, Math.PI / 2, s, !1),
  422. h = $this.getThirdPoint(g, u, Math.PI / 2, s, !0),
  423. d = $this.getThirdPoint(g, c, Math.PI / 2, a, !1),
  424. f = $this.getThirdPoint(g, c, Math.PI / 2, a, !0);
  425. return [d, p, g, h, f]
  426. }
  427. getAttackArrowBodyPoints = function(t, o, e, r) {
  428. var $this = this;
  429. for (var n = $this.wholeDistance(t), g = $this.getBaseLength(t), i = g * r, s = $this.distance(o, e), a = (i - s) / 2, l = 0, u = [], c = [], p = 1; p < t.length - 1; p++) {
  430. var h = $this.getAngleOfThreePoints(t[p - 1], t[p], t[p + 1]) / 2;
  431. l += $this.distance(t[p - 1], t[p]);
  432. var d = (i / 2 - l / n * a) / Math.sin(h),
  433. f = $this.getThirdPoint(t[p - 1], t[p], Math.PI - h, d, !0),
  434. E = $this.getThirdPoint(t[p - 1], t[p], h, d, !1);
  435. u.push(f),
  436. c.push(E)
  437. }
  438. return u.concat(c)
  439. }
  440. getAngleOfThreePoints(t, o, e) {
  441. var r = this.getAzimuth(o, t) - this.getAzimuth(o, e);
  442. return 0 > r ? r + Math.PI * 2 : r
  443. }
  444. dereplication(array) {
  445. var last = array[array.length - 1];
  446. var change = false;
  447. var newArray = [];
  448. newArray = array.filter(function(i) {
  449. if (i[0] != last[0] && i[1] != last[1]) {
  450. return i;
  451. }
  452. change = true;
  453. });
  454. if (change) newArray.push(last);
  455. return newArray;
  456. }
  457. getBaseLength(t) {
  458. return Math.pow(this.wholeDistance(t), .99)
  459. }
  460. wholeDistance(t) {
  461. for (var o = 0, e = 0; e < t.length - 1; e++) o += this.distance(t[e], t[e + 1]);
  462. return o
  463. }
  464. distance(t, o) {
  465. return Math.sqrt(Math.pow(t[0] - o[0], 2) + Math.pow(t[1] - o[1], 2))
  466. }
  467. getThirdPoint(t, o, e, r, n) {
  468. var g = this.getAzimuth(t, o),
  469. i = n ? g + e : g - e,
  470. s = r * Math.cos(i),
  471. a = r * Math.sin(i);
  472. return [o[0] + s, o[1] + a]
  473. }
  474. getAzimuth(t, o) {
  475. var e, r = Math.asin(Math.abs(o[1] - t[1]) / this.distance(t, o));
  476. return o[1] >= t[1] && o[0] >= t[0] ? e = r + Math.PI : o[1] >= t[1] && o[0] < t[0] ? e = 2 * Math.PI - r : o[1] < t[1] && o[0] < t[0] ? e = r : o[1] < t[1] && o[0] >= t[0] && (e = Math.PI - r), e
  477. }
  478. isClockWise(t, o, e) {
  479. return (e[1] - t[1]) * (o[0] - t[0]) > (o[1] - t[1]) * (e[0] - t[0])
  480. }
  481. mid(t, o) {
  482. return [(t[0] + o[0]) / 2, (t[1] + o[1]) / 2]
  483. }
  484. getQBSplinePoints = function(t) {
  485. if (t.length <= 2) return t;
  486. var o = 2,
  487. e = [],
  488. r = t.length - o - 1,
  489. y = 0;
  490. e.push(t[0]);
  491. for (var n = 0; r >= n; n++)
  492. for (var g = 0; 1 >= g; g += .05) {
  493. for (var i = y = 0, s = 0; o >= s; s++) {
  494. var a = this.getQuadricBSplineFactor(s, g);
  495. i += a * t[n + s][0], y += a * t[n + s][1]
  496. }
  497. e.push([i, y])
  498. }
  499. return e.push(t[t.length - 1]), e
  500. }
  501. getQuadricBSplineFactor = function(t, o) {
  502. return 0 == t ? Math.pow(o - 1, 2) / 2 : 1 == t ? (-2 * Math.pow(o, 2) + 2 * o + 1) / 2 : 2 == t ? Math.pow(o, 2) / 2 : 0
  503. }
  504. array2Dto1D = function(array) {
  505. var newArray = [];
  506. array.forEach(function(elt) {
  507. newArray.push(elt[0]);
  508. newArray.push(elt[1]);
  509. });
  510. return newArray;
  511. }
  512. }
  513. export default DrawAttackArrow