CorridorGeometryLibrary.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import Cartesian3 from './Cartesian3.js';
  2. import CornerType from './CornerType.js';
  3. import defined from './defined.js';
  4. import CesiumMath from './Math.js';
  5. import Matrix3 from './Matrix3.js';
  6. import PolylinePipeline from './PolylinePipeline.js';
  7. import PolylineVolumeGeometryLibrary from './PolylineVolumeGeometryLibrary.js';
  8. import Quaternion from './Quaternion.js';
  9. /**
  10. * @private
  11. */
  12. var CorridorGeometryLibrary = {};
  13. var scratch1 = new Cartesian3();
  14. var scratch2 = new Cartesian3();
  15. var scratch3 = new Cartesian3();
  16. var scratch4 = new Cartesian3();
  17. var scaleArray2 = [new Cartesian3(), new Cartesian3()];
  18. var cartesian1 = new Cartesian3();
  19. var cartesian2 = new Cartesian3();
  20. var cartesian3 = new Cartesian3();
  21. var cartesian4 = new Cartesian3();
  22. var cartesian5 = new Cartesian3();
  23. var cartesian6 = new Cartesian3();
  24. var cartesian7 = new Cartesian3();
  25. var cartesian8 = new Cartesian3();
  26. var cartesian9 = new Cartesian3();
  27. var cartesian10 = new Cartesian3();
  28. var quaterion = new Quaternion();
  29. var rotMatrix = new Matrix3();
  30. function computeRoundCorner(cornerPoint, startPoint, endPoint, cornerType, leftIsOutside) {
  31. var angle = Cartesian3.angleBetween(Cartesian3.subtract(startPoint, cornerPoint, scratch1), Cartesian3.subtract(endPoint, cornerPoint, scratch2));
  32. var granularity = (cornerType === CornerType.BEVELED) ? 1 : Math.ceil(angle / CesiumMath.toRadians(5)) + 1;
  33. var size = granularity * 3;
  34. var array = new Array(size);
  35. array[size - 3] = endPoint.x;
  36. array[size - 2] = endPoint.y;
  37. array[size - 1] = endPoint.z;
  38. var m;
  39. if (leftIsOutside) {
  40. m = Matrix3.fromQuaternion(Quaternion.fromAxisAngle(Cartesian3.negate(cornerPoint, scratch1), angle / granularity, quaterion), rotMatrix);
  41. } else {
  42. m = Matrix3.fromQuaternion(Quaternion.fromAxisAngle(cornerPoint, angle / granularity, quaterion), rotMatrix);
  43. }
  44. var index = 0;
  45. startPoint = Cartesian3.clone(startPoint, scratch1);
  46. for (var i = 0; i < granularity; i++) {
  47. startPoint = Matrix3.multiplyByVector(m, startPoint, startPoint);
  48. array[index++] = startPoint.x;
  49. array[index++] = startPoint.y;
  50. array[index++] = startPoint.z;
  51. }
  52. return array;
  53. }
  54. function addEndCaps(calculatedPositions) {
  55. var cornerPoint = cartesian1;
  56. var startPoint = cartesian2;
  57. var endPoint = cartesian3;
  58. var leftEdge = calculatedPositions[1];
  59. startPoint = Cartesian3.fromArray(calculatedPositions[1], leftEdge.length - 3, startPoint);
  60. endPoint = Cartesian3.fromArray(calculatedPositions[0], 0, endPoint);
  61. cornerPoint = Cartesian3.midpoint(startPoint, endPoint, cornerPoint);
  62. var firstEndCap = computeRoundCorner(cornerPoint, startPoint, endPoint, CornerType.ROUNDED, false);
  63. var length = calculatedPositions.length - 1;
  64. var rightEdge = calculatedPositions[length - 1];
  65. leftEdge = calculatedPositions[length];
  66. startPoint = Cartesian3.fromArray(rightEdge, rightEdge.length - 3, startPoint);
  67. endPoint = Cartesian3.fromArray(leftEdge, 0, endPoint);
  68. cornerPoint = Cartesian3.midpoint(startPoint, endPoint, cornerPoint);
  69. var lastEndCap = computeRoundCorner(cornerPoint, startPoint, endPoint, CornerType.ROUNDED, false);
  70. return [firstEndCap, lastEndCap];
  71. }
  72. function computeMiteredCorner(position, leftCornerDirection, lastPoint, leftIsOutside) {
  73. var cornerPoint = scratch1;
  74. if (leftIsOutside) {
  75. cornerPoint = Cartesian3.add(position, leftCornerDirection, cornerPoint);
  76. } else {
  77. leftCornerDirection = Cartesian3.negate(leftCornerDirection, leftCornerDirection);
  78. cornerPoint = Cartesian3.add(position, leftCornerDirection, cornerPoint);
  79. }
  80. return [cornerPoint.x, cornerPoint.y, cornerPoint.z, lastPoint.x, lastPoint.y, lastPoint.z];
  81. }
  82. function addShiftedPositions(positions, left, scalar, calculatedPositions) {
  83. var rightPositions = new Array(positions.length);
  84. var leftPositions = new Array(positions.length);
  85. var scaledLeft = Cartesian3.multiplyByScalar(left, scalar, scratch1);
  86. var scaledRight = Cartesian3.negate(scaledLeft, scratch2);
  87. var rightIndex = 0;
  88. var leftIndex = positions.length - 1;
  89. for (var i = 0; i < positions.length; i += 3) {
  90. var pos = Cartesian3.fromArray(positions, i, scratch3);
  91. var rightPos = Cartesian3.add(pos, scaledRight, scratch4);
  92. rightPositions[rightIndex++] = rightPos.x;
  93. rightPositions[rightIndex++] = rightPos.y;
  94. rightPositions[rightIndex++] = rightPos.z;
  95. var leftPos = Cartesian3.add(pos, scaledLeft, scratch4);
  96. leftPositions[leftIndex--] = leftPos.z;
  97. leftPositions[leftIndex--] = leftPos.y;
  98. leftPositions[leftIndex--] = leftPos.x;
  99. }
  100. calculatedPositions.push(rightPositions, leftPositions);
  101. return calculatedPositions;
  102. }
  103. /**
  104. * @private
  105. */
  106. CorridorGeometryLibrary.addAttribute = function(attribute, value, front, back) {
  107. var x = value.x;
  108. var y = value.y;
  109. var z = value.z;
  110. if (defined(front)) {
  111. attribute[front] = x;
  112. attribute[front + 1] = y;
  113. attribute[front + 2] = z;
  114. }
  115. if (defined(back)) {
  116. attribute[back] = z;
  117. attribute[back - 1] = y;
  118. attribute[back - 2] = x;
  119. }
  120. };
  121. var scratchForwardProjection = new Cartesian3();
  122. var scratchBackwardProjection = new Cartesian3();
  123. /**
  124. * @private
  125. */
  126. CorridorGeometryLibrary.computePositions = function(params) {
  127. var granularity = params.granularity;
  128. var positions = params.positions;
  129. var ellipsoid = params.ellipsoid;
  130. var width = params.width / 2;
  131. var cornerType = params.cornerType;
  132. var saveAttributes = params.saveAttributes;
  133. var normal = cartesian1;
  134. var forward = cartesian2;
  135. var backward = cartesian3;
  136. var left = cartesian4;
  137. var cornerDirection = cartesian5;
  138. var startPoint = cartesian6;
  139. var previousPos = cartesian7;
  140. var rightPos = cartesian8;
  141. var leftPos = cartesian9;
  142. var center = cartesian10;
  143. var calculatedPositions = [];
  144. var calculatedLefts = (saveAttributes) ? [] : undefined;
  145. var calculatedNormals = (saveAttributes) ? [] : undefined;
  146. var position = positions[0]; //add first point
  147. var nextPosition = positions[1];
  148. forward = Cartesian3.normalize(Cartesian3.subtract(nextPosition, position, forward), forward);
  149. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  150. left = Cartesian3.normalize(Cartesian3.cross(normal, forward, left), left);
  151. if (saveAttributes) {
  152. calculatedLefts.push(left.x, left.y, left.z);
  153. calculatedNormals.push(normal.x, normal.y, normal.z);
  154. }
  155. previousPos = Cartesian3.clone(position, previousPos);
  156. position = nextPosition;
  157. backward = Cartesian3.negate(forward, backward);
  158. var subdividedPositions;
  159. var corners = [];
  160. var i;
  161. var length = positions.length;
  162. for (i = 1; i < length - 1; i++) { // add middle points and corners
  163. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  164. nextPosition = positions[i + 1];
  165. forward = Cartesian3.normalize(Cartesian3.subtract(nextPosition, position, forward), forward);
  166. cornerDirection = Cartesian3.normalize(Cartesian3.add(forward, backward, cornerDirection), cornerDirection);
  167. var forwardProjection = Cartesian3.multiplyByScalar(normal, Cartesian3.dot(forward, normal), scratchForwardProjection);
  168. Cartesian3.subtract(forward, forwardProjection, forwardProjection);
  169. Cartesian3.normalize(forwardProjection, forwardProjection);
  170. var backwardProjection = Cartesian3.multiplyByScalar(normal, Cartesian3.dot(backward, normal), scratchBackwardProjection);
  171. Cartesian3.subtract(backward, backwardProjection, backwardProjection);
  172. Cartesian3.normalize(backwardProjection, backwardProjection);
  173. var doCorner = !CesiumMath.equalsEpsilon(Math.abs(Cartesian3.dot(forwardProjection, backwardProjection)), 1.0, CesiumMath.EPSILON7);
  174. if (doCorner) {
  175. cornerDirection = Cartesian3.cross(cornerDirection, normal, cornerDirection);
  176. cornerDirection = Cartesian3.cross(normal, cornerDirection, cornerDirection);
  177. cornerDirection = Cartesian3.normalize(cornerDirection, cornerDirection);
  178. var scalar = width / Math.max(0.25, Cartesian3.magnitude(Cartesian3.cross(cornerDirection, backward, scratch1)));
  179. var leftIsOutside = PolylineVolumeGeometryLibrary.angleIsGreaterThanPi(forward, backward, position, ellipsoid);
  180. cornerDirection = Cartesian3.multiplyByScalar(cornerDirection, scalar, cornerDirection);
  181. if (leftIsOutside) {
  182. rightPos = Cartesian3.add(position, cornerDirection, rightPos);
  183. center = Cartesian3.add(rightPos, Cartesian3.multiplyByScalar(left, width, center), center);
  184. leftPos = Cartesian3.add(rightPos, Cartesian3.multiplyByScalar(left, width * 2, leftPos), leftPos);
  185. scaleArray2[0] = Cartesian3.clone(previousPos, scaleArray2[0]);
  186. scaleArray2[1] = Cartesian3.clone(center, scaleArray2[1]);
  187. subdividedPositions = PolylinePipeline.generateArc({
  188. positions: scaleArray2,
  189. granularity: granularity,
  190. ellipsoid: ellipsoid
  191. });
  192. calculatedPositions = addShiftedPositions(subdividedPositions, left, width, calculatedPositions);
  193. if (saveAttributes) {
  194. calculatedLefts.push(left.x, left.y, left.z);
  195. calculatedNormals.push(normal.x, normal.y, normal.z);
  196. }
  197. startPoint = Cartesian3.clone(leftPos, startPoint);
  198. left = Cartesian3.normalize(Cartesian3.cross(normal, forward, left), left);
  199. leftPos = Cartesian3.add(rightPos, Cartesian3.multiplyByScalar(left, width * 2, leftPos), leftPos);
  200. previousPos = Cartesian3.add(rightPos, Cartesian3.multiplyByScalar(left, width, previousPos), previousPos);
  201. if (cornerType === CornerType.ROUNDED || cornerType === CornerType.BEVELED) {
  202. corners.push({
  203. leftPositions : computeRoundCorner(rightPos, startPoint, leftPos, cornerType, leftIsOutside)
  204. });
  205. } else {
  206. corners.push({
  207. leftPositions : computeMiteredCorner(position, Cartesian3.negate(cornerDirection, cornerDirection), leftPos, leftIsOutside)
  208. });
  209. }
  210. } else {
  211. leftPos = Cartesian3.add(position, cornerDirection, leftPos);
  212. center = Cartesian3.add(leftPos, Cartesian3.negate(Cartesian3.multiplyByScalar(left, width, center), center), center);
  213. rightPos = Cartesian3.add(leftPos, Cartesian3.negate(Cartesian3.multiplyByScalar(left, width * 2, rightPos), rightPos), rightPos);
  214. scaleArray2[0] = Cartesian3.clone(previousPos, scaleArray2[0]);
  215. scaleArray2[1] = Cartesian3.clone(center, scaleArray2[1]);
  216. subdividedPositions = PolylinePipeline.generateArc({
  217. positions: scaleArray2,
  218. granularity: granularity,
  219. ellipsoid: ellipsoid
  220. });
  221. calculatedPositions = addShiftedPositions(subdividedPositions, left, width, calculatedPositions);
  222. if (saveAttributes) {
  223. calculatedLefts.push(left.x, left.y, left.z);
  224. calculatedNormals.push(normal.x, normal.y, normal.z);
  225. }
  226. startPoint = Cartesian3.clone(rightPos, startPoint);
  227. left = Cartesian3.normalize(Cartesian3.cross(normal, forward, left), left);
  228. rightPos = Cartesian3.add(leftPos, Cartesian3.negate(Cartesian3.multiplyByScalar(left, width * 2, rightPos), rightPos), rightPos);
  229. previousPos = Cartesian3.add(leftPos, Cartesian3.negate(Cartesian3.multiplyByScalar(left, width, previousPos), previousPos), previousPos);
  230. if (cornerType === CornerType.ROUNDED || cornerType === CornerType.BEVELED) {
  231. corners.push({
  232. rightPositions : computeRoundCorner(leftPos, startPoint, rightPos, cornerType, leftIsOutside)
  233. });
  234. } else {
  235. corners.push({
  236. rightPositions : computeMiteredCorner(position, cornerDirection, rightPos, leftIsOutside)
  237. });
  238. }
  239. }
  240. backward = Cartesian3.negate(forward, backward);
  241. }
  242. position = nextPosition;
  243. }
  244. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  245. scaleArray2[0] = Cartesian3.clone(previousPos, scaleArray2[0]);
  246. scaleArray2[1] = Cartesian3.clone(position, scaleArray2[1]);
  247. subdividedPositions = PolylinePipeline.generateArc({
  248. positions: scaleArray2,
  249. granularity: granularity,
  250. ellipsoid: ellipsoid
  251. });
  252. calculatedPositions = addShiftedPositions(subdividedPositions, left, width, calculatedPositions);
  253. if (saveAttributes) {
  254. calculatedLefts.push(left.x, left.y, left.z);
  255. calculatedNormals.push(normal.x, normal.y, normal.z);
  256. }
  257. var endPositions;
  258. if (cornerType === CornerType.ROUNDED) {
  259. endPositions = addEndCaps(calculatedPositions);
  260. }
  261. return {
  262. positions : calculatedPositions,
  263. corners : corners,
  264. lefts : calculatedLefts,
  265. normals : calculatedNormals,
  266. endPositions : endPositions
  267. };
  268. };
  269. export default CorridorGeometryLibrary;