@vib3code/sdk 2.0.1
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/CHANGELOG.md +118 -0
- package/DOCS/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +34 -0
- package/DOCS/CI_TESTING.md +38 -0
- package/DOCS/CLI_ONBOARDING.md +75 -0
- package/DOCS/CONTROL_REFERENCE.md +64 -0
- package/DOCS/DEV_TRACK_ANALYSIS.md +77 -0
- package/DOCS/DEV_TRACK_PLAN_2026-01-07.md +42 -0
- package/DOCS/DEV_TRACK_SESSION_2026-01-31.md +220 -0
- package/DOCS/ENV_SETUP.md +189 -0
- package/DOCS/EXPORT_FORMATS.md +417 -0
- package/DOCS/GPU_DISPOSAL_GUIDE.md +21 -0
- package/DOCS/LICENSING_TIERS.md +275 -0
- package/DOCS/MASTER_PLAN_2026-01-31.md +570 -0
- package/DOCS/OBS_SETUP_GUIDE.md +98 -0
- package/DOCS/PROJECT_SETUP.md +66 -0
- package/DOCS/RENDERER_LIFECYCLE.md +40 -0
- package/DOCS/REPO_MANIFEST.md +121 -0
- package/DOCS/SESSION_014_PLAN.md +195 -0
- package/DOCS/SESSION_LOG_2026-01-07.md +56 -0
- package/DOCS/STRATEGIC_BLUEPRINT_2026-01-07.md +72 -0
- package/DOCS/SYSTEM_AUDIT_2026-01-30.md +738 -0
- package/DOCS/SYSTEM_INVENTORY.md +520 -0
- package/DOCS/TELEMETRY_EXPORTS.md +34 -0
- package/DOCS/WEBGPU_STATUS.md +38 -0
- package/DOCS/XR_BENCHMARKS.md +608 -0
- package/LICENSE +21 -0
- package/README.md +426 -0
- package/docs/.nojekyll +0 -0
- package/docs/01-dissolution_of_euclidean_hegemony.html +346 -0
- package/docs/02-hyperspatial_ego_death.html +346 -0
- package/docs/03-post_cartesian_sublime.html +346 -0
- package/docs/04-crystalline_void_meditation.html +346 -0
- package/docs/05-quantum_decoherence_ballet.html +346 -0
- package/docs/06-dissolution_of_euclidean_hegemony.html +346 -0
- package/docs/07-hyperspatial_ego_death.html +346 -0
- package/docs/08-post_cartesian_sublime.html +346 -0
- package/docs/09-crystalline_void_meditation.html +346 -0
- package/docs/10-quantum_decoherence_ballet.html +346 -0
- package/docs/11-dissolution_of_euclidean_hegemony.html +346 -0
- package/docs/12-hyperspatial_ego_death.html +346 -0
- package/docs/13-post_cartesian_sublime.html +346 -0
- package/docs/index.html +794 -0
- package/docs/test-hub.html +441 -0
- package/docs/url-state.js +102 -0
- package/docs/vib3-exports/01-quantum-quantum-tetrahedron-lattice.html +489 -0
- package/docs/vib3-exports/02-quantum-quantum-hypersphere-matrix.html +489 -0
- package/docs/vib3-exports/03-quantum-quantum-hypertetra-fractal.html +489 -0
- package/docs/vib3-exports/04-faceted-faceted-crystal-structure.html +407 -0
- package/docs/vib3-exports/05-faceted-faceted-klein-bottle.html +407 -0
- package/docs/vib3-exports/06-faceted-faceted-hypertetra-torus.html +407 -0
- package/docs/vib3-exports/07-holographic-holographic-wave-field.html +457 -0
- package/docs/vib3-exports/08-holographic-holographic-hypersphere-sphere.html +457 -0
- package/docs/vib3-exports/09-holographic-holographic-hypertetra-crystal.html +457 -0
- package/docs/vib3-exports/index.html +238 -0
- package/docs/webgpu-live.html +702 -0
- package/package.json +367 -0
- package/src/advanced/AIPresetGenerator.js +777 -0
- package/src/advanced/MIDIController.js +703 -0
- package/src/advanced/OffscreenWorker.js +1051 -0
- package/src/advanced/WebGPUCompute.js +1051 -0
- package/src/advanced/WebXRRenderer.js +680 -0
- package/src/agent/cli/AgentCLI.js +615 -0
- package/src/agent/cli/index.js +14 -0
- package/src/agent/index.js +73 -0
- package/src/agent/mcp/MCPServer.js +950 -0
- package/src/agent/mcp/index.js +9 -0
- package/src/agent/mcp/tools.js +548 -0
- package/src/agent/telemetry/EventStream.js +669 -0
- package/src/agent/telemetry/Instrumentation.js +618 -0
- package/src/agent/telemetry/TelemetryExporters.js +427 -0
- package/src/agent/telemetry/TelemetryService.js +464 -0
- package/src/agent/telemetry/index.js +52 -0
- package/src/benchmarks/BenchmarkRunner.js +381 -0
- package/src/benchmarks/MetricsCollector.js +299 -0
- package/src/benchmarks/index.js +9 -0
- package/src/benchmarks/scenes.js +259 -0
- package/src/cli/index.js +675 -0
- package/src/config/ApiConfig.js +88 -0
- package/src/core/CanvasManager.js +217 -0
- package/src/core/ErrorReporter.js +117 -0
- package/src/core/ParameterMapper.js +333 -0
- package/src/core/Parameters.js +396 -0
- package/src/core/RendererContracts.js +200 -0
- package/src/core/UnifiedResourceManager.js +370 -0
- package/src/core/VIB3Engine.js +636 -0
- package/src/core/renderers/FacetedRendererAdapter.js +32 -0
- package/src/core/renderers/HolographicRendererAdapter.js +29 -0
- package/src/core/renderers/QuantumRendererAdapter.js +29 -0
- package/src/core/renderers/RendererLifecycleManager.js +63 -0
- package/src/creative/ColorPresetsSystem.js +980 -0
- package/src/creative/ParameterTimeline.js +1061 -0
- package/src/creative/PostProcessingPipeline.js +1113 -0
- package/src/creative/TransitionAnimator.js +683 -0
- package/src/export/CSSExporter.js +226 -0
- package/src/export/CardGeneratorBase.js +279 -0
- package/src/export/ExportManager.js +580 -0
- package/src/export/FacetedCardGenerator.js +279 -0
- package/src/export/HolographicCardGenerator.js +543 -0
- package/src/export/LottieExporter.js +552 -0
- package/src/export/QuantumCardGenerator.js +315 -0
- package/src/export/SVGExporter.js +519 -0
- package/src/export/ShaderExporter.js +903 -0
- package/src/export/TradingCardGenerator.js +3055 -0
- package/src/export/TradingCardManager.js +181 -0
- package/src/export/VIB3PackageExporter.js +559 -0
- package/src/export/index.js +14 -0
- package/src/export/systems/TradingCardSystemFaceted.js +494 -0
- package/src/export/systems/TradingCardSystemHolographic.js +452 -0
- package/src/export/systems/TradingCardSystemQuantum.js +411 -0
- package/src/faceted/FacetedSystem.js +963 -0
- package/src/features/CollectionManager.js +433 -0
- package/src/gallery/CollectionManager.js +240 -0
- package/src/gallery/GallerySystem.js +485 -0
- package/src/geometry/GeometryFactory.js +314 -0
- package/src/geometry/GeometryLibrary.js +72 -0
- package/src/geometry/buffers/BufferBuilder.js +338 -0
- package/src/geometry/buffers/index.js +18 -0
- package/src/geometry/generators/Crystal.js +420 -0
- package/src/geometry/generators/Fractal.js +298 -0
- package/src/geometry/generators/KleinBottle.js +197 -0
- package/src/geometry/generators/Sphere.js +192 -0
- package/src/geometry/generators/Tesseract.js +160 -0
- package/src/geometry/generators/Tetrahedron.js +225 -0
- package/src/geometry/generators/Torus.js +304 -0
- package/src/geometry/generators/Wave.js +341 -0
- package/src/geometry/index.js +142 -0
- package/src/geometry/warp/HypersphereCore.js +211 -0
- package/src/geometry/warp/HypertetraCore.js +386 -0
- package/src/geometry/warp/index.js +57 -0
- package/src/holograms/HolographicVisualizer.js +1073 -0
- package/src/holograms/RealHolographicSystem.js +966 -0
- package/src/holograms/variantRegistry.js +69 -0
- package/src/integrations/FigmaPlugin.js +854 -0
- package/src/integrations/OBSMode.js +754 -0
- package/src/integrations/ThreeJsPackage.js +660 -0
- package/src/integrations/TouchDesignerExport.js +552 -0
- package/src/integrations/frameworks/Vib3React.js +591 -0
- package/src/integrations/frameworks/Vib3Svelte.js +654 -0
- package/src/integrations/frameworks/Vib3Vue.js +628 -0
- package/src/llm/LLMParameterInterface.js +240 -0
- package/src/llm/LLMParameterUI.js +577 -0
- package/src/math/Mat4x4.js +708 -0
- package/src/math/Projection.js +341 -0
- package/src/math/Rotor4D.js +637 -0
- package/src/math/Vec4.js +476 -0
- package/src/math/constants.js +164 -0
- package/src/math/index.js +68 -0
- package/src/math/projections.js +54 -0
- package/src/math/rotations.js +196 -0
- package/src/quantum/QuantumEngine.js +906 -0
- package/src/quantum/QuantumVisualizer.js +1103 -0
- package/src/reactivity/ReactivityConfig.js +499 -0
- package/src/reactivity/ReactivityManager.js +586 -0
- package/src/reactivity/SpatialInputSystem.js +1783 -0
- package/src/reactivity/index.js +93 -0
- package/src/render/CommandBuffer.js +465 -0
- package/src/render/MultiCanvasBridge.js +340 -0
- package/src/render/RenderCommand.js +514 -0
- package/src/render/RenderResourceRegistry.js +523 -0
- package/src/render/RenderState.js +552 -0
- package/src/render/RenderTarget.js +512 -0
- package/src/render/ShaderLoader.js +253 -0
- package/src/render/ShaderProgram.js +599 -0
- package/src/render/UnifiedRenderBridge.js +496 -0
- package/src/render/backends/WebGLBackend.js +1108 -0
- package/src/render/backends/WebGPUBackend.js +1409 -0
- package/src/render/commands/CommandBufferExecutor.js +607 -0
- package/src/render/commands/RenderCommandBuffer.js +661 -0
- package/src/render/commands/index.js +17 -0
- package/src/render/index.js +367 -0
- package/src/scene/Disposable.js +498 -0
- package/src/scene/MemoryPool.js +618 -0
- package/src/scene/Node4D.js +697 -0
- package/src/scene/ResourceManager.js +599 -0
- package/src/scene/Scene4D.js +540 -0
- package/src/scene/index.js +98 -0
- package/src/schemas/error.schema.json +84 -0
- package/src/schemas/extension.schema.json +88 -0
- package/src/schemas/index.js +214 -0
- package/src/schemas/parameters.schema.json +142 -0
- package/src/schemas/tool-pack.schema.json +44 -0
- package/src/schemas/tool-response.schema.json +127 -0
- package/src/shaders/common/fullscreen.vert.glsl +5 -0
- package/src/shaders/common/fullscreen.vert.wgsl +17 -0
- package/src/shaders/common/geometry24.glsl +65 -0
- package/src/shaders/common/geometry24.wgsl +54 -0
- package/src/shaders/common/rotation4d.glsl +85 -0
- package/src/shaders/common/rotation4d.wgsl +86 -0
- package/src/shaders/common/uniforms.glsl +44 -0
- package/src/shaders/common/uniforms.wgsl +48 -0
- package/src/shaders/faceted/faceted.frag.glsl +129 -0
- package/src/shaders/faceted/faceted.frag.wgsl +164 -0
- package/src/shaders/holographic/holographic.frag.glsl +406 -0
- package/src/shaders/holographic/holographic.frag.wgsl +185 -0
- package/src/shaders/quantum/quantum.frag.glsl +513 -0
- package/src/shaders/quantum/quantum.frag.wgsl +361 -0
- package/src/testing/ParallelTestFramework.js +519 -0
- package/src/testing/__snapshots__/exportFormats.test.js.snap +24 -0
- package/src/testing/exportFormats.test.js +8 -0
- package/src/testing/projections.test.js +14 -0
- package/src/testing/rotations.test.js +37 -0
- package/src/ui/InteractivityMenu.js +516 -0
- package/src/ui/StatusManager.js +96 -0
- package/src/ui/adaptive/renderers/webgpu/BufferLayout.ts +252 -0
- package/src/ui/adaptive/renderers/webgpu/PolytopeInstanceBuffer.ts +144 -0
- package/src/ui/adaptive/renderers/webgpu/TripleBufferedUniform.ts +170 -0
- package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +735 -0
- package/src/ui/adaptive/renderers/webgpu/index.ts +112 -0
- package/src/variations/VariationManager.js +431 -0
- package/src/viewer/AudioReactivity.js +505 -0
- package/src/viewer/CardBending.js +481 -0
- package/src/viewer/GalleryUI.js +832 -0
- package/src/viewer/ReactivityManager.js +590 -0
- package/src/viewer/TradingCardExporter.js +600 -0
- package/src/viewer/ViewerPortal.js +374 -0
- package/src/viewer/index.js +12 -0
- package/src/wasm/WasmLoader.js +296 -0
- package/src/wasm/index.js +132 -0
- package/tools/agentic/mcpTools.js +88 -0
- package/tools/cli/agent-cli.js +92 -0
- package/tools/export/formats.js +24 -0
- package/tools/math/rotation-baseline.mjs +64 -0
- package/tools/shader-sync-verify.js +937 -0
- package/tools/telemetry/manifestPipeline.js +141 -0
- package/tools/telemetry/telemetryEvents.js +35 -0
- package/types/adaptive-sdk.d.ts +185 -0
- package/types/advanced/AIPresetGenerator.d.ts +81 -0
- package/types/advanced/MIDIController.d.ts +100 -0
- package/types/advanced/OffscreenWorker.d.ts +82 -0
- package/types/advanced/WebGPUCompute.d.ts +52 -0
- package/types/advanced/WebXRRenderer.d.ts +77 -0
- package/types/advanced/index.d.ts +46 -0
- package/types/core/ErrorReporter.d.ts +50 -0
- package/types/core/VIB3Engine.d.ts +204 -0
- package/types/creative/ColorPresetsSystem.d.ts +91 -0
- package/types/creative/ParameterTimeline.d.ts +74 -0
- package/types/creative/PostProcessingPipeline.d.ts +109 -0
- package/types/creative/TransitionAnimator.d.ts +71 -0
- package/types/creative/index.d.ts +35 -0
- package/types/integrations/FigmaPlugin.d.ts +46 -0
- package/types/integrations/OBSMode.d.ts +74 -0
- package/types/integrations/ThreeJsPackage.d.ts +62 -0
- package/types/integrations/TouchDesignerExport.d.ts +36 -0
- package/types/integrations/Vib3React.d.ts +74 -0
- package/types/integrations/Vib3Svelte.d.ts +63 -0
- package/types/integrations/Vib3Vue.d.ts +55 -0
- package/types/integrations/index.d.ts +52 -0
- package/types/reactivity/SpatialInputSystem.d.ts +173 -0
- package/types/reactivity/index.d.ts +394 -0
- package/types/render/CommandBuffer.d.ts +169 -0
- package/types/render/RenderCommand.d.ts +312 -0
- package/types/render/RenderState.d.ts +279 -0
- package/types/render/RenderTarget.d.ts +254 -0
- package/types/render/ShaderProgram.d.ts +277 -0
- package/types/render/UnifiedRenderBridge.d.ts +143 -0
- package/types/render/WebGLBackend.d.ts +168 -0
- package/types/render/WebGPUBackend.d.ts +186 -0
- package/types/render/index.d.ts +141 -0
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rotor4D - 4D Rotation using Geometric Algebra
|
|
3
|
+
*
|
|
4
|
+
* A rotor represents a rotation in 4D space using 8 components:
|
|
5
|
+
* - 1 scalar (s)
|
|
6
|
+
* - 6 bivector components (one per rotation plane: xy, xz, yz, xw, yw, zw)
|
|
7
|
+
* - 1 pseudoscalar (xyzw)
|
|
8
|
+
*
|
|
9
|
+
* Unlike quaternions (which only work for 3D), rotors properly handle
|
|
10
|
+
* all 6 rotation planes in 4D. Rotation is applied via sandwich product:
|
|
11
|
+
* v' = R v R†
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // Create rotor for 45° rotation in XW plane
|
|
15
|
+
* const rotor = Rotor4D.fromAxisAngle('XW', Math.PI / 4);
|
|
16
|
+
* const rotated = rotor.rotate(vec4);
|
|
17
|
+
*
|
|
18
|
+
* // Compose rotations
|
|
19
|
+
* const combined = rotor1.multiply(rotor2);
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { Vec4 } from './Vec4.js';
|
|
23
|
+
|
|
24
|
+
export class Rotor4D {
|
|
25
|
+
/**
|
|
26
|
+
* Create a new 4D rotor
|
|
27
|
+
* Default is identity rotor (no rotation)
|
|
28
|
+
*
|
|
29
|
+
* @param {number} s - Scalar component
|
|
30
|
+
* @param {number} xy - XY bivector (rotation in XY plane)
|
|
31
|
+
* @param {number} xz - XZ bivector
|
|
32
|
+
* @param {number} yz - YZ bivector
|
|
33
|
+
* @param {number} xw - XW bivector (4D rotation plane)
|
|
34
|
+
* @param {number} yw - YW bivector
|
|
35
|
+
* @param {number} zw - ZW bivector
|
|
36
|
+
* @param {number} xyzw - Pseudoscalar (4D volume element)
|
|
37
|
+
*/
|
|
38
|
+
constructor(s = 1, xy = 0, xz = 0, yz = 0, xw = 0, yw = 0, zw = 0, xyzw = 0) {
|
|
39
|
+
this.s = s;
|
|
40
|
+
this.xy = xy;
|
|
41
|
+
this.xz = xz;
|
|
42
|
+
this.yz = yz;
|
|
43
|
+
this.xw = xw;
|
|
44
|
+
this.yw = yw;
|
|
45
|
+
this.zw = zw;
|
|
46
|
+
this.xyzw = xyzw;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Create identity rotor (no rotation)
|
|
51
|
+
* @returns {Rotor4D}
|
|
52
|
+
*/
|
|
53
|
+
static identity() {
|
|
54
|
+
return new Rotor4D(1, 0, 0, 0, 0, 0, 0, 0);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create a copy of this rotor
|
|
59
|
+
* @returns {Rotor4D}
|
|
60
|
+
*/
|
|
61
|
+
clone() {
|
|
62
|
+
return new Rotor4D(
|
|
63
|
+
this.s, this.xy, this.xz, this.yz,
|
|
64
|
+
this.xw, this.yw, this.zw, this.xyzw
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Copy values from another rotor
|
|
70
|
+
* @param {Rotor4D} r
|
|
71
|
+
* @returns {Rotor4D} this
|
|
72
|
+
*/
|
|
73
|
+
copy(r) {
|
|
74
|
+
this.s = r.s;
|
|
75
|
+
this.xy = r.xy;
|
|
76
|
+
this.xz = r.xz;
|
|
77
|
+
this.yz = r.yz;
|
|
78
|
+
this.xw = r.xw;
|
|
79
|
+
this.yw = r.yw;
|
|
80
|
+
this.zw = r.zw;
|
|
81
|
+
this.xyzw = r.xyzw;
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Create rotor from rotation in a single plane
|
|
87
|
+
*
|
|
88
|
+
* @param {string} plane - One of 'XY', 'XZ', 'YZ', 'XW', 'YW', 'ZW'
|
|
89
|
+
* @param {number} angle - Rotation angle in radians
|
|
90
|
+
* @returns {Rotor4D}
|
|
91
|
+
*/
|
|
92
|
+
static fromPlaneAngle(plane, angle) {
|
|
93
|
+
const halfAngle = angle / 2;
|
|
94
|
+
const c = Math.cos(halfAngle);
|
|
95
|
+
const s = Math.sin(halfAngle);
|
|
96
|
+
|
|
97
|
+
const rotor = new Rotor4D();
|
|
98
|
+
rotor.s = c;
|
|
99
|
+
|
|
100
|
+
// Set the appropriate bivector component
|
|
101
|
+
// Positive bivector for counterclockwise rotation convention
|
|
102
|
+
switch (plane.toUpperCase()) {
|
|
103
|
+
case 'XY': rotor.xy = s; break;
|
|
104
|
+
case 'XZ': rotor.xz = s; break;
|
|
105
|
+
case 'YZ': rotor.yz = s; break;
|
|
106
|
+
case 'XW': rotor.xw = s; break;
|
|
107
|
+
case 'YW': rotor.yw = s; break;
|
|
108
|
+
case 'ZW': rotor.zw = s; break;
|
|
109
|
+
default:
|
|
110
|
+
throw new Error(`Invalid rotation plane: ${plane}. Use XY, XZ, YZ, XW, YW, or ZW.`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return rotor;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Create rotor from all 6 rotation angles
|
|
118
|
+
* Composes rotations in order: XY, XZ, YZ, XW, YW, ZW
|
|
119
|
+
*
|
|
120
|
+
* @param {object} angles - Object with rotation angles
|
|
121
|
+
* @param {number} angles.xy - XY plane rotation
|
|
122
|
+
* @param {number} angles.xz - XZ plane rotation
|
|
123
|
+
* @param {number} angles.yz - YZ plane rotation
|
|
124
|
+
* @param {number} angles.xw - XW plane rotation
|
|
125
|
+
* @param {number} angles.yw - YW plane rotation
|
|
126
|
+
* @param {number} angles.zw - ZW plane rotation
|
|
127
|
+
* @returns {Rotor4D}
|
|
128
|
+
*/
|
|
129
|
+
static fromEuler6(angles) {
|
|
130
|
+
let result = Rotor4D.identity();
|
|
131
|
+
|
|
132
|
+
// Apply rotations in consistent order
|
|
133
|
+
if (angles.xy) result = result.multiply(Rotor4D.fromPlaneAngle('XY', angles.xy));
|
|
134
|
+
if (angles.xz) result = result.multiply(Rotor4D.fromPlaneAngle('XZ', angles.xz));
|
|
135
|
+
if (angles.yz) result = result.multiply(Rotor4D.fromPlaneAngle('YZ', angles.yz));
|
|
136
|
+
if (angles.xw) result = result.multiply(Rotor4D.fromPlaneAngle('XW', angles.xw));
|
|
137
|
+
if (angles.yw) result = result.multiply(Rotor4D.fromPlaneAngle('YW', angles.yw));
|
|
138
|
+
if (angles.zw) result = result.multiply(Rotor4D.fromPlaneAngle('ZW', angles.zw));
|
|
139
|
+
|
|
140
|
+
return result.normalizeInPlace();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Create rotor from parameter format (rot4dXY, rot4dXZ, etc.)
|
|
145
|
+
* @param {object} params - Parameters object
|
|
146
|
+
* @returns {Rotor4D}
|
|
147
|
+
*/
|
|
148
|
+
static fromParameters(params) {
|
|
149
|
+
return Rotor4D.fromEuler6({
|
|
150
|
+
xy: params.rot4dXY || 0,
|
|
151
|
+
xz: params.rot4dXZ || 0,
|
|
152
|
+
yz: params.rot4dYZ || 0,
|
|
153
|
+
xw: params.rot4dXW || 0,
|
|
154
|
+
yw: params.rot4dYW || 0,
|
|
155
|
+
zw: params.rot4dZW || 0
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Squared norm of the rotor
|
|
161
|
+
* @returns {number}
|
|
162
|
+
*/
|
|
163
|
+
normSquared() {
|
|
164
|
+
return (
|
|
165
|
+
this.s * this.s +
|
|
166
|
+
this.xy * this.xy +
|
|
167
|
+
this.xz * this.xz +
|
|
168
|
+
this.yz * this.yz +
|
|
169
|
+
this.xw * this.xw +
|
|
170
|
+
this.yw * this.yw +
|
|
171
|
+
this.zw * this.zw +
|
|
172
|
+
this.xyzw * this.xyzw
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Norm (magnitude) of the rotor
|
|
178
|
+
* @returns {number}
|
|
179
|
+
*/
|
|
180
|
+
norm() {
|
|
181
|
+
return Math.sqrt(this.normSquared());
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Normalize rotor to unit length (immutable)
|
|
186
|
+
* CRITICAL: Call this regularly to prevent drift!
|
|
187
|
+
* @returns {Rotor4D}
|
|
188
|
+
*/
|
|
189
|
+
normalize() {
|
|
190
|
+
const n = this.norm();
|
|
191
|
+
if (n < 1e-10) {
|
|
192
|
+
return Rotor4D.identity();
|
|
193
|
+
}
|
|
194
|
+
const invN = 1 / n;
|
|
195
|
+
return new Rotor4D(
|
|
196
|
+
this.s * invN,
|
|
197
|
+
this.xy * invN,
|
|
198
|
+
this.xz * invN,
|
|
199
|
+
this.yz * invN,
|
|
200
|
+
this.xw * invN,
|
|
201
|
+
this.yw * invN,
|
|
202
|
+
this.zw * invN,
|
|
203
|
+
this.xyzw * invN
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Normalize rotor in place (mutable)
|
|
209
|
+
* @returns {Rotor4D} this
|
|
210
|
+
*/
|
|
211
|
+
normalizeInPlace() {
|
|
212
|
+
const n = this.norm();
|
|
213
|
+
if (n < 1e-10) {
|
|
214
|
+
this.s = 1;
|
|
215
|
+
this.xy = this.xz = this.yz = 0;
|
|
216
|
+
this.xw = this.yw = this.zw = 0;
|
|
217
|
+
this.xyzw = 0;
|
|
218
|
+
return this;
|
|
219
|
+
}
|
|
220
|
+
const invN = 1 / n;
|
|
221
|
+
this.s *= invN;
|
|
222
|
+
this.xy *= invN;
|
|
223
|
+
this.xz *= invN;
|
|
224
|
+
this.yz *= invN;
|
|
225
|
+
this.xw *= invN;
|
|
226
|
+
this.yw *= invN;
|
|
227
|
+
this.zw *= invN;
|
|
228
|
+
this.xyzw *= invN;
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Reverse (conjugate) of the rotor
|
|
234
|
+
* For unit rotors: R† = R⁻¹
|
|
235
|
+
* @returns {Rotor4D}
|
|
236
|
+
*/
|
|
237
|
+
reverse() {
|
|
238
|
+
// Reverse flips sign of bivectors and pseudoscalar
|
|
239
|
+
return new Rotor4D(
|
|
240
|
+
this.s,
|
|
241
|
+
-this.xy,
|
|
242
|
+
-this.xz,
|
|
243
|
+
-this.yz,
|
|
244
|
+
-this.xw,
|
|
245
|
+
-this.yw,
|
|
246
|
+
-this.zw,
|
|
247
|
+
-this.xyzw
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Inverse of the rotor
|
|
253
|
+
* For unit rotors, this equals reverse()
|
|
254
|
+
* @returns {Rotor4D}
|
|
255
|
+
*/
|
|
256
|
+
inverse() {
|
|
257
|
+
const normSq = this.normSquared();
|
|
258
|
+
if (normSq < 1e-10) {
|
|
259
|
+
return Rotor4D.identity();
|
|
260
|
+
}
|
|
261
|
+
const invNormSq = 1 / normSq;
|
|
262
|
+
return new Rotor4D(
|
|
263
|
+
this.s * invNormSq,
|
|
264
|
+
-this.xy * invNormSq,
|
|
265
|
+
-this.xz * invNormSq,
|
|
266
|
+
-this.yz * invNormSq,
|
|
267
|
+
-this.xw * invNormSq,
|
|
268
|
+
-this.yw * invNormSq,
|
|
269
|
+
-this.zw * invNormSq,
|
|
270
|
+
-this.xyzw * invNormSq
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Multiply two rotors (compose rotations)
|
|
276
|
+
* The result applies this rotation, then r's rotation
|
|
277
|
+
*
|
|
278
|
+
* @param {Rotor4D} r - Right operand
|
|
279
|
+
* @returns {Rotor4D} Composed rotor
|
|
280
|
+
*/
|
|
281
|
+
multiply(r) {
|
|
282
|
+
// Full geometric product of two rotors in 4D
|
|
283
|
+
// This is derived from the geometric algebra product rules
|
|
284
|
+
|
|
285
|
+
const a = this;
|
|
286
|
+
const b = r;
|
|
287
|
+
|
|
288
|
+
return new Rotor4D(
|
|
289
|
+
// Scalar component
|
|
290
|
+
a.s * b.s - a.xy * b.xy - a.xz * b.xz - a.yz * b.yz -
|
|
291
|
+
a.xw * b.xw - a.yw * b.yw - a.zw * b.zw - a.xyzw * b.xyzw,
|
|
292
|
+
|
|
293
|
+
// XY bivector
|
|
294
|
+
a.s * b.xy + a.xy * b.s + a.xz * b.yz - a.yz * b.xz +
|
|
295
|
+
a.xw * b.yw - a.yw * b.xw - a.zw * b.xyzw - a.xyzw * b.zw,
|
|
296
|
+
|
|
297
|
+
// XZ bivector
|
|
298
|
+
a.s * b.xz + a.xz * b.s - a.xy * b.yz + a.yz * b.xy +
|
|
299
|
+
a.xw * b.zw + a.yw * b.xyzw - a.zw * b.xw + a.xyzw * b.yw,
|
|
300
|
+
|
|
301
|
+
// YZ bivector
|
|
302
|
+
a.s * b.yz + a.yz * b.s + a.xy * b.xz - a.xz * b.xy -
|
|
303
|
+
a.xw * b.xyzw + a.yw * b.zw - a.zw * b.yw - a.xyzw * b.xw,
|
|
304
|
+
|
|
305
|
+
// XW bivector
|
|
306
|
+
a.s * b.xw + a.xw * b.s - a.xy * b.yw + a.xz * b.zw +
|
|
307
|
+
a.yz * b.xyzw + a.yw * b.xy - a.zw * b.xz + a.xyzw * b.yz,
|
|
308
|
+
|
|
309
|
+
// YW bivector
|
|
310
|
+
a.s * b.yw + a.yw * b.s + a.xy * b.xw - a.xz * b.xyzw -
|
|
311
|
+
a.yz * b.zw - a.xw * b.xy + a.zw * b.yz - a.xyzw * b.xz,
|
|
312
|
+
|
|
313
|
+
// ZW bivector
|
|
314
|
+
a.s * b.zw + a.zw * b.s + a.xy * b.xyzw + a.xz * b.xw +
|
|
315
|
+
a.yz * b.yw - a.xw * b.xz - a.yw * b.yz + a.xyzw * b.xy,
|
|
316
|
+
|
|
317
|
+
// Pseudoscalar XYZW
|
|
318
|
+
a.s * b.xyzw + a.xyzw * b.s + a.xy * b.zw - a.xz * b.yw +
|
|
319
|
+
a.yz * b.xw + a.xw * b.yz - a.yw * b.xz + a.zw * b.xy
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Rotate a 4D vector using sandwich product: v' = R v R†
|
|
325
|
+
*
|
|
326
|
+
* @param {Vec4} v - Vector to rotate
|
|
327
|
+
* @returns {Vec4} Rotated vector
|
|
328
|
+
*/
|
|
329
|
+
rotate(v) {
|
|
330
|
+
// For efficiency, we expand the sandwich product directly
|
|
331
|
+
// rather than doing two rotor multiplications
|
|
332
|
+
|
|
333
|
+
const x = v.x, y = v.y, z = v.z, w = v.w;
|
|
334
|
+
|
|
335
|
+
// Compute R v (rotor times vector)
|
|
336
|
+
// Vector in GA is: x*e1 + y*e2 + z*e3 + w*e4
|
|
337
|
+
// This produces a mixed multivector
|
|
338
|
+
|
|
339
|
+
// Then multiply by R† (reverse of rotor)
|
|
340
|
+
// Extract the vector part of the result
|
|
341
|
+
|
|
342
|
+
// Pre-compute some common terms
|
|
343
|
+
const s = this.s;
|
|
344
|
+
const xy = this.xy, xz = this.xz, yz = this.yz;
|
|
345
|
+
const xw = this.xw, yw = this.yw, zw = this.zw;
|
|
346
|
+
const xyzw = this.xyzw;
|
|
347
|
+
|
|
348
|
+
// Squared terms for the rotation formula
|
|
349
|
+
const s2 = s * s;
|
|
350
|
+
const xy2 = xy * xy, xz2 = xz * xz, yz2 = yz * yz;
|
|
351
|
+
const xw2 = xw * xw, yw2 = yw * yw, zw2 = zw * zw;
|
|
352
|
+
const xyzw2 = xyzw * xyzw;
|
|
353
|
+
|
|
354
|
+
// The full rotation formula derived from R v R†
|
|
355
|
+
const newX =
|
|
356
|
+
x * (s2 + xy2 + xz2 - yz2 + xw2 - yw2 - zw2 - xyzw2) +
|
|
357
|
+
2 * y * (s * xy + xz * yz + xw * yw - s * xyzw * zw + xy * s - xyzw * zw) +
|
|
358
|
+
2 * z * (s * xz - xy * yz + xw * zw + xyzw * yw) +
|
|
359
|
+
2 * w * (s * xw - xy * yw - xz * zw - xyzw * yz);
|
|
360
|
+
|
|
361
|
+
// Simplified rotation using matrix form
|
|
362
|
+
// This is equivalent but clearer
|
|
363
|
+
|
|
364
|
+
// Actually, let's use the direct matrix multiplication approach
|
|
365
|
+
// which is more numerically stable
|
|
366
|
+
|
|
367
|
+
const m = this.toMatrix();
|
|
368
|
+
return new Vec4(
|
|
369
|
+
m[0] * x + m[4] * y + m[8] * z + m[12] * w,
|
|
370
|
+
m[1] * x + m[5] * y + m[9] * z + m[13] * w,
|
|
371
|
+
m[2] * x + m[6] * y + m[10] * z + m[14] * w,
|
|
372
|
+
m[3] * x + m[7] * y + m[11] * z + m[15] * w
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Convert rotor to 4x4 rotation matrix (column-major for WebGL)
|
|
378
|
+
* @returns {Float32Array} 16-element array in column-major order
|
|
379
|
+
*/
|
|
380
|
+
toMatrix() {
|
|
381
|
+
// Normalize first for numerical stability
|
|
382
|
+
const n = this.norm();
|
|
383
|
+
const invN = n > 1e-10 ? 1 / n : 1;
|
|
384
|
+
|
|
385
|
+
const s = this.s * invN;
|
|
386
|
+
const xy = this.xy * invN;
|
|
387
|
+
const xz = this.xz * invN;
|
|
388
|
+
const yz = this.yz * invN;
|
|
389
|
+
const xw = this.xw * invN;
|
|
390
|
+
const yw = this.yw * invN;
|
|
391
|
+
const zw = this.zw * invN;
|
|
392
|
+
const xyzw = this.xyzw * invN;
|
|
393
|
+
|
|
394
|
+
// Pre-compute products
|
|
395
|
+
const s2 = s * s;
|
|
396
|
+
const xy2 = xy * xy;
|
|
397
|
+
const xz2 = xz * xz;
|
|
398
|
+
const yz2 = yz * yz;
|
|
399
|
+
const xw2 = xw * xw;
|
|
400
|
+
const yw2 = yw * yw;
|
|
401
|
+
const zw2 = zw * zw;
|
|
402
|
+
const xyzw2 = xyzw * xyzw;
|
|
403
|
+
|
|
404
|
+
// Cross terms
|
|
405
|
+
const sxy = 2 * s * xy;
|
|
406
|
+
const sxz = 2 * s * xz;
|
|
407
|
+
const syz = 2 * s * yz;
|
|
408
|
+
const sxw = 2 * s * xw;
|
|
409
|
+
const syw = 2 * s * yw;
|
|
410
|
+
const szw = 2 * s * zw;
|
|
411
|
+
const sxyzw = 2 * s * xyzw;
|
|
412
|
+
|
|
413
|
+
const xyxz = 2 * xy * xz;
|
|
414
|
+
const xyyz = 2 * xy * yz;
|
|
415
|
+
const xyxw = 2 * xy * xw;
|
|
416
|
+
const xyyw = 2 * xy * yw;
|
|
417
|
+
const xyzw_c = 2 * xy * zw;
|
|
418
|
+
|
|
419
|
+
const xzyz = 2 * xz * yz;
|
|
420
|
+
const xzxw = 2 * xz * xw;
|
|
421
|
+
const xzyw = 2 * xz * yw;
|
|
422
|
+
const xzzw = 2 * xz * zw;
|
|
423
|
+
|
|
424
|
+
const yzxw = 2 * yz * xw;
|
|
425
|
+
const yzyw = 2 * yz * yw;
|
|
426
|
+
const yzzw = 2 * yz * zw;
|
|
427
|
+
|
|
428
|
+
const xwyw = 2 * xw * yw;
|
|
429
|
+
const xwzw = 2 * xw * zw;
|
|
430
|
+
const ywzw = 2 * yw * zw;
|
|
431
|
+
|
|
432
|
+
const xyxyzw = 2 * xy * xyzw;
|
|
433
|
+
const xzxyzw = 2 * xz * xyzw;
|
|
434
|
+
const yzxyzw = 2 * yz * xyzw;
|
|
435
|
+
const xwxyzw = 2 * xw * xyzw;
|
|
436
|
+
const ywxyzw = 2 * yw * xyzw;
|
|
437
|
+
const zwxyzw = 2 * zw * xyzw;
|
|
438
|
+
|
|
439
|
+
// 4x4 rotation matrix in column-major order
|
|
440
|
+
// Each column is a transformed basis vector
|
|
441
|
+
// Formula derived from sandwich product R v R†
|
|
442
|
+
// Diagonal: s² minus bivectors containing that axis, plus others
|
|
443
|
+
// Off-diagonal: 2*s*bivector terms for single-plane contributions
|
|
444
|
+
return new Float32Array([
|
|
445
|
+
// Column 0 (transformed X axis)
|
|
446
|
+
s2 - xy2 - xz2 + yz2 - xw2 + yw2 + zw2 - xyzw2,
|
|
447
|
+
sxy + xzyz + xwyw - zwxyzw,
|
|
448
|
+
sxz - xyyz + xwzw + ywxyzw,
|
|
449
|
+
sxw - xyyw - xzzw - yzxyzw,
|
|
450
|
+
|
|
451
|
+
// Column 1 (transformed Y axis)
|
|
452
|
+
-sxy + xzyz + xwyw + zwxyzw,
|
|
453
|
+
s2 - xy2 + xz2 - yz2 + xw2 - yw2 + zw2 - xyzw2,
|
|
454
|
+
syz + xyxz + ywzw - xwxyzw,
|
|
455
|
+
syw + xyxw - yzzw + xzxyzw,
|
|
456
|
+
|
|
457
|
+
// Column 2 (transformed Z axis)
|
|
458
|
+
-sxz - xyyz + xwzw - ywxyzw,
|
|
459
|
+
-syz + xyxz + ywzw + xwxyzw,
|
|
460
|
+
s2 + xy2 - xz2 - yz2 + xw2 + yw2 - zw2 - xyzw2,
|
|
461
|
+
szw + xzxw + yzyw - xyxyzw,
|
|
462
|
+
|
|
463
|
+
// Column 3 (transformed W axis)
|
|
464
|
+
-sxw - xyyw - xzzw + yzxyzw,
|
|
465
|
+
-syw + xyxw - yzzw - xzxyzw,
|
|
466
|
+
-szw + xzxw + yzyw + xyxyzw,
|
|
467
|
+
s2 + xy2 + xz2 + yz2 - xw2 - yw2 - zw2 - xyzw2
|
|
468
|
+
]);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Spherical linear interpolation between rotors
|
|
473
|
+
* @param {Rotor4D} target - Target rotor
|
|
474
|
+
* @param {number} t - Interpolation factor (0-1)
|
|
475
|
+
* @returns {Rotor4D}
|
|
476
|
+
*/
|
|
477
|
+
slerp(target, t) {
|
|
478
|
+
// Compute the cosine of the angle between rotors
|
|
479
|
+
let dot = this.s * target.s +
|
|
480
|
+
this.xy * target.xy + this.xz * target.xz + this.yz * target.yz +
|
|
481
|
+
this.xw * target.xw + this.yw * target.yw + this.zw * target.zw +
|
|
482
|
+
this.xyzw * target.xyzw;
|
|
483
|
+
|
|
484
|
+
// If dot is negative, negate one rotor to take shorter path
|
|
485
|
+
let b = target;
|
|
486
|
+
if (dot < 0) {
|
|
487
|
+
dot = -dot;
|
|
488
|
+
b = new Rotor4D(
|
|
489
|
+
-target.s, -target.xy, -target.xz, -target.yz,
|
|
490
|
+
-target.xw, -target.yw, -target.zw, -target.xyzw
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// If rotors are very close, use linear interpolation
|
|
495
|
+
if (dot > 0.9995) {
|
|
496
|
+
return new Rotor4D(
|
|
497
|
+
this.s + t * (b.s - this.s),
|
|
498
|
+
this.xy + t * (b.xy - this.xy),
|
|
499
|
+
this.xz + t * (b.xz - this.xz),
|
|
500
|
+
this.yz + t * (b.yz - this.yz),
|
|
501
|
+
this.xw + t * (b.xw - this.xw),
|
|
502
|
+
this.yw + t * (b.yw - this.yw),
|
|
503
|
+
this.zw + t * (b.zw - this.zw),
|
|
504
|
+
this.xyzw + t * (b.xyzw - this.xyzw)
|
|
505
|
+
).normalizeInPlace();
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Spherical interpolation
|
|
509
|
+
const theta = Math.acos(dot);
|
|
510
|
+
const sinTheta = Math.sin(theta);
|
|
511
|
+
const wa = Math.sin((1 - t) * theta) / sinTheta;
|
|
512
|
+
const wb = Math.sin(t * theta) / sinTheta;
|
|
513
|
+
|
|
514
|
+
return new Rotor4D(
|
|
515
|
+
wa * this.s + wb * b.s,
|
|
516
|
+
wa * this.xy + wb * b.xy,
|
|
517
|
+
wa * this.xz + wb * b.xz,
|
|
518
|
+
wa * this.yz + wb * b.yz,
|
|
519
|
+
wa * this.xw + wb * b.xw,
|
|
520
|
+
wa * this.yw + wb * b.yw,
|
|
521
|
+
wa * this.zw + wb * b.zw,
|
|
522
|
+
wa * this.xyzw + wb * b.xyzw
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Check if approximately equal to another rotor
|
|
528
|
+
* @param {Rotor4D} r
|
|
529
|
+
* @param {number} epsilon
|
|
530
|
+
* @returns {boolean}
|
|
531
|
+
*/
|
|
532
|
+
equals(r, epsilon = 1e-6) {
|
|
533
|
+
// Account for double cover (R and -R represent same rotation)
|
|
534
|
+
const diff1 = Math.abs(this.s - r.s) + Math.abs(this.xy - r.xy) +
|
|
535
|
+
Math.abs(this.xz - r.xz) + Math.abs(this.yz - r.yz) +
|
|
536
|
+
Math.abs(this.xw - r.xw) + Math.abs(this.yw - r.yw) +
|
|
537
|
+
Math.abs(this.zw - r.zw) + Math.abs(this.xyzw - r.xyzw);
|
|
538
|
+
|
|
539
|
+
const diff2 = Math.abs(this.s + r.s) + Math.abs(this.xy + r.xy) +
|
|
540
|
+
Math.abs(this.xz + r.xz) + Math.abs(this.yz + r.yz) +
|
|
541
|
+
Math.abs(this.xw + r.xw) + Math.abs(this.yw + r.yw) +
|
|
542
|
+
Math.abs(this.zw + r.zw) + Math.abs(this.xyzw + r.xyzw);
|
|
543
|
+
|
|
544
|
+
return Math.min(diff1, diff2) < epsilon * 8;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Check if this is the identity rotor
|
|
549
|
+
* @param {number} epsilon
|
|
550
|
+
* @returns {boolean}
|
|
551
|
+
*/
|
|
552
|
+
isIdentity(epsilon = 1e-6) {
|
|
553
|
+
return this.equals(Rotor4D.identity(), epsilon);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* String representation
|
|
558
|
+
* @param {number} precision
|
|
559
|
+
* @returns {string}
|
|
560
|
+
*/
|
|
561
|
+
toString(precision = 3) {
|
|
562
|
+
return `Rotor4D(s=${this.s.toFixed(precision)}, xy=${this.xy.toFixed(precision)}, xz=${this.xz.toFixed(precision)}, yz=${this.yz.toFixed(precision)}, xw=${this.xw.toFixed(precision)}, yw=${this.yw.toFixed(precision)}, zw=${this.zw.toFixed(precision)}, xyzw=${this.xyzw.toFixed(precision)})`;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* JSON representation
|
|
567
|
+
* @returns {object}
|
|
568
|
+
*/
|
|
569
|
+
toJSON() {
|
|
570
|
+
return {
|
|
571
|
+
s: this.s,
|
|
572
|
+
xy: this.xy, xz: this.xz, yz: this.yz,
|
|
573
|
+
xw: this.xw, yw: this.yw, zw: this.zw,
|
|
574
|
+
xyzw: this.xyzw
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Convert to array [s, xy, xz, yz, xw, yw, zw, xyzw]
|
|
580
|
+
* @returns {number[]}
|
|
581
|
+
*/
|
|
582
|
+
toArray() {
|
|
583
|
+
return [this.s, this.xy, this.xz, this.yz, this.xw, this.yw, this.zw, this.xyzw];
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Create rotor from array
|
|
588
|
+
* @param {number[]} arr - Array of 8 components [s, xy, xz, yz, xw, yw, zw, xyzw]
|
|
589
|
+
* @returns {Rotor4D}
|
|
590
|
+
*/
|
|
591
|
+
static fromArray(arr) {
|
|
592
|
+
return new Rotor4D(
|
|
593
|
+
arr[0] ?? 1,
|
|
594
|
+
arr[1] ?? 0,
|
|
595
|
+
arr[2] ?? 0,
|
|
596
|
+
arr[3] ?? 0,
|
|
597
|
+
arr[4] ?? 0,
|
|
598
|
+
arr[5] ?? 0,
|
|
599
|
+
arr[6] ?? 0,
|
|
600
|
+
arr[7] ?? 0
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Create rotor from JSON
|
|
606
|
+
* @param {object} json
|
|
607
|
+
* @returns {Rotor4D}
|
|
608
|
+
*/
|
|
609
|
+
static fromJSON(json) {
|
|
610
|
+
return new Rotor4D(
|
|
611
|
+
json.s || 1,
|
|
612
|
+
json.xy || 0, json.xz || 0, json.yz || 0,
|
|
613
|
+
json.xw || 0, json.yw || 0, json.zw || 0,
|
|
614
|
+
json.xyzw || 0
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Create random unit rotor (uniform distribution on rotation group)
|
|
620
|
+
* @returns {Rotor4D}
|
|
621
|
+
*/
|
|
622
|
+
static random() {
|
|
623
|
+
// Generate random 8D unit vector for uniform rotor distribution
|
|
624
|
+
const components = [];
|
|
625
|
+
for (let i = 0; i < 8; i++) {
|
|
626
|
+
// Box-Muller for Gaussian
|
|
627
|
+
const u1 = Math.random();
|
|
628
|
+
const u2 = Math.random();
|
|
629
|
+
components.push(Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2));
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const rotor = new Rotor4D(...components);
|
|
633
|
+
return rotor.normalizeInPlace();
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
export default Rotor4D;
|