@woosh/meep-engine 3.29.0 → 3.30.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-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +14 -2
- package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BVH.js +14 -1
- package/src/core/cache/FrequencySketch.d.ts +3 -1
- package/src/core/cache/FrequencySketch.d.ts.map +1 -1
- package/src/core/cache/FrequencySketch.js +10 -4
- package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -1
- package/src/core/cache/wtinylfu/CacheWTinylfu.js +24 -2
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts +20 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +69 -4
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +48 -18
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +262 -70
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts +25 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +228 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts +13 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js +10 -128
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +11 -1
- package/src/core/graph/mn_graph_collapse_weighted_edge.js +6 -6
- package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
- package/src/core/math/lookup/ParameterLookupTable.js +10 -5
- package/src/core/math/noise/sdnoise.d.ts.map +1 -1
- package/src/core/math/noise/sdnoise.js +16 -10
- package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
- package/src/core/model/object/ImmutableObjectPool.js +17 -7
- package/src/core/process/executor/ConcurrentExecutor.d.ts +1 -5
- package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
- package/src/core/process/executor/ConcurrentExecutor.js +95 -1
- package/src/core/process/task/task_find_dependency_cycle.d.ts +17 -0
- package/src/core/process/task/task_find_dependency_cycle.d.ts.map +1 -0
- package/src/core/process/task/task_find_dependency_cycle.js +81 -0
- package/src/core/wfc/WFCCellChoice.d.ts +17 -0
- package/src/core/wfc/WFCCellChoice.d.ts.map +1 -0
- package/src/core/wfc/WFCCellChoice.js +36 -0
- package/src/core/wfc/WFCLattice.d.ts +105 -0
- package/src/core/wfc/WFCLattice.d.ts.map +1 -0
- package/src/core/wfc/WFCLattice.js +235 -0
- package/src/core/wfc/WFCRuleTable.d.ts +172 -0
- package/src/core/wfc/WFCRuleTable.d.ts.map +1 -0
- package/src/core/wfc/WFCRuleTable.js +334 -0
- package/src/core/wfc/WFCState.d.ts +273 -0
- package/src/core/wfc/WFCState.d.ts.map +1 -0
- package/src/core/wfc/WFCState.js +552 -0
- package/src/core/wfc/WFCStatus.d.ts +11 -0
- package/src/core/wfc/WFCStatus.d.ts.map +1 -0
- package/src/core/wfc/WFCStatus.js +28 -0
- package/src/core/wfc/WFCTileWeights.d.ts +48 -0
- package/src/core/wfc/WFCTileWeights.d.ts.map +1 -0
- package/src/core/wfc/WFCTileWeights.js +86 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts +12 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts.map +1 -0
- package/src/core/wfc/WFC_UNRESOLVED.js +11 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts +24 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts.map +1 -0
- package/src/core/wfc/wfc_estimate_bytes.js +47 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts +27 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts.map +1 -0
- package/src/core/wfc/wfc_rule_table_tile_components.js +80 -0
- package/src/core/wfc/wfc_solve.d.ts +21 -0
- package/src/core/wfc/wfc_solve.d.ts.map +1 -0
- package/src/core/wfc/wfc_solve.js +154 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts +18 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_apply_boundary.js +61 -0
- package/src/core/wfc/wfc_state_assign.d.ts +11 -0
- package/src/core/wfc/wfc_state_assign.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_assign.js +36 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts +17 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_ban_bits.js +81 -0
- package/src/core/wfc/wfc_state_collapse.d.ts +12 -0
- package/src/core/wfc/wfc_state_collapse.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_collapse.js +73 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts +12 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_flush_dirty.js +39 -0
- package/src/core/wfc/wfc_state_propagate.d.ts +14 -0
- package/src/core/wfc/wfc_state_propagate.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_propagate.js +155 -0
- package/src/core/wfc/wfc_state_read.d.ts +11 -0
- package/src/core/wfc/wfc_state_read.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_read.js +38 -0
- package/src/core/wfc/wfc_state_restrict.d.ts +18 -0
- package/src/core/wfc/wfc_state_restrict.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_restrict.js +39 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts +24 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_set_eligible.js +49 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts +13 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_undo_to.js +84 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts +11 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts.map +1 -0
- package/src/core/wfc/wfc_words_per_cell.js +16 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts +8 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +37 -14
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +8 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +37 -2
- package/src/engine/ecs/guid/UUID.d.ts.map +1 -1
- package/src/engine/ecs/guid/UUID.js +45 -17
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +1 -1
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +3 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +366 -360
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +24 -10
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +24 -5
- package/src/engine/interpolation/Interpoland.d.ts +7 -1
- package/src/engine/interpolation/Interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/Interpoland.js +8 -1
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationSystem.js +3 -0
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +5 -3
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
- package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -3
- package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/pose_interpoland.js +2 -0
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +15 -10
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +17 -0
- package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
- package/src/engine/physics/mls-mpm/MLS_MPM.js +14 -0
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +1 -1
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +12 -3
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.js +4 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.d.ts.map +1 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.js +248 -259
- package/src/format/image/avif/av1/decode/read_golomb.d.ts +21 -0
- package/src/format/image/avif/av1/decode/read_golomb.d.ts.map +1 -0
- package/src/format/image/avif/av1/decode/read_golomb.js +49 -0
- package/src/format/image/avif/av1/filter/loop_restoration.js +461 -451
- package/src/format/image/avif/av1/util/round2.d.ts +19 -2
- package/src/format/image/avif/av1/util/round2.d.ts.map +1 -1
- package/src/format/image/avif/av1/util/round2.js +51 -27
- package/src/format/image/avif/heif/parse_avif_file.js +24 -0
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +14 -0
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +46 -3
- package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +91 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +0 -13
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +0 -15
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +5 -5
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +18 -9
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +20 -26
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +1 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +2 -5
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +14 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +12 -3
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.js +7 -1
- package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/GPULightMap.js +349 -336
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/load_gltf.js +1137 -1128
- package/src/shade/renderer/particles/DESIGN.md +14 -5
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +25 -10
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +182 -38
- package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/simplex_reference.js +16 -10
- package/src/shade/renderer/particles/graph_particles.d.ts +4 -2
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +8 -2
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +8 -2
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -4
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +31 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +62 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +13 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +95 -17
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +21 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +28 -0
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +19 -2
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +19 -2
- package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUStruct.js +12 -0
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts +8 -2
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +41 -6
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2383 -2356
- package/src/view/tooltip/DomTooltipManager.d.ts +7 -0
- package/src/view/tooltip/DomTooltipManager.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipManager.js +22 -0
- package/src/view/tooltip/DomTooltipObserver.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipObserver.js +13 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +0 -45
|
@@ -9,6 +9,7 @@ import { quadric_attribute_reduce } from "../../../../quadric/quadric_attribute_
|
|
|
9
9
|
import { quadric_attribute_size } from "../../../../quadric/quadric_attribute_size.js";
|
|
10
10
|
import { quadric_attribute_solve } from "../../../../quadric/quadric_attribute_solve.js";
|
|
11
11
|
import { NULL_POINTER } from "../BinaryTopology.js";
|
|
12
|
+
import { bt_edge_collapse_fold_limit } from "../query/bt_edge_collapse_fold_limit.js";
|
|
12
13
|
import { bt_edge_collapse_would_fold } from "../query/bt_edge_collapse_would_fold.js";
|
|
13
14
|
import { bt_loop_kill } from "./bt_loop_kill.js";
|
|
14
15
|
import { bt_mesh_compute_vertex_quadrics } from "./bt_mesh_compute_vertex_quadrics.js";
|
|
@@ -24,6 +25,28 @@ const scratch_coord_a = new Float32Array(3);
|
|
|
24
25
|
const scratch_coord_b = new Float32Array(3);
|
|
25
26
|
const scratch_target = new Float32Array(3);
|
|
26
27
|
const scratch_combined_q = new Quadric3();
|
|
28
|
+
const scratch_anchor = new Float32Array(3);
|
|
29
|
+
const scratch_candidate = new Float32Array(3);
|
|
30
|
+
const scratch_placement = new Float32Array(3);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* How much of the way to the fold limit a constrained placement is allowed to travel.
|
|
34
|
+
*
|
|
35
|
+
* The limit itself is where a surviving triangle reaches *zero* area, which is refused along with an
|
|
36
|
+
* outright flip and for the same reason: a zero-area triangle has no normal, so the quadrics built
|
|
37
|
+
* from it afterwards are meaningless and every later collapse around it is priced off nothing. So
|
|
38
|
+
* stopping short of the limit is a statement about the mesh rather than about arithmetic.
|
|
39
|
+
*
|
|
40
|
+
* Half, because the feasible interval along the segment is `[0, limit)` and its midpoint is the
|
|
41
|
+
* placement furthest from both ends of it — from the anchor, which is the placement this was trying
|
|
42
|
+
* to improve on, and from the degeneracy. Nothing is given up by stopping there: swept against 0.9
|
|
43
|
+
* and 0.99 over Zorah's 479k-triangle `mesh0[0]`, all three build the *same* 34 levels to the *same*
|
|
44
|
+
* root error of `1.0445e+3`, and differ only in cluster count, by 0.3% and in no particular
|
|
45
|
+
* direction (11,511 / 11,498 / 11,532). The choice is free on everything that was measured, so it
|
|
46
|
+
* goes to the end that cannot produce a sliver.
|
|
47
|
+
* @type {number}
|
|
48
|
+
*/
|
|
49
|
+
const FOLD_LIMIT_TRAVEL = 0.5;
|
|
27
50
|
|
|
28
51
|
/**
|
|
29
52
|
* The pair's summed attribute quadric, and its reduction. Grown to whatever channel count the
|
|
@@ -104,6 +127,143 @@ function count_edge_faces(mesh, edge_id) {
|
|
|
104
127
|
return count;
|
|
105
128
|
}
|
|
106
129
|
|
|
130
|
+
/**
|
|
131
|
+
* What a collapse of this pair costs with its surviving vertex at `(x, y, z)`.
|
|
132
|
+
*
|
|
133
|
+
* The two geometric quadrics say how far the placement is from the surface the pair was cut out of;
|
|
134
|
+
* the reduced attribute quadric, when there is one, says what the channels still cost once each has
|
|
135
|
+
* been given its best value there — in units of length, because the weights put them there.
|
|
136
|
+
*
|
|
137
|
+
* It is exactly the function the placement minimizes — quadric evaluation is linear in the quadric,
|
|
138
|
+
* so the sum `optimize` was handed evaluates to the sum of the two terms below — which is why
|
|
139
|
+
* constraining the placement can only ever raise this, never lower it. Read at the placement
|
|
140
|
+
* actually chosen, so the queue's order is a statement about the collapses that will happen rather
|
|
141
|
+
* than about ones that will not.
|
|
142
|
+
*
|
|
143
|
+
* @param {Quadric3} q1
|
|
144
|
+
* @param {Quadric3} q2
|
|
145
|
+
* @param {boolean} has_attributes whether {@link scratch_attribute_reduced} holds this pair's
|
|
146
|
+
* @param {number} x
|
|
147
|
+
* @param {number} y
|
|
148
|
+
* @param {number} z
|
|
149
|
+
* @returns {number}
|
|
150
|
+
*/
|
|
151
|
+
function placement_cost(q1, q2, has_attributes, x, y, z) {
|
|
152
|
+
// Cost can drift slightly negative for near-zero values due to fp noise.
|
|
153
|
+
const geometric = Math.abs(q1.evaluate(x, y, z) + q2.evaluate(x, y, z));
|
|
154
|
+
|
|
155
|
+
if (!has_attributes) {
|
|
156
|
+
return geometric;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return geometric + Math.abs(quadric3_evaluate(scratch_attribute_reduced, 0, x, y, z));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Move `out_target` to the cheapest placement near it that turns no surviving triangle over, or
|
|
164
|
+
* report that the pair has none.
|
|
165
|
+
*
|
|
166
|
+
* **A placement that folds is not an impossible collapse, and this is where the two stop being
|
|
167
|
+
* conflated.** What the quadric hands back is the unconstrained minimum of a convex cost. Keeping
|
|
168
|
+
* every surviving triangle facing the way it did is a *constraint* on that minimum — a linear one,
|
|
169
|
+
* as {@link bt_edge_collapse_fold_limit} derives, so the placements that satisfy it are a convex set
|
|
170
|
+
* and the constrained minimum is the thing this should be choosing. Testing the unconstrained
|
|
171
|
+
* answer and abandoning the collapse when it fails is the classic way of getting that wrong, and it
|
|
172
|
+
* is expensive: measured over one 479k-triangle Zorah primitive, 12% to 15% of every candidate
|
|
173
|
+
* collapse scored was discarded that way — and it is not a tail, it is the whole build, which is how
|
|
174
|
+
* a level of the DAG that could still have been halved came to be reported as having no coarser
|
|
175
|
+
* form at all.
|
|
176
|
+
*
|
|
177
|
+
* The constrained minimum lies on the boundary whenever the unconstrained one is outside, and the
|
|
178
|
+
* boundary is reached along a segment: the cost is convex with its minimum at `out_target`, so along
|
|
179
|
+
* a segment ending there it falls monotonically, and the best placement on that segment is simply
|
|
180
|
+
* the furthest one the fold limit allows. That makes this exact in one dimension rather than a
|
|
181
|
+
* search — what is heuristic is only the choice of where to measure *from*.
|
|
182
|
+
*
|
|
183
|
+
* Three anchors, and they are the three points the surface already passes through: either endpoint,
|
|
184
|
+
* or the middle of the edge. An anchor that folds on its own is no anchor and is skipped; when all
|
|
185
|
+
* three do, the pair really has nothing this can offer and the collapse is refused.
|
|
186
|
+
*
|
|
187
|
+
* @param {BinaryTopology} mesh
|
|
188
|
+
* @param {number} v1
|
|
189
|
+
* @param {number} v2
|
|
190
|
+
* @param {Quadric3} q1
|
|
191
|
+
* @param {Quadric3} q2
|
|
192
|
+
* @param {boolean} has_attributes
|
|
193
|
+
* @param {Float32Array|number[]} out_target the wanted placement, replaced by the chosen one
|
|
194
|
+
* @returns {boolean} `false` when every anchor folds, and the collapse has no placement at all
|
|
195
|
+
*/
|
|
196
|
+
function constrain_placement(mesh, v1, v2, q1, q2, has_attributes, out_target) {
|
|
197
|
+
if (!bt_edge_collapse_would_fold(mesh, v1, v2, out_target)) {
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
mesh.vertex_read_coordinate(scratch_coord_a, 0, v1);
|
|
202
|
+
mesh.vertex_read_coordinate(scratch_coord_b, 0, v2);
|
|
203
|
+
|
|
204
|
+
// Tracked separately rather than read off `best`, which cannot say the difference between "no
|
|
205
|
+
// anchor held" and "one did, at a price that overflowed" — a quadric carrying the planes of a
|
|
206
|
+
// few hundred thousand source triangles is not far off it.
|
|
207
|
+
let placed = false;
|
|
208
|
+
|
|
209
|
+
let best = Number.POSITIVE_INFINITY;
|
|
210
|
+
|
|
211
|
+
for (let anchor = 0; anchor < 3; anchor++) {
|
|
212
|
+
if (anchor === 0) {
|
|
213
|
+
scratch_anchor.set(scratch_coord_a);
|
|
214
|
+
} else if (anchor === 1) {
|
|
215
|
+
scratch_anchor.set(scratch_coord_b);
|
|
216
|
+
} else {
|
|
217
|
+
scratch_anchor[0] = (scratch_coord_a[0] + scratch_coord_b[0]) * 0.5;
|
|
218
|
+
scratch_anchor[1] = (scratch_coord_a[1] + scratch_coord_b[1]) * 0.5;
|
|
219
|
+
scratch_anchor[2] = (scratch_coord_a[2] + scratch_coord_b[2]) * 0.5;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const limit = bt_edge_collapse_fold_limit(mesh, v1, v2, scratch_anchor, out_target);
|
|
223
|
+
|
|
224
|
+
if (limit < 0) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const travel = limit * FOLD_LIMIT_TRAVEL;
|
|
229
|
+
|
|
230
|
+
scratch_candidate[0] = scratch_anchor[0] + (out_target[0] - scratch_anchor[0]) * travel;
|
|
231
|
+
scratch_candidate[1] = scratch_anchor[1] + (out_target[1] - scratch_anchor[1]) * travel;
|
|
232
|
+
scratch_candidate[2] = scratch_anchor[2] + (out_target[2] - scratch_anchor[2]) * travel;
|
|
233
|
+
|
|
234
|
+
if (bt_edge_collapse_would_fold(mesh, v1, v2, scratch_candidate)) {
|
|
235
|
+
/*
|
|
236
|
+
The limit is exact in real arithmetic and this is not real arithmetic: a fan whose
|
|
237
|
+
triangles are already slivers can put the crossing and the anchor within a few ulps of
|
|
238
|
+
each other, and half of nothing is still nothing. The anchor is feasible by
|
|
239
|
+
construction, so fall back to it rather than to a search for how much less to travel.
|
|
240
|
+
*/
|
|
241
|
+
scratch_candidate.set(scratch_anchor);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const cost = placement_cost(
|
|
245
|
+
q1, q2, has_attributes,
|
|
246
|
+
scratch_candidate[0], scratch_candidate[1], scratch_candidate[2]
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
if (!placed || cost < best) {
|
|
250
|
+
placed = true;
|
|
251
|
+
best = cost;
|
|
252
|
+
scratch_placement.set(scratch_candidate);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (!placed) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
out_target[0] = scratch_placement[0];
|
|
261
|
+
out_target[1] = scratch_placement[1];
|
|
262
|
+
out_target[2] = scratch_placement[2];
|
|
263
|
+
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
|
|
107
267
|
/**
|
|
108
268
|
* Evaluate a potential edge collapse: choose the optimal surviving vertex position
|
|
109
269
|
* and return the quadric-based cost. Returns Infinity if the edge cannot be collapsed.
|
|
@@ -116,7 +276,9 @@ function count_edge_faces(mesh, edge_id) {
|
|
|
116
276
|
* attributes the channels the collapse carries, or `null` to carry none
|
|
117
277
|
* @param {BtWedgeSet|null} wedges which corners of each vertex shade as one
|
|
118
278
|
* @param {Float32Array|number[]} out_target Target position is written here.
|
|
119
|
-
* @returns {number}
|
|
279
|
+
* @returns {number} the price at the placement written, which is the placement the collapse would
|
|
280
|
+
* actually use — so the queue this feeds is ordered on what the collapses cost rather than on
|
|
281
|
+
* what they would have cost somewhere they are not allowed to go
|
|
120
282
|
*/
|
|
121
283
|
function evaluate_edge_collapse(
|
|
122
284
|
mesh, edge_id, quadratics, restricted_vertices, attributes, wedges, out_target
|
|
@@ -146,9 +308,9 @@ function evaluate_edge_collapse(
|
|
|
146
308
|
return Number.POSITIVE_INFINITY;
|
|
147
309
|
}
|
|
148
310
|
|
|
149
|
-
|
|
311
|
+
const has_attributes = attributes !== null;
|
|
150
312
|
|
|
151
|
-
if (
|
|
313
|
+
if (has_attributes) {
|
|
152
314
|
reduce_pair_attributes(mesh, v1, v2, attributes, wedges, scratch_attribute_reduced);
|
|
153
315
|
}
|
|
154
316
|
|
|
@@ -160,7 +322,7 @@ function evaluate_edge_collapse(
|
|
|
160
322
|
scratch_combined_q.copy(q1);
|
|
161
323
|
scratch_combined_q.add(q2);
|
|
162
324
|
|
|
163
|
-
if (
|
|
325
|
+
if (has_attributes) {
|
|
164
326
|
/*
|
|
165
327
|
The channels decide where the vertex goes, and this is where they do it. `A` and `b` of
|
|
166
328
|
the reduced attribute quadric are what is left of them after the exact solve for their
|
|
@@ -187,24 +349,34 @@ function evaluate_edge_collapse(
|
|
|
187
349
|
}
|
|
188
350
|
}
|
|
189
351
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
352
|
+
if (v1_restricted || v2_restricted) {
|
|
353
|
+
/*
|
|
354
|
+
A pin takes the placement with it, so there is no segment to slide along and a fold here is
|
|
355
|
+
final. Refused with the price rather than by the caller, so the queue never holds an edge
|
|
356
|
+
whose cost describes a collapse that will not be performed.
|
|
357
|
+
*/
|
|
358
|
+
if (bt_edge_collapse_would_fold(mesh, v1, v2, out_target)) {
|
|
359
|
+
return Number.POSITIVE_INFINITY;
|
|
360
|
+
}
|
|
361
|
+
} else if (!constrain_placement(mesh, v1, v2, q1, q2, has_attributes, out_target)) {
|
|
362
|
+
return Number.POSITIVE_INFINITY;
|
|
198
363
|
}
|
|
199
364
|
|
|
200
|
-
|
|
201
|
-
|
|
365
|
+
return placement_cost(
|
|
366
|
+
q1, q2, has_attributes, out_target[0], out_target[1], out_target[2]
|
|
367
|
+
);
|
|
202
368
|
}
|
|
203
369
|
|
|
204
370
|
/**
|
|
205
371
|
* Re-score every edge in the disk cycle of `survivor` that is currently in the heap.
|
|
206
372
|
* Edges that were never inserted (e.g. both endpoints restricted) are left untouched.
|
|
207
373
|
*
|
|
374
|
+
* Left untouched including the ones that were left out because they had no placement at the time,
|
|
375
|
+
* which is a real limit and a deliberate one: an edge is excluded when *both* its fans leave it
|
|
376
|
+
* nowhere to go, and a collapse one edge away is unlikely to change that. Re-admitting them here was
|
|
377
|
+
* built and measured — it moved a 479k-triangle Zorah primitive from 34 levels to 33, and cost 60%
|
|
378
|
+
* of the build time to do it.
|
|
379
|
+
*
|
|
208
380
|
* @param {BinaryTopology} mesh
|
|
209
381
|
* @param {number} survivor
|
|
210
382
|
* @param {Quadric3[]} quadratics
|
|
@@ -818,9 +990,24 @@ function collapse_kills_protected_face(mesh, edge_id, protected_faces) {
|
|
|
818
990
|
* removed. If the target cannot be reached (e.g. too many restricted vertices),
|
|
819
991
|
* simplification stops early without failing.
|
|
820
992
|
*
|
|
821
|
-
*
|
|
822
|
-
*
|
|
823
|
-
*
|
|
993
|
+
* No collapse ever turns a surviving triangle inside out, and the quadric cannot help with that: it
|
|
994
|
+
* cannot see a fold at all, because a flat region scores zero for every placement in its plane. So
|
|
995
|
+
* the placement is *constrained* rather than merely checked. Where the quadric's own answer folds,
|
|
996
|
+
* the collapse is re-placed at the best point that does not — see {@link constrain_placement}, and
|
|
997
|
+
* {@link bt_edge_collapse_fold_limit} for why that point can be found exactly instead of hunted for.
|
|
998
|
+
* A collapse is refused only when the pair has no such placement anywhere, which is a statement
|
|
999
|
+
* about the geometry rather than about the quadric's preference.
|
|
1000
|
+
*
|
|
1001
|
+
* Every edge is priced at the placement it would actually use, including the constrained ones, and
|
|
1002
|
+
* the queue is ordered on that. It is the expensive way round — the constraint costs a walk of both
|
|
1003
|
+
* the pair's fans, and pricing happens once per edge at the start and again for every neighbour of
|
|
1004
|
+
* every collapse, which measures at 1.4x to 2.5x the build time of the alternative. The alternative
|
|
1005
|
+
* is to order on the unconstrained price, which is a genuine lower bound ({@link placement_cost}),
|
|
1006
|
+
* and settle only on the way out of the queue. That was built and measured, and it is not here: the
|
|
1007
|
+
* greedy order it produces is approximate, and on a pinwheel whose whole rim is pinned it stopped at
|
|
1008
|
+
* 28 faces against a target of 21 — which is precisely the shape a vgeo group step hands this, since
|
|
1009
|
+
* such a step pins its entire outer boundary. A cheaper order that cannot finish a pinned
|
|
1010
|
+
* simplification is no bargain.
|
|
824
1011
|
*
|
|
825
1012
|
* **Topology is not preserved**, and cannot be here. The other standard guard, the *link condition*
|
|
826
1013
|
* ({@link bt_edge_collapse_breaks_link_condition}), refuses collapses that weld together two parts
|
|
@@ -836,21 +1023,36 @@ function collapse_kills_protected_face(mesh, edge_id, protected_faces) {
|
|
|
836
1023
|
* At the end of the call the mesh is cleaned up so that no dangling loops, edges,
|
|
837
1024
|
* or vertices remain in the topology.
|
|
838
1025
|
*
|
|
839
|
-
* The return value is the **object-space distance** the surface moved: the largest
|
|
840
|
-
*
|
|
841
|
-
*
|
|
842
|
-
*
|
|
1026
|
+
* The return value is the **object-space distance** the surface moved: the largest reading taken at
|
|
1027
|
+
* any collapse the call performed, a collapse being read by evaluating *each* of its two endpoints'
|
|
1028
|
+
* accumulated quadrics at the placement the survivor is about to take, each normalized by its own
|
|
1029
|
+
* weight. Because a survivor inherits its victim's quadric, every such reading is a deviation from
|
|
1030
|
+
* the mesh as it stood when the call began — not merely from the step before.
|
|
1031
|
+
*
|
|
1032
|
+
* **At the collapses, and per endpoint, and both of those are what keep it from diluting.** The
|
|
1033
|
+
* weight is what makes the value a length ({@link Quadric3#distance}) and it is also a divisor that
|
|
1034
|
+
* grows every time a vertex absorbs another. A vertex that flattens a spike and then spends the rest
|
|
1035
|
+
* of the call swallowing the plane around it ends up standing mostly for planes it sits exactly on,
|
|
1036
|
+
* and a single reading taken at the end divides the spike it destroyed by all of them — measured on
|
|
1037
|
+
* a unit spike at the centre of a pinned grid, the same spike came back at 0.64 on a 7-vertex grid
|
|
1038
|
+
* and at 0.040 on a 33-vertex one, which is the reported error falling as the surface grows.
|
|
1039
|
+
* Reading at every collapse catches the spike while the quadric is still mostly about it. Reading
|
|
1040
|
+
* the two endpoints apart rather than summed stops a small victim's residual being averaged into a
|
|
1041
|
+
* large survivor's untouched history, which is that same dilution one collapse at a time.
|
|
843
1042
|
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
*
|
|
847
|
-
*
|
|
848
|
-
*
|
|
849
|
-
*
|
|
1043
|
+
* Nothing is given up by no longer scanning the survivors, and it is a domination rather than a
|
|
1044
|
+
* coincidence. What the scan would read off a survivor is its *merged* quadric at the placement its
|
|
1045
|
+
* last collapse chose — and a merged quadric's reading is the weight-weighted mean of its two parts'
|
|
1046
|
+
* readings at that same point, so it can never exceed the larger of the two this already took there.
|
|
1047
|
+
* Every value the scan could report is therefore one this maximum has seen or beaten, and the
|
|
1048
|
+
* maximum holds the earlier and sharper readings besides. A patch consumed entirely, which leaves
|
|
1049
|
+
* behind a faceless vertex that the cleanup then sweeps, is read at the collapse that consumed it
|
|
1050
|
+
* instead of in the window between the last collapse and the sweep.
|
|
850
1051
|
*
|
|
851
|
-
*
|
|
852
|
-
*
|
|
853
|
-
*
|
|
1052
|
+
* So what comes back is what *this call's* collapses cost. A caller carrying quadrics across calls
|
|
1053
|
+
* through {@link bt_mesh_simplify_with_quadrics} carries the maximum across them too — and the
|
|
1054
|
+
* deviation a vertex arrives already carrying is, by construction, a reading that the call which
|
|
1055
|
+
* placed it there has already returned.
|
|
854
1056
|
*
|
|
855
1057
|
* `protected_faces` names faces that must still be there when the call returns. Pinning vertices
|
|
856
1058
|
* does not by itself protect the *edges* between them: a collapse elsewhere in the fan can take away
|
|
@@ -974,6 +1176,14 @@ export function bt_mesh_simplify_with_quadrics(
|
|
|
974
1176
|
// Tracked from here on rather than re-counted, so progress costs nothing per iteration.
|
|
975
1177
|
let current_face_count = face_pool.count();
|
|
976
1178
|
|
|
1179
|
+
/**
|
|
1180
|
+
* The largest object-space distance any collapse so far has put the surface from the one the
|
|
1181
|
+
* quadrics remember. See {@link bt_mesh_simplify} for why it is a running maximum over the
|
|
1182
|
+
* collapses rather than one sweep of the survivors at the end.
|
|
1183
|
+
* @type {number}
|
|
1184
|
+
*/
|
|
1185
|
+
let deviation = 0;
|
|
1186
|
+
|
|
977
1187
|
if (current_face_count <= target_face_count) {
|
|
978
1188
|
return 0;
|
|
979
1189
|
}
|
|
@@ -1066,14 +1276,16 @@ export function bt_mesh_simplify_with_quadrics(
|
|
|
1066
1276
|
continue;
|
|
1067
1277
|
}
|
|
1068
1278
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1279
|
+
/*
|
|
1280
|
+
An invariant now, not a filter. `evaluate_edge_collapse` has just written the placement
|
|
1281
|
+
into `scratch_target`, and it returns a finite price only for a placement it has itself
|
|
1282
|
+
confirmed folds nothing -- so a fold reaching this point is this file being wrong, which is
|
|
1283
|
+
what an assertion is for and what a `continue` would have hidden.
|
|
1284
|
+
*/
|
|
1285
|
+
assert.notOk(
|
|
1286
|
+
bt_edge_collapse_would_fold(mesh, v1, v2, scratch_target),
|
|
1287
|
+
'the placement a finite collapse price was quoted for must not fold'
|
|
1288
|
+
);
|
|
1077
1289
|
|
|
1078
1290
|
const face_deaths = count_edge_faces(mesh, edge_id);
|
|
1079
1291
|
|
|
@@ -1086,6 +1298,18 @@ export function bt_mesh_simplify_with_quadrics(
|
|
|
1086
1298
|
const pre_survivor = mesh.edge_read_vertex1(edge_id);
|
|
1087
1299
|
const pre_victim = mesh.edge_read_vertex2(edge_id);
|
|
1088
1300
|
|
|
1301
|
+
const target_x = scratch_target[0];
|
|
1302
|
+
const target_y = scratch_target[1];
|
|
1303
|
+
const target_z = scratch_target[2];
|
|
1304
|
+
|
|
1305
|
+
// Priced before the accumulation below, which is the merge that would dilute it, and each
|
|
1306
|
+
// endpoint against its own weight for the same reason.
|
|
1307
|
+
deviation = Math.max(
|
|
1308
|
+
deviation,
|
|
1309
|
+
quadratics[pre_survivor].distance(target_x, target_y, target_z),
|
|
1310
|
+
quadratics[pre_victim].distance(target_x, target_y, target_z)
|
|
1311
|
+
);
|
|
1312
|
+
|
|
1089
1313
|
// Before the accumulation below, which is what makes the blend fallback weigh the two
|
|
1090
1314
|
// endpoints' own histories rather than the survivor's already carrying the victim's. And
|
|
1091
1315
|
// before the topology mutates, which is what lets the faces about to die say which corners
|
|
@@ -1125,11 +1349,6 @@ export function bt_mesh_simplify_with_quadrics(
|
|
|
1125
1349
|
);
|
|
1126
1350
|
}
|
|
1127
1351
|
|
|
1128
|
-
// Measured here, before the cleanup below, because a vertex left behind by a patch that was
|
|
1129
|
-
// consumed whole is faceless and about to be removed — and it is the only thing still carrying
|
|
1130
|
-
// the quadric of the geometry that used to be there.
|
|
1131
|
-
const deviation = measure_deviation(mesh, quadratics);
|
|
1132
|
-
|
|
1133
1352
|
// Drop any loose loops/edges/verts produced during collapses, preserving
|
|
1134
1353
|
// restricted vertices even if they ended up isolated.
|
|
1135
1354
|
cleanup_faceless_preserving_restricted(mesh, restricted_vertices);
|
|
@@ -1137,33 +1356,6 @@ export function bt_mesh_simplify_with_quadrics(
|
|
|
1137
1356
|
return deviation;
|
|
1138
1357
|
}
|
|
1139
1358
|
|
|
1140
|
-
/**
|
|
1141
|
-
* The largest distance any vertex now sits from the surface its quadric remembers.
|
|
1142
|
-
*
|
|
1143
|
-
* @param {BinaryTopology} mesh
|
|
1144
|
-
* @param {Quadric3[]} quadratics
|
|
1145
|
-
* @returns {number}
|
|
1146
|
-
*/
|
|
1147
|
-
function measure_deviation(mesh, quadratics) {
|
|
1148
|
-
const vertex_pool = mesh.vertices;
|
|
1149
|
-
|
|
1150
|
-
let result = 0;
|
|
1151
|
-
|
|
1152
|
-
for (let v = 0; v < vertex_pool.size; v++) {
|
|
1153
|
-
if (!vertex_pool.is_allocated(v) || quadratics[v] === null || quadratics[v] === undefined) {
|
|
1154
|
-
continue;
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
mesh.vertex_read_coordinate(scratch_coord_a, 0, v);
|
|
1158
|
-
|
|
1159
|
-
result = Math.max(
|
|
1160
|
-
result, quadratics[v].distance(scratch_coord_a[0], scratch_coord_a[1], scratch_coord_a[2])
|
|
1161
|
-
);
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
return result;
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
1359
|
/**
|
|
1168
1360
|
* Variant of bt_mesh_cleanup_faceless_references that never releases a restricted
|
|
1169
1361
|
* vertex even when it has no remaining edges.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How far from `from` toward `to` may a collapse of `survivor`-`victim` place the surviving vertex
|
|
3
|
+
* and still turn no surviving triangle over?
|
|
4
|
+
*
|
|
5
|
+
* Both fans are walked, because both endpoints move: the victim onto the placement by definition,
|
|
6
|
+
* and the survivor too wherever the caller puts it somewhere other than where it already sits. The
|
|
7
|
+
* union of the two is the set of faces the collapse reshapes, which is what makes the answer
|
|
8
|
+
* symmetric in the two endpoints -- a caller that has not yet settled which of them survives can
|
|
9
|
+
* rely on that.
|
|
10
|
+
*
|
|
11
|
+
* @param {BinaryTopology} mesh
|
|
12
|
+
* @param {number} survivor the endpoint that stays allocated
|
|
13
|
+
* @param {number} victim the endpoint that is removed
|
|
14
|
+
* @param {Float32Array|number[]} from the placement to measure from, at `t = 0`
|
|
15
|
+
* @param {Float32Array|number[]} to the placement wanted, at `t = 1`
|
|
16
|
+
* @param {number} [from_offset]
|
|
17
|
+
* @param {number} [to_offset]
|
|
18
|
+
* @returns {number} where the first surviving triangle reaches **zero** area, so the placements that
|
|
19
|
+
* fold nothing are `t` in `[0, limit)` -- open at the top, since zero area is refused along with
|
|
20
|
+
* a flip, and a caller therefore takes a fraction of this rather than this. `1` when nothing on
|
|
21
|
+
* the segment folds, and `-1` when `from` itself does, which is the one answer no amount of
|
|
22
|
+
* sliding recovers from.
|
|
23
|
+
*/
|
|
24
|
+
export function bt_edge_collapse_fold_limit(mesh: BinaryTopology, survivor: number, victim: number, from: Float32Array | number[], to: Float32Array | number[], from_offset?: number, to_offset?: number): number;
|
|
25
|
+
//# sourceMappingURL=bt_edge_collapse_fold_limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bt_edge_collapse_fold_limit.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js"],"names":[],"mappings":"AA4LA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,4EAZW,MAAM,UACN,MAAM,QACN,YAAY,GAAC,MAAM,EAAE,MACrB,YAAY,GAAC,MAAM,EAAE,gBACrB,MAAM,cACN,MAAM,GACJ,MAAM,CAsBlB"}
|