@math.gl/geometry 5.0.0-alpha.2 → 5.0.0-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/LICENSE +97 -49
  2. package/README.md +16 -1
  3. package/THIRD-PARTY-NOTICES.md +18 -0
  4. package/dist/culling/constants.d.ts +3 -0
  5. package/dist/culling/constants.d.ts.map +1 -0
  6. package/dist/culling/constants.js +5 -0
  7. package/dist/culling/constants.js.map +1 -0
  8. package/dist/culling/index.cjs +2014 -0
  9. package/dist/culling/index.cjs.map +6 -0
  10. package/dist/culling/index.d.ts +29 -0
  11. package/dist/culling/index.d.ts.map +1 -0
  12. package/dist/culling/index.js +23 -0
  13. package/dist/culling/index.js.map +1 -0
  14. package/dist/culling/lib/algorithms/bounding-box-from-points.d.ts +15 -0
  15. package/dist/culling/lib/algorithms/bounding-box-from-points.d.ts.map +1 -0
  16. package/dist/culling/lib/algorithms/bounding-box-from-points.js +137 -0
  17. package/dist/culling/lib/algorithms/bounding-box-from-points.js.map +1 -0
  18. package/dist/culling/lib/algorithms/bounding-sphere-from-points.d.ts +14 -0
  19. package/dist/culling/lib/algorithms/bounding-sphere-from-points.d.ts.map +1 -0
  20. package/dist/culling/lib/algorithms/bounding-sphere-from-points.js +146 -0
  21. package/dist/culling/lib/algorithms/bounding-sphere-from-points.js.map +1 -0
  22. package/dist/culling/lib/algorithms/compute-eigen-decomposition.d.ts +37 -0
  23. package/dist/culling/lib/algorithms/compute-eigen-decomposition.d.ts.map +1 -0
  24. package/dist/culling/lib/algorithms/compute-eigen-decomposition.js +137 -0
  25. package/dist/culling/lib/algorithms/compute-eigen-decomposition.js.map +1 -0
  26. package/dist/culling/lib/algorithms/oriented-bounding-box-quaternion.d.ts +7 -0
  27. package/dist/culling/lib/algorithms/oriented-bounding-box-quaternion.d.ts.map +1 -0
  28. package/dist/culling/lib/algorithms/oriented-bounding-box-quaternion.js +26 -0
  29. package/dist/culling/lib/algorithms/oriented-bounding-box-quaternion.js.map +1 -0
  30. package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.d.ts +56 -0
  31. package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.d.ts.map +1 -0
  32. package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.js +116 -0
  33. package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.js.map +1 -0
  34. package/dist/culling/lib/bounding-volumes/bounding-sphere.d.ts +40 -0
  35. package/dist/culling/lib/bounding-volumes/bounding-sphere.d.ts.map +1 -0
  36. package/dist/culling/lib/bounding-volumes/bounding-sphere.js +123 -0
  37. package/dist/culling/lib/bounding-volumes/bounding-sphere.js.map +1 -0
  38. package/dist/culling/lib/bounding-volumes/bounding-volume.d.ts +30 -0
  39. package/dist/culling/lib/bounding-volumes/bounding-volume.d.ts.map +1 -0
  40. package/dist/culling/lib/bounding-volumes/bounding-volume.js +7 -0
  41. package/dist/culling/lib/bounding-volumes/bounding-volume.js.map +1 -0
  42. package/dist/culling/lib/bounding-volumes/oriented-bounding-box.d.ts +62 -0
  43. package/dist/culling/lib/bounding-volumes/oriented-bounding-box.d.ts.map +1 -0
  44. package/dist/culling/lib/bounding-volumes/oriented-bounding-box.js +230 -0
  45. package/dist/culling/lib/bounding-volumes/oriented-bounding-box.js.map +1 -0
  46. package/dist/culling/lib/culling-volume.d.ts +46 -0
  47. package/dist/culling/lib/culling-volume.d.ts.map +1 -0
  48. package/dist/culling/lib/culling-volume.js +126 -0
  49. package/dist/culling/lib/culling-volume.js.map +1 -0
  50. package/dist/culling/lib/perspective-frustum.d.ts +153 -0
  51. package/dist/culling/lib/perspective-frustum.d.ts.map +1 -0
  52. package/dist/culling/lib/perspective-frustum.js +191 -0
  53. package/dist/culling/lib/perspective-frustum.js.map +1 -0
  54. package/dist/culling/lib/perspective-off-center-frustum.d.ts +158 -0
  55. package/dist/culling/lib/perspective-off-center-frustum.d.ts.map +1 -0
  56. package/dist/culling/lib/perspective-off-center-frustum.js +276 -0
  57. package/dist/culling/lib/perspective-off-center-frustum.js.map +1 -0
  58. package/dist/culling/lib/plane.d.ts +35 -0
  59. package/dist/culling/lib/plane.d.ts.map +1 -0
  60. package/dist/culling/lib/plane.js +90 -0
  61. package/dist/culling/lib/plane.js.map +1 -0
  62. package/dist/culling/lib/ray.d.ts +13 -0
  63. package/dist/culling/lib/ray.d.ts.map +1 -0
  64. package/dist/culling/lib/ray.js +30 -0
  65. package/dist/culling/lib/ray.js.map +1 -0
  66. package/dist/culling/lib/shapes/box-shape.d.ts +19 -0
  67. package/dist/culling/lib/shapes/box-shape.d.ts.map +1 -0
  68. package/dist/culling/lib/shapes/box-shape.js +69 -0
  69. package/dist/culling/lib/shapes/box-shape.js.map +1 -0
  70. package/dist/culling/lib/shapes/capsule-shape.d.ts +23 -0
  71. package/dist/culling/lib/shapes/capsule-shape.d.ts.map +1 -0
  72. package/dist/culling/lib/shapes/capsule-shape.js +151 -0
  73. package/dist/culling/lib/shapes/capsule-shape.js.map +1 -0
  74. package/dist/culling/lib/shapes/cylinder-shape.d.ts +22 -0
  75. package/dist/culling/lib/shapes/cylinder-shape.d.ts.map +1 -0
  76. package/dist/culling/lib/shapes/cylinder-shape.js +99 -0
  77. package/dist/culling/lib/shapes/cylinder-shape.js.map +1 -0
  78. package/dist/culling/lib/shapes/implicit-shape.d.ts +56 -0
  79. package/dist/culling/lib/shapes/implicit-shape.d.ts.map +1 -0
  80. package/dist/culling/lib/shapes/implicit-shape.js +142 -0
  81. package/dist/culling/lib/shapes/implicit-shape.js.map +1 -0
  82. package/dist/culling/lib/shapes/plane-shape.d.ts +27 -0
  83. package/dist/culling/lib/shapes/plane-shape.d.ts.map +1 -0
  84. package/dist/culling/lib/shapes/plane-shape.js +71 -0
  85. package/dist/culling/lib/shapes/plane-shape.js.map +1 -0
  86. package/dist/culling/lib/shapes/sphere-shape.d.ts +18 -0
  87. package/dist/culling/lib/shapes/sphere-shape.d.ts.map +1 -0
  88. package/dist/culling/lib/shapes/sphere-shape.js +43 -0
  89. package/dist/culling/lib/shapes/sphere-shape.js.map +1 -0
  90. package/dist/culling/oriented-box-2d.cjs +73 -0
  91. package/dist/culling/oriented-box-2d.cjs.map +6 -0
  92. package/dist/culling/oriented-box-2d.d.ts +22 -0
  93. package/dist/culling/oriented-box-2d.d.ts.map +1 -0
  94. package/dist/culling/oriented-box-2d.js +86 -0
  95. package/dist/culling/oriented-box-2d.js.map +1 -0
  96. package/dist/culling/queries.cjs +161 -0
  97. package/dist/culling/queries.cjs.map +6 -0
  98. package/dist/culling/queries.d.ts +20 -0
  99. package/dist/culling/queries.d.ts.map +1 -0
  100. package/dist/culling/queries.js +139 -0
  101. package/dist/culling/queries.js.map +1 -0
  102. package/dist/curves/bezier-curves.d.ts +18 -0
  103. package/dist/curves/bezier-curves.d.ts.map +1 -0
  104. package/dist/curves/bezier-curves.js +54 -0
  105. package/dist/curves/bezier-curves.js.map +1 -0
  106. package/dist/curves/catmull-rom-curve.d.ts +15 -0
  107. package/dist/curves/catmull-rom-curve.d.ts.map +1 -0
  108. package/dist/curves/catmull-rom-curve.js +77 -0
  109. package/dist/curves/catmull-rom-curve.js.map +1 -0
  110. package/dist/curves/curve-arc-length.d.ts +17 -0
  111. package/dist/curves/curve-arc-length.d.ts.map +1 -0
  112. package/dist/curves/curve-arc-length.js +58 -0
  113. package/dist/curves/curve-arc-length.js.map +1 -0
  114. package/dist/curves/curve.d.ts +23 -0
  115. package/dist/curves/curve.d.ts.map +1 -0
  116. package/dist/curves/curve.js +77 -0
  117. package/dist/curves/curve.js.map +1 -0
  118. package/dist/curves/hermite-curve.d.ts +9 -0
  119. package/dist/curves/hermite-curve.d.ts.map +1 -0
  120. package/dist/curves/hermite-curve.js +24 -0
  121. package/dist/curves/hermite-curve.js.map +1 -0
  122. package/dist/curves/index.cjs +293 -0
  123. package/dist/curves/index.cjs.map +6 -0
  124. package/dist/curves/index.d.ts +8 -0
  125. package/dist/curves/index.d.ts.map +1 -0
  126. package/dist/curves/index.js +9 -0
  127. package/dist/curves/index.js.map +1 -0
  128. package/dist/geometries/box-geometry.js +1 -1
  129. package/dist/geometries/box-geometry.js.map +1 -1
  130. package/dist/geometries/capsule-geometry.js +1 -1
  131. package/dist/geometries/capsule-geometry.js.map +1 -1
  132. package/dist/geometries/cylinder-geometry.js +1 -1
  133. package/dist/geometries/cylinder-geometry.js.map +1 -1
  134. package/dist/geometries/geometry-helpers.js +1 -1
  135. package/dist/geometries/geometry-helpers.js.map +1 -1
  136. package/dist/geometries/ico-sphere-geometry.js +1 -1
  137. package/dist/geometries/ico-sphere-geometry.js.map +1 -1
  138. package/dist/geometries/plane-geometry.js +1 -1
  139. package/dist/geometries/plane-geometry.js.map +1 -1
  140. package/dist/geometries/primitive-mesh-builder.d.ts +24 -0
  141. package/dist/geometries/primitive-mesh-builder.d.ts.map +1 -0
  142. package/dist/geometries/primitive-mesh-builder.js +74 -0
  143. package/dist/geometries/primitive-mesh-builder.js.map +1 -0
  144. package/dist/geometries/prism-geometry.d.ts +13 -0
  145. package/dist/geometries/prism-geometry.d.ts.map +1 -0
  146. package/dist/geometries/prism-geometry.js +34 -0
  147. package/dist/geometries/prism-geometry.js.map +1 -0
  148. package/dist/geometries/ring-geometry.d.ts +15 -0
  149. package/dist/geometries/ring-geometry.d.ts.map +1 -0
  150. package/dist/geometries/ring-geometry.js +64 -0
  151. package/dist/geometries/ring-geometry.js.map +1 -0
  152. package/dist/geometries/sphere-geometry.js +1 -1
  153. package/dist/geometries/sphere-geometry.js.map +1 -1
  154. package/dist/geometries/surface-of-revolution.js +1 -1
  155. package/dist/geometries/surface-of-revolution.js.map +1 -1
  156. package/dist/geometries/truncated-cone-geometry.js +1 -1
  157. package/dist/geometries/truncated-cone-geometry.js.map +1 -1
  158. package/dist/index.cjs +290 -9
  159. package/dist/index.cjs.map +3 -3
  160. package/dist/index.d.ts +6 -0
  161. package/dist/index.d.ts.map +1 -1
  162. package/dist/index.js +4 -1
  163. package/dist/index.js.map +1 -1
  164. package/dist/lib/geometry-utils.js +1 -1
  165. package/dist/lib/geometry-utils.js.map +1 -1
  166. package/dist/lib/geometry.d.ts +1 -1
  167. package/dist/lib/geometry.d.ts.map +1 -1
  168. package/dist/lib/geometry.js +1 -1
  169. package/dist/lib/geometry.js.map +1 -1
  170. package/dist/lib/hinge-tree.d.ts +33 -0
  171. package/dist/lib/hinge-tree.d.ts.map +1 -0
  172. package/dist/lib/hinge-tree.js +144 -0
  173. package/dist/lib/hinge-tree.js.map +1 -0
  174. package/dist/parametric/lathe-geometry.d.ts +14 -0
  175. package/dist/parametric/lathe-geometry.d.ts.map +1 -0
  176. package/dist/parametric/lathe-geometry.js +48 -0
  177. package/dist/parametric/lathe-geometry.js.map +1 -0
  178. package/dist/parametric/parametric-geometry.d.ts +20 -0
  179. package/dist/parametric/parametric-geometry.d.ts.map +1 -0
  180. package/dist/parametric/parametric-geometry.js +88 -0
  181. package/dist/parametric/parametric-geometry.js.map +1 -0
  182. package/dist/parametric/torus-geometry.d.ts +19 -0
  183. package/dist/parametric/torus-geometry.d.ts.map +1 -0
  184. package/dist/parametric/torus-geometry.js +89 -0
  185. package/dist/parametric/torus-geometry.js.map +1 -0
  186. package/dist/parametric.cjs +328 -0
  187. package/dist/parametric.cjs.map +6 -0
  188. package/dist/parametric.d.ts +7 -0
  189. package/dist/parametric.d.ts.map +1 -0
  190. package/dist/parametric.js +7 -0
  191. package/dist/parametric.js.map +1 -0
  192. package/dist/polygon/cut-by-grid.d.ts +24 -0
  193. package/dist/polygon/cut-by-grid.d.ts.map +1 -0
  194. package/dist/polygon/cut-by-grid.js +221 -0
  195. package/dist/polygon/cut-by-grid.js.map +1 -0
  196. package/dist/polygon/cut-by-mercator-bounds.d.ts +17 -0
  197. package/dist/polygon/cut-by-mercator-bounds.d.ts.map +1 -0
  198. package/dist/polygon/cut-by-mercator-bounds.js +149 -0
  199. package/dist/polygon/cut-by-mercator-bounds.js.map +1 -0
  200. package/dist/polygon/earcut.d.ts +13 -0
  201. package/dist/polygon/earcut.d.ts.map +1 -0
  202. package/dist/polygon/earcut.js +627 -0
  203. package/dist/polygon/earcut.js.map +1 -0
  204. package/dist/polygon/index.cjs +1437 -0
  205. package/dist/polygon/index.cjs.map +6 -0
  206. package/dist/polygon/index.d.ts +12 -0
  207. package/dist/polygon/index.d.ts.map +1 -0
  208. package/dist/polygon/index.js +12 -0
  209. package/dist/polygon/index.js.map +1 -0
  210. package/dist/polygon/lineclip.d.ts +31 -0
  211. package/dist/polygon/lineclip.d.ts.map +1 -0
  212. package/dist/polygon/lineclip.js +184 -0
  213. package/dist/polygon/lineclip.js.map +1 -0
  214. package/dist/polygon/polygon-utils.d.ts +103 -0
  215. package/dist/polygon/polygon-utils.d.ts.map +1 -0
  216. package/dist/polygon/polygon-utils.js +155 -0
  217. package/dist/polygon/polygon-utils.js.map +1 -0
  218. package/dist/polygon/polygon.d.ts +41 -0
  219. package/dist/polygon/polygon.d.ts.map +1 -0
  220. package/dist/polygon/polygon.js +76 -0
  221. package/dist/polygon/polygon.js.map +1 -0
  222. package/dist/polygon/subdivide-polyline.d.ts +56 -0
  223. package/dist/polygon/subdivide-polyline.d.ts.map +1 -0
  224. package/dist/polygon/subdivide-polyline.js +141 -0
  225. package/dist/polygon/subdivide-polyline.js.map +1 -0
  226. package/dist/polygon/subdivide-triangle-mesh.d.ts +68 -0
  227. package/dist/polygon/subdivide-triangle-mesh.d.ts.map +1 -0
  228. package/dist/polygon/subdivide-triangle-mesh.js +228 -0
  229. package/dist/polygon/subdivide-triangle-mesh.js.map +1 -0
  230. package/dist/polygon/utils.d.ts +5 -0
  231. package/dist/polygon/utils.d.ts.map +1 -0
  232. package/dist/polygon/utils.js +38 -0
  233. package/dist/polygon/utils.js.map +1 -0
  234. package/dist/spatial-index/box-index.cjs +328 -0
  235. package/dist/spatial-index/box-index.cjs.map +6 -0
  236. package/dist/spatial-index/box-index.d.ts +65 -0
  237. package/dist/spatial-index/box-index.d.ts.map +1 -0
  238. package/dist/spatial-index/box-index.js +263 -0
  239. package/dist/spatial-index/box-index.js.map +1 -0
  240. package/dist/spatial-index/index.cjs +494 -0
  241. package/dist/spatial-index/index.cjs.map +6 -0
  242. package/dist/spatial-index/index.d.ts +5 -0
  243. package/dist/spatial-index/index.d.ts.map +1 -0
  244. package/dist/spatial-index/index.js +6 -0
  245. package/dist/spatial-index/index.js.map +1 -0
  246. package/dist/spatial-index/triangle-bvh.d.ts +53 -0
  247. package/dist/spatial-index/triangle-bvh.d.ts.map +1 -0
  248. package/dist/spatial-index/triangle-bvh.js +102 -0
  249. package/dist/spatial-index/triangle-bvh.js.map +1 -0
  250. package/dist/utils/attribute-compression.d.ts +50 -0
  251. package/dist/utils/attribute-compression.d.ts.map +1 -0
  252. package/dist/utils/attribute-compression.js +186 -0
  253. package/dist/utils/attribute-compression.js.map +1 -0
  254. package/dist/utils/attribute-iterator.d.ts +8 -0
  255. package/dist/utils/attribute-iterator.d.ts.map +1 -0
  256. package/dist/utils/attribute-iterator.js +25 -0
  257. package/dist/utils/attribute-iterator.js.map +1 -0
  258. package/dist/utils/compute-vertex-normals.d.ts +4 -0
  259. package/dist/utils/compute-vertex-normals.d.ts.map +1 -0
  260. package/dist/utils/compute-vertex-normals.js +54 -0
  261. package/dist/utils/compute-vertex-normals.js.map +1 -0
  262. package/dist/utils/constants.d.ts +52 -0
  263. package/dist/utils/constants.d.ts.map +1 -0
  264. package/dist/utils/constants.js +39 -0
  265. package/dist/utils/constants.js.map +1 -0
  266. package/dist/utils/coordinates.d.ts +3 -0
  267. package/dist/utils/coordinates.d.ts.map +1 -0
  268. package/dist/utils/coordinates.js +8 -0
  269. package/dist/utils/coordinates.js.map +1 -0
  270. package/dist/utils/geometry.d.ts +20 -0
  271. package/dist/utils/geometry.d.ts.map +1 -0
  272. package/dist/utils/geometry.js +31 -0
  273. package/dist/utils/geometry.js.map +1 -0
  274. package/dist/utils/gl-type.d.ts +17 -0
  275. package/dist/utils/gl-type.d.ts.map +1 -0
  276. package/dist/utils/gl-type.js +69 -0
  277. package/dist/utils/gl-type.js.map +1 -0
  278. package/dist/utils/index.cjs +965 -0
  279. package/dist/utils/index.cjs.map +6 -0
  280. package/dist/utils/index.d.ts +18 -0
  281. package/dist/utils/index.d.ts.map +1 -0
  282. package/dist/utils/index.js +16 -0
  283. package/dist/utils/index.js.map +1 -0
  284. package/dist/utils/interpolate-packed-attributes.cjs +176 -0
  285. package/dist/utils/interpolate-packed-attributes.cjs.map +6 -0
  286. package/dist/utils/interpolate-packed-attributes.d.ts +43 -0
  287. package/dist/utils/interpolate-packed-attributes.d.ts.map +1 -0
  288. package/dist/utils/interpolate-packed-attributes.js +192 -0
  289. package/dist/utils/interpolate-packed-attributes.js.map +1 -0
  290. package/dist/utils/mesh-processing.d.ts +18 -0
  291. package/dist/utils/mesh-processing.d.ts.map +1 -0
  292. package/dist/utils/mesh-processing.js +300 -0
  293. package/dist/utils/mesh-processing.js.map +1 -0
  294. package/dist/utils/primitive-iterator.d.ts +21 -0
  295. package/dist/utils/primitive-iterator.d.ts.map +1 -0
  296. package/dist/utils/primitive-iterator.js +117 -0
  297. package/dist/utils/primitive-iterator.js.map +1 -0
  298. package/dist/utils/rgb565.d.ts +5 -0
  299. package/dist/utils/rgb565.d.ts.map +1 -0
  300. package/dist/utils/rgb565.js +24 -0
  301. package/dist/utils/rgb565.js.map +1 -0
  302. package/dist/utils/typed-array-utils.d.ts +3 -0
  303. package/dist/utils/typed-array-utils.d.ts.map +1 -0
  304. package/dist/utils/typed-array-utils.js +16 -0
  305. package/dist/utils/typed-array-utils.js.map +1 -0
  306. package/package.json +57 -4
  307. package/src/culling/constants.ts +6 -0
  308. package/src/culling/index.ts +45 -0
  309. package/src/culling/lib/algorithms/bounding-box-from-points.ts +174 -0
  310. package/src/culling/lib/algorithms/bounding-sphere-from-points.ts +175 -0
  311. package/src/culling/lib/algorithms/compute-eigen-decomposition.ts +171 -0
  312. package/src/culling/lib/algorithms/oriented-bounding-box-quaternion.ts +32 -0
  313. package/src/culling/lib/bounding-volumes/axis-aligned-bounding-box.ts +153 -0
  314. package/src/culling/lib/bounding-volumes/bounding-sphere.ts +154 -0
  315. package/src/culling/lib/bounding-volumes/bounding-volume.ts +38 -0
  316. package/src/culling/lib/bounding-volumes/oriented-bounding-box.ts +320 -0
  317. package/src/culling/lib/culling-volume.ts +163 -0
  318. package/src/culling/lib/perspective-frustum.ts +288 -0
  319. package/src/culling/lib/perspective-off-center-frustum.ts +381 -0
  320. package/src/culling/lib/plane.ts +118 -0
  321. package/src/culling/lib/ray.ts +33 -0
  322. package/src/culling/lib/shapes/box-shape.ts +78 -0
  323. package/src/culling/lib/shapes/capsule-shape.ts +232 -0
  324. package/src/culling/lib/shapes/cylinder-shape.ts +133 -0
  325. package/src/culling/lib/shapes/implicit-shape.ts +209 -0
  326. package/src/culling/lib/shapes/plane-shape.ts +78 -0
  327. package/src/culling/lib/shapes/sphere-shape.ts +60 -0
  328. package/src/culling/oriented-box-2d.ts +165 -0
  329. package/src/culling/queries.ts +155 -0
  330. package/src/curves/bezier-curves.ts +62 -0
  331. package/src/curves/catmull-rom-curve.ts +89 -0
  332. package/src/curves/curve-arc-length.ts +70 -0
  333. package/src/curves/curve.ts +96 -0
  334. package/src/curves/hermite-curve.ts +34 -0
  335. package/src/curves/index.ts +15 -0
  336. package/src/geometries/box-geometry.ts +1 -1
  337. package/src/geometries/capsule-geometry.ts +1 -1
  338. package/src/geometries/cylinder-geometry.ts +1 -1
  339. package/src/geometries/geometry-helpers.ts +1 -1
  340. package/src/geometries/ico-sphere-geometry.ts +1 -1
  341. package/src/geometries/plane-geometry.ts +1 -1
  342. package/src/geometries/primitive-mesh-builder.ts +84 -0
  343. package/src/geometries/prism-geometry.ts +57 -0
  344. package/src/geometries/ring-geometry.ts +102 -0
  345. package/src/geometries/sphere-geometry.ts +1 -1
  346. package/src/geometries/surface-of-revolution.ts +1 -1
  347. package/src/geometries/truncated-cone-geometry.ts +1 -1
  348. package/src/index.ts +10 -1
  349. package/src/lib/geometry-utils.ts +2 -2
  350. package/src/lib/geometry.ts +2 -2
  351. package/src/lib/hinge-tree.ts +170 -0
  352. package/src/parametric/lathe-geometry.ts +70 -0
  353. package/src/parametric/parametric-geometry.ts +118 -0
  354. package/src/parametric/torus-geometry.ts +118 -0
  355. package/src/parametric.ts +9 -0
  356. package/src/polygon/cut-by-grid.ts +313 -0
  357. package/src/polygon/cut-by-mercator-bounds.ts +204 -0
  358. package/src/polygon/earcut.ts +798 -0
  359. package/src/polygon/index.ts +35 -0
  360. package/src/polygon/lineclip.ts +218 -0
  361. package/src/polygon/polygon-utils.ts +273 -0
  362. package/src/polygon/polygon.ts +105 -0
  363. package/src/polygon/subdivide-polyline.ts +223 -0
  364. package/src/polygon/subdivide-triangle-mesh.ts +322 -0
  365. package/src/polygon/utils.ts +50 -0
  366. package/src/spatial-index/box-index.ts +343 -0
  367. package/src/spatial-index/index.ts +18 -0
  368. package/src/spatial-index/triangle-bvh.ts +162 -0
  369. package/src/utils/attribute-compression.ts +234 -0
  370. package/src/utils/attribute-iterator.ts +28 -0
  371. package/src/utils/compute-vertex-normals.ts +63 -0
  372. package/src/utils/constants.ts +42 -0
  373. package/src/utils/coordinates.ts +8 -0
  374. package/src/utils/geometry.ts +49 -0
  375. package/src/utils/gl-type.ts +87 -0
  376. package/src/utils/index.ts +55 -0
  377. package/src/utils/interpolate-packed-attributes.ts +284 -0
  378. package/src/utils/mesh-processing.ts +377 -0
  379. package/src/utils/primitive-iterator.ts +145 -0
  380. package/src/utils/rgb565.ts +26 -0
  381. package/src/utils/typed-array-utils.ts +16 -0
@@ -0,0 +1,284 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+
5
+ /** Scalar storage formats supported by packed attribute interpolation. */
6
+ export type PackedAttributeType =
7
+ | 'int8'
8
+ | 'uint8'
9
+ | 'int16'
10
+ | 'uint16'
11
+ | 'int32'
12
+ | 'uint32'
13
+ | 'float32'
14
+ | 'float64';
15
+
16
+ /** Interpolate numeric values, or require identical values at every contributing vertex. */
17
+ export type PackedAttributeInterpolation = 'linear' | 'flat';
18
+
19
+ /** One explicitly described attribute inside an interleaved vertex record. */
20
+ export type PackedAttribute = {
21
+ /** Scalar storage format; values are interpolated in the encoded domain. */
22
+ type: PackedAttributeType;
23
+ /** Number of scalar components. */
24
+ size: number;
25
+ /** Byte offset within each record; unaligned offsets are supported. */
26
+ byteOffset: number;
27
+ /** Policy for the whole attribute, or one explicit policy per component. */
28
+ interpolation: PackedAttributeInterpolation | readonly PackedAttributeInterpolation[];
29
+ };
30
+
31
+ /** Three original source indices and corresponding weights per output vertex. */
32
+ export type AttributeInterpolationProvenance = {
33
+ /** Indices into the original source records, matching polygon subdivision provenance. */
34
+ sourceVertexIndices: ArrayLike<number>;
35
+ /** Nonnegative finite weights summing to one per triplet; zero-weight indices are ignored. */
36
+ sourceVertexWeights: ArrayLike<number>;
37
+ };
38
+
39
+ /** Byte layout, interpolation policies and output allocation limit. */
40
+ export type PackedAttributeInterpolationOptions = {
41
+ /** Positive byte length of a source and output vertex record. */
42
+ byteStride: number;
43
+ /** Nonoverlapping attribute ranges. Unlisted bytes are copied from the first contributor. */
44
+ attributes: readonly PackedAttribute[];
45
+ /** Byte order for multibyte components. Default true. */
46
+ littleEndian?: boolean;
47
+ /** Maximum allocated output byte length. Default 64 MiB; zero permits empty output only. */
48
+ maxOutputBytes?: number;
49
+ };
50
+
51
+ const BYTE_SIZES: Record<PackedAttributeType, number> = {
52
+ int8: 1,
53
+ uint8: 1,
54
+ int16: 2,
55
+ uint16: 2,
56
+ int32: 4,
57
+ uint32: 4,
58
+ float32: 4,
59
+ float64: 8
60
+ };
61
+
62
+ /** Reconstruct interleaved attributes from subdivision's original-vertex provenance.
63
+ * Inputs are never modified. Linear integer components use Math.round once at final output;
64
+ * this is deliberately not repeated midpoint quantization. Flat components reject differing
65
+ * contributing values instead of guessing categorical semantics. Padding and unlisted bytes
66
+ * come from the first positive-weight contributor. Normals are not renormalized, and normalized
67
+ * GPU formats are not decoded. Duplicate source records at attribute seams before subdivision.
68
+ * @throws RangeError For invalid layout, provenance, nonfinite values or allocation limits.
69
+ */
70
+ export function interpolatePackedAttributes(
71
+ source: Uint8Array,
72
+ provenance: AttributeInterpolationProvenance,
73
+ options: PackedAttributeInterpolationOptions
74
+ ): Uint8Array {
75
+ const {byteStride, attributes, littleEndian = true, maxOutputBytes = 64 * 1024 * 1024} = options;
76
+ const {sourceVertexIndices, sourceVertexWeights} = provenance;
77
+ if (
78
+ !Number.isSafeInteger(byteStride) ||
79
+ byteStride <= 0 ||
80
+ source.byteLength % byteStride ||
81
+ !Array.isArray(options.attributes) ||
82
+ typeof littleEndian !== 'boolean' ||
83
+ !Number.isSafeInteger(maxOutputBytes) ||
84
+ maxOutputBytes < 0 ||
85
+ !Number.isSafeInteger(sourceVertexIndices.length) ||
86
+ sourceVertexIndices.length < 0 ||
87
+ sourceVertexIndices.length % 3 ||
88
+ sourceVertexIndices.length !== sourceVertexWeights.length
89
+ ) {
90
+ throw new RangeError('Invalid packed attribute layout or provenance lengths');
91
+ }
92
+ const outputCount = sourceVertexIndices.length / 3;
93
+ const outputBytes = outputCount * byteStride;
94
+ if (!Number.isSafeInteger(outputBytes) || outputBytes > maxOutputBytes) {
95
+ throw new RangeError('Packed attribute interpolation exceeded maxOutputBytes');
96
+ }
97
+ const ranges: [number, number][] = [];
98
+ for (const attribute of attributes) {
99
+ if (
100
+ !attribute ||
101
+ typeof attribute !== 'object' ||
102
+ !Object.prototype.hasOwnProperty.call(BYTE_SIZES, attribute.type) ||
103
+ !Number.isSafeInteger(attribute.size) ||
104
+ attribute.size <= 0 ||
105
+ !Number.isSafeInteger(attribute.byteOffset) ||
106
+ attribute.byteOffset < 0
107
+ ) {
108
+ throw new RangeError('Invalid packed attribute descriptor');
109
+ }
110
+ const end = attribute.byteOffset + attribute.size * BYTE_SIZES[attribute.type];
111
+ if (
112
+ !Number.isSafeInteger(end) ||
113
+ end > byteStride ||
114
+ ranges.some(([start, previousEnd]) => attribute.byteOffset < previousEnd && end > start)
115
+ ) {
116
+ throw new RangeError('Packed attribute ranges must fit the stride and not overlap');
117
+ }
118
+ ranges.push([attribute.byteOffset, end]);
119
+ if (typeof attribute.interpolation === 'string') {
120
+ validateInterpolation(attribute.interpolation);
121
+ } else {
122
+ if (
123
+ !Array.isArray(attribute.interpolation) ||
124
+ attribute.interpolation.length !== attribute.size
125
+ ) {
126
+ throw new RangeError('Expected one interpolation policy per component');
127
+ }
128
+ for (let component = 0; component < attribute.size; component++) {
129
+ validateInterpolation(attribute.interpolation[component]);
130
+ }
131
+ }
132
+ }
133
+ const sourceCount = source.byteLength / byteStride;
134
+ const input = new DataView(source.buffer, source.byteOffset, source.byteLength);
135
+ const output = new Uint8Array(outputBytes);
136
+ const result = new DataView(output.buffer);
137
+ for (let vertex = 0; vertex < outputCount; vertex++) {
138
+ let sum = 0;
139
+ let firstSource = -1;
140
+ let contributors = 0;
141
+ for (let slot = 0; slot < 3; slot++) {
142
+ const weight = sourceVertexWeights[vertex * 3 + slot];
143
+ const index = sourceVertexIndices[vertex * 3 + slot];
144
+ if (
145
+ !Number.isFinite(weight) ||
146
+ weight < 0 ||
147
+ weight > 1 ||
148
+ (weight > 0 && (!Number.isSafeInteger(index) || index < 0 || index >= sourceCount))
149
+ ) {
150
+ throw new RangeError('Invalid contributing source index or interpolation weight');
151
+ }
152
+ if (weight > 0) {
153
+ contributors++;
154
+ if (firstSource < 0) firstSource = index;
155
+ }
156
+ sum += weight;
157
+ }
158
+ if (firstSource < 0 || Math.abs(sum - 1) > 1e-10) {
159
+ throw new RangeError('Interpolation weights must sum to one');
160
+ }
161
+ output.set(
162
+ source.subarray(firstSource * byteStride, (firstSource + 1) * byteStride),
163
+ vertex * byteStride
164
+ );
165
+ for (const attribute of attributes) {
166
+ for (let component = 0; component < attribute.size; component++) {
167
+ const offset = attribute.byteOffset + component * BYTE_SIZES[attribute.type];
168
+ const policy =
169
+ typeof attribute.interpolation === 'string'
170
+ ? attribute.interpolation
171
+ : attribute.interpolation[component];
172
+ const firstValue = readComponent(
173
+ input,
174
+ firstSource * byteStride + offset,
175
+ attribute.type,
176
+ littleEndian
177
+ );
178
+ let value = 0;
179
+ for (let slot = 0; slot < 3; slot++) {
180
+ const weight = sourceVertexWeights[vertex * 3 + slot];
181
+ if (weight === 0) continue;
182
+ const sourceValue = readComponent(
183
+ input,
184
+ sourceVertexIndices[vertex * 3 + slot] * byteStride + offset,
185
+ attribute.type,
186
+ littleEndian
187
+ );
188
+ if (!Number.isFinite(sourceValue))
189
+ throw new RangeError('Packed attributes must be finite');
190
+ if (policy === 'flat' && sourceValue !== firstValue) {
191
+ throw new RangeError('Flat attribute contributors must agree');
192
+ }
193
+ value += sourceValue * weight;
194
+ }
195
+ if (policy === 'linear') {
196
+ if (!Number.isFinite(value))
197
+ throw new RangeError('Interpolated attributes must be finite');
198
+ // Identity provenance preserves every original encoded bit, including signed zero.
199
+ if (contributors !== 1 || sum !== 1) {
200
+ writeComponent(
201
+ result,
202
+ vertex * byteStride + offset,
203
+ attribute.type,
204
+ value,
205
+ littleEndian
206
+ );
207
+ }
208
+ }
209
+ }
210
+ }
211
+ }
212
+ return output;
213
+ }
214
+
215
+ /** Reject implicit or unknown interpolation semantics. */
216
+ function validateInterpolation(interpolation: unknown): void {
217
+ if (interpolation !== 'linear' && interpolation !== 'flat') {
218
+ throw new RangeError('Expected linear or flat interpolation');
219
+ }
220
+ }
221
+
222
+ /** Read an encoded scalar relative to the source view, including its byte offset. */
223
+ function readComponent(
224
+ view: DataView,
225
+ offset: number,
226
+ type: PackedAttributeType,
227
+ littleEndian: boolean
228
+ ): number {
229
+ switch (type) {
230
+ case 'int8':
231
+ return view.getInt8(offset);
232
+ case 'uint8':
233
+ return view.getUint8(offset);
234
+ case 'int16':
235
+ return view.getInt16(offset, littleEndian);
236
+ case 'uint16':
237
+ return view.getUint16(offset, littleEndian);
238
+ case 'int32':
239
+ return view.getInt32(offset, littleEndian);
240
+ case 'uint32':
241
+ return view.getUint32(offset, littleEndian);
242
+ case 'float32':
243
+ return view.getFloat32(offset, littleEndian);
244
+ case 'float64':
245
+ return view.getFloat64(offset, littleEndian);
246
+ }
247
+ }
248
+
249
+ /** Write one final interpolated scalar, rounding integer encodings consistently. */
250
+ function writeComponent(
251
+ view: DataView,
252
+ offset: number,
253
+ type: PackedAttributeType,
254
+ value: number,
255
+ littleEndian: boolean
256
+ ): void {
257
+ const integer = Math.round(value);
258
+ switch (type) {
259
+ case 'int8':
260
+ view.setInt8(offset, integer);
261
+ break;
262
+ case 'uint8':
263
+ view.setUint8(offset, integer);
264
+ break;
265
+ case 'int16':
266
+ view.setInt16(offset, integer, littleEndian);
267
+ break;
268
+ case 'uint16':
269
+ view.setUint16(offset, integer, littleEndian);
270
+ break;
271
+ case 'int32':
272
+ view.setInt32(offset, integer, littleEndian);
273
+ break;
274
+ case 'uint32':
275
+ view.setUint32(offset, integer, littleEndian);
276
+ break;
277
+ case 'float32':
278
+ view.setFloat32(offset, value, littleEndian);
279
+ break;
280
+ case 'float64':
281
+ view.setFloat64(offset, value, littleEndian);
282
+ break;
283
+ }
284
+ }
@@ -0,0 +1,377 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+
5
+ import {Matrix4} from '@math.gl/core';
6
+ import type {TypedArray, TypedArrayConstructor} from '@math.gl/core/types';
7
+ import {GL} from './constants';
8
+ import {getAttributeValues, type Geometry, type GeometryAttribute} from './geometry';
9
+
10
+ type MeshData = {
11
+ attributes: Record<string, {value: TypedArray; size: number}>;
12
+ position: string;
13
+ count: number;
14
+ indices: Uint32Array;
15
+ };
16
+
17
+ /** Fresh, indexed triangle-list geometry. No input buffers are changed. */
18
+ export function transformGeometry(
19
+ geometry: Geometry,
20
+ matrix: Readonly<ArrayLike<number>>
21
+ ): Geometry {
22
+ const mesh = readMesh(geometry);
23
+ if (
24
+ matrix.length !== 16 ||
25
+ Array.from(matrix).some(v => !Number.isFinite(v)) ||
26
+ matrix[3] !== 0 ||
27
+ matrix[7] !== 0 ||
28
+ matrix[11] !== 0 ||
29
+ matrix[15] !== 1
30
+ ) {
31
+ throw new RangeError('Transform must be a finite affine column-major matrix');
32
+ }
33
+ const transform = new Matrix4(Array.from(matrix));
34
+ // Factor out independent column scales before testing orientation/invertibility.
35
+ // A raw determinant can underflow or overflow for finite invertible matrices.
36
+ const columns = [0, 4, 8].map(offset => Array.from(matrix).slice(offset, offset + 3));
37
+ const scales = columns.map(column => Math.max(...column.map(Math.abs)));
38
+ const basis = columns.map((column, i) => column.map(v => (scales[i] ? v / scales[i] : 0)));
39
+ const cofactors = [
40
+ cross(basis[1], basis[2]),
41
+ cross(basis[2], basis[0]),
42
+ cross(basis[0], basis[1])
43
+ ];
44
+ const determinant = basis[0].reduce((sum, v, i) => sum + v * cofactors[0][i], 0);
45
+ const attributes = copyAttributes(mesh.attributes);
46
+ const normalName = attributes['NORMAL'] ? 'NORMAL' : attributes['normals'] ? 'normals' : null;
47
+ const tangentName = attributes['TANGENT'] ? 'TANGENT' : null;
48
+ if ((normalName || tangentName) && (!Number.isFinite(determinant) || determinant === 0))
49
+ throw new RangeError('Normals and tangents require an invertible transform');
50
+ const positions = new Float64Array(mesh.count * 3);
51
+ const source = mesh.attributes[mesh.position].value;
52
+ for (let i = 0; i < mesh.count; i++) {
53
+ const point = transform.transformAsPoint([source[i * 3], source[i * 3 + 1], source[i * 3 + 2]]);
54
+ positions.set(point, i * 3);
55
+ }
56
+ attributes[mesh.position] = {size: 3, value: positions};
57
+ if (normalName) {
58
+ const input = mesh.attributes[normalName];
59
+ if (input.size !== 3) throw new RangeError('Normals must have size 3');
60
+ const output = new Float64Array(mesh.count * 3);
61
+ for (let i = 0; i < mesh.count; i++) {
62
+ const value = normalizedLinearCombination(
63
+ cofactors,
64
+ Array.from(input.value.slice(i * 3, i * 3 + 3)),
65
+ scales.map(v => -Math.log(v))
66
+ );
67
+ output.set(
68
+ value.map(v => (determinant < 0 ? -v : v)),
69
+ i * 3
70
+ );
71
+ }
72
+ attributes[normalName] = {size: 3, value: output};
73
+ }
74
+ if (tangentName) {
75
+ const input = mesh.attributes[tangentName];
76
+ if (input.size !== 4) throw new RangeError('Tangents must have size 4');
77
+ const output = new Float64Array(mesh.count * 4);
78
+ for (let i = 0; i < mesh.count; i++) {
79
+ const value = normalizedLinearCombination(
80
+ basis,
81
+ Array.from(input.value.slice(i * 4, i * 4 + 3)),
82
+ scales.map(Math.log)
83
+ );
84
+ if (normalName) {
85
+ const n = attributes[normalName].value.slice(i * 3, i * 3 + 3);
86
+ const projection = value[0] * n[0] + value[1] * n[1] + value[2] * n[2];
87
+ for (let axis = 0; axis < 3; axis++) value[axis] -= projection * n[axis];
88
+ }
89
+ const length = Math.hypot(...value);
90
+ output.set(
91
+ value.map(v => (length ? v / length : 0)),
92
+ i * 4
93
+ );
94
+ output[i * 4 + 3] = input.value[i * 4 + 3] * (determinant < 0 ? -1 : 1);
95
+ }
96
+ attributes[tangentName] = {size: 4, value: output};
97
+ }
98
+ const indices = mesh.indices.slice();
99
+ if (determinant < 0)
100
+ for (let i = 0; i < indices.length; i += 3)
101
+ [indices[i + 1], indices[i + 2]] = [indices[i + 2], indices[i + 1]];
102
+ return {mode: GL.TRIANGLES, attributes, indices};
103
+ }
104
+
105
+ /** Concatenates compatible triangle meshes and offsets vertex indices. */
106
+ export function mergeGeometries(geometries: readonly Geometry[]): Geometry {
107
+ if (!geometries.length) throw new RangeError('At least one geometry is required');
108
+ const meshes = geometries.map(readMesh),
109
+ first = meshes[0],
110
+ names = Object.keys(first.attributes).sort();
111
+ let count = 0,
112
+ indexCount = 0;
113
+ for (const mesh of meshes) {
114
+ if (
115
+ mesh.position !== first.position ||
116
+ Object.keys(mesh.attributes).length !== names.length ||
117
+ names.some(name => !Object.prototype.hasOwnProperty.call(mesh.attributes, name))
118
+ )
119
+ throw new RangeError('Attribute names must match');
120
+ for (const name of names) {
121
+ if (
122
+ mesh.attributes[name].size !== first.attributes[name].size ||
123
+ mesh.attributes[name].value.constructor !== first.attributes[name].value.constructor
124
+ ) {
125
+ throw new RangeError('Attribute sizes and storage types must match');
126
+ }
127
+ }
128
+ count += mesh.count;
129
+ indexCount += mesh.indices.length;
130
+ }
131
+ if (count > 0xffffffff) throw new RangeError('Geometry exceeds 32-bit indexing');
132
+ const attributes: Record<string, GeometryAttribute> = {};
133
+ for (const name of names) {
134
+ const attribute = first.attributes[name],
135
+ Constructor = attribute.value.constructor as TypedArrayConstructor;
136
+ const value = new Constructor(count * attribute.size);
137
+ let offset = 0;
138
+ for (const mesh of meshes) {
139
+ value.set(mesh.attributes[name].value, offset);
140
+ offset += mesh.attributes[name].value.length;
141
+ }
142
+ attributes[name] = {size: attribute.size, value};
143
+ }
144
+ const indices = new Uint32Array(indexCount);
145
+ let vertexOffset = 0,
146
+ indexOffset = 0;
147
+ for (const mesh of meshes) {
148
+ for (const index of mesh.indices) indices[indexOffset++] = index + vertexOffset;
149
+ vertexOffset += mesh.count;
150
+ }
151
+ return {mode: GL.TRIANGLES, attributes, indices};
152
+ }
153
+
154
+ export type WeldGeometryOptions = {
155
+ /** Position quantization step; zero means exact matching. */ positionGridSize?: number;
156
+ };
157
+ export type WeldGeometryResult = {
158
+ geometry: Geometry;
159
+ vertexMap: Uint32Array;
160
+ removedVertices: number;
161
+ };
162
+
163
+ /** Welds full attribute tuples, preserving UV seams and hard normal edges. */
164
+ export function weldGeometry(
165
+ geometry: Geometry,
166
+ options: WeldGeometryOptions = {}
167
+ ): WeldGeometryResult {
168
+ const mesh = readMesh(geometry),
169
+ grid = options.positionGridSize ?? 0;
170
+ if (!Number.isFinite(grid) || grid < 0)
171
+ throw new RangeError('positionGridSize must be finite and nonnegative');
172
+ const names = Object.keys(mesh.attributes).sort(),
173
+ keys = new Map<string, number>(),
174
+ rows: number[] = [],
175
+ vertexMap = new Uint32Array(mesh.count);
176
+ for (let i = 0; i < mesh.count; i++) {
177
+ const tuple: number[] = [];
178
+ for (const name of names) {
179
+ const attribute = mesh.attributes[name];
180
+ for (let component = 0; component < attribute.size; component++) {
181
+ const value = attribute.value[i * attribute.size + component];
182
+ const quantized = name === mesh.position && grid ? Math.round(value / grid) : value;
183
+ if (!Number.isFinite(quantized)) throw new RangeError('Position quantization overflow');
184
+ tuple.push(quantized);
185
+ }
186
+ }
187
+ const key = tuple.join(',');
188
+ let row = keys.get(key);
189
+ if (row === undefined) {
190
+ row = rows.length;
191
+ keys.set(key, row);
192
+ rows.push(i);
193
+ }
194
+ vertexMap[i] = row;
195
+ }
196
+ const attributes: Record<string, GeometryAttribute> = {};
197
+ for (const name of names) {
198
+ const attribute = mesh.attributes[name],
199
+ Constructor = attribute.value.constructor as TypedArrayConstructor;
200
+ const value = new Constructor(rows.length * attribute.size);
201
+ rows.forEach((row, i) =>
202
+ value.set(
203
+ attribute.value.subarray(row * attribute.size, (row + 1) * attribute.size),
204
+ i * attribute.size
205
+ )
206
+ );
207
+ attributes[name] = {size: attribute.size, value};
208
+ }
209
+ return {
210
+ geometry: {
211
+ mode: GL.TRIANGLES,
212
+ attributes,
213
+ indices: Uint32Array.from(mesh.indices, index => vertexMap[index])
214
+ },
215
+ vertexMap,
216
+ removedVertices: mesh.count - rows.length
217
+ };
218
+ }
219
+
220
+ /** Returns triangle numbers with area <= areaEpsilon, in original draw order. */
221
+ export function getDegenerateTriangles(geometry: Geometry, areaEpsilon = 0): Uint32Array {
222
+ if (!Number.isFinite(areaEpsilon) || areaEpsilon < 0)
223
+ throw new RangeError('Area epsilon must be finite and nonnegative');
224
+ const mesh = readMesh(geometry),
225
+ positions = mesh.attributes[mesh.position].value,
226
+ result: number[] = [];
227
+ for (let i = 0; i < mesh.indices.length; i += 3) {
228
+ const [a, b, c] = Array.from(mesh.indices.subarray(i, i + 3), index => index * 3);
229
+ const ab = [
230
+ positions[b] - positions[a],
231
+ positions[b + 1] - positions[a + 1],
232
+ positions[b + 2] - positions[a + 2]
233
+ ];
234
+ const ac = [
235
+ positions[c] - positions[a],
236
+ positions[c + 1] - positions[a + 1],
237
+ positions[c + 2] - positions[a + 2]
238
+ ];
239
+ // Keep the common path in floating point, but use exact dyadic arithmetic
240
+ // when normalization loses a component or cannot distinguish collinearity.
241
+ const scaleAB = Math.max(...ab.map(Math.abs));
242
+ const scaleAC = Math.max(...ac.map(Math.abs));
243
+ const normalizedAB = ab.map(v => (scaleAB ? v / scaleAB : 0));
244
+ const normalizedAC = ac.map(v => (scaleAC ? v / scaleAC : 0));
245
+ const crossLength = Math.hypot(...cross(normalizedAB, normalizedAC));
246
+ const lostComponent = [ab, ac].some((edge, i) =>
247
+ edge.some((v, axis) => v !== 0 && (i ? normalizedAC : normalizedAB)[axis] === 0)
248
+ );
249
+ if (!Number.isFinite(crossLength) || crossLength === 0 || lostComponent) {
250
+ if (exactAreaAtMost(positions, a, b, c, areaEpsilon)) result.push(i / 3);
251
+ } else {
252
+ const logArea = Math.log(crossLength) + Math.log(scaleAB) + Math.log(scaleAC) - Math.log(2);
253
+ if (areaEpsilon > 0 && logArea <= Math.log(areaEpsilon)) result.push(i / 3);
254
+ }
255
+ }
256
+ return Uint32Array.from(result);
257
+ }
258
+
259
+ function readMesh(geometry: Geometry): MeshData {
260
+ if (geometry.mode !== GL.TRIANGLES)
261
+ throw new RangeError('Packed triangle-list geometry is required');
262
+ const position = geometry.attributes['POSITION']
263
+ ? 'POSITION'
264
+ : geometry.attributes['positions']
265
+ ? 'positions'
266
+ : null;
267
+ if (!position) throw new RangeError('POSITION or positions is required');
268
+ const attributes: MeshData['attributes'] = {};
269
+ let count: number;
270
+ for (const [name, attribute] of Object.entries(geometry.attributes)) {
271
+ const value = getAttributeValues(attribute),
272
+ size = attribute.size ?? (name === position ? 3 : undefined);
273
+ if (!Number.isSafeInteger(size) || size < 1 || value.length % size)
274
+ throw new RangeError('Attributes need explicit packed sizes');
275
+ const length = value.length / size;
276
+ if (name === position) {
277
+ if (size !== 3) throw new RangeError('Positions must have size 3');
278
+ count = length;
279
+ }
280
+ for (const component of value)
281
+ if (!Number.isFinite(component)) throw new RangeError('Attributes must be finite');
282
+ attributes[name] = {value, size};
283
+ }
284
+ for (const attribute of Object.values(attributes))
285
+ if (attribute.value.length / attribute.size !== count)
286
+ throw new RangeError('Attribute vertex counts must match');
287
+ if (count > 0xffffffff) throw new RangeError('Geometry exceeds 32-bit indexing');
288
+ const input = geometry.indices
289
+ ? getAttributeValues(geometry.indices)
290
+ : Uint32Array.from({length: count}, (_, i) => i);
291
+ if (input.length % 3) throw new RangeError('Indices must form triangles');
292
+ for (const index of input)
293
+ if (!Number.isSafeInteger(index) || index < 0 || index >= count)
294
+ throw new RangeError('Vertex index is out of bounds');
295
+ return {attributes, position, count, indices: Uint32Array.from(input)};
296
+ }
297
+ function copyAttributes(attributes: MeshData['attributes']): Record<string, GeometryAttribute> {
298
+ return Object.fromEntries(
299
+ Object.entries(attributes).map(([name, attribute]) => [
300
+ name,
301
+ {size: attribute.size, value: attribute.value.slice()}
302
+ ])
303
+ );
304
+ }
305
+
306
+ function cross(a: number[], b: number[]): number[] {
307
+ return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
308
+ }
309
+
310
+ /** Direction-only multiplication, avoiding overflow in scale-weighted components. */
311
+ function normalizedLinearCombination(
312
+ columns: number[][],
313
+ vector: number[],
314
+ logScales: number[]
315
+ ): number[] {
316
+ const logs = vector.map((v, i) => (v ? Math.log(Math.abs(v)) + logScales[i] : -Infinity));
317
+ const largest = Math.max(...logs);
318
+ if (largest === -Infinity) return [0, 0, 0];
319
+ const weights = logs.map((v, i) => Math.sign(vector[i]) * Math.exp(v - largest));
320
+ const result = [0, 1, 2].map(axis =>
321
+ columns.reduce((sum, column, i) => sum + column[axis] * weights[i], 0)
322
+ );
323
+ const length = Math.hypot(...result);
324
+ return result.map(v => (length ? v / length : 0));
325
+ }
326
+
327
+ // Every finite binary64 value is an integer times a power of two. The fallback
328
+ // compares squared cross lengths to 4*epsilon² without floating-point products.
329
+ type Dyadic = {n: bigint; exponent: number};
330
+ function exactAreaAtMost(
331
+ positions: TypedArray,
332
+ a: number,
333
+ b: number,
334
+ c: number,
335
+ epsilon: number
336
+ ): boolean {
337
+ const edge = (end: number) =>
338
+ [0, 1, 2].map(axis =>
339
+ subtractDyadic(toDyadic(positions[end + axis]), toDyadic(positions[a + axis]))
340
+ );
341
+ const ab = edge(b),
342
+ ac = edge(c);
343
+ const components = [0, 1, 2].map(axis => {
344
+ const j = (axis + 1) % 3,
345
+ k = (axis + 2) % 3;
346
+ return subtractDyadic(multiplyDyadic(ab[j], ac[k]), multiplyDyadic(ab[k], ac[j]));
347
+ });
348
+ if (epsilon === 0) return components.every(v => v.n === 0n);
349
+ const squared = components.map(v => multiplyDyadic(v, v));
350
+ const sum = squared.reduce((total, v) => subtractDyadic(total, {...v, n: -v.n}), {
351
+ n: 0n,
352
+ exponent: 0
353
+ });
354
+ const threshold = multiplyDyadic(toDyadic(epsilon), toDyadic(epsilon));
355
+ threshold.exponent += 2;
356
+ return subtractDyadic(sum, threshold).n <= 0n;
357
+ }
358
+ function toDyadic(value: number): Dyadic {
359
+ const bits = new DataView(new ArrayBuffer(8));
360
+ bits.setFloat64(0, value);
361
+ const high = bits.getUint32(0),
362
+ low = bits.getUint32(4);
363
+ const exponentBits = (high >>> 20) & 0x7ff;
364
+ const fraction = (BigInt(high & 0xfffff) << 32n) | BigInt(low);
365
+ const n = exponentBits ? (1n << 52n) | fraction : fraction;
366
+ return {n: high >>> 31 ? -n : n, exponent: exponentBits ? exponentBits - 1075 : -1074};
367
+ }
368
+ function subtractDyadic(a: Dyadic, b: Dyadic): Dyadic {
369
+ const exponent = Math.min(a.exponent, b.exponent);
370
+ return {
371
+ n: (a.n << BigInt(a.exponent - exponent)) - (b.n << BigInt(b.exponent - exponent)),
372
+ exponent
373
+ };
374
+ }
375
+ function multiplyDyadic(a: Dyadic, b: Dyadic): Dyadic {
376
+ return {n: a.n * b.n, exponent: a.exponent + b.exponent};
377
+ }