DrawCurve.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. // 三、曲线
  2. // DrawCurve
  3. /*
  4. 绘制曲线
  5. */
  6. class DrawCurve {
  7. constructor(arg) {
  8. this.viewer = arg.viewer;
  9. this.Cesium = arg.Cesium;
  10. this.floatingPoint = null;//标识点
  11. this._curveline = null; //活动曲线
  12. this._curvelineLast = null; //最后一条曲线
  13. this._positions = []; //活动点
  14. this._entities_point = []; //脏数据
  15. this._entities_line = []; //脏数据
  16. this._curvelineData = null; //用于构造曲线数据
  17. this.DrawStartEvent = new Cesium.Event(); //开始绘制事件
  18. this.DrawEndEvent = new Cesium.Event(); //结束绘制事件
  19. this.ZERO_TOLERANCE = 0.0001;
  20. this.FITTING_COUNT = 100;
  21. this.t = 0.3;
  22. /* 通用参数集合 */
  23. this._param = {
  24. id: "DrawStraightArrow",
  25. polygonColor: 'rgba(0,255,0,0.5)', //面填充颜色
  26. outlineColor: 'rgba(255, 255, 255, 1)', //边框颜色
  27. outlineWidth: 1, //边框宽度
  28. }
  29. /* 创建面材质 */
  30. this.polygonMaterial = Cesium.Color.fromCssColorString(this._param.polygonColor);
  31. /* 创建线材质 */
  32. // this.outlineMaterial = new Cesium.PolylineDashMaterialProperty({//曲线
  33. // dashLength: 16,
  34. // color: Cesium.Color.fromCssColorString(this._param.outlineColor)
  35. // });
  36. this.outlineMaterial = Cesium.Color.fromCssColorString(this._param.outlineColor);
  37. }
  38. //返回最后活动曲线
  39. get curveline() {
  40. return this._curvelineLast;
  41. }
  42. //返回线数据用于加载线
  43. getData() {
  44. return this._curvelineData;
  45. }
  46. //加载曲线
  47. addload(data) {
  48. var $this = this;
  49. let pnts = []
  50. for (let p = 0; p < data.length; p++) {
  51. pnts.push($this.lonLatToMercator(data[p]))
  52. }
  53. let CurvePoints = $this.getCurvePoints(pnts)
  54. let point = [];
  55. for (let i = 0; i < CurvePoints.length; i++) {
  56. point.push($this.LatlngTocartesian($this.WebMercator2lonLat(CurvePoints[i])))
  57. }
  58. var polyline = this.viewer.entities.add({
  59. Type: 'DrawCurve',
  60. Position: data,
  61. id: data.id || $this.objId,
  62. polyline: {
  63. positions: point,
  64. show: true,
  65. material: $this.Cesium.Color.YELLOW,
  66. width: 3,
  67. clampToGround: true
  68. }
  69. });
  70. return polyline;
  71. }
  72. // 修改编辑调用计算
  73. computePosition(data) {
  74. let pnts = [];
  75. let position = [];
  76. for (let p = 0; p < data.length; p++) {
  77. position.push(this.cartesianToLatlng(data[p]));
  78. pnts.push(this.lonLatToMercator(this.cartesianToLatlng(data[p])))
  79. }
  80. this._curvelineData = position;
  81. let CurvePoints = this.getCurvePoints(pnts)
  82. let point = [];
  83. for (let i = 0; i < CurvePoints.length; i++) {
  84. point.push(this.LatlngTocartesian(this.WebMercator2lonLat(CurvePoints[i])))
  85. }
  86. return point;
  87. }
  88. //开始创建
  89. startCreate(drawType) {
  90. this.drawType = drawType
  91. var $this = this;
  92. this.handler = new this.Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
  93. this.handler.setInputAction(function (evt) { //单机开始绘制
  94. //屏幕坐标转地形上坐标
  95. var cartesian = $this.getCatesian3FromPX(evt.position);
  96. if ($this._positions.length == 0) {
  97. $this._positions.push(cartesian.clone());
  98. $this.floatingPoint = $this.createPoint(cartesian);
  99. $this.createPoint(cartesian);// 绘制点
  100. }
  101. $this._positions.push(cartesian);
  102. }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK);
  103. this.handler.setInputAction(function (evt) { //移动时绘制线
  104. if ($this._positions.length < 3) return;
  105. var cartesian = $this.getCatesian3FromPX(evt.endPosition);
  106. if (!$this.Cesium.defined($this._curveline)) {
  107. $this._curveline = $this.createCurveline();
  108. }
  109. $this.floatingPoint.position.setValue(cartesian);
  110. if ($this._curveline) {
  111. $this._positions.pop();
  112. $this._positions.push(cartesian);
  113. }
  114. }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  115. this.handler.setInputAction(function (evt) {
  116. if (!$this._curveline) return;
  117. var cartesian = $this.getCatesian3FromPX(evt.position);
  118. $this._positions.pop();
  119. $this._positions.push(cartesian);
  120. $this.createPoint(cartesian);// 绘制点
  121. $this._curvelineData = $this._positions.concat();
  122. $this.viewer.entities.remove($this._curveline); //移除
  123. $this._curveline = null;
  124. $this._positions = [];
  125. $this.floatingPoint.position.setValue(cartesian);
  126. let lnglatArr = [];
  127. for (var i = 0; i < $this._curvelineData.length; i++) {
  128. var lnglat = $this.cartesianToLatlng($this._curvelineData[i]);
  129. lnglatArr.push(lnglat)
  130. }
  131. $this._curvelineData = lnglatArr;
  132. var line = $this.addload($this._curvelineData); //加载曲线
  133. $this._entities_line.push(line);
  134. $this._curvelineLast = line;
  135. $this.clearPoint()
  136. $this.destroy()
  137. }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  138. }
  139. //创建点
  140. createPoint(cartesian) {
  141. var $this = this;
  142. var point = this.viewer.entities.add({
  143. position: cartesian,
  144. point: {
  145. pixelSize: 10,
  146. color: $this.Cesium.Color.RED,
  147. heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
  148. }
  149. });
  150. $this._entities_point.push(point);
  151. return point;
  152. }
  153. //创建曲线
  154. createCurveline() {
  155. var $this = this;
  156. var polyline = this.viewer.entities.add({
  157. polyline: {
  158. //使用cesium的peoperty
  159. positions: new $this.Cesium.CallbackProperty(function () {
  160. let pnts = []
  161. for (let p = 0; p < $this._positions.length; p++) {
  162. pnts.push($this.lonLatToMercator($this.cartesianToLatlng($this._positions[p])))
  163. }
  164. let CurvePoints = $this.getCurvePoints(pnts)
  165. let point = [];
  166. for (let i = 0; i < CurvePoints.length; i++) {
  167. point.push($this.LatlngTocartesian($this.WebMercator2lonLat(CurvePoints[i])))
  168. }
  169. return point;
  170. }, false),
  171. show: true,
  172. material: $this.Cesium.Color.YELLOW,
  173. width: 3,
  174. clampToGround: true
  175. }
  176. });
  177. $this._entities_line.push(polyline);
  178. return polyline;
  179. }
  180. clearPoint() {
  181. this.DrawEndEvent.raiseEvent(this._curvelineLast, this._curvelineData, this.drawType);
  182. for (var i = 0; i < this._entities_point.length; i++) {
  183. this.viewer.entities.remove(this._entities_point[i]);
  184. }
  185. this._entities_point = []; //脏数据
  186. }
  187. //销毁
  188. destroy() {
  189. if (this.handler) {
  190. this.handler.destroy();
  191. this.handler = null;
  192. }
  193. }
  194. //清空实体对象
  195. clear() {
  196. for (var i = 0; i < this._entities_point.length; i++) {
  197. this.viewer.entities.remove(this._entities_point[i]);
  198. }
  199. for (var i = 0; i < this._entities_line.length; i++) {
  200. this.viewer.entities.remove(this._entities_line[i]);
  201. }
  202. this.floatingPoint = null;//标识点
  203. this._curveline = null; //活动曲线
  204. this._curvelineLast = null; //最后一条曲线
  205. this._positions = []; //活动点
  206. this._entities_point = []; //脏数据
  207. this._entities_line = []; //脏数据
  208. this._curvelineData = null; //用于构造曲线数据
  209. }
  210. getCatesian3FromPX(px) {
  211. var cartesian;
  212. var ray = this.viewer.camera.getPickRay(px);
  213. if (!ray) return null;
  214. cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
  215. return cartesian;
  216. }
  217. cartesianToLatlng(cartesian) {
  218. var latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
  219. var lat = this.Cesium.Math.toDegrees(latlng.latitude);
  220. var lng = this.Cesium.Math.toDegrees(latlng.longitude);
  221. return [lng, lat];
  222. }
  223. LatlngTocartesian(latlng) {
  224. let cartesian3 = this.Cesium.Cartesian3.fromDegrees(latlng[0], latlng[1]);
  225. return cartesian3
  226. }
  227. /**
  228. * 经纬度坐标转墨卡托坐标
  229. */
  230. // 墨卡托坐标系:展开地球,赤道作为x轴,向东为x轴正方,本初子午线作为y轴,向北为y轴正方向。
  231. // 数字20037508.34是地球赤道周长的一半:地球半径6378137米,赤道周长2*PI*r = 2 * 20037508.3427892,墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892]
  232. lonLatToMercator(Latlng) {
  233. var E = Latlng[0];
  234. var N = Latlng[1];
  235. var x = E * 20037508.34 / 180;
  236. var y = Math.log(Math.tan((90 + N) * Math.PI / 360)) / (Math.PI / 180);
  237. y = y * 20037508.34 / 180;
  238. return [x, y]
  239. }
  240. /**
  241. * 墨卡托坐标转经纬度坐标转
  242. */
  243. WebMercator2lonLat(mercator) {
  244. let x = mercator[0] / 20037508.34 * 180;
  245. let ly = mercator[1] / 20037508.34 * 180;
  246. let y = 180 / Math.PI * (2 * Math.atan(Math.exp(ly * Math.PI / 180)) - Math.PI / 2)
  247. return [x, y];
  248. }
  249. /**
  250. * 插值曲线点
  251. * @param t
  252. * @param controlPoints
  253. * @returns {null}
  254. */
  255. getCurvePoints( controlPoints) {
  256. let leftControl = this.getLeftMostControlPoint(controlPoints, this.t)
  257. let [pnt1, pnt2, pnt3, normals, points] = [null, null, null, [leftControl], []]
  258. for (let i = 0; i < controlPoints.length - 2; i++) {
  259. [pnt1, pnt2, pnt3] = [controlPoints[i], controlPoints[i + 1], controlPoints[i + 2]]
  260. let normalPoints = this.getBisectorNormals(this.t, pnt1, pnt2, pnt3)
  261. normals = normals.concat(normalPoints)
  262. }
  263. let rightControl = this.getRightMostControlPoint(controlPoints, this.t)
  264. if (rightControl) {
  265. normals.push(rightControl)
  266. }
  267. for (let i = 0; i < controlPoints.length - 1; i++) {
  268. pnt1 = controlPoints[i]
  269. pnt2 = controlPoints[i + 1]
  270. points.push(pnt1)
  271. for (let t = 0; t < this.FITTING_COUNT; t++) {
  272. let pnt = this.getCubicValue(t / this.FITTING_COUNT, pnt1, normals[i * 2], normals[i * 2 + 1], pnt2)
  273. points.push(pnt)
  274. }
  275. points.push(pnt2)
  276. }
  277. return points
  278. }
  279. /**
  280. * 获取左边控制点
  281. * @param controlPoints
  282. * @returns {[*,*]}
  283. */
  284. getLeftMostControlPoint(controlPoints, t) {
  285. let [pnt1, pnt2, pnt3, controlX, controlY] = [controlPoints[0], controlPoints[1], controlPoints[2], null, null]
  286. let pnts = this.getBisectorNormals(0, pnt1, pnt2, pnt3)
  287. let normalRight = pnts[0]
  288. let normal = this.getNormal(pnt1, pnt2, pnt3)
  289. let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
  290. if (dist > this.ZERO_TOLERANCE) {
  291. let mid = this.Mid(pnt1, pnt2)
  292. let pX = pnt1[0] - mid[0]
  293. let pY = pnt1[1] - mid[1]
  294. let d1 = this.MathDistance(pnt1, pnt2)
  295. let n = 2.0 / d1
  296. let nX = -n * pY
  297. let nY = n * pX
  298. let a11 = nX * nX - nY * nY
  299. let a12 = 2 * nX * nY
  300. let a22 = nY * nY - nX * nX
  301. let dX = normalRight[0] - mid[0]
  302. let dY = normalRight[1] - mid[1]
  303. controlX = mid[0] + a11 * dX + a12 * dY
  304. controlY = mid[1] + a12 * dX + a22 * dY
  305. } else {
  306. controlX = pnt1[0] + t * (pnt2[0] - pnt1[0])
  307. controlY = pnt1[1] + t * (pnt2[1] - pnt1[1])
  308. }
  309. return [controlX, controlY]
  310. }
  311. /**
  312. * getBisectorNormals
  313. * @param t
  314. * @param pnt1
  315. * @param pnt2
  316. * @param pnt3
  317. * @returns {[*,*]}
  318. */
  319. getBisectorNormals(t, pnt1, pnt2, pnt3) {
  320. let normal = this.getNormal(pnt1, pnt2, pnt3)
  321. let [bisectorNormalRight, bisectorNormalLeft, dt, x, y] = [null, null, null, null, null]
  322. let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
  323. let uX = normal[0] / dist
  324. let uY = normal[1] / dist
  325. let d1 = this.MathDistance(pnt1, pnt2)
  326. let d2 = this.MathDistance(pnt2, pnt3)
  327. if (dist > this.ZERO_TOLERANCE) {
  328. if (this.isClockWise(pnt1, pnt2, pnt3)) {
  329. dt = t * d1
  330. x = pnt2[0] - dt * uY
  331. y = pnt2[1] + dt * uX
  332. bisectorNormalRight = [x, y]
  333. dt = t * d2
  334. x = pnt2[0] + dt * uY
  335. y = pnt2[1] - dt * uX
  336. bisectorNormalLeft = [x, y]
  337. } else {
  338. dt = t * d1
  339. x = pnt2[0] + dt * uY
  340. y = pnt2[1] - dt * uX
  341. bisectorNormalRight = [x, y]
  342. dt = t * d2
  343. x = pnt2[0] - dt * uY
  344. y = pnt2[1] + dt * uX
  345. bisectorNormalLeft = [x, y]
  346. }
  347. } else {
  348. x = pnt2[0] + t * (pnt1[0] - pnt2[0])
  349. y = pnt2[1] + t * (pnt1[1] - pnt2[1])
  350. bisectorNormalRight = [x, y]
  351. x = pnt2[0] + t * (pnt3[0] - pnt2[0])
  352. y = pnt2[1] + t * (pnt3[1] - pnt2[1])
  353. bisectorNormalLeft = [x, y]
  354. }
  355. return [bisectorNormalRight, bisectorNormalLeft]
  356. }
  357. /**
  358. * 获取默认三点的内切圆
  359. * @param pnt1
  360. * @param pnt2
  361. * @param pnt3
  362. * @returns {[*,*]}
  363. */
  364. getNormal(pnt1, pnt2, pnt3) {
  365. let dX1 = pnt1[0] - pnt2[0]
  366. let dY1 = pnt1[1] - pnt2[1]
  367. let d1 = Math.sqrt(dX1 * dX1 + dY1 * dY1)
  368. dX1 /= d1
  369. dY1 /= d1
  370. let dX2 = pnt3[0] - pnt2[0]
  371. let dY2 = pnt3[1] - pnt2[1]
  372. let d2 = Math.sqrt(dX2 * dX2 + dY2 * dY2)
  373. dX2 /= d2
  374. dY2 /= d2
  375. let uX = dX1 + dX2
  376. let uY = dY1 + dY2
  377. return [uX, uY]
  378. }
  379. /**
  380. * 判断是否是顺时针
  381. * @param pnt1
  382. * @param pnt2
  383. * @param pnt3
  384. * @returns {boolean}
  385. */
  386. isClockWise(pnt1, pnt2, pnt3) {
  387. return ((pnt3[1] - pnt1[1]) * (pnt2[0] - pnt1[0]) > (pnt2[1] - pnt1[1]) * (pnt3[0] - pnt1[0]))
  388. }
  389. /**
  390. * 求取两个坐标的中间值
  391. * @param point1
  392. * @param point2
  393. * @returns {[*,*]}
  394. * @constructor
  395. */
  396. Mid(point1, point2) {
  397. return [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2]
  398. }
  399. /**
  400. * 计算两个坐标之间的距离
  401. * @ignore
  402. * @param pnt1
  403. * @param pnt2
  404. * @returns {number}
  405. * @constructor
  406. */
  407. MathDistance(pnt1, pnt2) {
  408. return (Math.sqrt(Math.pow((pnt1[0] - pnt2[0]), 2) + Math.pow((pnt1[1] - pnt2[1]), 2)))
  409. }
  410. /**
  411. * 获取右边控制点
  412. * @param controlPoints
  413. * @param t
  414. * @returns {[*,*]}
  415. */
  416. getRightMostControlPoint(controlPoints, t) {
  417. let count = controlPoints.length
  418. let pnt1 = controlPoints[count - 3]
  419. let pnt2 = controlPoints[count - 2]
  420. let pnt3 = controlPoints[count - 1]
  421. let pnts = this.getBisectorNormals(0, pnt1, pnt2, pnt3)
  422. let normalLeft = pnts[1]
  423. let normal = this.getNormal(pnt1, pnt2, pnt3)
  424. let dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1])
  425. let [controlX, controlY] = [null, null]
  426. if (dist > this.ZERO_TOLERANCE) {
  427. let mid = this.Mid(pnt2, pnt3)
  428. let pX = pnt3[0] - mid[0]
  429. let pY = pnt3[1] - mid[1]
  430. let d1 = this.MathDistance(pnt2, pnt3)
  431. let n = 2.0 / d1
  432. let nX = -n * pY
  433. let nY = n * pX
  434. let a11 = nX * nX - nY * nY
  435. let a12 = 2 * nX * nY
  436. let a22 = nY * nY - nX * nX
  437. let dX = normalLeft[0] - mid[0]
  438. let dY = normalLeft[1] - mid[1]
  439. controlX = mid[0] + a11 * dX + a12 * dY
  440. controlY = mid[1] + a12 * dX + a22 * dY
  441. } else {
  442. controlX = pnt3[0] + t * (pnt2[0] - pnt3[0])
  443. controlY = pnt3[1] + t * (pnt2[1] - pnt3[1])
  444. }
  445. return [controlX, controlY]
  446. }
  447. /**
  448. * 获取立方值
  449. * @param t
  450. * @param startPnt
  451. * @param cPnt1
  452. * @param cPnt2
  453. * @param endPnt
  454. * @returns {[*,*]}
  455. */
  456. getCubicValue(t, startPnt, cPnt1, cPnt2, endPnt) {
  457. t = Math.max(Math.min(t, 1), 0)
  458. let [tp, t2] = [(1 - t), (t * t)]
  459. let t3 = t2 * t
  460. let tp2 = tp * tp
  461. let tp3 = tp2 * tp
  462. let x = (tp3 * startPnt[0]) + (3 * tp2 * t * cPnt1[0]) + (3 * tp * t2 * cPnt2[0]) + (t3 * endPnt[0])
  463. let y = (tp3 * startPnt[1]) + (3 * tp2 * t * cPnt1[1]) + (3 * tp * t2 * cPnt2[1]) + (t3 * endPnt[1])
  464. return [x, y]
  465. }
  466. }
  467. export default DrawCurve