@vib3code/sdk 2.0.1 → 2.0.3-canary.0a63e71

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 (192) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/DOCS/AGENT_HARNESS_ARCHITECTURE.md +245 -0
  3. package/DOCS/ANDROID_DEPLOYMENT.md +59 -0
  4. package/DOCS/ARCHITECTURE.md +1 -0
  5. package/DOCS/CI_TESTING.md +2 -0
  6. package/DOCS/CLI_ONBOARDING.md +3 -1
  7. package/DOCS/CONTROL_REFERENCE.md +2 -0
  8. package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +119 -0
  9. package/DOCS/ENV_SETUP.md +2 -0
  10. package/DOCS/EPIC_SCROLL_EVENTS.md +775 -0
  11. package/DOCS/EXPANSION_DESIGN.md +979 -0
  12. package/DOCS/EXPANSION_DESIGN_ULTRA.md +389 -0
  13. package/DOCS/EXPORT_FORMATS.md +2 -0
  14. package/DOCS/GPU_DISPOSAL_GUIDE.md +2 -0
  15. package/DOCS/HANDOFF_LANDING_PAGE.md +156 -0
  16. package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +495 -0
  17. package/DOCS/LICENSING_TIERS.md +2 -0
  18. package/DOCS/MASTER_PLAN_2026-01-31.md +4 -2
  19. package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +939 -0
  20. package/DOCS/OBS_SETUP_GUIDE.md +2 -0
  21. package/DOCS/OPTIMIZATION_PLAN_MATH.md +119 -0
  22. package/DOCS/PRODUCT_STRATEGY.md +65 -0
  23. package/DOCS/PROJECT_SETUP.md +2 -0
  24. package/DOCS/README.md +105 -0
  25. package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +99 -0
  26. package/DOCS/RENDERER_LIFECYCLE.md +2 -0
  27. package/DOCS/REPO_MANIFEST.md +2 -0
  28. package/DOCS/ROADMAP.md +113 -0
  29. package/DOCS/SCROLL_TIMELINE_v3.md +271 -0
  30. package/DOCS/SITE_REFACTOR_PLAN.md +102 -0
  31. package/DOCS/STATUS.md +26 -0
  32. package/DOCS/SYSTEM_INVENTORY.md +37 -32
  33. package/DOCS/TELEMETRY_EXPORTS.md +2 -0
  34. package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +87 -0
  35. package/DOCS/VISUAL_ANALYSIS_FACETAD.md +135 -0
  36. package/DOCS/VISUAL_ANALYSIS_SIMONE.md +97 -0
  37. package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +88 -0
  38. package/DOCS/WEBGPU_STATUS.md +121 -38
  39. package/DOCS/XR_BENCHMARKS.md +2 -0
  40. package/DOCS/archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +1 -0
  41. package/DOCS/archive/DEV_TRACK_ANALYSIS.md +1 -0
  42. package/DOCS/archive/DEV_TRACK_PLAN_2026-01-07.md +1 -0
  43. package/DOCS/archive/SESSION_014_PLAN.md +1 -0
  44. package/DOCS/archive/SESSION_LOG_2026-01-07.md +1 -0
  45. package/DOCS/archive/STRATEGIC_BLUEPRINT_2026-01-07.md +1 -0
  46. package/DOCS/archive/SYSTEM_AUDIT_2026-01-30.md +1 -0
  47. package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +1 -0
  48. package/DOCS/{DEV_TRACK_SESSION_2026-01-31.md → dev-tracks/DEV_TRACK_SESSION_2026-01-31.md} +3 -1
  49. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +233 -0
  50. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +129 -0
  51. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +144 -0
  52. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +110 -0
  53. package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +310 -0
  54. package/DOCS/dev-tracks/README.md +12 -0
  55. package/README.md +26 -13
  56. package/cpp/CMakeLists.txt +236 -0
  57. package/cpp/bindings/embind.cpp +269 -0
  58. package/cpp/build.sh +129 -0
  59. package/cpp/geometry/Crystal.cpp +103 -0
  60. package/cpp/geometry/Fractal.cpp +136 -0
  61. package/cpp/geometry/GeometryGenerator.cpp +262 -0
  62. package/cpp/geometry/KleinBottle.cpp +71 -0
  63. package/cpp/geometry/Sphere.cpp +134 -0
  64. package/cpp/geometry/Tesseract.cpp +94 -0
  65. package/cpp/geometry/Tetrahedron.cpp +83 -0
  66. package/cpp/geometry/Torus.cpp +65 -0
  67. package/cpp/geometry/WarpFunctions.cpp +238 -0
  68. package/cpp/geometry/Wave.cpp +85 -0
  69. package/cpp/include/vib3_ffi.h +238 -0
  70. package/cpp/math/Mat4x4.cpp +409 -0
  71. package/cpp/math/Mat4x4.hpp +209 -0
  72. package/cpp/math/Projection.cpp +142 -0
  73. package/cpp/math/Projection.hpp +148 -0
  74. package/cpp/math/Rotor4D.cpp +322 -0
  75. package/cpp/math/Rotor4D.hpp +204 -0
  76. package/cpp/math/Vec4.cpp +303 -0
  77. package/cpp/math/Vec4.hpp +225 -0
  78. package/cpp/src/vib3_ffi.cpp +607 -0
  79. package/cpp/tests/Geometry_test.cpp +213 -0
  80. package/cpp/tests/Mat4x4_test.cpp +494 -0
  81. package/cpp/tests/Projection_test.cpp +298 -0
  82. package/cpp/tests/Rotor4D_test.cpp +423 -0
  83. package/cpp/tests/Vec4_test.cpp +489 -0
  84. package/docs/webgpu-live.html +1 -1
  85. package/package.json +41 -30
  86. package/src/agent/index.js +1 -3
  87. package/src/agent/mcp/MCPServer.js +1220 -144
  88. package/src/agent/mcp/index.js +1 -1
  89. package/src/agent/mcp/stdio-server.js +264 -0
  90. package/src/agent/mcp/tools.js +498 -31
  91. package/src/cli/index.js +431 -47
  92. package/src/core/CanvasManager.js +97 -204
  93. package/src/core/ErrorReporter.js +1 -1
  94. package/src/core/Parameters.js +1 -1
  95. package/src/core/VIB3Engine.js +93 -4
  96. package/src/core/VitalitySystem.js +53 -0
  97. package/src/core/index.js +18 -0
  98. package/src/core/renderers/FacetedRendererAdapter.js +10 -9
  99. package/src/core/renderers/HolographicRendererAdapter.js +13 -9
  100. package/src/core/renderers/QuantumRendererAdapter.js +11 -7
  101. package/src/creative/AestheticMapper.js +628 -0
  102. package/src/creative/ChoreographyPlayer.js +481 -0
  103. package/src/creative/index.js +11 -0
  104. package/src/experimental/GameLoop.js +72 -0
  105. package/src/experimental/LatticePhysics.js +100 -0
  106. package/src/experimental/LiveDirector.js +143 -0
  107. package/src/experimental/PlayerController4D.js +154 -0
  108. package/src/experimental/VIB3Actor.js +138 -0
  109. package/src/experimental/VIB3Compositor.js +117 -0
  110. package/src/experimental/VIB3Link.js +122 -0
  111. package/src/experimental/VIB3Orchestrator.js +146 -0
  112. package/src/experimental/VIB3Universe.js +109 -0
  113. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  114. package/src/export/TradingCardManager.js +3 -4
  115. package/src/export/index.js +11 -1
  116. package/src/faceted/FacetedSystem.js +260 -394
  117. package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
  118. package/src/geometry/generators/Crystal.js +2 -2
  119. package/src/geometry/warp/HypersphereCore.js +53 -24
  120. package/src/holograms/HolographicVisualizer.js +84 -98
  121. package/src/holograms/RealHolographicSystem.js +194 -43
  122. package/src/math/Mat4x4.js +308 -105
  123. package/src/math/Rotor4D.js +124 -40
  124. package/src/math/Vec4.js +200 -103
  125. package/src/math/index.js +7 -7
  126. package/src/polychora/PolychoraSystem.js +77 -0
  127. package/src/quantum/QuantumEngine.js +103 -66
  128. package/src/quantum/QuantumVisualizer.js +31 -22
  129. package/src/reactivity/index.js +3 -5
  130. package/src/render/LayerPresetManager.js +372 -0
  131. package/src/render/LayerReactivityBridge.js +344 -0
  132. package/src/render/LayerRelationshipGraph.js +610 -0
  133. package/src/render/MultiCanvasBridge.js +148 -25
  134. package/src/render/ShaderLoader.js +38 -0
  135. package/src/render/ShaderProgram.js +4 -4
  136. package/src/render/UnifiedRenderBridge.js +4 -1
  137. package/src/render/backends/WebGPUBackend.js +8 -4
  138. package/src/render/index.js +27 -2
  139. package/src/scene/Node4D.js +74 -24
  140. package/src/scene/index.js +4 -4
  141. package/src/shaders/common/geometry24.glsl +65 -0
  142. package/src/shaders/common/geometry24.wgsl +54 -0
  143. package/src/shaders/common/rotation4d.glsl +4 -4
  144. package/src/shaders/common/rotation4d.wgsl +2 -2
  145. package/src/shaders/common/uniforms.wgsl +15 -8
  146. package/src/shaders/faceted/faceted.frag.glsl +220 -80
  147. package/src/shaders/faceted/faceted.frag.wgsl +144 -90
  148. package/src/shaders/holographic/holographic.frag.glsl +28 -9
  149. package/src/shaders/holographic/holographic.frag.wgsl +112 -41
  150. package/src/shaders/quantum/quantum.frag.glsl +1 -0
  151. package/src/shaders/quantum/quantum.frag.wgsl +6 -4
  152. package/src/testing/ParallelTestFramework.js +2 -2
  153. package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
  154. package/src/viewer/GalleryUI.js +17 -0
  155. package/src/viewer/ViewerPortal.js +2 -2
  156. package/src/viewer/index.js +1 -1
  157. package/tools/headless-renderer.js +258 -0
  158. package/tools/shader-sync-verify.js +14 -8
  159. package/tools/site-analysis/all-reports.json +32 -0
  160. package/tools/site-analysis/combined-analysis.md +50 -0
  161. package/tools/site-analyzer.mjs +779 -0
  162. package/tools/visual-catalog/capture.js +276 -0
  163. package/tools/visual-catalog/composite.js +138 -0
  164. package/types/adaptive-sdk.d.ts +204 -5
  165. package/types/agent/cli.d.ts +78 -0
  166. package/types/agent/index.d.ts +18 -0
  167. package/types/agent/mcp.d.ts +87 -0
  168. package/types/agent/telemetry.d.ts +190 -0
  169. package/types/core/VIB3Engine.d.ts +26 -0
  170. package/types/core/index.d.ts +261 -0
  171. package/types/creative/AestheticMapper.d.ts +72 -0
  172. package/types/creative/ChoreographyPlayer.d.ts +96 -0
  173. package/types/creative/index.d.ts +17 -0
  174. package/types/export/index.d.ts +243 -0
  175. package/types/geometry/index.d.ts +164 -0
  176. package/types/math/index.d.ts +214 -0
  177. package/types/render/LayerPresetManager.d.ts +78 -0
  178. package/types/render/LayerReactivityBridge.d.ts +85 -0
  179. package/types/render/LayerRelationshipGraph.d.ts +174 -0
  180. package/types/render/index.d.ts +3 -0
  181. package/types/scene/index.d.ts +204 -0
  182. package/types/systems/index.d.ts +244 -0
  183. package/types/variations/index.d.ts +62 -0
  184. package/types/viewer/index.d.ts +225 -0
  185. package/DOCS/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +0 -34
  186. package/DOCS/DEV_TRACK_ANALYSIS.md +0 -77
  187. package/DOCS/DEV_TRACK_PLAN_2026-01-07.md +0 -42
  188. package/DOCS/SESSION_014_PLAN.md +0 -195
  189. package/DOCS/SESSION_LOG_2026-01-07.md +0 -56
  190. package/DOCS/STRATEGIC_BLUEPRINT_2026-01-07.md +0 -72
  191. package/DOCS/SYSTEM_AUDIT_2026-01-30.md +0 -738
  192. /package/src/viewer/{ReactivityManager.js → ViewerInputHandler.js} +0 -0
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Projection_test.cpp - Unit tests for 4D to 3D projection functions
3
+ *
4
+ * Tests perspective, stereographic, orthographic, oblique, and slice projections.
5
+ */
6
+
7
+ #include <gtest/gtest.h>
8
+ #include "math/Projection.hpp"
9
+ #include "math/Vec4.hpp"
10
+ #include <cmath>
11
+
12
+ using namespace vib3;
13
+
14
+ static constexpr float kEpsilon = 1e-5f;
15
+
16
+ // ============================================================================
17
+ // Perspective Projection
18
+ // ============================================================================
19
+
20
+ TEST(Projection, PerspectiveOriginStaysAtOrigin) {
21
+ Vec4 v(0.0f, 0.0f, 0.0f, 0.0f);
22
+ Projection3D p = projectPerspective(v, 2.0f);
23
+ EXPECT_NEAR(p.x, 0.0f, kEpsilon);
24
+ EXPECT_NEAR(p.y, 0.0f, kEpsilon);
25
+ EXPECT_NEAR(p.z, 0.0f, kEpsilon);
26
+ }
27
+
28
+ TEST(Projection, PerspectiveUnitXAtWZero) {
29
+ // P = x * d / (d - w) = 1 * 2 / (2 - 0) = 1
30
+ Vec4 v(1.0f, 0.0f, 0.0f, 0.0f);
31
+ Projection3D p = projectPerspective(v, 2.0f);
32
+ EXPECT_NEAR(p.x, 1.0f, kEpsilon);
33
+ EXPECT_NEAR(p.y, 0.0f, kEpsilon);
34
+ EXPECT_NEAR(p.z, 0.0f, kEpsilon);
35
+ }
36
+
37
+ TEST(Projection, PerspectiveScalesWithW) {
38
+ // Point with w=1, d=2: factor = 2/(2-1) = 2
39
+ Vec4 v(1.0f, 1.0f, 1.0f, 1.0f);
40
+ Projection3D p = projectPerspective(v, 2.0f);
41
+ EXPECT_NEAR(p.x, 2.0f, kEpsilon);
42
+ EXPECT_NEAR(p.y, 2.0f, kEpsilon);
43
+ EXPECT_NEAR(p.z, 2.0f, kEpsilon);
44
+ }
45
+
46
+ TEST(Projection, PerspectiveWithNegativeW) {
47
+ // Point with w=-1, d=2: factor = 2/(2-(-1)) = 2/3
48
+ Vec4 v(3.0f, 0.0f, 0.0f, -1.0f);
49
+ Projection3D p = projectPerspective(v, 2.0f);
50
+ EXPECT_NEAR(p.x, 2.0f, kEpsilon);
51
+ EXPECT_NEAR(p.y, 0.0f, kEpsilon);
52
+ EXPECT_NEAR(p.z, 0.0f, kEpsilon);
53
+ }
54
+
55
+ TEST(Projection, PerspectiveDefaultDistance) {
56
+ // Default distance is 2.0
57
+ Vec4 v(1.0f, 0.0f, 0.0f, 0.0f);
58
+ Projection3D p = projectPerspective(v);
59
+ EXPECT_NEAR(p.x, 1.0f, kEpsilon);
60
+ }
61
+
62
+ // ============================================================================
63
+ // Stereographic Projection
64
+ // ============================================================================
65
+
66
+ TEST(Projection, StereographicOriginStaysAtOrigin) {
67
+ Vec4 v(0.0f, 0.0f, 0.0f, 0.0f);
68
+ Projection3D p = projectStereographic(v);
69
+ EXPECT_NEAR(p.x, 0.0f, kEpsilon);
70
+ EXPECT_NEAR(p.y, 0.0f, kEpsilon);
71
+ EXPECT_NEAR(p.z, 0.0f, kEpsilon);
72
+ }
73
+
74
+ TEST(Projection, StereographicUnitXAtWZero) {
75
+ // P = x / (1 - w) = 1 / (1 - 0) = 1
76
+ Vec4 v(1.0f, 0.0f, 0.0f, 0.0f);
77
+ Projection3D p = projectStereographic(v);
78
+ EXPECT_NEAR(p.x, 1.0f, kEpsilon);
79
+ EXPECT_NEAR(p.y, 0.0f, kEpsilon);
80
+ EXPECT_NEAR(p.z, 0.0f, kEpsilon);
81
+ }
82
+
83
+ TEST(Projection, StereographicWithNegativeW) {
84
+ // P = x / (1 - w) = 1 / (1 - (-1)) = 1/2 = 0.5
85
+ Vec4 v(1.0f, 0.0f, 0.0f, -1.0f);
86
+ Projection3D p = projectStereographic(v);
87
+ EXPECT_NEAR(p.x, 0.5f, kEpsilon);
88
+ EXPECT_NEAR(p.y, 0.0f, kEpsilon);
89
+ }
90
+
91
+ TEST(Projection, StereographicAllComponents) {
92
+ // P = xyz / (1 - w) = (2, 4, 6) / (1 - 0.5) = (4, 8, 12)
93
+ Vec4 v(2.0f, 4.0f, 6.0f, 0.5f);
94
+ Projection3D p = projectStereographic(v);
95
+ EXPECT_NEAR(p.x, 4.0f, kEpsilon);
96
+ EXPECT_NEAR(p.y, 8.0f, kEpsilon);
97
+ EXPECT_NEAR(p.z, 12.0f, kEpsilon);
98
+ }
99
+
100
+ // ============================================================================
101
+ // Orthographic Projection
102
+ // ============================================================================
103
+
104
+ TEST(Projection, OrthographicDropsW) {
105
+ Vec4 v(1.0f, 2.0f, 3.0f, 99.0f);
106
+ Projection3D p = projectOrthographic(v);
107
+ EXPECT_NEAR(p.x, 1.0f, kEpsilon);
108
+ EXPECT_NEAR(p.y, 2.0f, kEpsilon);
109
+ EXPECT_NEAR(p.z, 3.0f, kEpsilon);
110
+ }
111
+
112
+ TEST(Projection, OrthographicOriginStaysAtOrigin) {
113
+ Vec4 v(0.0f, 0.0f, 0.0f, 0.0f);
114
+ Projection3D p = projectOrthographic(v);
115
+ EXPECT_NEAR(p.x, 0.0f, kEpsilon);
116
+ EXPECT_NEAR(p.y, 0.0f, kEpsilon);
117
+ EXPECT_NEAR(p.z, 0.0f, kEpsilon);
118
+ }
119
+
120
+ TEST(Projection, OrthographicIgnoresW) {
121
+ // Two points differing only in W should project to the same 3D point
122
+ Vec4 v1(5.0f, 6.0f, 7.0f, 0.0f);
123
+ Vec4 v2(5.0f, 6.0f, 7.0f, 100.0f);
124
+ Projection3D p1 = projectOrthographic(v1);
125
+ Projection3D p2 = projectOrthographic(v2);
126
+ EXPECT_NEAR(p1.x, p2.x, kEpsilon);
127
+ EXPECT_NEAR(p1.y, p2.y, kEpsilon);
128
+ EXPECT_NEAR(p1.z, p2.z, kEpsilon);
129
+ }
130
+
131
+ TEST(Projection, OrthographicNegativeValues) {
132
+ Vec4 v(-3.0f, -4.0f, -5.0f, 10.0f);
133
+ Projection3D p = projectOrthographic(v);
134
+ EXPECT_NEAR(p.x, -3.0f, kEpsilon);
135
+ EXPECT_NEAR(p.y, -4.0f, kEpsilon);
136
+ EXPECT_NEAR(p.z, -5.0f, kEpsilon);
137
+ }
138
+
139
+ // ============================================================================
140
+ // Oblique Projection
141
+ // ============================================================================
142
+
143
+ TEST(Projection, ObliqueOriginStaysAtOrigin) {
144
+ Vec4 v(0.0f, 0.0f, 0.0f, 0.0f);
145
+ Projection3D p = projectOblique(v);
146
+ EXPECT_NEAR(p.x, 0.0f, kEpsilon);
147
+ EXPECT_NEAR(p.y, 0.0f, kEpsilon);
148
+ EXPECT_NEAR(p.z, 0.0f, kEpsilon);
149
+ }
150
+
151
+ TEST(Projection, ObliqueWithWZeroMatchesOrthographic) {
152
+ Vec4 v(1.0f, 2.0f, 3.0f, 0.0f);
153
+ Projection3D pObl = projectOblique(v);
154
+ Projection3D pOrt = projectOrthographic(v);
155
+ EXPECT_NEAR(pObl.x, pOrt.x, kEpsilon);
156
+ EXPECT_NEAR(pObl.y, pOrt.y, kEpsilon);
157
+ EXPECT_NEAR(pObl.z, pOrt.z, kEpsilon);
158
+ }
159
+
160
+ TEST(Projection, ObliqueAddsShear) {
161
+ // With default shear (0.5, 0.5, 0.0), w=2:
162
+ // x' = x + shearX*w = 1 + 0.5*2 = 2
163
+ // y' = y + shearY*w = 0 + 0.5*2 = 1
164
+ // z' = z + shearZ*w = 0 + 0.0*2 = 0
165
+ Vec4 v(1.0f, 0.0f, 0.0f, 2.0f);
166
+ Projection3D p = projectOblique(v, 0.5f, 0.5f, 0.0f);
167
+ EXPECT_NEAR(p.x, 2.0f, kEpsilon);
168
+ EXPECT_NEAR(p.y, 1.0f, kEpsilon);
169
+ EXPECT_NEAR(p.z, 0.0f, kEpsilon);
170
+ }
171
+
172
+ // ============================================================================
173
+ // Slice Projection
174
+ // ============================================================================
175
+
176
+ TEST(Projection, SliceAtOriginValidForWZero) {
177
+ Vec4 v(1.0f, 2.0f, 3.0f, 0.0f);
178
+ SliceResult sr = projectSlice(v, 0.0f, 0.1f, true);
179
+ EXPECT_TRUE(sr.valid);
180
+ EXPECT_NEAR(sr.point.x, 1.0f, kEpsilon);
181
+ EXPECT_NEAR(sr.point.y, 2.0f, kEpsilon);
182
+ EXPECT_NEAR(sr.point.z, 3.0f, kEpsilon);
183
+ EXPECT_NEAR(sr.alpha, 1.0f, kEpsilon); // At center of slice
184
+ }
185
+
186
+ TEST(Projection, SliceOutsideThicknessIsInvalid) {
187
+ Vec4 v(1.0f, 2.0f, 3.0f, 5.0f);
188
+ SliceResult sr = projectSlice(v, 0.0f, 0.1f, true);
189
+ EXPECT_FALSE(sr.valid);
190
+ }
191
+
192
+ TEST(Projection, SliceAtEdgeHasLowAlpha) {
193
+ // Point at sliceW + thickness should have alpha near 0
194
+ float sliceW = 0.0f;
195
+ float thickness = 1.0f;
196
+ Vec4 v(1.0f, 0.0f, 0.0f, 0.9f); // Near the edge
197
+ SliceResult sr = projectSlice(v, sliceW, thickness, true);
198
+ if (sr.valid) {
199
+ EXPECT_LT(sr.alpha, 0.5f);
200
+ }
201
+ }
202
+
203
+ // ============================================================================
204
+ // Projection3D Helper
205
+ // ============================================================================
206
+
207
+ TEST(Projection, Projection3DDefaultConstructor) {
208
+ Projection3D p;
209
+ EXPECT_FLOAT_EQ(p.x, 0.0f);
210
+ EXPECT_FLOAT_EQ(p.y, 0.0f);
211
+ EXPECT_FLOAT_EQ(p.z, 0.0f);
212
+ }
213
+
214
+ TEST(Projection, Projection3DToArray) {
215
+ Projection3D p(1.0f, 2.0f, 3.0f);
216
+ auto arr = p.toArray();
217
+ EXPECT_FLOAT_EQ(arr[0], 1.0f);
218
+ EXPECT_FLOAT_EQ(arr[1], 2.0f);
219
+ EXPECT_FLOAT_EQ(arr[2], 3.0f);
220
+ }
221
+
222
+ // ============================================================================
223
+ // Batch Projections
224
+ // ============================================================================
225
+
226
+ TEST(Projection, BatchPerspectiveEmpty) {
227
+ std::vector<Vec4> empty;
228
+ auto result = projectPerspectiveBatch(empty, 2.0f);
229
+ EXPECT_TRUE(result.empty());
230
+ }
231
+
232
+ TEST(Projection, BatchPerspectiveSinglePoint) {
233
+ std::vector<Vec4> points = {Vec4(1.0f, 0.0f, 0.0f, 0.0f)};
234
+ auto result = projectPerspectiveBatch(points, 2.0f);
235
+ EXPECT_EQ(result.size(), 1u);
236
+ EXPECT_NEAR(result[0].x, 1.0f, kEpsilon);
237
+ }
238
+
239
+ TEST(Projection, BatchPerspectiveMultiplePoints) {
240
+ std::vector<Vec4> points = {
241
+ Vec4(0.0f, 0.0f, 0.0f, 0.0f),
242
+ Vec4(1.0f, 0.0f, 0.0f, 0.0f),
243
+ Vec4(0.0f, 1.0f, 0.0f, 0.0f)
244
+ };
245
+ auto result = projectPerspectiveBatch(points, 2.0f);
246
+ EXPECT_EQ(result.size(), 3u);
247
+ }
248
+
249
+ TEST(Projection, BatchStereographic) {
250
+ std::vector<Vec4> points = {Vec4(1.0f, 0.0f, 0.0f, 0.0f)};
251
+ auto result = projectStereographicBatch(points);
252
+ EXPECT_EQ(result.size(), 1u);
253
+ EXPECT_NEAR(result[0].x, 1.0f, kEpsilon);
254
+ }
255
+
256
+ TEST(Projection, BatchOrthographic) {
257
+ std::vector<Vec4> points = {Vec4(1.0f, 2.0f, 3.0f, 99.0f)};
258
+ auto result = projectOrthographicBatch(points);
259
+ EXPECT_EQ(result.size(), 1u);
260
+ EXPECT_NEAR(result[0].x, 1.0f, kEpsilon);
261
+ EXPECT_NEAR(result[0].y, 2.0f, kEpsilon);
262
+ EXPECT_NEAR(result[0].z, 3.0f, kEpsilon);
263
+ }
264
+
265
+ TEST(Projection, ProjectToFloatArray) {
266
+ std::vector<Vec4> points = {
267
+ Vec4(1.0f, 2.0f, 3.0f, 0.0f),
268
+ Vec4(4.0f, 5.0f, 6.0f, 0.0f)
269
+ };
270
+ auto result = projectToFloatArray(points, 2.0f);
271
+ // 2 points * 3 floats each = 6
272
+ EXPECT_EQ(result.size(), 6u);
273
+ EXPECT_NEAR(result[0], 1.0f, kEpsilon); // first point x
274
+ EXPECT_NEAR(result[1], 2.0f, kEpsilon); // first point y
275
+ EXPECT_NEAR(result[2], 3.0f, kEpsilon); // first point z
276
+ }
277
+
278
+ // ============================================================================
279
+ // ProjectionParams defaults
280
+ // ============================================================================
281
+
282
+ TEST(Projection, ProjectionParamsDefaults) {
283
+ auto params = ProjectionParams::defaults();
284
+ EXPECT_FLOAT_EQ(params.distance, 2.0f);
285
+ EXPECT_FLOAT_EQ(params.viewerW, 0.0f);
286
+ EXPECT_FLOAT_EQ(params.sliceW, 0.0f);
287
+ EXPECT_FLOAT_EQ(params.sliceThickness, 0.1f);
288
+ }
289
+
290
+ // ============================================================================
291
+ // SliceResult::invalid
292
+ // ============================================================================
293
+
294
+ TEST(Projection, SliceResultInvalid) {
295
+ auto sr = SliceResult::invalid();
296
+ EXPECT_FALSE(sr.valid);
297
+ EXPECT_FLOAT_EQ(sr.alpha, 0.0f);
298
+ }