algorithm.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. import type { Cartesian3 } from "cesium";
  2. import type { AllPlotI } from "../../interface";
  3. import type { PointArr } from "../../interface";
  4. import { P, lonLatToCartesian } from "../../tools";
  5. const doubleArrowParams = {
  6. headHeightFactor: 0.25,
  7. headWidthFactor: 0.3,
  8. neckHeightFactor: 0.85,
  9. neckWidthFactor: 0.15,
  10. };
  11. // * 细直箭头与突击方向type
  12. type FineOrAssault = {
  13. tailWidthFactor: number;
  14. neckWidthFactor: number;
  15. headWidthFactor: number;
  16. headAngle: number;
  17. neckAngle: number;
  18. };
  19. const fineArrowParams: FineOrAssault = {
  20. tailWidthFactor: 0.15,
  21. neckWidthFactor: 0.2,
  22. headWidthFactor: 0.25,
  23. headAngle: Math.PI / 8.5,
  24. neckAngle: Math.PI / 13,
  25. };
  26. const assaultDirectionParams: FineOrAssault = {
  27. tailWidthFactor: 0.2,
  28. neckWidthFactor: 0.25,
  29. headWidthFactor: 0.3,
  30. headAngle: Math.PI / 4,
  31. neckAngle: Math.PI * 0.17741,
  32. };
  33. const attackArrowParams = {
  34. headHeightFactor: 0.18,
  35. headWidthFactor: 0.3,
  36. neckHeightFactor: 0.85,
  37. neckWidthFactor: 0.15,
  38. headTailFactor: 0.8,
  39. tailWidthFactor: 0.1,
  40. swallowTailFactor: 1,
  41. };
  42. const squadCombatParams = {
  43. headHeightFactor: 0.18,
  44. headWidthFactor: 0.3,
  45. neckHeightFactor: 0.85,
  46. neckWidthFactor: 0.15,
  47. tailWidthFactor: 0.1,
  48. swallowTailFactor: 1,
  49. };
  50. export const arrowPlot: AllPlotI = {
  51. version: "1.0.0",
  52. createTime: "2023-3-3",
  53. updateTime: "2023-3-3",
  54. author: "c-lei-en",
  55. algorithm: {
  56. // * 计算对称点
  57. getTempPoint4: (
  58. pnt1: PointArr,
  59. pnt2: PointArr,
  60. point: PointArr
  61. ): PointArr => {
  62. const midPnt = P.PlotUtils.mid(pnt1, pnt2);
  63. const len = P.PlotUtils.distance(midPnt, point);
  64. const angle = P.PlotUtils.getAngleOfThreePoints(pnt1, midPnt, point);
  65. let symPnt, distance1, distance2, mid;
  66. if (angle < P.Constants.HALF_PI) {
  67. distance1 = len * Math.sin(angle);
  68. distance2 = len * Math.cos(angle);
  69. mid = P.PlotUtils.getThirdPoint(
  70. pnt1,
  71. midPnt,
  72. P.Constants.HALF_PI,
  73. distance1,
  74. false
  75. );
  76. symPnt = P.PlotUtils.getThirdPoint(
  77. midPnt,
  78. mid,
  79. P.Constants.HALF_PI,
  80. distance2,
  81. true
  82. );
  83. } else if (angle >= P.Constants.HALF_PI && angle < Math.PI) {
  84. distance1 = len * Math.sin(Math.PI - angle);
  85. distance2 = len * Math.cos(Math.PI - angle);
  86. mid = P.PlotUtils.getThirdPoint(
  87. pnt1,
  88. midPnt,
  89. P.Constants.HALF_PI,
  90. distance1,
  91. false
  92. );
  93. symPnt = P.PlotUtils.getThirdPoint(
  94. midPnt,
  95. mid,
  96. P.Constants.HALF_PI,
  97. distance2,
  98. false
  99. );
  100. } else if (angle >= Math.PI && angle < Math.PI * 1.5) {
  101. distance1 = len * Math.sin(angle - Math.PI);
  102. distance2 = len * Math.cos(angle - Math.PI);
  103. mid = P.PlotUtils.getThirdPoint(
  104. pnt1,
  105. midPnt,
  106. P.Constants.HALF_PI,
  107. distance1,
  108. true
  109. );
  110. symPnt = P.PlotUtils.getThirdPoint(
  111. midPnt,
  112. mid,
  113. P.Constants.HALF_PI,
  114. distance2,
  115. true
  116. );
  117. } else {
  118. distance1 = len * Math.sin(Math.PI * 2 - angle);
  119. distance2 = len * Math.cos(Math.PI * 2 - angle);
  120. mid = P.PlotUtils.getThirdPoint(
  121. pnt1,
  122. midPnt,
  123. P.Constants.HALF_PI,
  124. distance1,
  125. true
  126. );
  127. symPnt = P.PlotUtils.getThirdPoint(
  128. midPnt,
  129. mid,
  130. P.Constants.HALF_PI,
  131. distance2,
  132. false
  133. );
  134. }
  135. return symPnt;
  136. },
  137. // * 获取箭头坐标
  138. getArrowHeadPoints: (points: PointArr): PointArr => {
  139. const len = P.PlotUtils.getBaseLength(points);
  140. const headHeight = len * doubleArrowParams.headHeightFactor;
  141. const headPnt = points[points.length - 1];
  142. const headWidth = headHeight * doubleArrowParams.headWidthFactor;
  143. const neckWidth = headHeight * doubleArrowParams.neckWidthFactor;
  144. const neckHeight = headHeight * doubleArrowParams.neckHeightFactor;
  145. const headEndPnt = P.PlotUtils.getThirdPoint(
  146. points[points.length - 2],
  147. headPnt,
  148. 0,
  149. headHeight,
  150. true
  151. );
  152. const neckEndPnt = P.PlotUtils.getThirdPoint(
  153. points[points.length - 2],
  154. headPnt,
  155. 0,
  156. neckHeight,
  157. true
  158. );
  159. const headLeft = P.PlotUtils.getThirdPoint(
  160. headPnt,
  161. headEndPnt,
  162. P.Constants.HALF_PI,
  163. headWidth,
  164. false
  165. );
  166. const headRight = P.PlotUtils.getThirdPoint(
  167. headPnt,
  168. headEndPnt,
  169. P.Constants.HALF_PI,
  170. headWidth,
  171. true
  172. );
  173. const neckLeft = P.PlotUtils.getThirdPoint(
  174. headPnt,
  175. neckEndPnt,
  176. P.Constants.HALF_PI,
  177. neckWidth,
  178. false
  179. );
  180. const neckRight = P.PlotUtils.getThirdPoint(
  181. headPnt,
  182. neckEndPnt,
  183. P.Constants.HALF_PI,
  184. neckWidth,
  185. true
  186. );
  187. return [neckLeft, headLeft, headPnt, headRight, neckRight];
  188. },
  189. // * 获取钳击箭身坐标
  190. getArrowBodyPoints: (
  191. points: PointArr,
  192. neckLeft: PointArr,
  193. neckRight: PointArr,
  194. tailWidthFactor: number
  195. ): PointArr => {
  196. const allLen = P.PlotUtils.wholeDistance(points);
  197. const len = P.PlotUtils.getBaseLength(points);
  198. const tailWidth = len * tailWidthFactor;
  199. const neckWidth = P.PlotUtils.distance(neckLeft, neckRight);
  200. const widthDif = (tailWidth - neckWidth) / 2;
  201. let tempLen = 0;
  202. const leftBodyPnts = [],
  203. rightBodyPnts = [];
  204. for (let i = 1; i < points.length - 1; i++) {
  205. const angle =
  206. P.PlotUtils.getAngleOfThreePoints(
  207. points[i - 1],
  208. points[i],
  209. points[i + 1]
  210. ) / 2;
  211. tempLen += P.PlotUtils.distance(points[i - 1], points[i]);
  212. const w =
  213. (tailWidth / 2 - (tempLen / allLen) * widthDif) / Math.sin(angle);
  214. const left = P.PlotUtils.getThirdPoint(
  215. points[i - 1],
  216. points[i],
  217. Math.PI - angle,
  218. w,
  219. true
  220. );
  221. const right = P.PlotUtils.getThirdPoint(
  222. points[i - 1],
  223. points[i],
  224. angle,
  225. w,
  226. false
  227. );
  228. leftBodyPnts.push(left);
  229. rightBodyPnts.push(right);
  230. }
  231. return leftBodyPnts.concat(rightBodyPnts);
  232. },
  233. // * 获取箭头点
  234. getArrowPoints: (
  235. pnt1: PointArr,
  236. pnt2: PointArr,
  237. pnt3: PointArr,
  238. clockWise: number
  239. ): PointArr => {
  240. const midPnt = P.PlotUtils.mid(pnt1, pnt2);
  241. const len = P.PlotUtils.distance(midPnt, pnt3);
  242. let midPnt1 = P.PlotUtils.getThirdPoint(pnt3, midPnt, 0, len * 0.3, true);
  243. let midPnt2 = P.PlotUtils.getThirdPoint(pnt3, midPnt, 0, len * 0.5, true);
  244. midPnt1 = P.PlotUtils.getThirdPoint(
  245. midPnt,
  246. midPnt1,
  247. P.Constants.HALF_PI,
  248. len / 5,
  249. clockWise
  250. );
  251. midPnt2 = P.PlotUtils.getThirdPoint(
  252. midPnt,
  253. midPnt2,
  254. P.Constants.HALF_PI,
  255. len / 4,
  256. clockWise
  257. );
  258. const points = [midPnt, midPnt1, midPnt2, pnt3];
  259. // 计算箭头部分
  260. const arrowPnts = arrowPlot.algorithm.getArrowHeadPoints(
  261. points,
  262. doubleArrowParams.headHeightFactor,
  263. doubleArrowParams.headWidthFactor,
  264. doubleArrowParams.neckHeightFactor,
  265. doubleArrowParams.neckWidthFactor
  266. );
  267. const neckLeftPoint = arrowPnts[0];
  268. const neckRightPoint = arrowPnts[4];
  269. // 计算箭身部分
  270. const tailWidthFactor =
  271. P.PlotUtils.distance(pnt1, pnt2) /
  272. P.PlotUtils.getBaseLength(points) /
  273. 2;
  274. const bodyPnts = arrowPlot.algorithm.getArrowBodyPoints(
  275. points,
  276. neckLeftPoint,
  277. neckRightPoint,
  278. tailWidthFactor
  279. );
  280. const n = bodyPnts.length;
  281. let lPoints = bodyPnts.slice(0, n / 2);
  282. let rPoints = bodyPnts.slice(n / 2, n);
  283. lPoints.push(neckLeftPoint);
  284. rPoints.push(neckRightPoint);
  285. lPoints = lPoints.reverse();
  286. lPoints.push(pnt2);
  287. rPoints = rPoints.reverse();
  288. rPoints.push(pnt1);
  289. return lPoints.reverse().concat(arrowPnts, rPoints);
  290. },
  291. // * 获取钳击箭头坐标
  292. getDoubleArrow: (pnts: PointArr[]): Cartesian3[] => {
  293. const pnt1 = pnts[0];
  294. const pnt2 = pnts[1];
  295. const pnt3 = pnts[2];
  296. let tempPoint4, connPoint;
  297. if (pnts.length == 3)
  298. tempPoint4 = arrowPlot.algorithm.getTempPoint4(pnt1, pnt2, pnt3);
  299. else tempPoint4 = pnts[3];
  300. if (pnts.length == 3 || pnts.length == 4)
  301. connPoint = P.PlotUtils.mid(pnt1, pnt2);
  302. else connPoint = pnts[4];
  303. let leftArrowPnts, rightArrowPnts;
  304. if (P.PlotUtils.isClockWise(pnt1, pnt2, pnt3)) {
  305. leftArrowPnts = arrowPlot.algorithm.getArrowPoints(
  306. pnt1,
  307. connPoint,
  308. tempPoint4,
  309. false
  310. );
  311. rightArrowPnts = arrowPlot.algorithm.getArrowPoints(
  312. connPoint,
  313. pnt2,
  314. pnt3,
  315. true
  316. );
  317. } else {
  318. leftArrowPnts = arrowPlot.algorithm.getArrowPoints(
  319. pnt2,
  320. connPoint,
  321. pnt3,
  322. false
  323. );
  324. rightArrowPnts = arrowPlot.algorithm.getArrowPoints(
  325. connPoint,
  326. pnt1,
  327. tempPoint4,
  328. true
  329. );
  330. }
  331. const m = leftArrowPnts.length;
  332. const t = (m - 5) / 2;
  333. const llBodyPnts = leftArrowPnts.slice(0, t);
  334. const lArrowPnts = leftArrowPnts.slice(t, t + 5);
  335. let lrBodyPnts = leftArrowPnts.slice(t + 5, m);
  336. let rlBodyPnts = rightArrowPnts.slice(0, t);
  337. const rArrowPnts = rightArrowPnts.slice(t, t + 5);
  338. const rrBodyPnts = rightArrowPnts.slice(t + 5, m);
  339. rlBodyPnts = P.PlotUtils.getBezierPoints(rlBodyPnts);
  340. const bodyPnts = P.PlotUtils.getBezierPoints(
  341. rrBodyPnts.concat(llBodyPnts.slice(1))
  342. );
  343. lrBodyPnts = P.PlotUtils.getBezierPoints(lrBodyPnts);
  344. const positions = rlBodyPnts.concat(
  345. rArrowPnts,
  346. bodyPnts,
  347. lArrowPnts,
  348. lrBodyPnts
  349. );
  350. const res = [] as Cartesian3[];
  351. positions.forEach((pos: PointArr) => {
  352. res.push(lonLatToCartesian(pos));
  353. });
  354. return res;
  355. },
  356. // * 获取细直箭头或者突击方向箭头坐标
  357. getFineOrAssault: (pnts: PointArr, param: FineOrAssault): Cartesian3[] => {
  358. const pnt1 = pnts[0];
  359. const pnt2 = pnts[1];
  360. const len = P.PlotUtils.getBaseLength(pnts);
  361. const tailWidth = len * param.tailWidthFactor;
  362. const neckWidth = len * param.neckWidthFactor;
  363. const headWidth = len * param.headWidthFactor;
  364. const tailLeft = P.PlotUtils.getThirdPoint(
  365. pnt2,
  366. pnt1,
  367. P.Constants.HALF_PI,
  368. tailWidth,
  369. true
  370. );
  371. const tailRight = P.PlotUtils.getThirdPoint(
  372. pnt2,
  373. pnt1,
  374. P.Constants.HALF_PI,
  375. tailWidth,
  376. false
  377. );
  378. const headLeft = P.PlotUtils.getThirdPoint(
  379. pnt1,
  380. pnt2,
  381. param.headAngle,
  382. headWidth,
  383. false
  384. );
  385. const headRight = P.PlotUtils.getThirdPoint(
  386. pnt1,
  387. pnt2,
  388. param.headAngle,
  389. headWidth,
  390. true
  391. );
  392. const neckLeft = P.PlotUtils.getThirdPoint(
  393. pnt1,
  394. pnt2,
  395. param.neckAngle,
  396. neckWidth,
  397. false
  398. );
  399. const neckRight = P.PlotUtils.getThirdPoint(
  400. pnt1,
  401. pnt2,
  402. param.neckAngle,
  403. neckWidth,
  404. true
  405. );
  406. return [
  407. lonLatToCartesian(tailLeft),
  408. lonLatToCartesian(neckLeft),
  409. lonLatToCartesian(headLeft),
  410. lonLatToCartesian(pnt2),
  411. lonLatToCartesian(headRight),
  412. lonLatToCartesian(neckRight),
  413. lonLatToCartesian(tailRight),
  414. ];
  415. },
  416. // * 获取细直箭头坐标
  417. getFineArrow: (pnts: PointArr): Cartesian3[] => {
  418. return arrowPlot.algorithm.getFineOrAssault(pnts, fineArrowParams);
  419. },
  420. // * 获取突击方向坐标
  421. getAssaultDirection: (pnts: PointArr): Cartesian3[] => {
  422. return arrowPlot.algorithm.getFineOrAssault(pnts, assaultDirectionParams);
  423. },
  424. // * 获取进攻方向箭头坐标
  425. getAttackArrowHeadPoints: (
  426. points: PointArr,
  427. tailLeft: PointArr,
  428. tailRight: PointArr
  429. ): PointArr => {
  430. let len = P.PlotUtils.getBaseLength(points);
  431. let headHeight = len * attackArrowParams.headHeightFactor;
  432. const headPnt = points[points.length - 1];
  433. len = P.PlotUtils.distance(headPnt, points[points.length - 2]);
  434. const tailWidth = P.PlotUtils.distance(tailLeft, tailRight);
  435. if (headHeight > tailWidth * attackArrowParams.headTailFactor) {
  436. headHeight = tailWidth * attackArrowParams.headTailFactor;
  437. }
  438. const headWidth = headHeight * attackArrowParams.headWidthFactor;
  439. const neckWidth = headHeight * attackArrowParams.neckWidthFactor;
  440. headHeight = headHeight > len ? len : headHeight;
  441. const neckHeight = headHeight * attackArrowParams.neckHeightFactor;
  442. const headEndPnt = P.PlotUtils.getThirdPoint(
  443. points[points.length - 2],
  444. headPnt,
  445. 0,
  446. headHeight,
  447. true
  448. );
  449. const neckEndPnt = P.PlotUtils.getThirdPoint(
  450. points[points.length - 2],
  451. headPnt,
  452. 0,
  453. neckHeight,
  454. true
  455. );
  456. const headLeft = P.PlotUtils.getThirdPoint(
  457. headPnt,
  458. headEndPnt,
  459. P.Constants.HALF_PI,
  460. headWidth,
  461. false
  462. );
  463. const headRight = P.PlotUtils.getThirdPoint(
  464. headPnt,
  465. headEndPnt,
  466. P.Constants.HALF_PI,
  467. headWidth,
  468. true
  469. );
  470. const neckLeft = P.PlotUtils.getThirdPoint(
  471. headPnt,
  472. neckEndPnt,
  473. P.Constants.HALF_PI,
  474. neckWidth,
  475. false
  476. );
  477. const neckRight = P.PlotUtils.getThirdPoint(
  478. headPnt,
  479. neckEndPnt,
  480. P.Constants.HALF_PI,
  481. neckWidth,
  482. true
  483. );
  484. return [neckLeft, headLeft, headPnt, headRight, neckRight];
  485. },
  486. // * 获取进攻方向箭身坐标
  487. getAttackArrowBodyPoints: (
  488. points: PointArr,
  489. neckLeft: PointArr,
  490. neckRight: PointArr,
  491. tailWidthFactor: number
  492. ): PointArr => {
  493. const allLen = P.PlotUtils.wholeDistance(points);
  494. const len = P.PlotUtils.getBaseLength(points);
  495. const tailWidth = len * tailWidthFactor;
  496. const neckWidth = P.PlotUtils.distance(neckLeft, neckRight);
  497. const widthDif = (tailWidth - neckWidth) / 2;
  498. let tempLen = 0;
  499. const leftBodyPnts = [],
  500. rightBodyPnts = [];
  501. for (let i = 1; i < points.length - 1; i++) {
  502. const angle =
  503. P.PlotUtils.getAngleOfThreePoints(
  504. points[i - 1],
  505. points[i],
  506. points[i + 1]
  507. ) / 2;
  508. tempLen += P.PlotUtils.distance(points[i - 1], points[i]);
  509. const w =
  510. (tailWidth / 2 - (tempLen / allLen) * widthDif) / Math.sin(angle);
  511. const left = P.PlotUtils.getThirdPoint(
  512. points[i - 1],
  513. points[i],
  514. Math.PI - angle,
  515. w,
  516. true
  517. );
  518. const right = P.PlotUtils.getThirdPoint(
  519. points[i - 1],
  520. points[i],
  521. angle,
  522. w,
  523. false
  524. );
  525. leftBodyPnts.push(left);
  526. rightBodyPnts.push(right);
  527. }
  528. return leftBodyPnts.concat(rightBodyPnts);
  529. },
  530. // * 获取进攻方向坐标
  531. getAttackArrow: (pnts: PointArr[]): Cartesian3[] => {
  532. // 计算箭尾
  533. let tailLeft = pnts[0];
  534. let tailRight = pnts[1];
  535. if (P.PlotUtils.isClockWise(pnts[0], pnts[1], pnts[2])) {
  536. tailLeft = pnts[1];
  537. tailRight = pnts[0];
  538. }
  539. const midTail = P.PlotUtils.mid(tailLeft, tailRight);
  540. const bonePnts = [midTail].concat(pnts.slice(2));
  541. // 计算箭头
  542. const headPnts = arrowPlot.algorithm.getAttackArrowHeadPoints(
  543. bonePnts,
  544. tailLeft,
  545. tailRight
  546. );
  547. const neckLeft = headPnts[0];
  548. const neckRight = headPnts[4];
  549. const tailWidthFactor =
  550. P.PlotUtils.distance(tailLeft, tailRight) /
  551. P.PlotUtils.getBaseLength(bonePnts);
  552. // 计算箭身
  553. const bodyPnts = arrowPlot.algorithm.getAttackArrowBodyPoints(
  554. bonePnts,
  555. neckLeft,
  556. neckRight,
  557. tailWidthFactor
  558. );
  559. // 整合
  560. const count = bodyPnts.length;
  561. let leftPnts = [tailLeft].concat(bodyPnts.slice(0, count / 2));
  562. leftPnts.push(neckLeft);
  563. let rightPnts = [tailRight].concat(bodyPnts.slice(count / 2, count));
  564. rightPnts.push(neckRight);
  565. leftPnts = P.PlotUtils.getQBSplinePoints(leftPnts);
  566. rightPnts = P.PlotUtils.getQBSplinePoints(rightPnts);
  567. const positions = leftPnts.concat(headPnts, rightPnts.reverse());
  568. const res = [] as Cartesian3[];
  569. positions.forEach((pos: PointArr) => {
  570. res.push(lonLatToCartesian(pos));
  571. });
  572. return res;
  573. },
  574. // * 获取进攻方向尾坐标
  575. getTailedAttackArrow: (pnts: PointArr[]): Cartesian3[] => {
  576. let tailLeft = pnts[0];
  577. let tailRight = pnts[1];
  578. if (P.PlotUtils.isClockWise(pnts[0], pnts[1], pnts[2])) {
  579. tailLeft = pnts[1];
  580. tailRight = pnts[0];
  581. }
  582. const midTail = P.PlotUtils.mid(tailLeft, tailRight);
  583. const bonePnts = [midTail].concat(pnts.slice(2));
  584. const headPnts = arrowPlot.algorithm.getAttackArrowHeadPoints(
  585. bonePnts,
  586. tailLeft,
  587. tailRight
  588. );
  589. const neckLeft = headPnts[0];
  590. const neckRight = headPnts[4];
  591. const tailWidth = P.PlotUtils.distance(tailLeft, tailRight);
  592. const allLen = P.PlotUtils.getBaseLength(bonePnts);
  593. const len =
  594. allLen *
  595. attackArrowParams.tailWidthFactor *
  596. attackArrowParams.swallowTailFactor;
  597. const swallowTailPnt = P.PlotUtils.getThirdPoint(
  598. bonePnts[1],
  599. bonePnts[0],
  600. 0,
  601. len,
  602. true
  603. );
  604. const factor = tailWidth / allLen;
  605. const bodyPnts = arrowPlot.algorithm.getAttackArrowBodyPoints(
  606. bonePnts,
  607. neckLeft,
  608. neckRight,
  609. factor
  610. );
  611. const count = bodyPnts.length;
  612. let leftPnts = [tailLeft].concat(bodyPnts.slice(0, count / 2));
  613. leftPnts.push(neckLeft);
  614. let rightPnts = [tailRight].concat(bodyPnts.slice(count / 2, count));
  615. rightPnts.push(neckRight);
  616. leftPnts = P.PlotUtils.getQBSplinePoints(leftPnts);
  617. rightPnts = P.PlotUtils.getQBSplinePoints(rightPnts);
  618. const positions = leftPnts.concat(headPnts, rightPnts.reverse(), [
  619. swallowTailPnt,
  620. leftPnts[0],
  621. ]);
  622. const res = [] as Cartesian3[];
  623. positions.forEach((pos: PointArr) => {
  624. res.push(lonLatToCartesian(pos));
  625. });
  626. return res;
  627. },
  628. // * 获取尾点
  629. getTailPoints: (points: PointArr): PointArr[] => {
  630. const allLen = P.PlotUtils.getBaseLength(points);
  631. const tailWidth = allLen * squadCombatParams.tailWidthFactor;
  632. const tailLeft = P.PlotUtils.getThirdPoint(
  633. points[1],
  634. points[0],
  635. P.Constants.HALF_PI,
  636. tailWidth,
  637. false
  638. );
  639. const tailRight = P.PlotUtils.getThirdPoint(
  640. points[1],
  641. points[0],
  642. P.Constants.HALF_PI,
  643. tailWidth,
  644. true
  645. );
  646. return [tailLeft, tailRight];
  647. },
  648. // * 获取分队战斗行动坐标
  649. getSquadCombat: (pnts: PointArr[]): Cartesian3[] => {
  650. const tailPnts = arrowPlot.algorithm.getTailPoints(pnts);
  651. const headPnts = arrowPlot.algorithm.getAttackArrowHeadPoints(
  652. pnts,
  653. tailPnts[0],
  654. tailPnts[1]
  655. );
  656. const neckLeft = headPnts[0];
  657. const neckRight = headPnts[4];
  658. const bodyPnts = arrowPlot.algorithm.getAttackArrowBodyPoints(
  659. pnts,
  660. neckLeft,
  661. neckRight,
  662. squadCombatParams.tailWidthFactor
  663. );
  664. const count = bodyPnts.length;
  665. let leftPnts = [tailPnts[0]].concat(bodyPnts.slice(0, count / 2));
  666. leftPnts.push(neckLeft);
  667. let rightPnts = [tailPnts[1]].concat(bodyPnts.slice(count / 2, count));
  668. rightPnts.push(neckRight);
  669. leftPnts = P.PlotUtils.getQBSplinePoints(leftPnts);
  670. rightPnts = P.PlotUtils.getQBSplinePoints(rightPnts);
  671. const positions = leftPnts.concat(headPnts, rightPnts.reverse());
  672. const res = [] as Cartesian3[];
  673. positions.forEach((pos: PointArr) => {
  674. res.push(lonLatToCartesian(pos));
  675. });
  676. return res;
  677. },
  678. // * 获取分队战斗行动尾尾点
  679. getTailedTailPoints: (points: PointArr): PointArr[] => {
  680. const allLen = P.PlotUtils.getBaseLength(points);
  681. const tailWidth = allLen * squadCombatParams.tailWidthFactor;
  682. const tailLeft = P.PlotUtils.getThirdPoint(
  683. points[1],
  684. points[0],
  685. P.Constants.HALF_PI,
  686. tailWidth,
  687. false
  688. );
  689. const tailRight = P.PlotUtils.getThirdPoint(
  690. points[1],
  691. points[0],
  692. P.Constants.HALF_PI,
  693. tailWidth,
  694. true
  695. );
  696. const len = tailWidth * squadCombatParams.swallowTailFactor;
  697. const swallowTailPnt = P.PlotUtils.getThirdPoint(
  698. points[1],
  699. points[0],
  700. 0,
  701. len,
  702. true
  703. );
  704. return [tailLeft, swallowTailPnt, tailRight];
  705. },
  706. // * 获取分队战斗行动尾坐标
  707. getTailedSquadCombat: (pnts: PointArr[]): Cartesian3[] => {
  708. const tailPnts = arrowPlot.algorithm.getTailedTailPoints(pnts);
  709. const headPnts = arrowPlot.algorithm.getAttackArrowHeadPoints(
  710. pnts,
  711. tailPnts[0],
  712. tailPnts[2]
  713. );
  714. const neckLeft = headPnts[0];
  715. const neckRight = headPnts[4];
  716. const bodyPnts = arrowPlot.algorithm.getAttackArrowBodyPoints(
  717. pnts,
  718. neckLeft,
  719. neckRight,
  720. squadCombatParams.tailWidthFactor
  721. );
  722. const count = bodyPnts.length;
  723. let leftPnts = [tailPnts[0]].concat(bodyPnts.slice(0, count / 2));
  724. leftPnts.push(neckLeft);
  725. let rightPnts = [tailPnts[2]].concat(bodyPnts.slice(count / 2, count));
  726. rightPnts.push(neckRight);
  727. leftPnts = P.PlotUtils.getQBSplinePoints(leftPnts);
  728. rightPnts = P.PlotUtils.getQBSplinePoints(rightPnts);
  729. const positions = leftPnts.concat(headPnts, rightPnts.reverse(), [
  730. tailPnts[1],
  731. leftPnts[0],
  732. ]);
  733. const res = [] as Cartesian3[];
  734. positions.forEach((pos: PointArr) => {
  735. res.push(lonLatToCartesian(pos));
  736. });
  737. return res;
  738. },
  739. },
  740. };