@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.
- package/LICENSE +97 -49
- package/README.md +16 -1
- package/THIRD-PARTY-NOTICES.md +18 -0
- package/dist/culling/constants.d.ts +3 -0
- package/dist/culling/constants.d.ts.map +1 -0
- package/dist/culling/constants.js +5 -0
- package/dist/culling/constants.js.map +1 -0
- package/dist/culling/index.cjs +2014 -0
- package/dist/culling/index.cjs.map +6 -0
- package/dist/culling/index.d.ts +29 -0
- package/dist/culling/index.d.ts.map +1 -0
- package/dist/culling/index.js +23 -0
- package/dist/culling/index.js.map +1 -0
- package/dist/culling/lib/algorithms/bounding-box-from-points.d.ts +15 -0
- package/dist/culling/lib/algorithms/bounding-box-from-points.d.ts.map +1 -0
- package/dist/culling/lib/algorithms/bounding-box-from-points.js +137 -0
- package/dist/culling/lib/algorithms/bounding-box-from-points.js.map +1 -0
- package/dist/culling/lib/algorithms/bounding-sphere-from-points.d.ts +14 -0
- package/dist/culling/lib/algorithms/bounding-sphere-from-points.d.ts.map +1 -0
- package/dist/culling/lib/algorithms/bounding-sphere-from-points.js +146 -0
- package/dist/culling/lib/algorithms/bounding-sphere-from-points.js.map +1 -0
- package/dist/culling/lib/algorithms/compute-eigen-decomposition.d.ts +37 -0
- package/dist/culling/lib/algorithms/compute-eigen-decomposition.d.ts.map +1 -0
- package/dist/culling/lib/algorithms/compute-eigen-decomposition.js +137 -0
- package/dist/culling/lib/algorithms/compute-eigen-decomposition.js.map +1 -0
- package/dist/culling/lib/algorithms/oriented-bounding-box-quaternion.d.ts +7 -0
- package/dist/culling/lib/algorithms/oriented-bounding-box-quaternion.d.ts.map +1 -0
- package/dist/culling/lib/algorithms/oriented-bounding-box-quaternion.js +26 -0
- package/dist/culling/lib/algorithms/oriented-bounding-box-quaternion.js.map +1 -0
- package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.d.ts +56 -0
- package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.d.ts.map +1 -0
- package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.js +116 -0
- package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.js.map +1 -0
- package/dist/culling/lib/bounding-volumes/bounding-sphere.d.ts +40 -0
- package/dist/culling/lib/bounding-volumes/bounding-sphere.d.ts.map +1 -0
- package/dist/culling/lib/bounding-volumes/bounding-sphere.js +123 -0
- package/dist/culling/lib/bounding-volumes/bounding-sphere.js.map +1 -0
- package/dist/culling/lib/bounding-volumes/bounding-volume.d.ts +30 -0
- package/dist/culling/lib/bounding-volumes/bounding-volume.d.ts.map +1 -0
- package/dist/culling/lib/bounding-volumes/bounding-volume.js +7 -0
- package/dist/culling/lib/bounding-volumes/bounding-volume.js.map +1 -0
- package/dist/culling/lib/bounding-volumes/oriented-bounding-box.d.ts +62 -0
- package/dist/culling/lib/bounding-volumes/oriented-bounding-box.d.ts.map +1 -0
- package/dist/culling/lib/bounding-volumes/oriented-bounding-box.js +230 -0
- package/dist/culling/lib/bounding-volumes/oriented-bounding-box.js.map +1 -0
- package/dist/culling/lib/culling-volume.d.ts +46 -0
- package/dist/culling/lib/culling-volume.d.ts.map +1 -0
- package/dist/culling/lib/culling-volume.js +126 -0
- package/dist/culling/lib/culling-volume.js.map +1 -0
- package/dist/culling/lib/perspective-frustum.d.ts +153 -0
- package/dist/culling/lib/perspective-frustum.d.ts.map +1 -0
- package/dist/culling/lib/perspective-frustum.js +191 -0
- package/dist/culling/lib/perspective-frustum.js.map +1 -0
- package/dist/culling/lib/perspective-off-center-frustum.d.ts +158 -0
- package/dist/culling/lib/perspective-off-center-frustum.d.ts.map +1 -0
- package/dist/culling/lib/perspective-off-center-frustum.js +276 -0
- package/dist/culling/lib/perspective-off-center-frustum.js.map +1 -0
- package/dist/culling/lib/plane.d.ts +35 -0
- package/dist/culling/lib/plane.d.ts.map +1 -0
- package/dist/culling/lib/plane.js +90 -0
- package/dist/culling/lib/plane.js.map +1 -0
- package/dist/culling/lib/ray.d.ts +13 -0
- package/dist/culling/lib/ray.d.ts.map +1 -0
- package/dist/culling/lib/ray.js +30 -0
- package/dist/culling/lib/ray.js.map +1 -0
- package/dist/culling/lib/shapes/box-shape.d.ts +19 -0
- package/dist/culling/lib/shapes/box-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/box-shape.js +69 -0
- package/dist/culling/lib/shapes/box-shape.js.map +1 -0
- package/dist/culling/lib/shapes/capsule-shape.d.ts +23 -0
- package/dist/culling/lib/shapes/capsule-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/capsule-shape.js +151 -0
- package/dist/culling/lib/shapes/capsule-shape.js.map +1 -0
- package/dist/culling/lib/shapes/cylinder-shape.d.ts +22 -0
- package/dist/culling/lib/shapes/cylinder-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/cylinder-shape.js +99 -0
- package/dist/culling/lib/shapes/cylinder-shape.js.map +1 -0
- package/dist/culling/lib/shapes/implicit-shape.d.ts +56 -0
- package/dist/culling/lib/shapes/implicit-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/implicit-shape.js +142 -0
- package/dist/culling/lib/shapes/implicit-shape.js.map +1 -0
- package/dist/culling/lib/shapes/plane-shape.d.ts +27 -0
- package/dist/culling/lib/shapes/plane-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/plane-shape.js +71 -0
- package/dist/culling/lib/shapes/plane-shape.js.map +1 -0
- package/dist/culling/lib/shapes/sphere-shape.d.ts +18 -0
- package/dist/culling/lib/shapes/sphere-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/sphere-shape.js +43 -0
- package/dist/culling/lib/shapes/sphere-shape.js.map +1 -0
- package/dist/culling/oriented-box-2d.cjs +73 -0
- package/dist/culling/oriented-box-2d.cjs.map +6 -0
- package/dist/culling/oriented-box-2d.d.ts +22 -0
- package/dist/culling/oriented-box-2d.d.ts.map +1 -0
- package/dist/culling/oriented-box-2d.js +86 -0
- package/dist/culling/oriented-box-2d.js.map +1 -0
- package/dist/culling/queries.cjs +161 -0
- package/dist/culling/queries.cjs.map +6 -0
- package/dist/culling/queries.d.ts +20 -0
- package/dist/culling/queries.d.ts.map +1 -0
- package/dist/culling/queries.js +139 -0
- package/dist/culling/queries.js.map +1 -0
- package/dist/curves/bezier-curves.d.ts +18 -0
- package/dist/curves/bezier-curves.d.ts.map +1 -0
- package/dist/curves/bezier-curves.js +54 -0
- package/dist/curves/bezier-curves.js.map +1 -0
- package/dist/curves/catmull-rom-curve.d.ts +15 -0
- package/dist/curves/catmull-rom-curve.d.ts.map +1 -0
- package/dist/curves/catmull-rom-curve.js +77 -0
- package/dist/curves/catmull-rom-curve.js.map +1 -0
- package/dist/curves/curve-arc-length.d.ts +17 -0
- package/dist/curves/curve-arc-length.d.ts.map +1 -0
- package/dist/curves/curve-arc-length.js +58 -0
- package/dist/curves/curve-arc-length.js.map +1 -0
- package/dist/curves/curve.d.ts +23 -0
- package/dist/curves/curve.d.ts.map +1 -0
- package/dist/curves/curve.js +77 -0
- package/dist/curves/curve.js.map +1 -0
- package/dist/curves/hermite-curve.d.ts +9 -0
- package/dist/curves/hermite-curve.d.ts.map +1 -0
- package/dist/curves/hermite-curve.js +24 -0
- package/dist/curves/hermite-curve.js.map +1 -0
- package/dist/curves/index.cjs +293 -0
- package/dist/curves/index.cjs.map +6 -0
- package/dist/curves/index.d.ts +8 -0
- package/dist/curves/index.d.ts.map +1 -0
- package/dist/curves/index.js +9 -0
- package/dist/curves/index.js.map +1 -0
- package/dist/geometries/box-geometry.js +1 -1
- package/dist/geometries/box-geometry.js.map +1 -1
- package/dist/geometries/capsule-geometry.js +1 -1
- package/dist/geometries/capsule-geometry.js.map +1 -1
- package/dist/geometries/cylinder-geometry.js +1 -1
- package/dist/geometries/cylinder-geometry.js.map +1 -1
- package/dist/geometries/geometry-helpers.js +1 -1
- package/dist/geometries/geometry-helpers.js.map +1 -1
- package/dist/geometries/ico-sphere-geometry.js +1 -1
- package/dist/geometries/ico-sphere-geometry.js.map +1 -1
- package/dist/geometries/plane-geometry.js +1 -1
- package/dist/geometries/plane-geometry.js.map +1 -1
- package/dist/geometries/primitive-mesh-builder.d.ts +24 -0
- package/dist/geometries/primitive-mesh-builder.d.ts.map +1 -0
- package/dist/geometries/primitive-mesh-builder.js +74 -0
- package/dist/geometries/primitive-mesh-builder.js.map +1 -0
- package/dist/geometries/prism-geometry.d.ts +13 -0
- package/dist/geometries/prism-geometry.d.ts.map +1 -0
- package/dist/geometries/prism-geometry.js +34 -0
- package/dist/geometries/prism-geometry.js.map +1 -0
- package/dist/geometries/ring-geometry.d.ts +15 -0
- package/dist/geometries/ring-geometry.d.ts.map +1 -0
- package/dist/geometries/ring-geometry.js +64 -0
- package/dist/geometries/ring-geometry.js.map +1 -0
- package/dist/geometries/sphere-geometry.js +1 -1
- package/dist/geometries/sphere-geometry.js.map +1 -1
- package/dist/geometries/surface-of-revolution.js +1 -1
- package/dist/geometries/surface-of-revolution.js.map +1 -1
- package/dist/geometries/truncated-cone-geometry.js +1 -1
- package/dist/geometries/truncated-cone-geometry.js.map +1 -1
- package/dist/index.cjs +290 -9
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/geometry-utils.js +1 -1
- package/dist/lib/geometry-utils.js.map +1 -1
- package/dist/lib/geometry.d.ts +1 -1
- package/dist/lib/geometry.d.ts.map +1 -1
- package/dist/lib/geometry.js +1 -1
- package/dist/lib/geometry.js.map +1 -1
- package/dist/lib/hinge-tree.d.ts +33 -0
- package/dist/lib/hinge-tree.d.ts.map +1 -0
- package/dist/lib/hinge-tree.js +144 -0
- package/dist/lib/hinge-tree.js.map +1 -0
- package/dist/parametric/lathe-geometry.d.ts +14 -0
- package/dist/parametric/lathe-geometry.d.ts.map +1 -0
- package/dist/parametric/lathe-geometry.js +48 -0
- package/dist/parametric/lathe-geometry.js.map +1 -0
- package/dist/parametric/parametric-geometry.d.ts +20 -0
- package/dist/parametric/parametric-geometry.d.ts.map +1 -0
- package/dist/parametric/parametric-geometry.js +88 -0
- package/dist/parametric/parametric-geometry.js.map +1 -0
- package/dist/parametric/torus-geometry.d.ts +19 -0
- package/dist/parametric/torus-geometry.d.ts.map +1 -0
- package/dist/parametric/torus-geometry.js +89 -0
- package/dist/parametric/torus-geometry.js.map +1 -0
- package/dist/parametric.cjs +328 -0
- package/dist/parametric.cjs.map +6 -0
- package/dist/parametric.d.ts +7 -0
- package/dist/parametric.d.ts.map +1 -0
- package/dist/parametric.js +7 -0
- package/dist/parametric.js.map +1 -0
- package/dist/polygon/cut-by-grid.d.ts +24 -0
- package/dist/polygon/cut-by-grid.d.ts.map +1 -0
- package/dist/polygon/cut-by-grid.js +221 -0
- package/dist/polygon/cut-by-grid.js.map +1 -0
- package/dist/polygon/cut-by-mercator-bounds.d.ts +17 -0
- package/dist/polygon/cut-by-mercator-bounds.d.ts.map +1 -0
- package/dist/polygon/cut-by-mercator-bounds.js +149 -0
- package/dist/polygon/cut-by-mercator-bounds.js.map +1 -0
- package/dist/polygon/earcut.d.ts +13 -0
- package/dist/polygon/earcut.d.ts.map +1 -0
- package/dist/polygon/earcut.js +627 -0
- package/dist/polygon/earcut.js.map +1 -0
- package/dist/polygon/index.cjs +1437 -0
- package/dist/polygon/index.cjs.map +6 -0
- package/dist/polygon/index.d.ts +12 -0
- package/dist/polygon/index.d.ts.map +1 -0
- package/dist/polygon/index.js +12 -0
- package/dist/polygon/index.js.map +1 -0
- package/dist/polygon/lineclip.d.ts +31 -0
- package/dist/polygon/lineclip.d.ts.map +1 -0
- package/dist/polygon/lineclip.js +184 -0
- package/dist/polygon/lineclip.js.map +1 -0
- package/dist/polygon/polygon-utils.d.ts +103 -0
- package/dist/polygon/polygon-utils.d.ts.map +1 -0
- package/dist/polygon/polygon-utils.js +155 -0
- package/dist/polygon/polygon-utils.js.map +1 -0
- package/dist/polygon/polygon.d.ts +41 -0
- package/dist/polygon/polygon.d.ts.map +1 -0
- package/dist/polygon/polygon.js +76 -0
- package/dist/polygon/polygon.js.map +1 -0
- package/dist/polygon/subdivide-polyline.d.ts +56 -0
- package/dist/polygon/subdivide-polyline.d.ts.map +1 -0
- package/dist/polygon/subdivide-polyline.js +141 -0
- package/dist/polygon/subdivide-polyline.js.map +1 -0
- package/dist/polygon/subdivide-triangle-mesh.d.ts +68 -0
- package/dist/polygon/subdivide-triangle-mesh.d.ts.map +1 -0
- package/dist/polygon/subdivide-triangle-mesh.js +228 -0
- package/dist/polygon/subdivide-triangle-mesh.js.map +1 -0
- package/dist/polygon/utils.d.ts +5 -0
- package/dist/polygon/utils.d.ts.map +1 -0
- package/dist/polygon/utils.js +38 -0
- package/dist/polygon/utils.js.map +1 -0
- package/dist/spatial-index/box-index.cjs +328 -0
- package/dist/spatial-index/box-index.cjs.map +6 -0
- package/dist/spatial-index/box-index.d.ts +65 -0
- package/dist/spatial-index/box-index.d.ts.map +1 -0
- package/dist/spatial-index/box-index.js +263 -0
- package/dist/spatial-index/box-index.js.map +1 -0
- package/dist/spatial-index/index.cjs +494 -0
- package/dist/spatial-index/index.cjs.map +6 -0
- package/dist/spatial-index/index.d.ts +5 -0
- package/dist/spatial-index/index.d.ts.map +1 -0
- package/dist/spatial-index/index.js +6 -0
- package/dist/spatial-index/index.js.map +1 -0
- package/dist/spatial-index/triangle-bvh.d.ts +53 -0
- package/dist/spatial-index/triangle-bvh.d.ts.map +1 -0
- package/dist/spatial-index/triangle-bvh.js +102 -0
- package/dist/spatial-index/triangle-bvh.js.map +1 -0
- package/dist/utils/attribute-compression.d.ts +50 -0
- package/dist/utils/attribute-compression.d.ts.map +1 -0
- package/dist/utils/attribute-compression.js +186 -0
- package/dist/utils/attribute-compression.js.map +1 -0
- package/dist/utils/attribute-iterator.d.ts +8 -0
- package/dist/utils/attribute-iterator.d.ts.map +1 -0
- package/dist/utils/attribute-iterator.js +25 -0
- package/dist/utils/attribute-iterator.js.map +1 -0
- package/dist/utils/compute-vertex-normals.d.ts +4 -0
- package/dist/utils/compute-vertex-normals.d.ts.map +1 -0
- package/dist/utils/compute-vertex-normals.js +54 -0
- package/dist/utils/compute-vertex-normals.js.map +1 -0
- package/dist/utils/constants.d.ts +52 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +39 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/coordinates.d.ts +3 -0
- package/dist/utils/coordinates.d.ts.map +1 -0
- package/dist/utils/coordinates.js +8 -0
- package/dist/utils/coordinates.js.map +1 -0
- package/dist/utils/geometry.d.ts +20 -0
- package/dist/utils/geometry.d.ts.map +1 -0
- package/dist/utils/geometry.js +31 -0
- package/dist/utils/geometry.js.map +1 -0
- package/dist/utils/gl-type.d.ts +17 -0
- package/dist/utils/gl-type.d.ts.map +1 -0
- package/dist/utils/gl-type.js +69 -0
- package/dist/utils/gl-type.js.map +1 -0
- package/dist/utils/index.cjs +965 -0
- package/dist/utils/index.cjs.map +6 -0
- package/dist/utils/index.d.ts +18 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +16 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/interpolate-packed-attributes.cjs +176 -0
- package/dist/utils/interpolate-packed-attributes.cjs.map +6 -0
- package/dist/utils/interpolate-packed-attributes.d.ts +43 -0
- package/dist/utils/interpolate-packed-attributes.d.ts.map +1 -0
- package/dist/utils/interpolate-packed-attributes.js +192 -0
- package/dist/utils/interpolate-packed-attributes.js.map +1 -0
- package/dist/utils/mesh-processing.d.ts +18 -0
- package/dist/utils/mesh-processing.d.ts.map +1 -0
- package/dist/utils/mesh-processing.js +300 -0
- package/dist/utils/mesh-processing.js.map +1 -0
- package/dist/utils/primitive-iterator.d.ts +21 -0
- package/dist/utils/primitive-iterator.d.ts.map +1 -0
- package/dist/utils/primitive-iterator.js +117 -0
- package/dist/utils/primitive-iterator.js.map +1 -0
- package/dist/utils/rgb565.d.ts +5 -0
- package/dist/utils/rgb565.d.ts.map +1 -0
- package/dist/utils/rgb565.js +24 -0
- package/dist/utils/rgb565.js.map +1 -0
- package/dist/utils/typed-array-utils.d.ts +3 -0
- package/dist/utils/typed-array-utils.d.ts.map +1 -0
- package/dist/utils/typed-array-utils.js +16 -0
- package/dist/utils/typed-array-utils.js.map +1 -0
- package/package.json +57 -4
- package/src/culling/constants.ts +6 -0
- package/src/culling/index.ts +45 -0
- package/src/culling/lib/algorithms/bounding-box-from-points.ts +174 -0
- package/src/culling/lib/algorithms/bounding-sphere-from-points.ts +175 -0
- package/src/culling/lib/algorithms/compute-eigen-decomposition.ts +171 -0
- package/src/culling/lib/algorithms/oriented-bounding-box-quaternion.ts +32 -0
- package/src/culling/lib/bounding-volumes/axis-aligned-bounding-box.ts +153 -0
- package/src/culling/lib/bounding-volumes/bounding-sphere.ts +154 -0
- package/src/culling/lib/bounding-volumes/bounding-volume.ts +38 -0
- package/src/culling/lib/bounding-volumes/oriented-bounding-box.ts +320 -0
- package/src/culling/lib/culling-volume.ts +163 -0
- package/src/culling/lib/perspective-frustum.ts +288 -0
- package/src/culling/lib/perspective-off-center-frustum.ts +381 -0
- package/src/culling/lib/plane.ts +118 -0
- package/src/culling/lib/ray.ts +33 -0
- package/src/culling/lib/shapes/box-shape.ts +78 -0
- package/src/culling/lib/shapes/capsule-shape.ts +232 -0
- package/src/culling/lib/shapes/cylinder-shape.ts +133 -0
- package/src/culling/lib/shapes/implicit-shape.ts +209 -0
- package/src/culling/lib/shapes/plane-shape.ts +78 -0
- package/src/culling/lib/shapes/sphere-shape.ts +60 -0
- package/src/culling/oriented-box-2d.ts +165 -0
- package/src/culling/queries.ts +155 -0
- package/src/curves/bezier-curves.ts +62 -0
- package/src/curves/catmull-rom-curve.ts +89 -0
- package/src/curves/curve-arc-length.ts +70 -0
- package/src/curves/curve.ts +96 -0
- package/src/curves/hermite-curve.ts +34 -0
- package/src/curves/index.ts +15 -0
- package/src/geometries/box-geometry.ts +1 -1
- package/src/geometries/capsule-geometry.ts +1 -1
- package/src/geometries/cylinder-geometry.ts +1 -1
- package/src/geometries/geometry-helpers.ts +1 -1
- package/src/geometries/ico-sphere-geometry.ts +1 -1
- package/src/geometries/plane-geometry.ts +1 -1
- package/src/geometries/primitive-mesh-builder.ts +84 -0
- package/src/geometries/prism-geometry.ts +57 -0
- package/src/geometries/ring-geometry.ts +102 -0
- package/src/geometries/sphere-geometry.ts +1 -1
- package/src/geometries/surface-of-revolution.ts +1 -1
- package/src/geometries/truncated-cone-geometry.ts +1 -1
- package/src/index.ts +10 -1
- package/src/lib/geometry-utils.ts +2 -2
- package/src/lib/geometry.ts +2 -2
- package/src/lib/hinge-tree.ts +170 -0
- package/src/parametric/lathe-geometry.ts +70 -0
- package/src/parametric/parametric-geometry.ts +118 -0
- package/src/parametric/torus-geometry.ts +118 -0
- package/src/parametric.ts +9 -0
- package/src/polygon/cut-by-grid.ts +313 -0
- package/src/polygon/cut-by-mercator-bounds.ts +204 -0
- package/src/polygon/earcut.ts +798 -0
- package/src/polygon/index.ts +35 -0
- package/src/polygon/lineclip.ts +218 -0
- package/src/polygon/polygon-utils.ts +273 -0
- package/src/polygon/polygon.ts +105 -0
- package/src/polygon/subdivide-polyline.ts +223 -0
- package/src/polygon/subdivide-triangle-mesh.ts +322 -0
- package/src/polygon/utils.ts +50 -0
- package/src/spatial-index/box-index.ts +343 -0
- package/src/spatial-index/index.ts +18 -0
- package/src/spatial-index/triangle-bvh.ts +162 -0
- package/src/utils/attribute-compression.ts +234 -0
- package/src/utils/attribute-iterator.ts +28 -0
- package/src/utils/compute-vertex-normals.ts +63 -0
- package/src/utils/constants.ts +42 -0
- package/src/utils/coordinates.ts +8 -0
- package/src/utils/geometry.ts +49 -0
- package/src/utils/gl-type.ts +87 -0
- package/src/utils/index.ts +55 -0
- package/src/utils/interpolate-packed-attributes.ts +284 -0
- package/src/utils/mesh-processing.ts +377 -0
- package/src/utils/primitive-iterator.ts +145 -0
- package/src/utils/rgb565.ts +26 -0
- package/src/utils/typed-array-utils.ts +16 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// math.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
ImplicitShapeBase,
|
|
7
|
+
solveQuadratic,
|
|
8
|
+
type ImplicitShape,
|
|
9
|
+
type LocalRayIntersection
|
|
10
|
+
} from './implicit-shape';
|
|
11
|
+
|
|
12
|
+
const EPSILON = 1e-6;
|
|
13
|
+
|
|
14
|
+
export type SphereShapeProps = {radius?: number; matrix?: readonly number[]};
|
|
15
|
+
|
|
16
|
+
/** Analytic glTF sphere shape. */
|
|
17
|
+
export class SphereShape extends ImplicitShapeBase {
|
|
18
|
+
readonly type = 'sphere' as const;
|
|
19
|
+
readonly radius: number;
|
|
20
|
+
constructor(props: SphereShapeProps = {}) {
|
|
21
|
+
super(props.matrix);
|
|
22
|
+
this.radius = props.radius ?? 0.5;
|
|
23
|
+
if (!Number.isFinite(this.radius) || this.radius <= 0)
|
|
24
|
+
throw new Error('Sphere radius must be greater than zero');
|
|
25
|
+
}
|
|
26
|
+
clone(): SphereShape {
|
|
27
|
+
return new SphereShape({radius: this.radius, matrix: this.matrix});
|
|
28
|
+
}
|
|
29
|
+
override equals(shape: ImplicitShape): boolean {
|
|
30
|
+
return shape instanceof SphereShape && super.equals(shape) && this.radius === shape.radius;
|
|
31
|
+
}
|
|
32
|
+
containsLocalPoint(point: readonly number[]): boolean {
|
|
33
|
+
return Math.hypot(...point) <= this.radius + EPSILON;
|
|
34
|
+
}
|
|
35
|
+
distanceToLocalPoint(point: readonly number[]): number {
|
|
36
|
+
return Math.max(0, Math.hypot(...point) - this.radius);
|
|
37
|
+
}
|
|
38
|
+
supportLocal(direction: readonly number[]): readonly number[] {
|
|
39
|
+
const length = Math.hypot(...direction);
|
|
40
|
+
return length ? direction.map(value => (value / length) * this.radius) : [this.radius, 0, 0];
|
|
41
|
+
}
|
|
42
|
+
intersectLocalRay(
|
|
43
|
+
origin: readonly number[],
|
|
44
|
+
direction: readonly number[]
|
|
45
|
+
): LocalRayIntersection | undefined {
|
|
46
|
+
const roots = solveQuadratic(
|
|
47
|
+
dot(direction, direction),
|
|
48
|
+
2 * dot(origin, direction),
|
|
49
|
+
dot(origin, origin) - this.radius * this.radius
|
|
50
|
+
);
|
|
51
|
+
const distance = roots.find(value => value >= 0);
|
|
52
|
+
if (distance === undefined) return undefined;
|
|
53
|
+
const point = origin.map((value, i) => value + distance * direction[i]);
|
|
54
|
+
return {distance, normal: point.map(value => value / this.radius)};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function dot(a: readonly number[], b: readonly number[]): number {
|
|
59
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
60
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// math.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
/** A rectangle in a shared two-dimensional Euclidean coordinate space. */
|
|
6
|
+
export type OrientedBox2D = {
|
|
7
|
+
/** Two finite center coordinates; arrays, typed arrays and core vectors are accepted. */
|
|
8
|
+
readonly center: Readonly<ArrayLike<number>>;
|
|
9
|
+
/** Nonnegative half-width and half-height, in the center's coordinate units. */
|
|
10
|
+
readonly halfSize: Readonly<ArrayLike<number>>;
|
|
11
|
+
/** Nonzero finite width-axis direction. Its magnitude does not change the size. */
|
|
12
|
+
readonly direction: Readonly<ArrayLike<number>>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/** Test closed rectangles using their four separating axes, without allocating query objects.
|
|
16
|
+
* Directions are normalized locally; the height axis is the perpendicular of the width axis.
|
|
17
|
+
* Points and line segments (zero half-sizes) are supported. Inputs are never modified.
|
|
18
|
+
* Subtracting centers before projection avoids projecting large translated corner coordinates.
|
|
19
|
+
* @param first First rectangle in the shared coordinate space.
|
|
20
|
+
* @param second Second rectangle in the shared coordinate space.
|
|
21
|
+
* @param epsilon Nonnegative finite separation allowance in coordinate units; default zero.
|
|
22
|
+
* Touching edges/vertices intersect. A gap no larger than epsilon on every tested axis also
|
|
23
|
+
* intersects; this is a SAT allowance, not a Euclidean-distance query.
|
|
24
|
+
* @throws RangeError For invalid vectors, sizes, directions or epsilon.
|
|
25
|
+
*/
|
|
26
|
+
export function intersectOrientedBoxes2D(
|
|
27
|
+
first: OrientedBox2D,
|
|
28
|
+
second: OrientedBox2D,
|
|
29
|
+
epsilon = 0
|
|
30
|
+
): boolean {
|
|
31
|
+
validateBox(first);
|
|
32
|
+
validateBox(second);
|
|
33
|
+
if (!Number.isFinite(epsilon) || epsilon < 0) {
|
|
34
|
+
throw new RangeError('Box separation allowance must be finite and nonnegative');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Scale before normalizing so both huge and subnormal directions remain usable.
|
|
38
|
+
const firstDirectionScale = Math.max(Math.abs(first.direction[0]), Math.abs(first.direction[1]));
|
|
39
|
+
const secondDirectionScale = Math.max(
|
|
40
|
+
Math.abs(second.direction[0]),
|
|
41
|
+
Math.abs(second.direction[1])
|
|
42
|
+
);
|
|
43
|
+
const firstWidthX = first.direction[0] / firstDirectionScale;
|
|
44
|
+
const firstWidthY = first.direction[1] / firstDirectionScale;
|
|
45
|
+
const secondWidthX = second.direction[0] / secondDirectionScale;
|
|
46
|
+
const secondWidthY = second.direction[1] / secondDirectionScale;
|
|
47
|
+
const firstLength = Math.hypot(firstWidthX, firstWidthY);
|
|
48
|
+
const secondLength = Math.hypot(secondWidthX, secondWidthY);
|
|
49
|
+
const firstX = firstWidthX / firstLength;
|
|
50
|
+
const firstY = firstWidthY / firstLength;
|
|
51
|
+
const secondX = secondWidthX / secondLength;
|
|
52
|
+
const secondY = secondWidthY / secondLength;
|
|
53
|
+
|
|
54
|
+
// Clamp unit-axis dot products against rounding slightly above one.
|
|
55
|
+
const cosine = Math.min(1, Math.abs(firstX * secondX + firstY * secondY));
|
|
56
|
+
const sine = Math.min(1, Math.abs(firstX * secondY - firstY * secondX));
|
|
57
|
+
return (
|
|
58
|
+
overlapsOnAxis(
|
|
59
|
+
first,
|
|
60
|
+
second,
|
|
61
|
+
firstX,
|
|
62
|
+
firstY,
|
|
63
|
+
first.halfSize[0],
|
|
64
|
+
second.halfSize[0] * cosine,
|
|
65
|
+
second.halfSize[1] * sine,
|
|
66
|
+
epsilon
|
|
67
|
+
) &&
|
|
68
|
+
overlapsOnAxis(
|
|
69
|
+
first,
|
|
70
|
+
second,
|
|
71
|
+
-firstY,
|
|
72
|
+
firstX,
|
|
73
|
+
first.halfSize[1],
|
|
74
|
+
second.halfSize[0] * sine,
|
|
75
|
+
second.halfSize[1] * cosine,
|
|
76
|
+
epsilon
|
|
77
|
+
) &&
|
|
78
|
+
overlapsOnAxis(
|
|
79
|
+
first,
|
|
80
|
+
second,
|
|
81
|
+
secondX,
|
|
82
|
+
secondY,
|
|
83
|
+
second.halfSize[0],
|
|
84
|
+
first.halfSize[0] * cosine,
|
|
85
|
+
first.halfSize[1] * sine,
|
|
86
|
+
epsilon
|
|
87
|
+
) &&
|
|
88
|
+
overlapsOnAxis(
|
|
89
|
+
first,
|
|
90
|
+
second,
|
|
91
|
+
-secondY,
|
|
92
|
+
secondX,
|
|
93
|
+
second.halfSize[1],
|
|
94
|
+
first.halfSize[0] * sine,
|
|
95
|
+
first.halfSize[1] * cosine,
|
|
96
|
+
epsilon
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Scale each projection independently so an irrelevant huge extent cannot erase a small gap. */
|
|
102
|
+
function overlapsOnAxis(
|
|
103
|
+
first: OrientedBox2D,
|
|
104
|
+
second: OrientedBox2D,
|
|
105
|
+
axisX: number,
|
|
106
|
+
axisY: number,
|
|
107
|
+
ownRadius: number,
|
|
108
|
+
otherWidthRadius: number,
|
|
109
|
+
otherHeightRadius: number,
|
|
110
|
+
epsilon: number
|
|
111
|
+
): boolean {
|
|
112
|
+
const displacementX = second.center[0] - first.center[0];
|
|
113
|
+
const displacementY = second.center[1] - first.center[1];
|
|
114
|
+
// Keep a representable center difference before multiplying. If subtraction overflows,
|
|
115
|
+
// project the finite centers first; a zero axis component then stays exactly zero.
|
|
116
|
+
const projectionX = Number.isFinite(displacementX)
|
|
117
|
+
? displacementX * axisX
|
|
118
|
+
: second.center[0] * axisX - first.center[0] * axisX;
|
|
119
|
+
const projectionY = Number.isFinite(displacementY)
|
|
120
|
+
? displacementY * axisY
|
|
121
|
+
: second.center[1] * axisY - first.center[1] * axisY;
|
|
122
|
+
const scale =
|
|
123
|
+
Math.max(
|
|
124
|
+
ownRadius,
|
|
125
|
+
otherWidthRadius,
|
|
126
|
+
otherHeightRadius,
|
|
127
|
+
epsilon,
|
|
128
|
+
Number.isFinite(projectionX)
|
|
129
|
+
? Math.abs(projectionX)
|
|
130
|
+
: Math.max(Math.abs(first.center[0] * axisX), Math.abs(second.center[0] * axisX)),
|
|
131
|
+
Number.isFinite(projectionY)
|
|
132
|
+
? Math.abs(projectionY)
|
|
133
|
+
: Math.max(Math.abs(first.center[1] * axisY), Math.abs(second.center[1] * axisY))
|
|
134
|
+
) || 1;
|
|
135
|
+
const normalizedX = Number.isFinite(projectionX)
|
|
136
|
+
? projectionX / scale
|
|
137
|
+
: (second.center[0] * axisX) / scale - (first.center[0] * axisX) / scale;
|
|
138
|
+
const normalizedY = Number.isFinite(projectionY)
|
|
139
|
+
? projectionY / scale
|
|
140
|
+
: (second.center[1] * axisY) / scale - (first.center[1] * axisY) / scale;
|
|
141
|
+
return (
|
|
142
|
+
Math.abs(normalizedX + normalizedY) <=
|
|
143
|
+
ownRadius / scale + otherWidthRadius / scale + otherHeightRadius / scale + epsilon / scale
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Validate structural boxes before entering the scalar query kernel. */
|
|
148
|
+
function validateBox(box: OrientedBox2D): void {
|
|
149
|
+
validateVector(box.center);
|
|
150
|
+
validateVector(box.halfSize);
|
|
151
|
+
validateVector(box.direction);
|
|
152
|
+
if (box.halfSize[0] < 0 || box.halfSize[1] < 0) {
|
|
153
|
+
throw new RangeError('Box half-sizes must be nonnegative');
|
|
154
|
+
}
|
|
155
|
+
if (box.direction[0] === 0 && box.direction[1] === 0) {
|
|
156
|
+
throw new RangeError('Box direction must be nonzero');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Require exactly two finite components, without copying the vector. */
|
|
161
|
+
function validateVector(vector: Readonly<ArrayLike<number>>): void {
|
|
162
|
+
if (vector.length !== 2 || !Number.isFinite(vector[0]) || !Number.isFinite(vector[1])) {
|
|
163
|
+
throw new RangeError('Box vectors must have exactly two finite components');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// math.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
/** Low-level Euclidean query kernels shared with spatial indexes. */
|
|
6
|
+
export type QueryPoint = Readonly<ArrayLike<number>>;
|
|
7
|
+
export type TriangleRayHit = {t: number; barycentric: [number, number, number]};
|
|
8
|
+
|
|
9
|
+
export function validateQueryPoint(point: QueryPoint, dimension: number): void {
|
|
10
|
+
if (point.length !== dimension) throw new RangeError('Query dimension must match the index');
|
|
11
|
+
for (let i = 0; i < dimension; i++) {
|
|
12
|
+
if (!Number.isFinite(point[i])) throw new RangeError('Coordinates must be finite');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function validateQueryDistance(distance: number): void {
|
|
17
|
+
if (Number.isNaN(distance) || distance < 0) throw new RangeError('Distance must be nonnegative');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Returns a unit direction; ray distances in indexes are always coordinate units. */
|
|
21
|
+
export function normalizeQueryDirection(direction: QueryPoint, dimension: number): number[] {
|
|
22
|
+
validateQueryPoint(direction, dimension);
|
|
23
|
+
const scale = Math.max(...Array.from(direction, Math.abs));
|
|
24
|
+
if (scale === 0) throw new RangeError('Ray direction must be nonzero');
|
|
25
|
+
const scaled = Array.from(direction, x => x / scale);
|
|
26
|
+
const length = Math.hypot(...scaled);
|
|
27
|
+
return scaled.map(x => x / length);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Closed bounds; returns zero for an origin inside. t uses the supplied direction scale. */
|
|
31
|
+
export function intersectRayBounds(
|
|
32
|
+
origin: QueryPoint,
|
|
33
|
+
direction: QueryPoint,
|
|
34
|
+
minimum: QueryPoint,
|
|
35
|
+
maximum: QueryPoint,
|
|
36
|
+
maxT = Infinity
|
|
37
|
+
): number | null {
|
|
38
|
+
const dimension = origin.length;
|
|
39
|
+
if (dimension !== 2 && dimension !== 3) throw new RangeError('Bounds must be 2D or 3D');
|
|
40
|
+
validateQueryPoint(origin, dimension);
|
|
41
|
+
validateQueryPoint(direction, dimension);
|
|
42
|
+
validateQueryPoint(minimum, dimension);
|
|
43
|
+
validateQueryPoint(maximum, dimension);
|
|
44
|
+
validateQueryDistance(maxT);
|
|
45
|
+
let near = 0,
|
|
46
|
+
far = maxT,
|
|
47
|
+
nonzero = false;
|
|
48
|
+
for (let i = 0; i < dimension; i++) {
|
|
49
|
+
if (minimum[i] > maximum[i]) throw new RangeError('Bounds must be ordered');
|
|
50
|
+
nonzero ||= direction[i] !== 0;
|
|
51
|
+
}
|
|
52
|
+
if (!nonzero) throw new RangeError('Ray direction must be nonzero');
|
|
53
|
+
for (let i = 0; i < dimension; i++) {
|
|
54
|
+
if (direction[i] === 0) {
|
|
55
|
+
if (origin[i] < minimum[i] || origin[i] > maximum[i]) return null;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
let a = (minimum[i] - origin[i]) / direction[i];
|
|
59
|
+
let b = (maximum[i] - origin[i]) / direction[i];
|
|
60
|
+
if (a > b) [a, b] = [b, a];
|
|
61
|
+
near = Math.max(near, a);
|
|
62
|
+
far = Math.min(far, b);
|
|
63
|
+
if (near > far) return null;
|
|
64
|
+
}
|
|
65
|
+
return Number.isFinite(near) ? near : null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Two-sided Möller–Trumbore test; degenerates and coplanar rays have no hit. */
|
|
69
|
+
export function intersectRayTriangle(
|
|
70
|
+
origin: QueryPoint,
|
|
71
|
+
direction: QueryPoint,
|
|
72
|
+
a: QueryPoint,
|
|
73
|
+
b: QueryPoint,
|
|
74
|
+
c: QueryPoint,
|
|
75
|
+
options: {backfaceCulling?: boolean; maxT?: number} = {}
|
|
76
|
+
): TriangleRayHit | null {
|
|
77
|
+
for (const point of [origin, direction, a, b, c]) validateQueryPoint(point, 3);
|
|
78
|
+
if (direction[0] === 0 && direction[1] === 0 && direction[2] === 0) {
|
|
79
|
+
throw new RangeError('Ray direction must be nonzero');
|
|
80
|
+
}
|
|
81
|
+
const maxT = options.maxT ?? Infinity;
|
|
82
|
+
validateQueryDistance(maxT);
|
|
83
|
+
const e1 = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
|
|
84
|
+
const e2 = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
|
|
85
|
+
const p = cross(direction, e2);
|
|
86
|
+
const determinant = dot(e1, p);
|
|
87
|
+
if (determinant === 0 || (options.backfaceCulling && determinant < 0)) return null;
|
|
88
|
+
const offset = [origin[0] - a[0], origin[1] - a[1], origin[2] - a[2]];
|
|
89
|
+
const u = dot(offset, p) / determinant;
|
|
90
|
+
if (u < 0 || u > 1) return null;
|
|
91
|
+
const q = cross(offset, e1);
|
|
92
|
+
const v = dot(direction, q) / determinant;
|
|
93
|
+
if (v < 0 || u + v > 1) return null;
|
|
94
|
+
const t = dot(e2, q) / determinant;
|
|
95
|
+
if (!Number.isFinite(t) || t < 0 || t > maxT) return null;
|
|
96
|
+
return {t: Math.max(0, t), barycentric: [1 - u - v, u, v]};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Closest point on a filled triangle; degenerate triangles reduce to segments/points. */
|
|
100
|
+
export function getClosestPointOnTriangle(
|
|
101
|
+
point: QueryPoint,
|
|
102
|
+
a: QueryPoint,
|
|
103
|
+
b: QueryPoint,
|
|
104
|
+
c: QueryPoint
|
|
105
|
+
): [number, number, number] {
|
|
106
|
+
for (const value of [point, a, b, c]) validateQueryPoint(value, 3);
|
|
107
|
+
const ab = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
|
|
108
|
+
const ac = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
|
|
109
|
+
const ap = [point[0] - a[0], point[1] - a[1], point[2] - a[2]];
|
|
110
|
+
const aa = dot(ab, ab),
|
|
111
|
+
bb = dot(ac, ac),
|
|
112
|
+
cc = dot(ab, ac);
|
|
113
|
+
const denominator = aa * bb - cc * cc;
|
|
114
|
+
if (denominator > 0 && Number.isFinite(denominator)) {
|
|
115
|
+
const u = (bb * dot(ap, ab) - cc * dot(ap, ac)) / denominator;
|
|
116
|
+
const v = (aa * dot(ap, ac) - cc * dot(ap, ab)) / denominator;
|
|
117
|
+
if (u >= 0 && v >= 0 && u + v <= 1) {
|
|
118
|
+
return [
|
|
119
|
+
a[0] + u * ab[0] + v * ac[0],
|
|
120
|
+
a[1] + u * ab[1] + v * ac[1],
|
|
121
|
+
a[2] + u * ab[2] + v * ac[2]
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
let best: [number, number, number] = [a[0], a[1], a[2]];
|
|
126
|
+
let distance = Infinity;
|
|
127
|
+
for (const [start, end] of [
|
|
128
|
+
[a, b],
|
|
129
|
+
[b, c],
|
|
130
|
+
[c, a]
|
|
131
|
+
]) {
|
|
132
|
+
const edge = [end[0] - start[0], end[1] - start[1], end[2] - start[2]];
|
|
133
|
+
const offset = [point[0] - start[0], point[1] - start[1], point[2] - start[2]];
|
|
134
|
+
const squared = dot(edge, edge);
|
|
135
|
+
const t = squared > 0 ? Math.max(0, Math.min(1, dot(offset, edge) / squared)) : 0;
|
|
136
|
+
const candidate: [number, number, number] = [
|
|
137
|
+
start[0] + t * edge[0],
|
|
138
|
+
start[1] + t * edge[1],
|
|
139
|
+
start[2] + t * edge[2]
|
|
140
|
+
];
|
|
141
|
+
const d = Math.hypot(point[0] - candidate[0], point[1] - candidate[1], point[2] - candidate[2]);
|
|
142
|
+
if (d < distance) {
|
|
143
|
+
distance = d;
|
|
144
|
+
best = candidate;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return best;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function dot(a: QueryPoint, b: QueryPoint): number {
|
|
151
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
152
|
+
}
|
|
153
|
+
function cross(a: QueryPoint, b: QueryPoint): number[] {
|
|
154
|
+
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]];
|
|
155
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// math.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import type {NumericArray} from '@math.gl/core/types';
|
|
6
|
+
import {Curve, copyPoints, type CurvePoint} from './curve';
|
|
7
|
+
|
|
8
|
+
abstract class BezierCurve extends Curve {
|
|
9
|
+
private readonly points: number[][];
|
|
10
|
+
|
|
11
|
+
protected constructor(points: readonly CurvePoint[]) {
|
|
12
|
+
const copied = copyPoints(points);
|
|
13
|
+
super(copied[0].length);
|
|
14
|
+
this.points = copied;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
protected evaluate(t: number, result: NumericArray, derivative: boolean): void {
|
|
18
|
+
const degree = this.points.length - 1;
|
|
19
|
+
// Scalar de Casteljau evaluation avoids temporary vectors and preserves endpoints.
|
|
20
|
+
for (let i = 0; i < this.dimension; i++) {
|
|
21
|
+
let a = this.points[0][i];
|
|
22
|
+
let b = this.points[1][i];
|
|
23
|
+
let c = degree >= 2 ? this.points[2][i] : 0;
|
|
24
|
+
const d = degree === 3 ? this.points[3][i] : 0;
|
|
25
|
+
let order = degree;
|
|
26
|
+
if (derivative) {
|
|
27
|
+
a = degree * (b - a);
|
|
28
|
+
b = degree * (c - b);
|
|
29
|
+
c = degree * (d - c);
|
|
30
|
+
order--;
|
|
31
|
+
}
|
|
32
|
+
if (order === 3) {
|
|
33
|
+
a = (1 - t) * a + t * b;
|
|
34
|
+
b = (1 - t) * b + t * c;
|
|
35
|
+
c = (1 - t) * c + t * d;
|
|
36
|
+
}
|
|
37
|
+
if (order >= 2) {
|
|
38
|
+
a = (1 - t) * a + t * b;
|
|
39
|
+
b = (1 - t) * b + t * c;
|
|
40
|
+
}
|
|
41
|
+
result[i] = order >= 1 ? (1 - t) * a + t * b : a;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class LineCurve extends BezierCurve {
|
|
47
|
+
constructor(start: CurvePoint, end: CurvePoint) {
|
|
48
|
+
super([start, end]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class QuadraticBezierCurve extends BezierCurve {
|
|
53
|
+
constructor(start: CurvePoint, control: CurvePoint, end: CurvePoint) {
|
|
54
|
+
super([start, control, end]);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class CubicBezierCurve extends BezierCurve {
|
|
59
|
+
constructor(start: CurvePoint, control1: CurvePoint, control2: CurvePoint, end: CurvePoint) {
|
|
60
|
+
super([start, control1, control2, end]);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// math.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import type {NumericArray} from '@math.gl/core/types';
|
|
6
|
+
import {Curve, copyPoints, type CurvePoint} from './curve';
|
|
7
|
+
import {HermiteCurve} from './hermite-curve';
|
|
8
|
+
|
|
9
|
+
export type CatmullRomCurveOptions = {
|
|
10
|
+
closed?: boolean;
|
|
11
|
+
parameterization?: 'centripetal' | 'chordal' | 'uniform';
|
|
12
|
+
/** Uniform splines only. Default 0.5; zero gives stationary knot tangents. */
|
|
13
|
+
tension?: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export class CatmullRomCurve extends Curve {
|
|
17
|
+
readonly closed: boolean;
|
|
18
|
+
private readonly segments: HermiteCurve[];
|
|
19
|
+
|
|
20
|
+
constructor(points: readonly CurvePoint[], options: CatmullRomCurveOptions = {}) {
|
|
21
|
+
const data = copyPoints(points);
|
|
22
|
+
super(data[0].length);
|
|
23
|
+
this.closed = options.closed ?? false;
|
|
24
|
+
if (data.length < (this.closed ? 3 : 2)) throw new RangeError('Not enough spline points');
|
|
25
|
+
const mode = options.parameterization ?? 'centripetal';
|
|
26
|
+
if (!['centripetal', 'chordal', 'uniform'].includes(mode)) {
|
|
27
|
+
throw new RangeError('Unknown Catmull-Rom parameterization');
|
|
28
|
+
}
|
|
29
|
+
const tension = options.tension ?? 0.5;
|
|
30
|
+
if (!Number.isFinite(tension) || tension < 0 || tension > 1) {
|
|
31
|
+
throw new RangeError('tension must be in [0, 1]');
|
|
32
|
+
}
|
|
33
|
+
if (options.tension !== undefined && mode !== 'uniform') {
|
|
34
|
+
throw new RangeError('tension is only supported for uniform splines');
|
|
35
|
+
}
|
|
36
|
+
const point = (index: number): number[] => {
|
|
37
|
+
if (this.closed) return data[(index + data.length) % data.length];
|
|
38
|
+
if (index < 0) return data[0].map((x, i) => 2 * x - data[1][i]);
|
|
39
|
+
if (index >= data.length) {
|
|
40
|
+
return data[data.length - 1].map((x, i) => 2 * x - data[data.length - 2][i]);
|
|
41
|
+
}
|
|
42
|
+
return data[index];
|
|
43
|
+
};
|
|
44
|
+
this.segments = [];
|
|
45
|
+
for (let s = 0; s < data.length - (this.closed ? 0 : 1); s++) {
|
|
46
|
+
const p0 = point(s - 1);
|
|
47
|
+
const p1 = point(s);
|
|
48
|
+
const p2 = point(s + 1);
|
|
49
|
+
const p3 = point(s + 2);
|
|
50
|
+
const interval = (a: number[], b: number[]): number => {
|
|
51
|
+
const distance = Math.hypot(...a.map((x, i) => b[i] - x));
|
|
52
|
+
return distance ** (mode === 'chordal' ? 1 : 0.5);
|
|
53
|
+
};
|
|
54
|
+
const d1 = interval(p1, p2);
|
|
55
|
+
if (mode !== 'uniform' && d1 === 0) {
|
|
56
|
+
// A repeated knot is a stationary segment, rather than a spurious loop.
|
|
57
|
+
const zero = new Array<number>(this.dimension).fill(0);
|
|
58
|
+
this.segments.push(new HermiteCurve(p1, p2, zero, zero));
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
// Reuse the current interval for coincident neighbors. This is scale invariant.
|
|
62
|
+
const d0 = interval(p0, p1) || d1;
|
|
63
|
+
const d2 = interval(p2, p3) || d1;
|
|
64
|
+
const m1 = p1.map((x, i) =>
|
|
65
|
+
mode === 'uniform'
|
|
66
|
+
? tension * (p2[i] - p0[i])
|
|
67
|
+
: d1 * ((x - p0[i]) / d0 - (p2[i] - p0[i]) / (d0 + d1) + (p2[i] - x) / d1)
|
|
68
|
+
);
|
|
69
|
+
const m2 = p2.map((x, i) =>
|
|
70
|
+
mode === 'uniform'
|
|
71
|
+
? tension * (p3[i] - p1[i])
|
|
72
|
+
: d1 * ((x - p1[i]) / d1 - (p3[i] - p1[i]) / (d1 + d2) + (p3[i] - x) / d2)
|
|
73
|
+
);
|
|
74
|
+
this.segments.push(new HermiteCurve(p1, p2, m1, m2));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
protected evaluate(t: number, result: NumericArray, derivative: boolean): void {
|
|
79
|
+
const scaled = t * this.segments.length;
|
|
80
|
+
const index = Math.min(Math.floor(scaled), this.segments.length - 1);
|
|
81
|
+
const local = scaled - index;
|
|
82
|
+
if (derivative) {
|
|
83
|
+
this.segments[index].getDerivative(local, result);
|
|
84
|
+
for (let i = 0; i < this.dimension; i++) result[i] *= this.segments.length;
|
|
85
|
+
} else {
|
|
86
|
+
this.segments[index].getPoint(local, result);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// math.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import type {NumericArray} from '@math.gl/core/types';
|
|
6
|
+
import {Curve, validateDivisions, validateParameter} from './curve';
|
|
7
|
+
|
|
8
|
+
/** Reusable polyline approximation to a curve's cumulative arc length. */
|
|
9
|
+
export class CurveArcLength {
|
|
10
|
+
readonly curve: Curve;
|
|
11
|
+
readonly divisions: number;
|
|
12
|
+
readonly length: number;
|
|
13
|
+
private readonly cumulativeLengths: Float64Array;
|
|
14
|
+
|
|
15
|
+
constructor(curve: Curve, divisions = 1024) {
|
|
16
|
+
validateDivisions(divisions);
|
|
17
|
+
this.curve = curve;
|
|
18
|
+
this.divisions = divisions;
|
|
19
|
+
this.cumulativeLengths = new Float64Array(divisions + 1);
|
|
20
|
+
let previous = curve.getPoint(0);
|
|
21
|
+
let current = new Array<number>(curve.dimension);
|
|
22
|
+
let length = 0;
|
|
23
|
+
for (let i = 1; i <= divisions; i++) {
|
|
24
|
+
curve.getPoint(i / divisions, current);
|
|
25
|
+
length += Math.hypot(
|
|
26
|
+
current[0] - previous[0],
|
|
27
|
+
current[1] - previous[1],
|
|
28
|
+
curve.dimension === 3 ? current[2] - previous[2] : 0
|
|
29
|
+
);
|
|
30
|
+
if (!Number.isFinite(length)) throw new RangeError('Curve arc length must be finite');
|
|
31
|
+
this.cumulativeLengths[i] = length;
|
|
32
|
+
[previous, current] = [current, previous];
|
|
33
|
+
}
|
|
34
|
+
this.length = length;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Map a fraction of total length to t, preserving endpoints and zero-length curves. */
|
|
38
|
+
getParameterAt(u: number): number {
|
|
39
|
+
validateParameter(u);
|
|
40
|
+
if (u === 0 || u === 1 || this.length === 0) return u;
|
|
41
|
+
const target = u * this.length;
|
|
42
|
+
let low = 0;
|
|
43
|
+
let high = this.divisions;
|
|
44
|
+
while (low + 1 < high) {
|
|
45
|
+
const middle = Math.floor((low + high) / 2);
|
|
46
|
+
if (this.cumulativeLengths[middle] <= target) low = middle;
|
|
47
|
+
else high = middle;
|
|
48
|
+
}
|
|
49
|
+
const span = this.cumulativeLengths[high] - this.cumulativeLengths[low];
|
|
50
|
+
return (low + (span > 0 ? (target - this.cumulativeLengths[low]) / span : 0)) / this.divisions;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getPointAt(u: number): number[];
|
|
54
|
+
getPointAt<T extends NumericArray>(u: number, result: T): T;
|
|
55
|
+
getPointAt(u: number, result: NumericArray = new Array(this.curve.dimension)): NumericArray {
|
|
56
|
+
return this.curve.getPoint(this.getParameterAt(u), result);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Flat samples at approximately equal distances along the curve. */
|
|
60
|
+
getSpacedPoints(divisions = 64): Float64Array {
|
|
61
|
+
validateDivisions(divisions);
|
|
62
|
+
const points = new Float64Array((divisions + 1) * this.curve.dimension);
|
|
63
|
+
const point = new Array<number>(this.curve.dimension);
|
|
64
|
+
for (let i = 0; i <= divisions; i++) {
|
|
65
|
+
this.getPointAt(i / divisions, point);
|
|
66
|
+
points.set(point, i * this.curve.dimension);
|
|
67
|
+
}
|
|
68
|
+
return points;
|
|
69
|
+
}
|
|
70
|
+
}
|