@woosh/meep-engine 2.164.0 → 2.165.0
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/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BitImage2.d.ts +91 -0
- package/src/core/binary/BitImage2.d.ts.map +1 -0
- package/src/core/binary/BitImage2.js +242 -0
- package/src/core/geom/2d/oriented-box/min_area_rect_2d.d.ts +22 -0
- package/src/core/geom/2d/oriented-box/min_area_rect_2d.d.ts.map +1 -0
- package/src/core/geom/2d/oriented-box/min_area_rect_2d.js +69 -0
- package/src/core/geom/2d/packing/skyline.d.ts +116 -0
- package/src/core/geom/2d/packing/skyline.d.ts.map +1 -0
- package/src/core/geom/2d/packing/skyline.js +258 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_conservative.d.ts +18 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_conservative.d.ts.map +1 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_conservative.js +86 -0
- package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +486 -0
- package/src/core/geom/3d/atlas/BFF_PLAN.md +174 -0
- package/src/core/geom/3d/atlas/Chart.d.ts +58 -0
- package/src/core/geom/3d/atlas/Chart.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/Chart.js +77 -0
- package/src/core/geom/3d/atlas/REVIEW_02.md +392 -0
- package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts +73 -0
- package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_bench_lib.js +315 -0
- package/src/core/geom/3d/atlas/atlas_chart_type.d.ts +17 -0
- package/src/core/geom/3d/atlas/atlas_chart_type.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_chart_type.js +16 -0
- package/src/core/geom/3d/atlas/atlas_compute_charts.d.ts +25 -0
- package/src/core/geom/3d/atlas/atlas_compute_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_compute_charts.js +188 -0
- package/src/core/geom/3d/atlas/atlas_extract_chart.d.ts +17 -0
- package/src/core/geom/3d/atlas/atlas_extract_chart.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_extract_chart.js +107 -0
- package/src/core/geom/3d/atlas/atlas_generate.d.ts +39 -0
- package/src/core/geom/3d/atlas/atlas_generate.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_generate.js +43 -0
- package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts +84 -0
- package/src/core/geom/3d/atlas/atlas_test_fixtures.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_test_fixtures.js +266 -0
- package/src/core/geom/3d/atlas/atlas_write_chart_uvs.d.ts +25 -0
- package/src/core/geom/3d/atlas/atlas_write_chart_uvs.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/atlas_write_chart_uvs.js +36 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.d.ts +22 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.js +62 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.d.ts +9 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.js +33 -0
- package/src/core/geom/3d/atlas/data/atlas_build_face_areas.d.ts +9 -0
- package/src/core/geom/3d/atlas/data/atlas_build_face_areas.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/data/atlas_build_face_areas.js +50 -0
- package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.d.ts +27 -0
- package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.js +39 -0
- package/src/core/geom/3d/atlas/io/bt_loop_uv.d.ts +22 -0
- package/src/core/geom/3d/atlas/io/bt_loop_uv.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/io/bt_loop_uv.js +57 -0
- package/src/core/geom/3d/atlas/pack/ChartPlacement.d.ts +36 -0
- package/src/core/geom/3d/atlas/pack/ChartPlacement.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/pack/ChartPlacement.js +46 -0
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts +62 -0
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +551 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_param_validity.d.ts +22 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_param_validity.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_param_validity.js +73 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts +37 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +270 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts +23 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +224 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.d.ts +14 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.js +38 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.d.ts +22 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.js +86 -0
- package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.d.ts +20 -0
- package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.js +183 -0
- package/src/core/geom/3d/atlas/param/fit_plane_basis.d.ts +27 -0
- package/src/core/geom/3d/atlas/param/fit_plane_basis.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/param/fit_plane_basis.js +66 -0
- package/src/core/geom/3d/atlas/segment/RegionGraph.d.ts +31 -0
- package/src/core/geom/3d/atlas/segment/RegionGraph.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/RegionGraph.js +40 -0
- package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.d.ts +23 -0
- package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.js +136 -0
- package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.d.ts +24 -0
- package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.js +77 -0
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts +27 -0
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +113 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts +44 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.js +275 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts +22 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.js +199 -0
- package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.d.ts +32 -0
- package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.d.ts.map +1 -0
- package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.js +64 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.d.ts +20 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.js +66 -0
- package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.d.ts.map +1 -1
- package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +13 -11
- package/src/core/geom/3d/sphere/sphere_compute_bounding_of_2_spheres.d.ts.map +1 -1
- package/src/core/geom/3d/sphere/sphere_compute_bounding_of_2_spheres.js +4 -3
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.js +4 -3
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.js +4 -3
- package/src/core/geom/3d/topology/simplify/quadratic/apply_border_penalty_to_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/apply_border_penalty_to_vertex_quadrics.js +10 -6
- package/src/core/geom/3d/topology/struct/TopoMesh.js +2 -2
- package/src/core/geom/3d/topology/struct/TopoTriangle.d.ts +0 -2
- package/src/core/geom/3d/topology/struct/TopoTriangle.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/TopoTriangle.js +2 -2
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +8 -27
- package/src/core/geom/vec3/v3_cotangent.d.ts +20 -0
- package/src/core/geom/vec3/v3_cotangent.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_cotangent.js +29 -0
- package/src/core/geom/vec3/v3_matrix3_multiply.d.ts +19 -0
- package/src/core/geom/vec3/v3_matrix3_multiply.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_matrix3_multiply.js +30 -0
- package/src/core/geom/vec3/v3_multiply.d.ts +16 -0
- package/src/core/geom/vec3/v3_multiply.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_multiply.js +19 -0
- package/src/core/math/linalg/cg/cg_solve.d.ts +24 -0
- package/src/core/math/linalg/cg/cg_solve.d.ts.map +1 -0
- package/src/core/math/linalg/cg/cg_solve.js +106 -0
- package/src/core/math/linalg/cg/cg_solve_normal_equations.d.ts +21 -0
- package/src/core/math/linalg/cg/cg_solve_normal_equations.d.ts.map +1 -0
- package/src/core/math/linalg/cg/cg_solve_normal_equations.js +59 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts +19 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.d.ts.map +1 -0
- package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.js +117 -0
- package/src/core/math/linalg/sparse/SparseMatrixCSR.d.ts +50 -0
- package/src/core/math/linalg/sparse/SparseMatrixCSR.d.ts.map +1 -0
- package/src/core/math/linalg/sparse/SparseMatrixCSR.js +88 -0
- package/src/core/math/linalg/sparse/spm_matvec.d.ts +9 -0
- package/src/core/math/linalg/sparse/spm_matvec.d.ts.map +1 -0
- package/src/core/math/linalg/sparse/spm_matvec.js +22 -0
- package/src/core/math/linalg/sparse/spm_matvec_transpose.d.ts +12 -0
- package/src/core/math/linalg/sparse/spm_matvec_transpose.d.ts.map +1 -0
- package/src/core/math/linalg/sparse/spm_matvec_transpose.js +29 -0
- package/src/core/math/physics/mie/MIE_PARTICLES_STANDARD_PRECOMPUTED.d.ts +39 -0
- package/src/core/math/physics/mie/MIE_PARTICLES_STANDARD_PRECOMPUTED.js +22 -1
- package/src/core/math/physics/mie/compute_mie_particle_properties_rgb.d.ts.map +1 -1
- package/src/core/math/physics/mie/compute_mie_particle_properties_rgb.js +32 -9
- package/src/core/math/physics/mie/compute_mie_phase.d.ts +2 -3
- package/src/core/math/physics/mie/compute_mie_phase.d.ts.map +1 -1
- package/src/core/math/physics/mie/compute_mie_phase.js +1 -3
- package/src/core/math/physics/mie/lorenz_mie_coefs.d.ts +0 -1
- package/src/core/math/physics/mie/lorenz_mie_coefs.d.ts.map +1 -1
- package/src/core/math/physics/mie/lorenz_mie_coefs.js +0 -7
- package/src/engine/ecs/attachment/TransformAttachmentBinding.js +3 -3
- package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +2 -2
- package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/Terrain.js +4 -3
- package/src/engine/ecs/terrain/tiles/TerrainTile.js +2 -2
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +9 -8
- package/src/engine/graphics/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics/GraphicsEngine.js +2 -1
- package/src/engine/graphics/ecs/decal/v2/FPDecalSystem.js +2 -2
- package/src/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +2 -2
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +2 -2
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +0 -1
- package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.d.ts.map +1 -1
- package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +8 -7
- package/src/engine/graphics/geometry/MikkT/AvgTSpace.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/AvgTSpace.js +11 -6
- package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/BuildNeighborsFast.js +2 -3
- package/src/engine/graphics/geometry/MikkT/CalcTexArea.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/CalcTexArea.js +3 -4
- package/src/engine/graphics/geometry/MikkT/DegenEpilogue.js +4 -4
- package/src/engine/graphics/geometry/MikkT/EvalTspace.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/EvalTspace.js +11 -8
- package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/GenerateSharedVerticesIndexList.js +7 -8
- package/src/engine/graphics/geometry/MikkT/GenerateTSpaces.js +8 -8
- package/src/engine/graphics/geometry/MikkT/InitTriInfo.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/InitTriInfo.js +30 -25
- package/src/engine/graphics/geometry/MikkT/MikkTSpace.js +7 -7
- package/src/engine/graphics/geometry/MikkT/NormalizeSafe.d.ts +0 -1
- package/src/engine/graphics/geometry/MikkT/NormalizeSafe.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/NormalizeSafe.js +6 -4
- package/src/engine/graphics/geometry/MikkT/STSpace.d.ts +0 -2
- package/src/engine/graphics/geometry/MikkT/STSpace.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/STSpace.js +3 -3
- package/src/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.d.ts +0 -2
- package/src/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/v3_scale_dot_sub_normalize.js +0 -1
- package/src/engine/graphics/impostors/octahedral/ImpostorBaker.d.ts +0 -2
- package/src/engine/graphics/impostors/octahedral/ImpostorBaker.d.ts.map +1 -1
- package/src/engine/graphics/impostors/octahedral/ImpostorBaker.js +4 -3
- package/src/engine/graphics/impostors/octahedral/grid/HemiOctahedralUvEncoder.js +2 -2
- package/src/engine/graphics/impostors/octahedral/grid/UvEncoder.d.ts +17 -7
- package/src/engine/graphics/impostors/voxel/VoxelImpostorBaker.js +2 -2
- package/src/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.js +3 -3
- package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +4 -3
- package/src/engine/graphics/render/forward_plus/LightManager.js +2 -2
- package/src/engine/graphics/render/forward_plus/model/Decal.d.ts +0 -2
- package/src/engine/graphics/render/forward_plus/model/Decal.d.ts.map +1 -1
- package/src/engine/graphics/render/forward_plus/model/Decal.js +3 -3
- package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +4 -3
- package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +6 -4
- package/src/engine/graphics/sh3/lightmap/ARTIFACTS_PLAN.md +146 -0
- package/src/engine/graphics/sh3/lightmap/CODE_REVIEW.md +121 -0
- package/src/engine/graphics/sh3/lightmap/LIGHTMAPPER_REVIEW.md +183 -0
- package/src/engine/graphics/sh3/lightmap/bake_lightmap_for_scene.d.ts +90 -0
- package/src/engine/graphics/sh3/lightmap/bake_lightmap_for_scene.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/bake_lightmap_for_scene.js +678 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_build_geometry.d.ts +32 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_build_geometry.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_build_geometry.js +155 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_denoise.d.ts +49 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_denoise.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_denoise.js +136 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_dilate.d.ts +19 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_dilate.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_dilate.js +89 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_gather.d.ts +54 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_gather.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_gather.js +168 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.d.ts +30 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_rasterize_triangle.js +145 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_seam_fix.d.ts +38 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_seam_fix.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/lightmap_seam_fix.js +152 -0
- package/src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.d.ts +2 -0
- package/src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.d.ts.map +1 -0
- package/src/engine/graphics/sh3/lightmap/prototypeLightmapBaker.js +186 -0
- package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.js +2 -2
- package/src/engine/graphics/sh3/path_tracer/PathTracer.js +2 -2
- package/src/engine/graphics/sh3/path_tracer/prepare_scene_gltf.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/prepare_scene_gltf.js +6 -4
- package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +3 -3
- package/src/engine/graphics/sh3/path_tracer/texture/sample_material.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/texture/sample_material.js +5 -4
- package/src/engine/graphics/sh3/sky/hosek/prototype_hosek.js +2 -2
- package/src/engine/input/devices/KeyboardDevice.d.ts +61 -14
- package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
- package/src/engine/input/devices/KeyboardDevice.js +41 -15
- package/src/engine/input/devices/isHTMLElementFocusable.d.ts.map +1 -1
- package/src/engine/input/devices/isHTMLElementFocusable.js +2 -9
- package/src/engine/sound/simulation/prototypeAcousticSolver.js +261 -143
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { cg_solve } from "../../../../math/linalg/cg/cg_solve.js";
|
|
2
|
+
import { cg_solve_normal_equations } from "../../../../math/linalg/cg/cg_solve_normal_equations.js";
|
|
3
|
+
import { SparseMatrixCSR } from "../../../../math/linalg/sparse/SparseMatrixCSR.js";
|
|
4
|
+
import { v3_cotangent } from "../../../vec3/v3_cotangent.js";
|
|
5
|
+
|
|
6
|
+
const TWO_PI = 2 * Math.PI;
|
|
7
|
+
/** Cotangent weights are clamped to [0, COT_MAX]: ≥0 keeps the Dirichlet
|
|
8
|
+
* Laplacian an SPD M-matrix (obtuse triangles otherwise make it indefinite) and
|
|
9
|
+
* preserves zero row sums (so the DtN boundary curvature still closes); the upper
|
|
10
|
+
* bound stops a sliver corner from dominating. */
|
|
11
|
+
const COT_MAX = 1e3;
|
|
12
|
+
|
|
13
|
+
/** Cotangent of the angle at o (opposite edge p-q), clamped to [0, COT_MAX].
|
|
14
|
+
* ≥0 keeps the interior Poisson SPD (`cg_solve`) and preserves zero row sums
|
|
15
|
+
* (so the DtN boundary still closes); measured to give marginally more rescues
|
|
16
|
+
* than the true signed cotangent (the indefinite solve is no better here). */
|
|
17
|
+
function clamped_cot(pos, o, p, q) {
|
|
18
|
+
const c = v3_cotangent(
|
|
19
|
+
pos[p * 3] - pos[o * 3], pos[p * 3 + 1] - pos[o * 3 + 1], pos[p * 3 + 2] - pos[o * 3 + 2],
|
|
20
|
+
pos[q * 3] - pos[o * 3], pos[q * 3 + 1] - pos[o * 3 + 1], pos[q * 3 + 2] - pos[o * 3 + 2]
|
|
21
|
+
);
|
|
22
|
+
if (!Number.isFinite(c) || c <= 0) return 0;
|
|
23
|
+
return c > COT_MAX ? COT_MAX : c;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Interior angle (radians) at vertex i0 in triangle (i0,i1,i2). */
|
|
27
|
+
function interior_angle(pos, i0, i1, i2) {
|
|
28
|
+
const ux = pos[i1 * 3] - pos[i0 * 3], uy = pos[i1 * 3 + 1] - pos[i0 * 3 + 1], uz = pos[i1 * 3 + 2] - pos[i0 * 3 + 2];
|
|
29
|
+
const vx = pos[i2 * 3] - pos[i0 * 3], vy = pos[i2 * 3 + 1] - pos[i0 * 3 + 1], vz = pos[i2 * 3 + 2] - pos[i0 * 3 + 2];
|
|
30
|
+
const lu = Math.sqrt(ux * ux + uy * uy + uz * uz);
|
|
31
|
+
const lv = Math.sqrt(vx * vx + vy * vy + vz * vz);
|
|
32
|
+
if (lu < 1e-20 || lv < 1e-20) return 0;
|
|
33
|
+
const c = (ux * vx + uy * vy + uz * vz) / (lu * lv);
|
|
34
|
+
return Math.acos(Math.max(-1, Math.min(1, c)));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Flatten a triangle into an isometric local 2D frame (vertex 0 at origin,
|
|
38
|
+
* vertex 1 on +x): writes [x2, x3, y3] into `out`. (Same as LSCM.) */
|
|
39
|
+
function project_triangle(pos, i0, i1, i2, out) {
|
|
40
|
+
const ax = pos[i0 * 3], ay = pos[i0 * 3 + 1], az = pos[i0 * 3 + 2];
|
|
41
|
+
const e1x = pos[i1 * 3] - ax, e1y = pos[i1 * 3 + 1] - ay, e1z = pos[i1 * 3 + 2] - az;
|
|
42
|
+
const len1 = Math.sqrt(e1x * e1x + e1y * e1y + e1z * e1z);
|
|
43
|
+
const inv1 = len1 > 0 ? 1 / len1 : 0;
|
|
44
|
+
const ux = e1x * inv1, uy = e1y * inv1, uz = e1z * inv1;
|
|
45
|
+
const e2x = pos[i2 * 3] - ax, e2y = pos[i2 * 3 + 1] - ay, e2z = pos[i2 * 3 + 2] - az;
|
|
46
|
+
const x3 = e2x * ux + e2y * uy + e2z * uz;
|
|
47
|
+
const px = e2x - x3 * ux, py = e2y - x3 * uy, pz = e2z - x3 * uz;
|
|
48
|
+
out[0] = len1;
|
|
49
|
+
out[1] = x3;
|
|
50
|
+
out[2] = Math.sqrt(px * px + py * py + pz * pz);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Intrinsic boundary-first flattening (a tractable BFF, Sawhney & Crane 2018).
|
|
55
|
+
*
|
|
56
|
+
* Unlike a Tutte/convex embedding (which forces a circle and so distorts
|
|
57
|
+
* thin/curled charts catastrophically — the aspect cannot be guessed without
|
|
58
|
+
* already flattening), this builds the flattened boundary from the chart's OWN
|
|
59
|
+
* geometry: keep each boundary edge's 3D length and turn at each boundary vertex
|
|
60
|
+
* by the optimal Dirichlet-to-Neumann curvature — fix the boundary scale to 0,
|
|
61
|
+
* solve the interior Poisson `L_II u = Ω_I` (flatten the interior), then
|
|
62
|
+
* `k̃_b = (π − θ_b) − (L u)_b`. By the cot-Laplacian's zero row sums ∑ k̃ = 2π so
|
|
63
|
+
* the boundary closes, with the curvature distributed by the mesh's harmonic
|
|
64
|
+
* structure (not uniformly). The interior is then a CONFORMAL extension of that
|
|
65
|
+
* boundary (least-squares Cauchy-Riemann, every boundary vertex pinned) — the u,v
|
|
66
|
+
* coupling is far less flip-prone than a harmonic interior on a non-convex
|
|
67
|
+
* boundary. The result is a natural, low-distortion, length-preserving boundary —
|
|
68
|
+
* not a forced convex shape.
|
|
69
|
+
*
|
|
70
|
+
* Measured outcome (decimated terrain): a Pareto-safe rescue but SMALL — the DtN
|
|
71
|
+
* boundary fixed the conformal-interior flips (25 → 2), yet only ~2 of 31
|
|
72
|
+
* self-intersecting charts are rescued because the flattened BOUNDARY itself then
|
|
73
|
+
* self-intersects on ~27/31. That is fundamental, not an implementation gap (true
|
|
74
|
+
* unclamped cotangents made it worse): these high-curvature decimated charts can't
|
|
75
|
+
* be developed to a SIMPLE boundary while preserving edge lengths, so cutting
|
|
76
|
+
* (piecewise) is the correct injective answer for them. Injectivity is NOT
|
|
77
|
+
* guaranteed; the caller validates and falls back to piecewise otherwise. Solves
|
|
78
|
+
* in place on `chart.uv`. See BFF_PLAN.md / REVIEW_02.md §5.0.
|
|
79
|
+
*
|
|
80
|
+
* @param {Chart} chart with `boundary_edges`, `tri_local`, `positions`, `uv`
|
|
81
|
+
* @param {{tolerance?:number, maxIterations?:number}} [options]
|
|
82
|
+
* @returns {boolean} true if a flattening was produced; false if the chart is not
|
|
83
|
+
* a single-boundary-loop disk or the interior system is degenerate
|
|
84
|
+
*/
|
|
85
|
+
export function atlas_chart_parameterize_bff(chart, options = {}) {
|
|
86
|
+
const V = chart.vertex_count;
|
|
87
|
+
const be = chart.boundary_edges;
|
|
88
|
+
if (be.length === 0) return false;
|
|
89
|
+
const pos = chart.positions;
|
|
90
|
+
const uv = chart.uv;
|
|
91
|
+
const tri = chart.tri_local;
|
|
92
|
+
const T = chart.triangle_count;
|
|
93
|
+
|
|
94
|
+
// ── 1. trace the single oriented boundary loop (disk check) ──────────────
|
|
95
|
+
const is_boundary = new Uint8Array(V);
|
|
96
|
+
const succ = new Int32Array(V).fill(-1);
|
|
97
|
+
let boundary_count = 0;
|
|
98
|
+
for (let i = 0; i < be.length; i += 2) {
|
|
99
|
+
const a = be[i], b = be[i + 1];
|
|
100
|
+
if (!is_boundary[a]) { is_boundary[a] = 1; boundary_count++; }
|
|
101
|
+
if (!is_boundary[b]) { is_boundary[b] = 1; boundary_count++; }
|
|
102
|
+
if (succ[a] !== -1) return false;
|
|
103
|
+
succ[a] = b;
|
|
104
|
+
}
|
|
105
|
+
const loop = [];
|
|
106
|
+
let cur = be[0];
|
|
107
|
+
do {
|
|
108
|
+
loop.push(cur);
|
|
109
|
+
cur = succ[cur];
|
|
110
|
+
if (cur === -1) return false;
|
|
111
|
+
if (loop.length > boundary_count) return false;
|
|
112
|
+
} while (cur !== be[0]);
|
|
113
|
+
if (loop.length !== boundary_count) return false;
|
|
114
|
+
const n = loop.length;
|
|
115
|
+
|
|
116
|
+
// ── 2. interior angle sums + Gaussian curvature ──────────────────────────
|
|
117
|
+
const angle_sum = new Float64Array(V);
|
|
118
|
+
for (let t = 0; t < T; t++) {
|
|
119
|
+
const a = tri[t * 3], b = tri[t * 3 + 1], c = tri[t * 3 + 2];
|
|
120
|
+
angle_sum[a] += interior_angle(pos, a, b, c);
|
|
121
|
+
angle_sum[b] += interior_angle(pos, b, c, a);
|
|
122
|
+
angle_sum[c] += interior_angle(pos, c, a, b);
|
|
123
|
+
}
|
|
124
|
+
// re-index interior (shared by the DtN boundary solve and the conformal interior)
|
|
125
|
+
const interior = new Int32Array(V).fill(-1);
|
|
126
|
+
const vertex_of = new Int32Array(V);
|
|
127
|
+
let m = 0;
|
|
128
|
+
for (let v = 0; v < V; v++) {
|
|
129
|
+
if (!is_boundary[v]) { vertex_of[m] = v; interior[v] = m++; }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ── 3. Dirichlet-to-Neumann optimal boundary curvature. Fix the boundary
|
|
133
|
+
// scale factor to 0 (preserve boundary edge lengths), solve the interior
|
|
134
|
+
// Poisson L_II u = Ω_I (flatten the interior), then read off the boundary
|
|
135
|
+
// turning k̃_b = (π − θ_b) − (L u)_b. By the (clamped) cot-Laplacian's zero
|
|
136
|
+
// row sums ∑ k̃ = 2π, so the flattened boundary still closes — but the
|
|
137
|
+
// curvature is now distributed by the mesh's harmonic structure rather
|
|
138
|
+
// than uniformly, giving a far less contorted boundary. ───────────────
|
|
139
|
+
const kappa = new Float64Array(n);
|
|
140
|
+
if (m === 0) {
|
|
141
|
+
for (let k = 0; k < n; k++) kappa[k] = Math.PI - angle_sum[loop[k]];
|
|
142
|
+
} else {
|
|
143
|
+
const wmap = new Array(V).fill(null);
|
|
144
|
+
const add_w = (i, j, w) => {
|
|
145
|
+
const M = wmap[i] ?? (wmap[i] = new Map());
|
|
146
|
+
M.set(j, (M.get(j) ?? 0) + w);
|
|
147
|
+
};
|
|
148
|
+
for (let t = 0; t < T; t++) {
|
|
149
|
+
const a = tri[t * 3], b = tri[t * 3 + 1], c = tri[t * 3 + 2];
|
|
150
|
+
const wa = 0.5 * clamped_cot(pos, a, b, c); // opposite edge (b,c)
|
|
151
|
+
const wb = 0.5 * clamped_cot(pos, b, c, a); // opposite edge (c,a)
|
|
152
|
+
const wc = 0.5 * clamped_cot(pos, c, a, b); // opposite edge (a,b)
|
|
153
|
+
add_w(b, c, wa); add_w(c, b, wa);
|
|
154
|
+
add_w(c, a, wb); add_w(a, c, wb);
|
|
155
|
+
add_w(a, b, wc); add_w(b, a, wc);
|
|
156
|
+
}
|
|
157
|
+
// assemble + solve the interior Poisson L_II u = Ω_I
|
|
158
|
+
const diag = new Float64Array(m);
|
|
159
|
+
const adj = [];
|
|
160
|
+
const rhs = new Float64Array(m);
|
|
161
|
+
for (let i = 0; i < m; i++) {
|
|
162
|
+
const vi = vertex_of[i];
|
|
163
|
+
let d = 0;
|
|
164
|
+
const list = [];
|
|
165
|
+
const M = wmap[vi];
|
|
166
|
+
if (M) for (const [j, w] of M) { d += w; if (!is_boundary[j]) list.push(interior[j], w); }
|
|
167
|
+
if (d <= 0) return false; // fully-clamped interior vertex -> not solvable
|
|
168
|
+
diag[i] = d;
|
|
169
|
+
adj.push(list);
|
|
170
|
+
rhs[i] = TWO_PI - angle_sum[vi];
|
|
171
|
+
}
|
|
172
|
+
const apply = (out, vec) => {
|
|
173
|
+
for (let i = 0; i < m; i++) {
|
|
174
|
+
let s = diag[i] * vec[i];
|
|
175
|
+
const list = adj[i];
|
|
176
|
+
for (let k = 0; k < list.length; k += 2) s -= list[k + 1] * vec[list[k]];
|
|
177
|
+
out[i] = s;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
const u = new Float64Array(m);
|
|
181
|
+
cg_solve(u, apply, rhs, m, Math.max(200, 10 * m), 1e-10);
|
|
182
|
+
// k̃_b = (π − θ_b) − (L u)_b, with (L u)_b = −Σ_{interior nbr j} w_bj u_j
|
|
183
|
+
for (let k = 0; k < n; k++) {
|
|
184
|
+
const bv = loop[k];
|
|
185
|
+
let lu_b = 0;
|
|
186
|
+
const M = wmap[bv];
|
|
187
|
+
if (M) for (const [j, w] of M) if (!is_boundary[j]) lu_b -= w * u[interior[j]];
|
|
188
|
+
kappa[k] = (Math.PI - angle_sum[bv]) - lu_b;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// integrate the flattened boundary curve (preserve 3D edge lengths, turn by k̃)
|
|
193
|
+
const bx = new Float64Array(n);
|
|
194
|
+
const by = new Float64Array(n);
|
|
195
|
+
let dir = 0, px = 0, py = 0;
|
|
196
|
+
for (let k = 0; k < n; k++) {
|
|
197
|
+
bx[k] = px;
|
|
198
|
+
by[k] = py;
|
|
199
|
+
const a = loop[k], b = loop[(k + 1) % n];
|
|
200
|
+
const ex = pos[a * 3] - pos[b * 3], ey = pos[a * 3 + 1] - pos[b * 3 + 1], ez = pos[a * 3 + 2] - pos[b * 3 + 2];
|
|
201
|
+
const len = Math.sqrt(ex * ex + ey * ey + ez * ez);
|
|
202
|
+
px += len * Math.cos(dir);
|
|
203
|
+
py += len * Math.sin(dir);
|
|
204
|
+
dir += kappa[(k + 1) % n];
|
|
205
|
+
}
|
|
206
|
+
for (let k = 0; k < n; k++) {
|
|
207
|
+
uv[loop[k] * 2] = bx[k];
|
|
208
|
+
uv[loop[k] * 2 + 1] = by[k];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ── 4. conformal interior extension with the boundary pinned to the BFF
|
|
212
|
+
// curve: least-squares conformal (Cauchy-Riemann) energy over all
|
|
213
|
+
// triangles, every boundary vertex locked, interior free. Couples u,v
|
|
214
|
+
// (unlike harmonic) so it is far less flip-prone on a non-convex
|
|
215
|
+
// boundary. Solved via the matrix-free normal-equations CG. ──────────
|
|
216
|
+
if (m === 0) return true; // boundary-only chart already placed
|
|
217
|
+
|
|
218
|
+
const rows = 2 * T;
|
|
219
|
+
const tr = [];
|
|
220
|
+
const tc = [];
|
|
221
|
+
const tv = [];
|
|
222
|
+
const b = new Float64Array(rows);
|
|
223
|
+
/** Accumulate `coef · (component of vertex)`: pinned → RHS, free → triplet. */
|
|
224
|
+
const add = (row, vtx, comp, coef) => {
|
|
225
|
+
if (is_boundary[vtx]) {
|
|
226
|
+
b[row] -= coef * uv[vtx * 2 + comp];
|
|
227
|
+
} else {
|
|
228
|
+
tr.push(row); tc.push(interior[vtx] * 2 + comp); tv.push(coef);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const local = [0, 0, 0];
|
|
233
|
+
let row = 0;
|
|
234
|
+
for (let t = 0; t < T; t++) {
|
|
235
|
+
const i0 = tri[t * 3], i1 = tri[t * 3 + 1], i2 = tri[t * 3 + 2];
|
|
236
|
+
project_triangle(pos, i0, i1, i2, local);
|
|
237
|
+
const x2 = local[0], x3 = local[1], y3 = local[2];
|
|
238
|
+
const area = 0.5 * x2 * y3;
|
|
239
|
+
if (area <= 1e-20) { row += 2; continue; }
|
|
240
|
+
const w = 1 / Math.sqrt(area);
|
|
241
|
+
const wr = [(x3 - x2) * w, -x3 * w, x2 * w];
|
|
242
|
+
const wi = [y3 * w, -y3 * w, 0];
|
|
243
|
+
const verts = [i0, i1, i2];
|
|
244
|
+
const rr = row, ir = row + 1;
|
|
245
|
+
for (let j = 0; j < 3; j++) {
|
|
246
|
+
const a_j = wr[j], b_j = wi[j], vtx = verts[j];
|
|
247
|
+
add(rr, vtx, 0, a_j); // real: a_j·u
|
|
248
|
+
add(rr, vtx, 1, -b_j); // - b_j·v
|
|
249
|
+
add(ir, vtx, 0, b_j); // imag: b_j·u
|
|
250
|
+
add(ir, vtx, 1, a_j); // + a_j·v
|
|
251
|
+
}
|
|
252
|
+
row += 2;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const A = SparseMatrixCSR.from_triplets(rows, 2 * m, tr, tc, tv, tr.length);
|
|
256
|
+
const sol = new Float64Array(2 * m);
|
|
257
|
+
for (let v = 0; v < V; v++) {
|
|
258
|
+
const ii = interior[v];
|
|
259
|
+
if (ii >= 0) { sol[ii * 2] = uv[v * 2]; sol[ii * 2 + 1] = uv[v * 2 + 1]; } // warm start from prior interior
|
|
260
|
+
}
|
|
261
|
+
const tolerance = options.tolerance ?? 1e-8;
|
|
262
|
+
const max_iterations = options.maxIterations ?? Math.max(200, 20 * m);
|
|
263
|
+
cg_solve_normal_equations(sol, A, b, max_iterations, tolerance);
|
|
264
|
+
|
|
265
|
+
for (let v = 0; v < V; v++) {
|
|
266
|
+
const ii = interior[v];
|
|
267
|
+
if (ii >= 0) { uv[v * 2] = sol[ii * 2]; uv[v * 2 + 1] = sol[ii * 2 + 1]; }
|
|
268
|
+
}
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Least-Squares Conformal Map parameterization (xatlas
|
|
3
|
+
* `computeLeastSquaresConformalMap`). Solves the discrete Cauchy-Riemann
|
|
4
|
+
* (conformal energy) least-squares system with two pinned boundary vertices,
|
|
5
|
+
* via the matrix-free normal-equations CG ({@link cg_solve_normal_equations}).
|
|
6
|
+
*
|
|
7
|
+
* Each triangle is flattened isometrically and contributes one complex equation
|
|
8
|
+
* `Σ_j W_j (u_j + i v_j) = 0` (two real rows), weighted by `1/sqrt(area)`. The
|
|
9
|
+
* two diameter pins are locked to their current (ortho) UVs, anchoring the
|
|
10
|
+
* conformal map's translation/rotation/scale; the rest is warm-started from the
|
|
11
|
+
* ortho layout. Writes the solved UVs into `chart.uv`.
|
|
12
|
+
*
|
|
13
|
+
* @param {Chart} chart from atlas_extract_chart, with `chart.uv` pre-filled by
|
|
14
|
+
* the ortho pass (used for pins + warm start)
|
|
15
|
+
* @param {{tolerance?:number, maxIterations?:number}} [options]
|
|
16
|
+
* @returns {boolean} true if LSCM ran; false if the chart has no boundary
|
|
17
|
+
* (caller should keep ortho or re-segment piecewise)
|
|
18
|
+
*/
|
|
19
|
+
export function atlas_chart_parameterize_lscm(chart: Chart, options?: {
|
|
20
|
+
tolerance?: number;
|
|
21
|
+
maxIterations?: number;
|
|
22
|
+
}): boolean;
|
|
23
|
+
//# sourceMappingURL=atlas_chart_parameterize_lscm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas_chart_parameterize_lscm.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js"],"names":[],"mappings":"AAmFA;;;;;;;;;;;;;;;;;GAiBG;AACH;gBAJuB,MAAM;oBAAiB,MAAM;IACvC,OAAO,CA6HnB"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { cg_solve_normal_equations } from "../../../../math/linalg/cg/cg_solve_normal_equations.js";
|
|
2
|
+
import { SparseMatrixCSR } from "../../../../math/linalg/sparse/SparseMatrixCSR.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Find the two boundary vertices to pin: the extremes along the chart's widest
|
|
6
|
+
* 3D bounding-box axis (xatlas `findApproximateDiameterVertices`). Returns null
|
|
7
|
+
* when the chart has no boundary (LSCM is then not applicable) or the pins are
|
|
8
|
+
* degenerate.
|
|
9
|
+
*
|
|
10
|
+
* @param {Chart} chart
|
|
11
|
+
* @returns {[number, number]|null}
|
|
12
|
+
*/
|
|
13
|
+
function find_diameter_pins(chart) {
|
|
14
|
+
const be = chart.boundary_edges;
|
|
15
|
+
if (be.length === 0) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const is_boundary = new Uint8Array(chart.vertex_count);
|
|
20
|
+
for (let i = 0; i < be.length; i++) {
|
|
21
|
+
is_boundary[be[i]] = 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const min_i = [-1, -1, -1];
|
|
25
|
+
const max_i = [-1, -1, -1];
|
|
26
|
+
const min_v = [Infinity, Infinity, Infinity];
|
|
27
|
+
const max_v = [-Infinity, -Infinity, -Infinity];
|
|
28
|
+
|
|
29
|
+
for (let v = 0; v < chart.vertex_count; v++) {
|
|
30
|
+
if (!is_boundary[v]) continue;
|
|
31
|
+
for (let a = 0; a < 3; a++) {
|
|
32
|
+
const c = chart.positions[v * 3 + a];
|
|
33
|
+
if (c < min_v[a]) { min_v[a] = c; min_i[a] = v; }
|
|
34
|
+
if (c > max_v[a]) { max_v[a] = c; max_i[a] = v; }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let best_axis = 0;
|
|
39
|
+
let best_extent = -1;
|
|
40
|
+
for (let a = 0; a < 3; a++) {
|
|
41
|
+
const ext = max_v[a] - min_v[a];
|
|
42
|
+
if (ext > best_extent) { best_extent = ext; best_axis = a; }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const p0 = min_i[best_axis];
|
|
46
|
+
const p1 = max_i[best_axis];
|
|
47
|
+
if (p0 < 0 || p1 < 0 || p0 === p1) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return [p0, p1];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Flatten a triangle into an isometric local 2D frame: vertex 0 at the origin,
|
|
55
|
+
* vertex 1 along +x. Writes [x2, x3, y3] (x1=y1=y2=0) into `out`.
|
|
56
|
+
*
|
|
57
|
+
* @param {Float64Array} pos packed xyz vertex positions (3 floats per vertex)
|
|
58
|
+
* @param {number} i0 local index of the first triangle vertex (origin)
|
|
59
|
+
* @param {number} i1 local index of the second triangle vertex (along +x)
|
|
60
|
+
* @param {number} i2 local index of the third triangle vertex
|
|
61
|
+
* @param {number[]} out destination [x2, x3, y3]
|
|
62
|
+
* @returns {void}
|
|
63
|
+
*/
|
|
64
|
+
function project_triangle(pos, i0, i1, i2, out) {
|
|
65
|
+
const ax = pos[i0 * 3], ay = pos[i0 * 3 + 1], az = pos[i0 * 3 + 2];
|
|
66
|
+
const bx = pos[i1 * 3], by = pos[i1 * 3 + 1], bz = pos[i1 * 3 + 2];
|
|
67
|
+
const cx = pos[i2 * 3], cy = pos[i2 * 3 + 1], cz = pos[i2 * 3 + 2];
|
|
68
|
+
|
|
69
|
+
const e1x = bx - ax, e1y = by - ay, e1z = bz - az;
|
|
70
|
+
const len1 = Math.sqrt(e1x * e1x + e1y * e1y + e1z * e1z);
|
|
71
|
+
const inv1 = len1 > 0 ? 1 / len1 : 0;
|
|
72
|
+
const ux = e1x * inv1, uy = e1y * inv1, uz = e1z * inv1;
|
|
73
|
+
|
|
74
|
+
const e2x = cx - ax, e2y = cy - ay, e2z = cz - az;
|
|
75
|
+
const x3 = e2x * ux + e2y * uy + e2z * uz;
|
|
76
|
+
const px = e2x - x3 * ux, py = e2y - x3 * uy, pz = e2z - x3 * uz;
|
|
77
|
+
const y3 = Math.sqrt(px * px + py * py + pz * pz);
|
|
78
|
+
|
|
79
|
+
out[0] = len1;
|
|
80
|
+
out[1] = x3;
|
|
81
|
+
out[2] = y3;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Least-Squares Conformal Map parameterization (xatlas
|
|
86
|
+
* `computeLeastSquaresConformalMap`). Solves the discrete Cauchy-Riemann
|
|
87
|
+
* (conformal energy) least-squares system with two pinned boundary vertices,
|
|
88
|
+
* via the matrix-free normal-equations CG ({@link cg_solve_normal_equations}).
|
|
89
|
+
*
|
|
90
|
+
* Each triangle is flattened isometrically and contributes one complex equation
|
|
91
|
+
* `Σ_j W_j (u_j + i v_j) = 0` (two real rows), weighted by `1/sqrt(area)`. The
|
|
92
|
+
* two diameter pins are locked to their current (ortho) UVs, anchoring the
|
|
93
|
+
* conformal map's translation/rotation/scale; the rest is warm-started from the
|
|
94
|
+
* ortho layout. Writes the solved UVs into `chart.uv`.
|
|
95
|
+
*
|
|
96
|
+
* @param {Chart} chart from atlas_extract_chart, with `chart.uv` pre-filled by
|
|
97
|
+
* the ortho pass (used for pins + warm start)
|
|
98
|
+
* @param {{tolerance?:number, maxIterations?:number}} [options]
|
|
99
|
+
* @returns {boolean} true if LSCM ran; false if the chart has no boundary
|
|
100
|
+
* (caller should keep ortho or re-segment piecewise)
|
|
101
|
+
*/
|
|
102
|
+
export function atlas_chart_parameterize_lscm(chart, options = {}) {
|
|
103
|
+
const pins = find_diameter_pins(chart);
|
|
104
|
+
if (pins === null) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const p0 = pins[0];
|
|
109
|
+
const p1 = pins[1];
|
|
110
|
+
const V = chart.vertex_count;
|
|
111
|
+
const T = chart.triangle_count;
|
|
112
|
+
|
|
113
|
+
const pinned = new Uint8Array(2 * V);
|
|
114
|
+
pinned[2 * p0] = 1;
|
|
115
|
+
pinned[2 * p0 + 1] = 1;
|
|
116
|
+
pinned[2 * p1] = 1;
|
|
117
|
+
pinned[2 * p1 + 1] = 1;
|
|
118
|
+
|
|
119
|
+
const col_of = new Int32Array(2 * V).fill(-1);
|
|
120
|
+
let free_cols = 0;
|
|
121
|
+
for (let s = 0; s < 2 * V; s++) {
|
|
122
|
+
if (!pinned[s]) {
|
|
123
|
+
col_of[s] = free_cols++;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const pin_val = chart.uv;
|
|
128
|
+
const rows = 2 * T;
|
|
129
|
+
const tr = [];
|
|
130
|
+
const tc = [];
|
|
131
|
+
const tv = [];
|
|
132
|
+
const b = new Float64Array(rows);
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Accumulate one coefficient into the least-squares system. A pinned scalar
|
|
136
|
+
* moves to the right-hand side `b`; a free scalar becomes a triplet entry.
|
|
137
|
+
*
|
|
138
|
+
* @param {number} row destination row in the 2T-row system
|
|
139
|
+
* @param {number} scalar packed unknown index (2*vertex for u, +1 for v)
|
|
140
|
+
* @param {number} coef coefficient multiplying that scalar
|
|
141
|
+
* @returns {void}
|
|
142
|
+
*/
|
|
143
|
+
function add(row, scalar, coef) {
|
|
144
|
+
if (pinned[scalar]) {
|
|
145
|
+
b[row] -= coef * pin_val[scalar];
|
|
146
|
+
} else {
|
|
147
|
+
tr.push(row);
|
|
148
|
+
tc.push(col_of[scalar]);
|
|
149
|
+
tv.push(coef);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const local = [0, 0, 0];
|
|
154
|
+
let row = 0;
|
|
155
|
+
|
|
156
|
+
for (let t = 0; t < T; t++) {
|
|
157
|
+
const i0 = chart.tri_local[t * 3];
|
|
158
|
+
const i1 = chart.tri_local[t * 3 + 1];
|
|
159
|
+
const i2 = chart.tri_local[t * 3 + 2];
|
|
160
|
+
|
|
161
|
+
project_triangle(chart.positions, i0, i1, i2, local);
|
|
162
|
+
const x2 = local[0];
|
|
163
|
+
const x3 = local[1];
|
|
164
|
+
const y3 = local[2];
|
|
165
|
+
|
|
166
|
+
const area = 0.5 * x2 * y3;
|
|
167
|
+
if (area <= 1e-20) {
|
|
168
|
+
// degenerate triangle contributes nothing; leave the two rows zero
|
|
169
|
+
row += 2;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const w = 1 / Math.sqrt(area);
|
|
174
|
+
|
|
175
|
+
// W1 = p3 - p2, W2 = p1 - p3, W3 = p2 - p1 (complex, local coords)
|
|
176
|
+
const w1r = (x3 - x2) * w, w1i = y3 * w;
|
|
177
|
+
const w2r = -x3 * w, w2i = -y3 * w;
|
|
178
|
+
const w3r = x2 * w, w3i = 0;
|
|
179
|
+
|
|
180
|
+
const verts = [i0, i1, i2];
|
|
181
|
+
const wr = [w1r, w2r, w3r];
|
|
182
|
+
const wi = [w1i, w2i, w3i];
|
|
183
|
+
|
|
184
|
+
const real_row = row;
|
|
185
|
+
const imag_row = row + 1;
|
|
186
|
+
|
|
187
|
+
for (let j = 0; j < 3; j++) {
|
|
188
|
+
const a_j = wr[j];
|
|
189
|
+
const b_j = wi[j];
|
|
190
|
+
const su = 2 * verts[j];
|
|
191
|
+
const sv = 2 * verts[j] + 1;
|
|
192
|
+
|
|
193
|
+
// real part: a_j*u_j - b_j*v_j
|
|
194
|
+
add(real_row, su, a_j);
|
|
195
|
+
add(real_row, sv, -b_j);
|
|
196
|
+
// imaginary part: b_j*u_j + a_j*v_j
|
|
197
|
+
add(imag_row, su, b_j);
|
|
198
|
+
add(imag_row, sv, a_j);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
row += 2;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const A = SparseMatrixCSR.from_triplets(rows, free_cols, tr, tc, tv, tr.length);
|
|
205
|
+
|
|
206
|
+
const x = new Float64Array(free_cols);
|
|
207
|
+
for (let s = 0; s < 2 * V; s++) {
|
|
208
|
+
if (col_of[s] >= 0) {
|
|
209
|
+
x[col_of[s]] = chart.uv[s];
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const tolerance = options.tolerance ?? 1e-8;
|
|
214
|
+
const max_iterations = options.maxIterations ?? Math.max(200, 10 * free_cols);
|
|
215
|
+
cg_solve_normal_equations(x, A, b, max_iterations, tolerance);
|
|
216
|
+
|
|
217
|
+
for (let s = 0; s < 2 * V; s++) {
|
|
218
|
+
if (col_of[s] >= 0) {
|
|
219
|
+
chart.uv[s] = x[col_of[s]];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orthographic chart parameterization (xatlas Ortho/Planar path): fit the
|
|
3
|
+
* chart's proxy plane, then project every vertex onto it —
|
|
4
|
+
* `uv = (dot(tangent, p), dot(bitangent, p))`. Exact and isometric for a planar
|
|
5
|
+
* chart; for a non-planar chart this is the cheap first attempt whose quality
|
|
6
|
+
* the validity gate / stretch metric then accepts or rejects in favour of LSCM.
|
|
7
|
+
*
|
|
8
|
+
* Writes `chart.uv` in place.
|
|
9
|
+
*
|
|
10
|
+
* @param {Chart} chart
|
|
11
|
+
* @returns {Float64Array} the fitted 9-float basis (tangent, bitangent, normal)
|
|
12
|
+
*/
|
|
13
|
+
export function atlas_chart_parameterize_ortho(chart: Chart): Float64Array;
|
|
14
|
+
//# sourceMappingURL=atlas_chart_parameterize_ortho.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas_chart_parameterize_ortho.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,8DAFa,YAAY,CAwBxB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { v3_dot } from "../../../vec3/v3_dot.js";
|
|
2
|
+
import { ATLAS_BASIS_BITANGENT, ATLAS_BASIS_TANGENT, fit_plane_basis } from "./fit_plane_basis.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Orthographic chart parameterization (xatlas Ortho/Planar path): fit the
|
|
6
|
+
* chart's proxy plane, then project every vertex onto it —
|
|
7
|
+
* `uv = (dot(tangent, p), dot(bitangent, p))`. Exact and isometric for a planar
|
|
8
|
+
* chart; for a non-planar chart this is the cheap first attempt whose quality
|
|
9
|
+
* the validity gate / stretch metric then accepts or rejects in favour of LSCM.
|
|
10
|
+
*
|
|
11
|
+
* Writes `chart.uv` in place.
|
|
12
|
+
*
|
|
13
|
+
* @param {Chart} chart
|
|
14
|
+
* @returns {Float64Array} the fitted 9-float basis (tangent, bitangent, normal)
|
|
15
|
+
*/
|
|
16
|
+
export function atlas_chart_parameterize_ortho(chart) {
|
|
17
|
+
const basis = new Float64Array(9);
|
|
18
|
+
fit_plane_basis(basis, chart.positions, chart.vertex_count);
|
|
19
|
+
|
|
20
|
+
const tx = basis[ATLAS_BASIS_TANGENT];
|
|
21
|
+
const ty = basis[ATLAS_BASIS_TANGENT + 1];
|
|
22
|
+
const tz = basis[ATLAS_BASIS_TANGENT + 2];
|
|
23
|
+
const bx = basis[ATLAS_BASIS_BITANGENT];
|
|
24
|
+
const by = basis[ATLAS_BASIS_BITANGENT + 1];
|
|
25
|
+
const bz = basis[ATLAS_BASIS_BITANGENT + 2];
|
|
26
|
+
|
|
27
|
+
const pos = chart.positions;
|
|
28
|
+
const uv = chart.uv;
|
|
29
|
+
for (let i = 0; i < chart.vertex_count; i++) {
|
|
30
|
+
const px = pos[i * 3];
|
|
31
|
+
const py = pos[i * 3 + 1];
|
|
32
|
+
const pz = pos[i * 3 + 2];
|
|
33
|
+
uv[i * 2] = v3_dot(tx, ty, tz, px, py, pz);
|
|
34
|
+
uv[i * 2 + 1] = v3_dot(bx, by, bz, px, py, pz);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return basis;
|
|
38
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sander/Hoppe texture-stretch metric of a chart's UV map (xatlas
|
|
3
|
+
* `computeMetrics`). For each triangle it forms the parameterization gradients
|
|
4
|
+
* Ss = dq/du, St = dq/dv, whose first fundamental form `[[a,b],[b,c]]` has
|
|
5
|
+
* singular values Gamma_max, Gamma_min. The per-triangle L2 stretch is
|
|
6
|
+
* `(Gamma_max^2 + Gamma_min^2)/2 = (a + c)/2`.
|
|
7
|
+
*
|
|
8
|
+
* Results are normalized by the chart's global UV-to-3D linear scale, so a
|
|
9
|
+
* pure isometry OR any uniform similarity returns exactly 1; non-uniform
|
|
10
|
+
* distortion returns > 1. `mean_stretch` is the area-weighted RMS;
|
|
11
|
+
* `max_stretch` is the worst per-triangle Gamma_max.
|
|
12
|
+
*
|
|
13
|
+
* @param {Chart} chart
|
|
14
|
+
* @returns {{mean_stretch:number, max_stretch:number, geom_area:number, param_area:number}}
|
|
15
|
+
*/
|
|
16
|
+
export function atlas_chart_stretch_metric(chart: Chart): {
|
|
17
|
+
mean_stretch: number;
|
|
18
|
+
max_stretch: number;
|
|
19
|
+
geom_area: number;
|
|
20
|
+
param_area: number;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=atlas_chart_stretch_metric.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas_chart_stretch_metric.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,0DAFa;IAAC,YAAY,EAAC,MAAM,CAAC;IAAC,WAAW,EAAC,MAAM,CAAC;IAAC,SAAS,EAAC,MAAM,CAAC;IAAC,UAAU,EAAC,MAAM,CAAA;CAAC,CAsE1F"}
|