@woosh/meep-engine 2.49.8 → 2.50.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.
Files changed (197) hide show
  1. package/editor/actions/concrete/ArrayCopyAction.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/binary/BinaryBuffer.js +1 -1
  4. package/src/core/binary/BinaryBuffer.spec.js +128 -0
  5. package/src/core/binary/int32_to_binary_string.js +4 -1
  6. package/src/core/binary/int32_to_binary_string.spec.js +9 -0
  7. package/src/core/bvh2/BinaryNode.js +0 -30
  8. package/src/core/bvh2/binary/2/BinaryUint32BVH.js +1 -1
  9. package/src/core/bvh2/binary/IndexedBinaryBVH.js +1 -1
  10. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +1 -1
  11. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +1 -1
  12. package/src/core/cache/Cache.js +31 -29
  13. package/src/core/cache/Cache.spec.js +4 -1
  14. package/src/core/collection/HashMap.js +1 -1
  15. package/src/core/collection/array/{copyArray.js → array_copy.js} +1 -24
  16. package/src/core/collection/array/array_copy_entire.js +21 -0
  17. package/src/core/collection/array/typed/typed_array_copy.js +1 -1
  18. package/src/core/collection/queue/Deque.d.ts +4 -0
  19. package/src/core/collection/queue/Deque.js +5 -7
  20. package/src/core/collection/queue/Deque.spec.js +107 -0
  21. package/src/core/collection/table/RowFirstTable.js +1 -1
  22. package/src/core/geom/2d/aabb/AABB2.d.ts +14 -0
  23. package/src/core/geom/2d/aabb/AABB2.js +9 -7
  24. package/src/core/geom/2d/aabb/AABB2.spec.js +100 -0
  25. package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.spec.js +11 -0
  26. package/src/core/geom/2d/aabb/aabb2_compute_overlap.spec.js +56 -0
  27. package/src/core/geom/2d/aabb/aabb2_contains.spec.js +40 -0
  28. package/src/core/geom/2d/bvh/Node2.js +1 -1
  29. package/src/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +1 -1
  30. package/src/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +1 -1
  31. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_2d.js +35 -0
  32. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_array_2d.js +51 -0
  33. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_2d.js +15 -0
  34. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_array_2d.js +30 -0
  35. package/src/core/geom/2d/line/line_segment_line_segment_intersection_exists_2d.js +29 -0
  36. package/src/core/geom/3d/aabb/AABB3.d.ts +4 -0
  37. package/src/core/geom/3d/aabb/AABB3.spec.js +30 -0
  38. package/src/core/geom/3d/matrix/m4_make_translation.js +1 -1
  39. package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +1 -1
  40. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +1 -1
  41. package/src/core/geom/3d/tetrahedra/compute_circumsphere.js +1 -1
  42. package/src/core/geom/3d/tetrahedra/delaunay/fill_in_a_cavity.js +1 -1
  43. package/src/core/geom/3d/topology/bounds/computeTriangleClusterNormalBoundingCone.js +1 -1
  44. package/src/core/geom/3d/topology/expandConnectivityByLocality.js +1 -1
  45. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.js +1 -1
  46. package/src/core/geom/Quaternion.d.ts +11 -0
  47. package/src/core/geom/Quaternion.js +36 -27
  48. package/src/core/geom/Quaternion.spec.js +141 -0
  49. package/src/core/geom/Vector2.d.ts +5 -1
  50. package/src/core/geom/Vector2.js +24 -0
  51. package/src/core/geom/Vector3.d.ts +4 -0
  52. package/src/core/geom/Vector3.spec.js +60 -0
  53. package/src/core/graph/GraphUtils.js +4 -2
  54. package/src/core/graph/layout/CircleLayout.js +4 -2
  55. package/src/core/math/bessel_i0.spec.js +43 -0
  56. package/src/core/math/bessel_j0.js +30 -0
  57. package/src/core/math/hash/murmur3_32.spec.js +8 -0
  58. package/src/core/math/hash/squirrel3.spec.js +16 -0
  59. package/src/core/math/interval/NumericInterval.js +1 -0
  60. package/src/core/math/{bessel_i0.js → modified_bessel_i0.js} +5 -2
  61. package/src/core/math/noise/{create_noise_2d.js → create_simplex_noise_2d.js} +2 -2
  62. package/src/core/math/noise/create_simplex_noise_2d.spec.js +21 -0
  63. package/src/core/math/physics/irradiance/interpolate_irradiance_linear.spec.js +20 -0
  64. package/src/core/math/physics/irradiance/interpolate_irradiance_lograrithmic.js +4 -4
  65. package/src/core/math/physics/irradiance/interpolate_irradiance_lograrithmic.spec.js +18 -0
  66. package/src/core/math/physics/irradiance/interpolate_irradiance_smith.js +1 -1
  67. package/src/core/math/physics/irradiance/interpolate_irradiance_smith.spec.js +20 -0
  68. package/src/core/math/random/seededRandomMersenneTwister.spec.js +10 -0
  69. package/src/core/math/spline/spline_bezier3.js +1 -1
  70. package/src/core/math/spline/spline_bezier3_bounds.js +2 -1
  71. package/src/core/math/spline/spline_bezier3_bounds.spec.js +37 -0
  72. package/src/core/math/statistics/computeSampleSize_Cochran.spec.js +12 -0
  73. package/src/core/math/statistics/computeStatisticalPartialMedian.js +4 -0
  74. package/src/core/math/statistics/computeStatisticalPartialMedian.spec.js +13 -0
  75. package/src/core/math/vector_nd_dot.js +16 -0
  76. package/src/core/math/{normalizeArrayVector.js → vector_nd_normalize.js} +3 -3
  77. package/src/core/math/vector_nd_normalize.spec.js +15 -0
  78. package/src/core/process/PromiseWatcher.spec.js +1 -1
  79. package/src/engine/achievements/Achievement.spec.js +21 -0
  80. package/src/engine/animation/curve/compression/downsample_float_array_curve_by_error.js +1 -1
  81. package/src/engine/animation/curve/compression/prototypeCurveCompression.js +2 -2
  82. package/src/engine/animation/curve/compression/{animation_curve_to_float_array.js → sample_animation_curve_to_float_array.js} +10 -3
  83. package/src/engine/animation/curve/compression/sample_animation_curve_to_float_array.spec.js +29 -0
  84. package/src/engine/animation/curve/draw/build_curve_editor.js +3 -3
  85. package/src/engine/development/performance/RingBufferMetric.js +1 -1
  86. package/src/engine/ecs/EntityManager.js +1 -205
  87. package/src/engine/ecs/animation/Animation.js +2 -180
  88. package/src/engine/ecs/animation/AnimationClip.js +132 -0
  89. package/src/engine/ecs/animation/AnimationClip.spec.js +5 -0
  90. package/src/engine/ecs/animation/AnimationClipFlag.js +7 -0
  91. package/src/engine/ecs/animation/AnimationFlags.js +8 -0
  92. package/src/engine/ecs/animation/AnimationSerializationAdapter.js +32 -0
  93. package/src/engine/ecs/fow/FogOfWar.js +1 -1
  94. package/src/engine/ecs/guid/GUID.js +1 -1
  95. package/src/engine/ecs/systems/AnimationSystem.js +3 -1
  96. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +1 -1
  97. package/src/engine/ecs/terrain/overlay/TerrainOverlay.js +1 -1
  98. package/src/engine/ecs/terrain/tiles/TerrainTile.js +1 -1
  99. package/src/engine/ecs/transform/Transform.d.ts +2 -0
  100. package/src/engine/ecs/transform/Transform.spec.js +63 -0
  101. package/src/engine/ecs/transform-attachment/TransformAttachment.d.ts +17 -1
  102. package/src/engine/ecs/transform-attachment/TransformAttachment.js +12 -2
  103. package/src/engine/ecs/transform-attachment/TransformAttachment.spec.js +103 -0
  104. package/src/engine/graphics/camera/testClippingPlaneComputation.js +1 -1
  105. package/src/engine/graphics/ecs/animation/AnimationControllerSystem.js +2 -1
  106. package/src/engine/graphics/ecs/path/testPathDisplaySystem.js +1 -1
  107. package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +1 -1
  108. package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +1 -1
  109. package/src/engine/graphics/geometry/MikkT/GenerateTSpaces.js +1 -1
  110. package/src/engine/graphics/geometry/MikkT/m_getNormal.js +1 -1
  111. package/src/engine/graphics/geometry/MikkT/m_getTexCoord.js +1 -1
  112. package/src/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +1 -1
  113. package/src/engine/graphics/geometry/instancing/InstancedMeshGroup.js +1 -1
  114. package/src/engine/graphics/geometry/optimization/merge/merge_geometry_hierarchy.js +1 -1
  115. package/src/engine/graphics/impostors/octahedral/util/build_cutout_from_atlas_by_alpha.js +1 -1
  116. package/src/engine/graphics/load_and_set_cubemap_v0.js +1 -1
  117. package/src/engine/graphics/particles/particular/engine/utils/volume/AttributeValue.js +1 -1
  118. package/src/engine/graphics/render/Lines.js +1 -1
  119. package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +1 -1
  120. package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +1 -1
  121. package/src/engine/graphics/render/forward_plus/LightManager.js +1 -1
  122. package/src/engine/graphics/render/forward_plus/model/Decal.js +1 -1
  123. package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +1 -1
  124. package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +1 -1
  125. package/src/engine/graphics/render/gizmo/GizmoShapeRenderingInterface.js +1 -1
  126. package/src/engine/graphics/render/view/CameraView.js +1 -1
  127. package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +1 -1
  128. package/src/engine/graphics/render/visibility/hiz/query/BatchOcclusionQuery.js +1 -1
  129. package/src/engine/graphics/render/webgpu/sample/MeshInstance.js +1 -1
  130. package/src/engine/graphics/sh3/LightProbeVolume.js +1 -1
  131. package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.js +1 -1
  132. package/src/engine/graphics/sh3/path_tracer/PathTracer.js +1 -1
  133. package/src/engine/graphics/sh3/path_tracer/make_sky_hosek.js +1 -1
  134. package/src/engine/graphics/sh3/prototypeSH3Probe.js +1 -1
  135. package/src/engine/graphics/texture/3d/scs3d_read_2d_slice.js +1 -1
  136. package/src/engine/graphics/texture/CanvasClone.js +5 -1
  137. package/src/engine/graphics/texture/sampler/Sampler2D.js +14 -75
  138. package/src/engine/graphics/texture/sampler/bicubic.js +19 -19
  139. package/src/engine/graphics/texture/sampler/convertSampler2D2DataURL.spec.js +10 -0
  140. package/src/engine/graphics/texture/sampler/copy_Sampler2D_channel_data.spec.js +90 -0
  141. package/src/engine/graphics/texture/sampler/differenceSampler.js +13 -8
  142. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_Chamfer.js +140 -0
  143. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_NaiveFlood.js +130 -0
  144. package/src/engine/graphics/texture/sampler/distance/computeUnsignedDistanceField.js +10 -0
  145. package/src/engine/graphics/texture/sampler/distance/computeUnsignedDistanceField.spec.js +183 -0
  146. package/src/engine/graphics/texture/sampler/distance/computeUnsignedDistanceField_Chamfer.js +133 -0
  147. package/src/engine/graphics/texture/sampler/filter/kaiser_1.js +8 -4
  148. package/src/engine/graphics/texture/sampler/filter/kaiser_bessel_window.js +2 -0
  149. package/src/engine/graphics/texture/sampler/filter/mitchell.js +4 -0
  150. package/src/engine/graphics/texture/sampler/loadSampler2D.js +5 -2
  151. package/src/engine/graphics/texture/sampler/resize/sampler2d_downsample_mipmap.js +8 -3
  152. package/src/engine/graphics/texture/sampler/resize/sampler2d_downsample_mipmap.spec.js +13 -0
  153. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +58 -0
  154. package/src/engine/graphics/trail/TemporalPath.js +0 -36
  155. package/src/engine/intelligence/behavior/composite/ParallelBehavior.spec.js +12 -12
  156. package/src/engine/intelligence/behavior/composite/SequenceBehavior.spec.js +17 -0
  157. package/src/engine/intelligence/behavior/primitive/SucceedingBehavior.js +2 -0
  158. package/src/engine/knowledge/database/StaticKnowledgeDataTable.d.ts +7 -1
  159. package/src/engine/knowledge/database/StaticKnowledgeDataTable.spec.js +21 -0
  160. package/src/engine/knowledge/database/StaticKnowledgeDataTableDescriptor.d.ts +2 -2
  161. package/src/engine/logging/ConsoleLoggerBackend.js +4 -0
  162. package/src/engine/logging/VoidLoggerBackend.js +12 -0
  163. package/src/engine/navigation/ecs/components/computeCatmullRomSpline.js +1 -1
  164. package/src/engine/navigation/ecs/components/computeCatmullRomSplineUniformDistance.js +1 -1
  165. package/src/engine/physics/cannon/CannonJSPhysicsSystem.js +1 -1
  166. package/src/engine/save/GameStateLoader.js +1 -1
  167. package/src/engine/scene/Scene.d.ts +2 -0
  168. package/src/engine/scene/Scene.js +2 -2
  169. package/src/engine/scene/Scene.spec.js +20 -0
  170. package/src/engine/scene/SceneManager.d.ts +4 -0
  171. package/src/engine/scene/SceneManager.js +46 -23
  172. package/src/engine/scene/SceneManager.spec.js +107 -0
  173. package/src/engine/sound/material/detector/terrain/TerrainSoundMaterialSurfaceDetector.js +2 -2
  174. package/src/engine/ui/GUIEngine.js +1 -1
  175. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.js +11 -4
  176. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.spec.js +30 -0
  177. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +18 -2
  178. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.spec.js +17 -0
  179. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +2 -2
  180. package/src/generation/grid/GridData.js +0 -60
  181. package/src/generation/grid/generation/util/buildUnsignedDistanceField.js +3 -1
  182. package/src/generation/markers/MarkerNode.js +2 -2
  183. package/src/generation/theme/AreaMask.js +3 -1
  184. package/src/view/elements/progress/RectangularPieProgressView.js +8 -6
  185. package/src/core/geom/2d/LineSegment2.js +0 -175
  186. package/src/core/geom/Matrix4.js +0 -275
  187. package/src/engine/graphics/texture/sampler/distanceField.js +0 -411
  188. package/src/engine/graphics/texture/sampler/distanceField.spec.js +0 -184
  189. package/src/engine/physics/cannon/cannon.min.js +0 -27
  190. /package/src/engine/ecs/{animation → ik}/IKMath.js +0 -0
  191. /package/src/engine/ecs/{animation → ik}/IKProblem.js +0 -0
  192. /package/src/engine/ecs/{animation → ik}/IKSolver.js +0 -0
  193. /package/src/engine/ecs/{animation → ik}/InverseKinematics.js +0 -0
  194. /package/src/engine/ecs/{animation → ik}/InverseKinematicsSystem.js +0 -0
  195. /package/src/engine/ecs/{animation → ik}/OneBoneSurfaceAlignmentSolver.js +0 -0
  196. /package/src/engine/ecs/{animation → ik}/TwoBoneInverseKinematicsSolver.js +0 -0
  197. /package/src/engine/physics/spring/{Spring.js → computeHookeForce.js} +0 -0
@@ -1,5 +1,6 @@
1
- import Vector4 from "../../../../core/geom/Vector4.js";
2
1
  import { Sampler2D } from "./Sampler2D.js";
2
+ import { vector_nd_normalize } from "../../../../core/math/vector_nd_normalize.js";
3
+ import { vector_nd_dot } from "../../../../core/math/vector_nd_dot.js";
3
4
 
4
5
  /**
5
6
  *
@@ -8,8 +9,10 @@ import { Sampler2D } from "./Sampler2D.js";
8
9
  * @returns {Sampler2D}
9
10
  */
10
11
  export function differenceSampler(sampler0, sampler1) {
11
- let v0 = new Vector4();
12
- let v1 = new Vector4();
12
+ const dimension_count = sampler0.itemSize;
13
+
14
+ const v0 = new Float64Array(dimension_count);
15
+ const v1 = new Float64Array(dimension_count);
13
16
  //
14
17
  const width = sampler0.width;
15
18
  const height = sampler0.height;
@@ -17,12 +20,14 @@ export function differenceSampler(sampler0, sampler1) {
17
20
  const difference = new Float32Array(width * height);
18
21
  for (let y = 0; y < height; y++) {
19
22
  for (let x = 0; x < width; x++) {
20
- v0 = sampler0.get(x, y, v0);
21
- v1 = sampler1.get(x, y, v1);
22
- v0.normalize();
23
- v1.normalize();
23
+ sampler0.sampleBilinear(x, y, v0);
24
+ sampler1.sampleBilinear(x, y, v1);
25
+
26
+ vector_nd_normalize(v0, v0, dimension_count);
27
+ vector_nd_normalize(v1, v1, dimension_count);
28
+
24
29
  //check distance
25
- difference[x + y * width] = 1 - v0.dot(v1);
30
+ difference[x + y * width] = 1 - vector_nd_dot(v0, v1, dimension_count);
26
31
  }
27
32
  }
28
33
  //
@@ -0,0 +1,140 @@
1
+ import { clamp } from "../../../../../core/math/clamp.js";
2
+ import { min2 } from "../../../../../core/math/min2.js";
3
+
4
+ /**
5
+ * algorithm proposed by Borgefors, Chamfer distance [J. ACM 15 (1968) 600, Comput. Vis. Graph. Image Process. 34 (1986) 344], h
6
+ * @param {Sampler2D} source
7
+ * @param {Sampler2D} distanceField
8
+ * @param {number} emptyValue
9
+ * @param {number} d1 distance between two adjacent pixels in either x or y direction
10
+ * @param {number} d2 distance between two diagonally adjacent pixels
11
+ * @param maxD
12
+ */
13
+ export function computeSignedDistanceField_Chamfer(source, distanceField, emptyValue, d1, d2, maxD) {
14
+ const sourceData = source.data;
15
+ const distanceFieldData = distanceField.data;
16
+
17
+ const width = source.width;
18
+ const height = source.height;
19
+
20
+ const maxX = width - 1;
21
+ const maxY = height - 1;
22
+
23
+ function getS(x, y) {
24
+ x = clamp(x, 0, maxX);
25
+ y = clamp(y, 0, maxY);
26
+
27
+ const index = x + y * width;
28
+
29
+ return sourceData[index];
30
+ }
31
+
32
+ function getD(x, y) {
33
+ x = clamp(x, 0, maxX);
34
+ y = clamp(y, 0, maxY);
35
+
36
+ const index = x + y * width;
37
+
38
+ return distanceFieldData[index];
39
+ }
40
+
41
+ function setD(x, y, v) {
42
+ x = clamp(x, 0, maxX);
43
+ y = clamp(y, 0, maxY);
44
+
45
+ const index = x + y * width;
46
+
47
+ distanceFieldData[index] = min2(v, maxD);
48
+ }
49
+
50
+ let x, y;
51
+
52
+ //initialize distance field
53
+ for (y = 0; y < height; y++) {
54
+ for (x = 0; x < width; x++) {
55
+ if (
56
+ getS(x - 1, y) !== getS(x, y)
57
+ || getS(x + 1, y) !== getS(x, y)
58
+ || getS(x, y - 1) !== getS(x, y)
59
+ || getS(x, y + 1) !== getS(x, y)
60
+ ) {
61
+ setD(x, y, 0);
62
+ } else {
63
+ setD(x, y, 255);
64
+ }
65
+ }
66
+ }
67
+
68
+ //first pass (forward)
69
+ for (y = 0; y < height; y++) {
70
+ for (x = 0; x < width; x++) {
71
+
72
+ const v = getD(x, y);
73
+
74
+ const v0 = getD(x - 1, y - 1) + d2;
75
+
76
+ if (v0 < v) {
77
+ setD(x, y, v0);
78
+ }
79
+
80
+ const v1 = getD(x, y - 1) + d1;
81
+
82
+ if (v1 < v) {
83
+ setD(x, y, v1);
84
+ }
85
+
86
+ const v2 = getD(x + 1, y - 1) + d2;
87
+
88
+ if (v2 < v) {
89
+ setD(x, y, v2);
90
+ }
91
+
92
+ const v3 = getD(x - 1, y) + d1;
93
+
94
+ if (v3 < v) {
95
+ setD(x, y, v3);
96
+ }
97
+ }
98
+ }
99
+
100
+ //second pass (backward)
101
+ for (y = maxY; y >= 0; y--) {
102
+ for (x = maxX; x >= 0; x--) {
103
+ const v = getD(x, y);
104
+
105
+ const v0 = getD(x + 1, y) + d1;
106
+
107
+ if (v0 < v) {
108
+ setD(x, y, v0);
109
+ }
110
+
111
+ const v1 = getD(x - 1, y + 1) + d2;
112
+
113
+ if (v1 < v) {
114
+ setD(x, y, v1);
115
+ }
116
+
117
+ const v2 = getD(x, y + 1) + d1;
118
+
119
+ if (v2 < v) {
120
+ setD(x, y, v2);
121
+ }
122
+
123
+ const v3 = getD(x + 1, y + 1) + d2;
124
+
125
+ if (v3 < v) {
126
+ setD(x, y, v3);
127
+ }
128
+ }
129
+ }
130
+
131
+ //indicate inside & outside
132
+ for (y = 0; y < height; y++) {
133
+ for (x = 0; x < width; x++) {
134
+ if (getS(x, y) !== emptyValue) {
135
+ //inside
136
+ setD(x, y, -getD(x, y));
137
+ }
138
+ }
139
+ }
140
+ }
@@ -0,0 +1,130 @@
1
+ import { assert } from "../../../../../core/assert.js";
2
+ import { BitSet } from "../../../../../core/binary/BitSet.js";
3
+
4
+ /**
5
+ * Naive flood implementation of a distance field computation algorithm
6
+ * @author Alex Goldring Dec 2018
7
+ * @param {Sampler2D} source
8
+ * @param {Sampler2D} destination
9
+ * @param {number} emptyValue
10
+ */
11
+ export function computeSignedDistanceField_NaiveFlood(source, destination, emptyValue) {
12
+ assert.equal(source.itemSize, 1, `unsupported source.itemSize, expected 1, got '${source.itemSize}'`);
13
+ assert.typeOf(emptyValue, 'number', 'emptyValue');
14
+
15
+ let i, j;
16
+
17
+ const distanceData = destination.data;
18
+
19
+ const visited = new BitSet();
20
+
21
+ const openSet = new BitSet();
22
+
23
+ //use "flood" algorithm
24
+
25
+ //mark all visible tiles as visited
26
+ const samplerData = source.data;
27
+ const totalCellCount = samplerData.length;
28
+
29
+ function traverseNeighbours(index, visitor) {
30
+ let i = index - (width + 1);
31
+
32
+ const top = index > width;
33
+ const bottom = index < (totalCellCount - width);
34
+
35
+ const x = index % width;
36
+
37
+ const left = x > 0;
38
+ const right = x < width - 1;
39
+
40
+ if (top) {
41
+ if (left) {
42
+ visitor(i);
43
+ }
44
+
45
+ visitor(i + 1);
46
+
47
+ if (right) {
48
+ visitor(i + 2);
49
+ }
50
+ }
51
+
52
+ i += width;
53
+
54
+ if (left) {
55
+ visitor(i);
56
+ }
57
+
58
+ if (right) {
59
+ visitor(i + 2);
60
+ }
61
+
62
+ i += width;
63
+
64
+ if (bottom) {
65
+ if (left) {
66
+ visitor(i);
67
+ }
68
+
69
+ visitor(i + 1);
70
+
71
+ if (right) {
72
+ visitor(i + 2);
73
+ }
74
+ }
75
+
76
+ }
77
+
78
+ const width = destination.width;
79
+
80
+ for (i = 0; i < totalCellCount; i++) {
81
+ const sampleValue = samplerData[i];
82
+ if (sampleValue !== emptyValue) {
83
+ visited.set(i, true);
84
+ //write distance data
85
+ distanceData[i] = 0;
86
+ } else {
87
+ distanceData[i] = 255;
88
+ }
89
+ }
90
+
91
+ //populate initial open set
92
+ for (i = visited.nextSetBit(0); i !== -1; i = visited.nextSetBit(i + 1)) {
93
+ j = 0;
94
+ traverseNeighbours(i, function (neighbourIndex) {
95
+ if (!visited.get(neighbourIndex)) {
96
+ //increment number of not visited
97
+ j++;
98
+ }
99
+ });
100
+
101
+ if (j === 0) {
102
+ //all neighbours are visited, we can safely ignore this cell
103
+ } else {
104
+ openSet.set(i, true);
105
+ }
106
+ }
107
+
108
+ for (i = openSet.nextSetBit(0); i !== -1; i = openSet.nextSetBit(0)) {
109
+ //remove from open set
110
+ openSet.set(i, false);
111
+
112
+ const value = distanceData[i];
113
+
114
+ traverseNeighbours(i, function (neighbourIndex) {
115
+ const neighbourValue = value + 1;
116
+
117
+ if (visited.get(neighbourIndex)) {
118
+ if (distanceData[neighbourIndex] <= neighbourValue) {
119
+ return;
120
+ }
121
+ } else {
122
+ visited.set(neighbourIndex, true);
123
+ }
124
+
125
+ distanceData[neighbourIndex] = neighbourValue;
126
+ //add neighbour to open set
127
+ openSet.set(neighbourIndex, true);
128
+ });
129
+ }
130
+ }
@@ -0,0 +1,10 @@
1
+ import { computeUnsignedDistanceField_Chamfer } from "./computeUnsignedDistanceField_Chamfer.js";
2
+
3
+ /**
4
+ * @param {Sampler2D} source
5
+ * @param {Sampler2D} distanceField
6
+ * @param {number} emptyValue
7
+ */
8
+ export function computeUnsignedDistanceField(source, distanceField, emptyValue) {
9
+ computeUnsignedDistanceField_Chamfer(source, distanceField, emptyValue, 1, 1, 255);
10
+ }
@@ -0,0 +1,183 @@
1
+ import { seededRandom } from "../../../../../core/math/random/seededRandom.js";
2
+ import { Sampler2D } from "../Sampler2D.js";
3
+ import { randomIntegerBetween } from "../../../../../core/math/random/randomIntegerBetween.js";
4
+ import { computeUnsignedDistanceField } from "./computeUnsignedDistanceField.js";
5
+
6
+ test('empty', () => {
7
+ const source = Sampler2D.uint8(1, 0, 0);
8
+ const target = Sampler2D.uint8(1, 0, 0);
9
+
10
+ computeUnsignedDistanceField(source, target, 0);
11
+ });
12
+
13
+ test('1 pixel empty source', () => {
14
+ const source = Sampler2D.uint8(1, 1, 1);
15
+ const target = Sampler2D.uint8(1, 1, 1);
16
+
17
+ computeUnsignedDistanceField(source, target, 0);
18
+
19
+ expect(target.readChannel(0, 0, 0)).toBe(255);
20
+ });
21
+
22
+ test('1 pixel filled source', () => {
23
+ const source = Sampler2D.uint8(1, 1, 1);
24
+ source.set(0, 0, [255]);
25
+
26
+ const target = Sampler2D.uint8(1, 1, 1);
27
+
28
+ computeUnsignedDistanceField(source, target, 0);
29
+
30
+ expect(target.readChannel(0, 0, 0)).toBe(0);
31
+ });
32
+
33
+ test('3x3 pixel source with filled middle', () => {
34
+ const source = Sampler2D.uint8(1, 3, 3);
35
+ source.set(1, 1, [255]);
36
+
37
+ const target = Sampler2D.uint8(1, 3, 3);
38
+
39
+ computeUnsignedDistanceField(source, target, 0);
40
+
41
+ expect(target.readChannel(0, 0, 0)).toBe(1);
42
+ expect(target.readChannel(1, 0, 0)).toBe(1);
43
+ expect(target.readChannel(2, 0, 0)).toBe(1);
44
+
45
+ expect(target.readChannel(0, 1, 0)).toBe(1);
46
+ expect(target.readChannel(1, 1, 0)).toBe(0);
47
+ expect(target.readChannel(2, 1, 0)).toBe(1);
48
+
49
+ expect(target.readChannel(0, 2, 0)).toBe(1);
50
+ expect(target.readChannel(1, 2, 0)).toBe(1);
51
+ expect(target.readChannel(2, 2, 0)).toBe(1);
52
+ });
53
+
54
+ test('3x3 pixel source with empty middle', () => {
55
+ const source = Sampler2D.uint8(1, 3, 3);
56
+ source.data.fill(255);
57
+ source.set(1, 1, [0]);
58
+
59
+ const target = Sampler2D.uint8(1, 3, 3);
60
+
61
+ computeUnsignedDistanceField(source, target, 0);
62
+
63
+ expect(target.readChannel(0, 0, 0)).toBe(0);
64
+ expect(target.readChannel(1, 0, 0)).toBe(0);
65
+ expect(target.readChannel(2, 0, 0)).toBe(0);
66
+
67
+ expect(target.readChannel(0, 1, 0)).toBe(0);
68
+ expect(target.readChannel(1, 1, 0)).toBe(1);
69
+ expect(target.readChannel(2, 1, 0)).toBe(0);
70
+
71
+ expect(target.readChannel(0, 2, 0)).toBe(0);
72
+ expect(target.readChannel(1, 2, 0)).toBe(0);
73
+ expect(target.readChannel(2, 2, 0)).toBe(0);
74
+ });
75
+
76
+ test('3x3 pixel source with empty corners', () => {
77
+ const source = Sampler2D.uint8(1, 3, 3);
78
+ source.data.fill(255);
79
+ source.set(0, 0, [0]);
80
+ source.set(2, 0, [0]);
81
+ source.set(0, 2, [0]);
82
+ source.set(2, 2, [0]);
83
+
84
+ const target = Sampler2D.uint8(1, 3, 3);
85
+
86
+ computeUnsignedDistanceField(source, target, 0);
87
+
88
+ expect(target.readChannel(0, 0, 0)).toBe(1);
89
+ expect(target.readChannel(1, 0, 0)).toBe(0);
90
+ expect(target.readChannel(2, 0, 0)).toBe(1);
91
+
92
+ expect(target.readChannel(0, 1, 0)).toBe(0);
93
+ expect(target.readChannel(1, 1, 0)).toBe(0);
94
+ expect(target.readChannel(2, 1, 0)).toBe(0);
95
+
96
+ expect(target.readChannel(0, 2, 0)).toBe(1);
97
+ expect(target.readChannel(1, 2, 0)).toBe(0);
98
+ expect(target.readChannel(2, 2, 0)).toBe(1);
99
+ });
100
+
101
+ test('3x3 pixel source with filled corners', () => {
102
+ const source = Sampler2D.uint8(1, 3, 3);
103
+ source.data.fill(0);
104
+ source.set(0, 0, [255]);
105
+ source.set(2, 0, [255]);
106
+ source.set(0, 2, [255]);
107
+ source.set(2, 2, [255]);
108
+
109
+ const target = Sampler2D.uint8(1, 3, 3);
110
+
111
+ computeUnsignedDistanceField(source, target, 0);
112
+
113
+ expect(target.readChannel(0, 0, 0)).toBe(0);
114
+ expect(target.readChannel(1, 0, 0)).toBe(1);
115
+ expect(target.readChannel(2, 0, 0)).toBe(0);
116
+
117
+ expect(target.readChannel(0, 1, 0)).toBe(1);
118
+ expect(target.readChannel(1, 1, 0)).toBe(1);
119
+ expect(target.readChannel(2, 1, 0)).toBe(1);
120
+
121
+ expect(target.readChannel(0, 2, 0)).toBe(0);
122
+ expect(target.readChannel(1, 2, 0)).toBe(1);
123
+ expect(target.readChannel(2, 2, 0)).toBe(0);
124
+ });
125
+
126
+ test('3x1 pixel source with 1 filled corner', () => {
127
+ const source = Sampler2D.uint8(1, 3, 1);
128
+ source.data.fill(0);
129
+ source.set(0, 0, [255]);
130
+
131
+ const target = Sampler2D.uint8(1, 3, 1);
132
+
133
+ computeUnsignedDistanceField(source, target, 0);
134
+
135
+ expect(target.readChannel(0, 0, 0)).toBe(0);
136
+ expect(target.readChannel(1, 0, 0)).toBe(1);
137
+ expect(target.readChannel(2, 0, 0)).toBe(2);
138
+ });
139
+
140
+ test('3x3 pixel source with 1 filled corner', () => {
141
+ const source = Sampler2D.uint8(1, 3, 3);
142
+ source.data.fill(0);
143
+ source.set(0, 0, [255]);
144
+
145
+ const target = Sampler2D.uint8(1, 3, 3);
146
+
147
+ computeUnsignedDistanceField(source, target, 0);
148
+
149
+ expect(target.readChannel(0, 0, 0)).toBe(0);
150
+ expect(target.readChannel(1, 0, 0)).toBe(1);
151
+ expect(target.readChannel(2, 0, 0)).toBe(2);
152
+
153
+ expect(target.readChannel(0, 1, 0)).toBe(1);
154
+ expect(target.readChannel(1, 1, 0)).toBe(1);
155
+ expect(target.readChannel(2, 1, 0)).toBe(2);
156
+
157
+ expect(target.readChannel(0, 2, 0)).toBe(2);
158
+ expect(target.readChannel(1, 2, 0)).toBe(2);
159
+ expect(target.readChannel(2, 2, 0)).toBe(2);
160
+ });
161
+
162
+ test.skip('performance', () => {
163
+
164
+ const sizeX = 100;
165
+ const sizeY = 100;
166
+
167
+ const source = Sampler2D.uint8(1, sizeX, sizeY);
168
+
169
+ const random = seededRandom(42);
170
+ source.data.fill(0);
171
+ for (let i = 0; i < source.data.length * 0.1; i++) {
172
+ const x = randomIntegerBetween(random, 0, sizeX);
173
+ const y = randomIntegerBetween(random, 0, sizeY);
174
+ source.set(x, y, [255]);
175
+ }
176
+
177
+ const target = Sampler2D.uint8(1, sizeX, sizeY);
178
+
179
+ console.time('p');
180
+ computeUnsignedDistanceField(source, target, 0);
181
+ console.timeEnd('p');
182
+
183
+ });
@@ -0,0 +1,133 @@
1
+ import { max2 } from "../../../../../core/math/max2.js";
2
+ import { min2 } from "../../../../../core/math/min2.js";
3
+
4
+ /**
5
+ * algorithm proposed by Borgefors, Chamfer distance [J. ACM 15 (1968) 600, Comput. Vis. Graph. Image Process. 34 (1986) 344], h
6
+ * @param {Sampler2D} source
7
+ * @param {Sampler2D} distanceField
8
+ * @param {number} emptyValue
9
+ * @param {number} d1 distance between two adjacent pixels in either x or y direction
10
+ * @param {number} d2 distance between two diagonally adjacent pixels
11
+ * @param {number} maxD highest value that distance field can hold
12
+ */
13
+ export function computeUnsignedDistanceField_Chamfer(source, distanceField, emptyValue, d1, d2, maxD) {
14
+ const sourceData = source.data;
15
+ const distanceFieldData = distanceField.data;
16
+
17
+ const width = source.width;
18
+ const height = source.height;
19
+
20
+ const maxX = width - 1;
21
+ const maxY = height - 1;
22
+
23
+ let x, y, i, v;
24
+
25
+ //initialize distance field
26
+ const dataSize = height * width;
27
+ for (i = 0; i < dataSize; i++) {
28
+ if (sourceData[i] !== emptyValue) {
29
+ distanceFieldData[i] = 0;
30
+ } else {
31
+ distanceFieldData[i] = maxD;
32
+ }
33
+ }
34
+
35
+ //first pass (forward)
36
+ for (y = 0; y < height; y++) {
37
+
38
+ const y_m1 = max2(y - 1, 0);
39
+
40
+ const y_w = y * width;
41
+
42
+ const y_m1_w = y_m1 * width;
43
+
44
+ for (x = 0; x < width; x++) {
45
+
46
+ i = y_w + x;
47
+
48
+ v = distanceFieldData[i];
49
+
50
+ const x_m1 = max2(x - 1, 0);
51
+ const x_p1 = min2(x + 1, maxX);
52
+
53
+ const v0_i = x_m1 + y_m1_w;
54
+ const v0 = distanceFieldData[v0_i] + d2;
55
+
56
+ if (v0 < v) {
57
+ distanceFieldData[i] = v0;
58
+ v = v0;
59
+ }
60
+
61
+ const v1_i = x + y_m1_w;
62
+ const v1 = distanceFieldData[v1_i] + d1;
63
+
64
+ if (v1 < v) {
65
+ distanceFieldData[i] = v1;
66
+ v = v1;
67
+ }
68
+
69
+ const v2_i = x_p1 + y_m1_w;
70
+ const v2 = distanceFieldData[v2_i] + d2;
71
+
72
+ if (v2 < v) {
73
+ distanceFieldData[i] = v2;
74
+ v = v2;
75
+ }
76
+
77
+ const v3_i = x_m1 + y_w;
78
+ const v3 = distanceFieldData[v3_i] + d1;
79
+
80
+ if (v3 < v) {
81
+ distanceFieldData[i] = v3;
82
+ }
83
+ }
84
+ }
85
+
86
+ //second pass (backward)
87
+ for (y = maxY; y >= 0; y--) {
88
+ const y_w = y * width;
89
+
90
+ const y_p1 = min2(y + 1, maxY);
91
+ const y_p1_w = y_p1 * width;
92
+
93
+ for (x = maxX; x >= 0; x--) {
94
+ const x_p1 = min2(x + 1, maxX);
95
+ const x_m1 = max2(x - 1, 0);
96
+
97
+ i = y_w + x;
98
+
99
+ v = distanceFieldData[i];
100
+
101
+ const v0_i = x_p1 + y_w;
102
+ const v0 = distanceFieldData[v0_i] + d1;
103
+
104
+ if (v0 < v) {
105
+ distanceFieldData[i] = v0;
106
+ v = v0;
107
+ }
108
+
109
+ const v1_i = x_m1 + y_p1_w;
110
+ const v1 = distanceFieldData[v1_i] + d2;
111
+
112
+ if (v1 < v) {
113
+ distanceFieldData[i] = v1;
114
+ v = v1;
115
+ }
116
+
117
+ const v2_i = x + y_p1_w;
118
+ const v2 = distanceFieldData[v2_i] + d1;
119
+
120
+ if (v2 < v) {
121
+ distanceFieldData[i] = v2;
122
+ v = v2;
123
+ }
124
+
125
+ const v3_i = x_p1 + y_p1_w;
126
+ const v3 = distanceFieldData[v3_i] + d2;
127
+
128
+ if (v3 < v) {
129
+ distanceFieldData[i] = v3;
130
+ }
131
+ }
132
+ }
133
+ }
@@ -1,7 +1,10 @@
1
- import { bessel_i0 } from "../../../../../core/math/bessel_i0.js";
1
+ import { modified_bessel_i0 } from "../../../../../core/math/modified_bessel_i0.js";
2
2
  import { clamp } from "../../../../../core/math/clamp.js";
3
3
 
4
- const BASE_I0 = bessel_i0(6.5);
4
+ const PI2 = 2 * Math.PI;
5
+
6
+ const BASE_I0 = modified_bessel_i0(PI2);
7
+ const INV_BESSEL_I0 = 1 / BASE_I0;
5
8
 
6
9
  /**
7
10
  * Support kernel size is 1
@@ -11,9 +14,10 @@ const BASE_I0 = bessel_i0(6.5);
11
14
  */
12
15
  export function kaiser_1(x) {
13
16
  const i = clamp(x * 0.6666666666666666, -1.0, 1.0);
14
- const i0a = 1 / BASE_I0;
15
17
 
16
- return bessel_i0(6.5 * Math.sqrt(1 - i * i)) * i0a;
18
+ const t = Math.sqrt(1 - i * i);
19
+
20
+ return modified_bessel_i0(PI2 * t) * INV_BESSEL_I0;
17
21
  }
18
22
 
19
23
  kaiser_1.support = 1;
@@ -13,7 +13,9 @@ const INV_BESSEL_3_PI_3 = 1 / BESSEL_3_PI_3;
13
13
  */
14
14
  export function kaiser_bessel_window(x) {
15
15
  const i = clamp(x * 0.6666666666666666, -1.0, 1.0);
16
+
16
17
  const t = Math.sqrt(1.0 - i * i);
18
+
17
19
  return bessel_3(PI3 * t) * INV_BESSEL_3_PI_3;
18
20
  }
19
21
 
@@ -1,3 +1,5 @@
1
+ import { assert } from "../../../../../core/assert.js";
2
+
1
3
  const b = 1.0 / 3.0;
2
4
  const c = 1.0 / 3.0;
3
5
 
@@ -33,6 +35,7 @@ export function mitchell(x) {
33
35
  }
34
36
  return 0.0;
35
37
  }
38
+
36
39
  mitchell.support = 2;
37
40
 
38
41
  /**
@@ -42,6 +45,7 @@ mitchell.support = 2;
42
45
  * @returns {number}
43
46
  */
44
47
  export function mitchell_v1(x) {
48
+ assert.greaterThanOrEqual(x, 0);
45
49
 
46
50
  if (x < 1.0) {
47
51
  return 0.8888888888888888 + x * x * (-2 + x * 1.1666666666666667);