PolylineVolumeGeometryLibrary.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. import Cartesian2 from "./Cartesian2.js";
  2. import Cartesian3 from "./Cartesian3.js";
  3. import Cartesian4 from "./Cartesian4.js";
  4. import Cartographic from "./Cartographic.js";
  5. import CornerType from "./CornerType.js";
  6. import EllipsoidTangentPlane from "./EllipsoidTangentPlane.js";
  7. import CesiumMath from "./Math.js";
  8. import Matrix3 from "./Matrix3.js";
  9. import Matrix4 from "./Matrix4.js";
  10. import PolylinePipeline from "./PolylinePipeline.js";
  11. import Quaternion from "./Quaternion.js";
  12. import Transforms from "./Transforms.js";
  13. var scratch2Array = [new Cartesian3(), new Cartesian3()];
  14. var scratchCartesian1 = new Cartesian3();
  15. var scratchCartesian2 = new Cartesian3();
  16. var scratchCartesian3 = new Cartesian3();
  17. var scratchCartesian4 = new Cartesian3();
  18. var scratchCartesian5 = new Cartesian3();
  19. var scratchCartesian6 = new Cartesian3();
  20. var scratchCartesian7 = new Cartesian3();
  21. var scratchCartesian8 = new Cartesian3();
  22. var scratchCartesian9 = new Cartesian3();
  23. var scratch1 = new Cartesian3();
  24. var scratch2 = new Cartesian3();
  25. /**
  26. * @private
  27. */
  28. var PolylineVolumeGeometryLibrary = {};
  29. var cartographic = new Cartographic();
  30. function scaleToSurface(positions, ellipsoid) {
  31. var heights = new Array(positions.length);
  32. for (var i = 0; i < positions.length; i++) {
  33. var pos = positions[i];
  34. cartographic = ellipsoid.cartesianToCartographic(pos, cartographic);
  35. heights[i] = cartographic.height;
  36. positions[i] = ellipsoid.scaleToGeodeticSurface(pos, pos);
  37. }
  38. return heights;
  39. }
  40. function subdivideHeights(points, h0, h1, granularity) {
  41. var p0 = points[0];
  42. var p1 = points[1];
  43. var angleBetween = Cartesian3.angleBetween(p0, p1);
  44. var numPoints = Math.ceil(angleBetween / granularity);
  45. var heights = new Array(numPoints);
  46. var i;
  47. if (h0 === h1) {
  48. for (i = 0; i < numPoints; i++) {
  49. heights[i] = h0;
  50. }
  51. heights.push(h1);
  52. return heights;
  53. }
  54. var dHeight = h1 - h0;
  55. var heightPerVertex = dHeight / numPoints;
  56. for (i = 1; i < numPoints; i++) {
  57. var h = h0 + i * heightPerVertex;
  58. heights[i] = h;
  59. }
  60. heights[0] = h0;
  61. heights.push(h1);
  62. return heights;
  63. }
  64. var nextScratch = new Cartesian3();
  65. var prevScratch = new Cartesian3();
  66. function computeRotationAngle(start, end, position, ellipsoid) {
  67. var tangentPlane = new EllipsoidTangentPlane(position, ellipsoid);
  68. var next = tangentPlane.projectPointOntoPlane(
  69. Cartesian3.add(position, start, nextScratch),
  70. nextScratch
  71. );
  72. var prev = tangentPlane.projectPointOntoPlane(
  73. Cartesian3.add(position, end, prevScratch),
  74. prevScratch
  75. );
  76. var angle = Cartesian2.angleBetween(next, prev);
  77. return prev.x * next.y - prev.y * next.x >= 0.0 ? -angle : angle;
  78. }
  79. var negativeX = new Cartesian3(-1, 0, 0);
  80. var transform = new Matrix4();
  81. var translation = new Matrix4();
  82. var rotationZ = new Matrix3();
  83. var scaleMatrix = Matrix3.IDENTITY.clone();
  84. var westScratch = new Cartesian3();
  85. var finalPosScratch = new Cartesian4();
  86. var heightCartesian = new Cartesian3();
  87. function addPosition(
  88. center,
  89. left,
  90. shape,
  91. finalPositions,
  92. ellipsoid,
  93. height,
  94. xScalar,
  95. repeat
  96. ) {
  97. var west = westScratch;
  98. var finalPosition = finalPosScratch;
  99. transform = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, transform);
  100. west = Matrix4.multiplyByPointAsVector(transform, negativeX, west);
  101. west = Cartesian3.normalize(west, west);
  102. var angle = computeRotationAngle(west, left, center, ellipsoid);
  103. rotationZ = Matrix3.fromRotationZ(angle, rotationZ);
  104. heightCartesian.z = height;
  105. transform = Matrix4.multiplyTransformation(
  106. transform,
  107. Matrix4.fromRotationTranslation(rotationZ, heightCartesian, translation),
  108. transform
  109. );
  110. var scale = scaleMatrix;
  111. scale[0] = xScalar;
  112. for (var j = 0; j < repeat; j++) {
  113. for (var i = 0; i < shape.length; i += 3) {
  114. finalPosition = Cartesian3.fromArray(shape, i, finalPosition);
  115. finalPosition = Matrix3.multiplyByVector(
  116. scale,
  117. finalPosition,
  118. finalPosition
  119. );
  120. finalPosition = Matrix4.multiplyByPoint(
  121. transform,
  122. finalPosition,
  123. finalPosition
  124. );
  125. finalPositions.push(finalPosition.x, finalPosition.y, finalPosition.z);
  126. }
  127. }
  128. return finalPositions;
  129. }
  130. var centerScratch = new Cartesian3();
  131. function addPositions(
  132. centers,
  133. left,
  134. shape,
  135. finalPositions,
  136. ellipsoid,
  137. heights,
  138. xScalar
  139. ) {
  140. for (var i = 0; i < centers.length; i += 3) {
  141. var center = Cartesian3.fromArray(centers, i, centerScratch);
  142. finalPositions = addPosition(
  143. center,
  144. left,
  145. shape,
  146. finalPositions,
  147. ellipsoid,
  148. heights[i / 3],
  149. xScalar,
  150. 1
  151. );
  152. }
  153. return finalPositions;
  154. }
  155. function convertShapeTo3DDuplicate(shape2D, boundingRectangle) {
  156. //orientate 2D shape to XZ plane center at (0, 0, 0), duplicate points
  157. var length = shape2D.length;
  158. var shape = new Array(length * 6);
  159. var index = 0;
  160. var xOffset = boundingRectangle.x + boundingRectangle.width / 2;
  161. var yOffset = boundingRectangle.y + boundingRectangle.height / 2;
  162. var point = shape2D[0];
  163. shape[index++] = point.x - xOffset;
  164. shape[index++] = 0.0;
  165. shape[index++] = point.y - yOffset;
  166. for (var i = 1; i < length; i++) {
  167. point = shape2D[i];
  168. var x = point.x - xOffset;
  169. var z = point.y - yOffset;
  170. shape[index++] = x;
  171. shape[index++] = 0.0;
  172. shape[index++] = z;
  173. shape[index++] = x;
  174. shape[index++] = 0.0;
  175. shape[index++] = z;
  176. }
  177. point = shape2D[0];
  178. shape[index++] = point.x - xOffset;
  179. shape[index++] = 0.0;
  180. shape[index++] = point.y - yOffset;
  181. return shape;
  182. }
  183. function convertShapeTo3D(shape2D, boundingRectangle) {
  184. //orientate 2D shape to XZ plane center at (0, 0, 0)
  185. var length = shape2D.length;
  186. var shape = new Array(length * 3);
  187. var index = 0;
  188. var xOffset = boundingRectangle.x + boundingRectangle.width / 2;
  189. var yOffset = boundingRectangle.y + boundingRectangle.height / 2;
  190. for (var i = 0; i < length; i++) {
  191. shape[index++] = shape2D[i].x - xOffset;
  192. shape[index++] = 0;
  193. shape[index++] = shape2D[i].y - yOffset;
  194. }
  195. return shape;
  196. }
  197. var quaterion = new Quaternion();
  198. var startPointScratch = new Cartesian3();
  199. var rotMatrix = new Matrix3();
  200. function computeRoundCorner(
  201. pivot,
  202. startPoint,
  203. endPoint,
  204. cornerType,
  205. leftIsOutside,
  206. ellipsoid,
  207. finalPositions,
  208. shape,
  209. height,
  210. duplicatePoints
  211. ) {
  212. var angle = Cartesian3.angleBetween(
  213. Cartesian3.subtract(startPoint, pivot, scratch1),
  214. Cartesian3.subtract(endPoint, pivot, scratch2)
  215. );
  216. var granularity =
  217. cornerType === CornerType.BEVELED
  218. ? 0
  219. : Math.ceil(angle / CesiumMath.toRadians(5));
  220. var m;
  221. if (leftIsOutside) {
  222. m = Matrix3.fromQuaternion(
  223. Quaternion.fromAxisAngle(
  224. Cartesian3.negate(pivot, scratch1),
  225. angle / (granularity + 1),
  226. quaterion
  227. ),
  228. rotMatrix
  229. );
  230. } else {
  231. m = Matrix3.fromQuaternion(
  232. Quaternion.fromAxisAngle(pivot, angle / (granularity + 1), quaterion),
  233. rotMatrix
  234. );
  235. }
  236. var left;
  237. var surfacePoint;
  238. startPoint = Cartesian3.clone(startPoint, startPointScratch);
  239. if (granularity > 0) {
  240. var repeat = duplicatePoints ? 2 : 1;
  241. for (var i = 0; i < granularity; i++) {
  242. startPoint = Matrix3.multiplyByVector(m, startPoint, startPoint);
  243. left = Cartesian3.subtract(startPoint, pivot, scratch1);
  244. left = Cartesian3.normalize(left, left);
  245. if (!leftIsOutside) {
  246. left = Cartesian3.negate(left, left);
  247. }
  248. surfacePoint = ellipsoid.scaleToGeodeticSurface(startPoint, scratch2);
  249. finalPositions = addPosition(
  250. surfacePoint,
  251. left,
  252. shape,
  253. finalPositions,
  254. ellipsoid,
  255. height,
  256. 1,
  257. repeat
  258. );
  259. }
  260. } else {
  261. left = Cartesian3.subtract(startPoint, pivot, scratch1);
  262. left = Cartesian3.normalize(left, left);
  263. if (!leftIsOutside) {
  264. left = Cartesian3.negate(left, left);
  265. }
  266. surfacePoint = ellipsoid.scaleToGeodeticSurface(startPoint, scratch2);
  267. finalPositions = addPosition(
  268. surfacePoint,
  269. left,
  270. shape,
  271. finalPositions,
  272. ellipsoid,
  273. height,
  274. 1,
  275. 1
  276. );
  277. endPoint = Cartesian3.clone(endPoint, startPointScratch);
  278. left = Cartesian3.subtract(endPoint, pivot, scratch1);
  279. left = Cartesian3.normalize(left, left);
  280. if (!leftIsOutside) {
  281. left = Cartesian3.negate(left, left);
  282. }
  283. surfacePoint = ellipsoid.scaleToGeodeticSurface(endPoint, scratch2);
  284. finalPositions = addPosition(
  285. surfacePoint,
  286. left,
  287. shape,
  288. finalPositions,
  289. ellipsoid,
  290. height,
  291. 1,
  292. 1
  293. );
  294. }
  295. return finalPositions;
  296. }
  297. PolylineVolumeGeometryLibrary.removeDuplicatesFromShape = function (
  298. shapePositions
  299. ) {
  300. var length = shapePositions.length;
  301. var cleanedPositions = [];
  302. for (var i0 = length - 1, i1 = 0; i1 < length; i0 = i1++) {
  303. var v0 = shapePositions[i0];
  304. var v1 = shapePositions[i1];
  305. if (!Cartesian2.equals(v0, v1)) {
  306. cleanedPositions.push(v1); // Shallow copy!
  307. }
  308. }
  309. return cleanedPositions;
  310. };
  311. PolylineVolumeGeometryLibrary.angleIsGreaterThanPi = function (
  312. forward,
  313. backward,
  314. position,
  315. ellipsoid
  316. ) {
  317. var tangentPlane = new EllipsoidTangentPlane(position, ellipsoid);
  318. var next = tangentPlane.projectPointOntoPlane(
  319. Cartesian3.add(position, forward, nextScratch),
  320. nextScratch
  321. );
  322. var prev = tangentPlane.projectPointOntoPlane(
  323. Cartesian3.add(position, backward, prevScratch),
  324. prevScratch
  325. );
  326. return prev.x * next.y - prev.y * next.x >= 0.0;
  327. };
  328. var scratchForwardProjection = new Cartesian3();
  329. var scratchBackwardProjection = new Cartesian3();
  330. PolylineVolumeGeometryLibrary.computePositions = function (
  331. positions,
  332. shape2D,
  333. boundingRectangle,
  334. geometry,
  335. duplicatePoints
  336. ) {
  337. var ellipsoid = geometry._ellipsoid;
  338. var heights = scaleToSurface(positions, ellipsoid);
  339. var granularity = geometry._granularity;
  340. var cornerType = geometry._cornerType;
  341. var shapeForSides = duplicatePoints
  342. ? convertShapeTo3DDuplicate(shape2D, boundingRectangle)
  343. : convertShapeTo3D(shape2D, boundingRectangle);
  344. var shapeForEnds = duplicatePoints
  345. ? convertShapeTo3D(shape2D, boundingRectangle)
  346. : undefined;
  347. var heightOffset = boundingRectangle.height / 2;
  348. var width = boundingRectangle.width / 2;
  349. var length = positions.length;
  350. var finalPositions = [];
  351. var ends = duplicatePoints ? [] : undefined;
  352. var forward = scratchCartesian1;
  353. var backward = scratchCartesian2;
  354. var cornerDirection = scratchCartesian3;
  355. var surfaceNormal = scratchCartesian4;
  356. var pivot = scratchCartesian5;
  357. var start = scratchCartesian6;
  358. var end = scratchCartesian7;
  359. var left = scratchCartesian8;
  360. var previousPosition = scratchCartesian9;
  361. var position = positions[0];
  362. var nextPosition = positions[1];
  363. surfaceNormal = ellipsoid.geodeticSurfaceNormal(position, surfaceNormal);
  364. forward = Cartesian3.subtract(nextPosition, position, forward);
  365. forward = Cartesian3.normalize(forward, forward);
  366. left = Cartesian3.cross(surfaceNormal, forward, left);
  367. left = Cartesian3.normalize(left, left);
  368. var h0 = heights[0];
  369. var h1 = heights[1];
  370. if (duplicatePoints) {
  371. ends = addPosition(
  372. position,
  373. left,
  374. shapeForEnds,
  375. ends,
  376. ellipsoid,
  377. h0 + heightOffset,
  378. 1,
  379. 1
  380. );
  381. }
  382. previousPosition = Cartesian3.clone(position, previousPosition);
  383. position = nextPosition;
  384. backward = Cartesian3.negate(forward, backward);
  385. var subdividedHeights;
  386. var subdividedPositions;
  387. for (var i = 1; i < length - 1; i++) {
  388. var repeat = duplicatePoints ? 2 : 1;
  389. nextPosition = positions[i + 1];
  390. forward = Cartesian3.subtract(nextPosition, position, forward);
  391. forward = Cartesian3.normalize(forward, forward);
  392. cornerDirection = Cartesian3.add(forward, backward, cornerDirection);
  393. cornerDirection = Cartesian3.normalize(cornerDirection, cornerDirection);
  394. surfaceNormal = ellipsoid.geodeticSurfaceNormal(position, surfaceNormal);
  395. var forwardProjection = Cartesian3.multiplyByScalar(
  396. surfaceNormal,
  397. Cartesian3.dot(forward, surfaceNormal),
  398. scratchForwardProjection
  399. );
  400. Cartesian3.subtract(forward, forwardProjection, forwardProjection);
  401. Cartesian3.normalize(forwardProjection, forwardProjection);
  402. var backwardProjection = Cartesian3.multiplyByScalar(
  403. surfaceNormal,
  404. Cartesian3.dot(backward, surfaceNormal),
  405. scratchBackwardProjection
  406. );
  407. Cartesian3.subtract(backward, backwardProjection, backwardProjection);
  408. Cartesian3.normalize(backwardProjection, backwardProjection);
  409. var doCorner = !CesiumMath.equalsEpsilon(
  410. Math.abs(Cartesian3.dot(forwardProjection, backwardProjection)),
  411. 1.0,
  412. CesiumMath.EPSILON7
  413. );
  414. if (doCorner) {
  415. cornerDirection = Cartesian3.cross(
  416. cornerDirection,
  417. surfaceNormal,
  418. cornerDirection
  419. );
  420. cornerDirection = Cartesian3.cross(
  421. surfaceNormal,
  422. cornerDirection,
  423. cornerDirection
  424. );
  425. cornerDirection = Cartesian3.normalize(cornerDirection, cornerDirection);
  426. var scalar =
  427. 1 /
  428. Math.max(
  429. 0.25,
  430. Cartesian3.magnitude(
  431. Cartesian3.cross(cornerDirection, backward, scratch1)
  432. )
  433. );
  434. var leftIsOutside = PolylineVolumeGeometryLibrary.angleIsGreaterThanPi(
  435. forward,
  436. backward,
  437. position,
  438. ellipsoid
  439. );
  440. if (leftIsOutside) {
  441. pivot = Cartesian3.add(
  442. position,
  443. Cartesian3.multiplyByScalar(
  444. cornerDirection,
  445. scalar * width,
  446. cornerDirection
  447. ),
  448. pivot
  449. );
  450. start = Cartesian3.add(
  451. pivot,
  452. Cartesian3.multiplyByScalar(left, width, start),
  453. start
  454. );
  455. scratch2Array[0] = Cartesian3.clone(previousPosition, scratch2Array[0]);
  456. scratch2Array[1] = Cartesian3.clone(start, scratch2Array[1]);
  457. subdividedHeights = subdivideHeights(
  458. scratch2Array,
  459. h0 + heightOffset,
  460. h1 + heightOffset,
  461. granularity
  462. );
  463. subdividedPositions = PolylinePipeline.generateArc({
  464. positions: scratch2Array,
  465. granularity: granularity,
  466. ellipsoid: ellipsoid,
  467. });
  468. finalPositions = addPositions(
  469. subdividedPositions,
  470. left,
  471. shapeForSides,
  472. finalPositions,
  473. ellipsoid,
  474. subdividedHeights,
  475. 1
  476. );
  477. left = Cartesian3.cross(surfaceNormal, forward, left);
  478. left = Cartesian3.normalize(left, left);
  479. end = Cartesian3.add(
  480. pivot,
  481. Cartesian3.multiplyByScalar(left, width, end),
  482. end
  483. );
  484. if (
  485. cornerType === CornerType.ROUNDED ||
  486. cornerType === CornerType.BEVELED
  487. ) {
  488. computeRoundCorner(
  489. pivot,
  490. start,
  491. end,
  492. cornerType,
  493. leftIsOutside,
  494. ellipsoid,
  495. finalPositions,
  496. shapeForSides,
  497. h1 + heightOffset,
  498. duplicatePoints
  499. );
  500. } else {
  501. cornerDirection = Cartesian3.negate(cornerDirection, cornerDirection);
  502. finalPositions = addPosition(
  503. position,
  504. cornerDirection,
  505. shapeForSides,
  506. finalPositions,
  507. ellipsoid,
  508. h1 + heightOffset,
  509. scalar,
  510. repeat
  511. );
  512. }
  513. previousPosition = Cartesian3.clone(end, previousPosition);
  514. } else {
  515. pivot = Cartesian3.add(
  516. position,
  517. Cartesian3.multiplyByScalar(
  518. cornerDirection,
  519. scalar * width,
  520. cornerDirection
  521. ),
  522. pivot
  523. );
  524. start = Cartesian3.add(
  525. pivot,
  526. Cartesian3.multiplyByScalar(left, -width, start),
  527. start
  528. );
  529. scratch2Array[0] = Cartesian3.clone(previousPosition, scratch2Array[0]);
  530. scratch2Array[1] = Cartesian3.clone(start, scratch2Array[1]);
  531. subdividedHeights = subdivideHeights(
  532. scratch2Array,
  533. h0 + heightOffset,
  534. h1 + heightOffset,
  535. granularity
  536. );
  537. subdividedPositions = PolylinePipeline.generateArc({
  538. positions: scratch2Array,
  539. granularity: granularity,
  540. ellipsoid: ellipsoid,
  541. });
  542. finalPositions = addPositions(
  543. subdividedPositions,
  544. left,
  545. shapeForSides,
  546. finalPositions,
  547. ellipsoid,
  548. subdividedHeights,
  549. 1
  550. );
  551. left = Cartesian3.cross(surfaceNormal, forward, left);
  552. left = Cartesian3.normalize(left, left);
  553. end = Cartesian3.add(
  554. pivot,
  555. Cartesian3.multiplyByScalar(left, -width, end),
  556. end
  557. );
  558. if (
  559. cornerType === CornerType.ROUNDED ||
  560. cornerType === CornerType.BEVELED
  561. ) {
  562. computeRoundCorner(
  563. pivot,
  564. start,
  565. end,
  566. cornerType,
  567. leftIsOutside,
  568. ellipsoid,
  569. finalPositions,
  570. shapeForSides,
  571. h1 + heightOffset,
  572. duplicatePoints
  573. );
  574. } else {
  575. finalPositions = addPosition(
  576. position,
  577. cornerDirection,
  578. shapeForSides,
  579. finalPositions,
  580. ellipsoid,
  581. h1 + heightOffset,
  582. scalar,
  583. repeat
  584. );
  585. }
  586. previousPosition = Cartesian3.clone(end, previousPosition);
  587. }
  588. backward = Cartesian3.negate(forward, backward);
  589. } else {
  590. finalPositions = addPosition(
  591. previousPosition,
  592. left,
  593. shapeForSides,
  594. finalPositions,
  595. ellipsoid,
  596. h0 + heightOffset,
  597. 1,
  598. 1
  599. );
  600. previousPosition = position;
  601. }
  602. h0 = h1;
  603. h1 = heights[i + 1];
  604. position = nextPosition;
  605. }
  606. scratch2Array[0] = Cartesian3.clone(previousPosition, scratch2Array[0]);
  607. scratch2Array[1] = Cartesian3.clone(position, scratch2Array[1]);
  608. subdividedHeights = subdivideHeights(
  609. scratch2Array,
  610. h0 + heightOffset,
  611. h1 + heightOffset,
  612. granularity
  613. );
  614. subdividedPositions = PolylinePipeline.generateArc({
  615. positions: scratch2Array,
  616. granularity: granularity,
  617. ellipsoid: ellipsoid,
  618. });
  619. finalPositions = addPositions(
  620. subdividedPositions,
  621. left,
  622. shapeForSides,
  623. finalPositions,
  624. ellipsoid,
  625. subdividedHeights,
  626. 1
  627. );
  628. if (duplicatePoints) {
  629. ends = addPosition(
  630. position,
  631. left,
  632. shapeForEnds,
  633. ends,
  634. ellipsoid,
  635. h1 + heightOffset,
  636. 1,
  637. 1
  638. );
  639. }
  640. length = finalPositions.length;
  641. var posLength = duplicatePoints ? length + ends.length : length;
  642. var combinedPositions = new Float64Array(posLength);
  643. combinedPositions.set(finalPositions);
  644. if (duplicatePoints) {
  645. combinedPositions.set(ends, length);
  646. }
  647. return combinedPositions;
  648. };
  649. export default PolylineVolumeGeometryLibrary;