angular-three-soba 2.1.0 → 2.2.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.
Files changed (151) hide show
  1. package/abstractions/lib/catmull-rom-line.d.ts +139 -139
  2. package/abstractions/lib/edges.d.ts +164 -164
  3. package/abstractions/lib/grid.d.ts +39 -39
  4. package/abstractions/lib/line.d.ts +8 -7
  5. package/abstractions/lib/prism-geometry.d.ts +4 -4
  6. package/abstractions/lib/rounded-box.d.ts +3 -3
  7. package/abstractions/lib/text-3d.d.ts +46 -46
  8. package/abstractions/lib/text.d.ts +1 -2
  9. package/cameras/lib/cube-camera.d.ts +1 -1
  10. package/cameras/lib/orthographic-camera.d.ts +7 -8
  11. package/cameras/lib/perspective-camera.d.ts +2 -3
  12. package/controls/index.d.ts +9 -1
  13. package/controls/lib/camera-controls.d.ts +1 -1
  14. package/controls/lib/orbit-controls.d.ts +1 -1
  15. package/esm2022/abstractions/lib/billboard.mjs +3 -3
  16. package/esm2022/abstractions/lib/catmull-rom-line.mjs +3 -3
  17. package/esm2022/abstractions/lib/cubic-bezier-line.mjs +3 -3
  18. package/esm2022/abstractions/lib/edges.mjs +30 -34
  19. package/esm2022/abstractions/lib/gradient-texture.mjs +3 -3
  20. package/esm2022/abstractions/lib/grid.mjs +3 -3
  21. package/esm2022/abstractions/lib/helper.mjs +18 -20
  22. package/esm2022/abstractions/lib/line.mjs +25 -28
  23. package/esm2022/abstractions/lib/prism-geometry.mjs +3 -3
  24. package/esm2022/abstractions/lib/quadratic-bezier-line.mjs +3 -3
  25. package/esm2022/abstractions/lib/rounded-box.mjs +11 -17
  26. package/esm2022/abstractions/lib/text-3d.mjs +14 -17
  27. package/esm2022/abstractions/lib/text.mjs +11 -16
  28. package/esm2022/cameras/lib/camera-content.mjs +3 -3
  29. package/esm2022/cameras/lib/cube-camera.mjs +18 -27
  30. package/esm2022/cameras/lib/orthographic-camera.mjs +20 -20
  31. package/esm2022/cameras/lib/perspective-camera.mjs +21 -21
  32. package/esm2022/controls/index.mjs +6 -2
  33. package/esm2022/controls/lib/camera-controls.mjs +3 -3
  34. package/esm2022/controls/lib/orbit-controls.mjs +3 -3
  35. package/esm2022/controls/lib/scroll-controls.mjs +124 -130
  36. package/esm2022/gizmos/angular-three-soba-gizmos.mjs +5 -0
  37. package/esm2022/gizmos/index.mjs +6 -0
  38. package/esm2022/gizmos/lib/gizmo-helper/gizmo-helper.mjs +187 -0
  39. package/esm2022/gizmos/lib/gizmo-helper/gizmo-viewcube.mjs +304 -0
  40. package/esm2022/gizmos/lib/gizmo-helper/gizmo-viewport.mjs +332 -0
  41. package/esm2022/gizmos/lib/pivot-controls/axis-arrow.mjs +265 -0
  42. package/esm2022/gizmos/lib/pivot-controls/axis-rotator.mjs +264 -0
  43. package/esm2022/gizmos/lib/pivot-controls/pivot-controls.mjs +337 -0
  44. package/esm2022/gizmos/lib/pivot-controls/plane-slider.mjs +266 -0
  45. package/esm2022/gizmos/lib/pivot-controls/scaling-sphere.mjs +232 -0
  46. package/esm2022/gizmos/lib/transform-controls.mjs +177 -0
  47. package/esm2022/loaders/lib/loader.mjs +3 -3
  48. package/esm2022/materials/lib/custom-shader-material.mjs +8 -12
  49. package/esm2022/materials/lib/mesh-distort-material.mjs +3 -3
  50. package/esm2022/materials/lib/mesh-reflector-material.mjs +11 -15
  51. package/esm2022/materials/lib/mesh-refraction-material.mjs +26 -30
  52. package/esm2022/materials/lib/mesh-transmission-material.mjs +3 -3
  53. package/esm2022/materials/lib/mesh-wobble-material.mjs +3 -3
  54. package/esm2022/materials/lib/point-material.mjs +3 -3
  55. package/esm2022/misc/lib/bake-shadows.mjs +8 -10
  56. package/esm2022/misc/lib/computed-attribute.mjs +15 -19
  57. package/esm2022/misc/lib/decal.mjs +56 -53
  58. package/esm2022/misc/lib/fbo.mjs +10 -10
  59. package/esm2022/misc/lib/html/html-content.mjs +62 -67
  60. package/esm2022/misc/lib/html/html.mjs +3 -3
  61. package/esm2022/misc/lib/intersect.mjs +6 -9
  62. package/esm2022/misc/lib/sampler.mjs +48 -42
  63. package/esm2022/performances/lib/adaptive-dpr.mjs +29 -35
  64. package/esm2022/performances/lib/adaptive-events.mjs +12 -16
  65. package/esm2022/performances/lib/detailed.mjs +14 -18
  66. package/esm2022/performances/lib/instances/instances.mjs +16 -22
  67. package/esm2022/performances/lib/points/points.mjs +19 -25
  68. package/esm2022/performances/lib/segments/segments.mjs +11 -14
  69. package/esm2022/shaders/lib/mesh-refraction-material.mjs +1 -1
  70. package/esm2022/staging/index.mjs +3 -2
  71. package/esm2022/staging/lib/accumulative-shadows.mjs +19 -21
  72. package/esm2022/staging/lib/backdrop.mjs +19 -23
  73. package/esm2022/staging/lib/bb-anchor.mjs +3 -3
  74. package/esm2022/staging/lib/bounds.mjs +39 -43
  75. package/esm2022/staging/lib/camera-shake.mjs +14 -18
  76. package/esm2022/staging/lib/caustics.mjs +24 -28
  77. package/esm2022/staging/lib/center.mjs +28 -32
  78. package/esm2022/staging/lib/contact-shadows.mjs +3 -3
  79. package/esm2022/staging/lib/environment/environment.mjs +338 -0
  80. package/esm2022/staging/lib/environment/inject-environment.mjs +184 -0
  81. package/esm2022/staging/lib/float.mjs +3 -3
  82. package/esm2022/staging/lib/lightformer.mjs +18 -22
  83. package/esm2022/staging/lib/mask.mjs +8 -12
  84. package/esm2022/staging/lib/matcap-texture.mjs +9 -11
  85. package/esm2022/staging/lib/normal-texture.mjs +9 -11
  86. package/esm2022/staging/lib/randomized-lights.mjs +9 -13
  87. package/esm2022/staging/lib/render-texture.mjs +19 -20
  88. package/esm2022/staging/lib/sky.mjs +3 -3
  89. package/esm2022/staging/lib/spot-light.mjs +32 -40
  90. package/esm2022/staging/lib/stage.mjs +13 -17
  91. package/esm2022/stats/lib/stats.mjs +21 -27
  92. package/fesm2022/angular-three-soba-abstractions.mjs +119 -138
  93. package/fesm2022/angular-three-soba-abstractions.mjs.map +1 -1
  94. package/fesm2022/angular-three-soba-cameras.mjs +57 -64
  95. package/fesm2022/angular-three-soba-cameras.mjs.map +1 -1
  96. package/fesm2022/angular-three-soba-controls.mjs +141 -1470
  97. package/fesm2022/angular-three-soba-controls.mjs.map +1 -1
  98. package/fesm2022/angular-three-soba-gizmos.mjs +2318 -0
  99. package/fesm2022/angular-three-soba-gizmos.mjs.map +1 -0
  100. package/fesm2022/angular-three-soba-loaders.mjs +3 -3
  101. package/fesm2022/angular-three-soba-materials.mjs +52 -62
  102. package/fesm2022/angular-three-soba-materials.mjs.map +1 -1
  103. package/fesm2022/angular-three-soba-misc.mjs +194 -195
  104. package/fesm2022/angular-three-soba-misc.mjs.map +1 -1
  105. package/fesm2022/angular-three-soba-performances.mjs +90 -114
  106. package/fesm2022/angular-three-soba-performances.mjs.map +1 -1
  107. package/fesm2022/angular-three-soba-shaders.mjs.map +1 -1
  108. package/fesm2022/angular-three-soba-staging.mjs +427 -430
  109. package/fesm2022/angular-three-soba-staging.mjs.map +1 -1
  110. package/fesm2022/angular-three-soba-stats.mjs +20 -26
  111. package/fesm2022/angular-three-soba-stats.mjs.map +1 -1
  112. package/gizmos/README.md +3 -0
  113. package/gizmos/index.d.ts +5 -0
  114. package/gizmos/lib/gizmo-helper/gizmo-helper.d.ts +45 -0
  115. package/gizmos/lib/gizmo-helper/gizmo-viewcube.d.ts +74 -0
  116. package/gizmos/lib/gizmo-helper/gizmo-viewport.d.ts +64 -0
  117. package/{controls → gizmos}/lib/pivot-controls/pivot-controls.d.ts +1 -1
  118. package/gizmos/lib/transform-controls.d.ts +50 -0
  119. package/materials/lib/mesh-transmission-material.d.ts +1 -1
  120. package/misc/lib/computed-attribute.d.ts +2 -2
  121. package/misc/lib/decal.d.ts +4 -4
  122. package/misc/lib/html/html-content.d.ts +6 -6
  123. package/misc/lib/html/html.d.ts +1 -1
  124. package/misc/lib/sampler.d.ts +1 -3
  125. package/package.json +14 -8
  126. package/performances/lib/instances/instances.d.ts +3 -3
  127. package/shaders/lib/mesh-refraction-material.d.ts +2 -5
  128. package/staging/index.d.ts +2 -1
  129. package/staging/lib/camera-shake.d.ts +0 -1
  130. package/staging/lib/caustics.d.ts +1 -1
  131. package/staging/lib/center.d.ts +2 -2
  132. package/staging/lib/contact-shadows.d.ts +1 -1
  133. package/staging/lib/{environment.d.ts → environment/environment.d.ts} +20 -49
  134. package/staging/lib/environment/inject-environment.d.ts +33 -0
  135. package/staging/lib/lightformer.d.ts +1 -1
  136. package/staging/lib/mask.d.ts +1 -1
  137. package/staging/lib/matcap-texture.d.ts +0 -1
  138. package/staging/lib/normal-texture.d.ts +0 -1
  139. package/staging/lib/render-texture.d.ts +1 -1
  140. package/staging/lib/sky.d.ts +1 -1
  141. package/staging/lib/stage.d.ts +3 -2
  142. package/esm2022/controls/lib/pivot-controls/axis-arrow.mjs +0 -263
  143. package/esm2022/controls/lib/pivot-controls/axis-rotator.mjs +0 -264
  144. package/esm2022/controls/lib/pivot-controls/pivot-controls.mjs +0 -340
  145. package/esm2022/controls/lib/pivot-controls/plane-slider.mjs +0 -266
  146. package/esm2022/controls/lib/pivot-controls/scaling-sphere.mjs +0 -232
  147. package/esm2022/staging/lib/environment.mjs +0 -481
  148. /package/{controls → gizmos}/lib/pivot-controls/axis-arrow.d.ts +0 -0
  149. /package/{controls → gizmos}/lib/pivot-controls/axis-rotator.d.ts +0 -0
  150. /package/{controls → gizmos}/lib/pivot-controls/plane-slider.d.ts +0 -0
  151. /package/{controls → gizmos}/lib/pivot-controls/scaling-sphere.d.ts +0 -0
@@ -0,0 +1,2318 @@
1
+ import { NgTemplateOutlet, DOCUMENT } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { Directive, input, output, contentChild, TemplateRef, viewChild, computed, effect, Component, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, inject, signal, ElementRef } from '@angular/core';
4
+ import { pick, injectStore, extend, injectBeforeRender, hasListener, NgtPortal, NgtPortalContent, NgtArgs, getEmitter, omit, getLocalState, resolveRef } from 'angular-three';
5
+ import { NgtsOrthographicCamera } from 'angular-three-soba/cameras';
6
+ import { mergeInputs } from 'ngxtension/inject-inputs';
7
+ import { Object3D, Matrix4, Quaternion, Vector3, Scene, Group, CanvasTexture, MeshBasicMaterial, Mesh, BoxGeometry, Sprite, SpriteMaterial, DoubleSide, ConeGeometry, CylinderGeometry, Ray, Plane, PlaneGeometry, SphereGeometry, Box3 } from 'three';
8
+ import { NgtsHTML, NgtsHTMLContent, calculateScaleFactor } from 'angular-three-soba/misc';
9
+ import { NgtsLine } from 'angular-three-soba/abstractions';
10
+ import { TransformControls } from 'three-stdlib';
11
+
12
+ const turnRate = 2 * Math.PI; // turn rate in angles per second
13
+ const dummy = new Object3D();
14
+ const matrix = new Matrix4();
15
+ const [q1, q2] = [new Quaternion(), new Quaternion()];
16
+ const target = new Vector3();
17
+ const targetPosition = new Vector3();
18
+ class NgtsGizmoHelperContent {
19
+ static ngTemplateContextGuard(_, ctx) {
20
+ return true;
21
+ }
22
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsGizmoHelperContent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
23
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.4", type: NgtsGizmoHelperContent, isStandalone: true, selector: "ng-template[gizmoHelperContent]", ngImport: i0 }); }
24
+ }
25
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsGizmoHelperContent, decorators: [{
26
+ type: Directive,
27
+ args: [{ selector: 'ng-template[gizmoHelperContent]', standalone: true }]
28
+ }] });
29
+ const defaultOptions$2 = {
30
+ alignment: 'bottom-right',
31
+ margin: [80, 80],
32
+ renderPriority: 1,
33
+ };
34
+ class NgtsGizmoHelper {
35
+ constructor() {
36
+ this.options = input(defaultOptions$2, { transform: mergeInputs(defaultOptions$2) });
37
+ this.update = output();
38
+ this.renderPriority = pick(this.options, 'renderPriority');
39
+ this.margin = pick(this.options, 'margin');
40
+ this.alignment = pick(this.options, 'alignment');
41
+ this.scene = new Scene();
42
+ this.content = contentChild.required(NgtsGizmoHelperContent, { read: TemplateRef });
43
+ this.gizmoRef = viewChild('gizmo');
44
+ this.virtualCameraRef = viewChild(NgtsOrthographicCamera);
45
+ this.store = injectStore();
46
+ this.size = this.store.select('size');
47
+ this.mainCamera = this.store.select('camera');
48
+ this.defaultControls = this.store.select('controls');
49
+ this.invalidate = this.store.select('invalidate');
50
+ this.x = computed(() => {
51
+ const alignment = this.alignment();
52
+ if (alignment.endsWith('-center'))
53
+ return 0;
54
+ const [{ width }, [marginX]] = [this.size(), this.margin()];
55
+ return alignment.endsWith('-left') ? -width / 2 + marginX : width / 2 - marginX;
56
+ });
57
+ this.y = computed(() => {
58
+ const alignment = this.alignment();
59
+ if (alignment.startsWith('center-'))
60
+ return 0;
61
+ const [{ height }, [marginY]] = [this.size(), this.margin()];
62
+ return alignment.startsWith('top-') ? height / 2 - marginY : -height / 2 + marginY;
63
+ });
64
+ this.animating = false;
65
+ this.radius = 0;
66
+ this.focusPoint = new Vector3(0, 0, 0);
67
+ this.defaultUp = new Vector3(0, 0, 0);
68
+ extend({ Group });
69
+ effect(() => {
70
+ this.updateDefaultUpEffect();
71
+ });
72
+ injectBeforeRender(({ delta }) => {
73
+ const [virtualCamera, gizmo] = [
74
+ this.virtualCameraRef()?.cameraRef()?.nativeElement,
75
+ this.gizmoRef()?.nativeElement,
76
+ ];
77
+ if (!virtualCamera || !gizmo)
78
+ return;
79
+ const [defaultControls, mainCamera, invalidate] = [this.defaultControls(), this.mainCamera(), this.invalidate()];
80
+ // Animate step
81
+ if (this.animating) {
82
+ if (q1.angleTo(q2) < 0.01) {
83
+ this.animating = false;
84
+ // Orbit controls uses UP vector as the orbit axes,
85
+ // so we need to reset it after the animation is done
86
+ // moving it around for the controls to work correctly
87
+ if (this.isOrbitControls(defaultControls)) {
88
+ mainCamera.up.copy(this.defaultUp);
89
+ }
90
+ }
91
+ else {
92
+ const step = delta * turnRate;
93
+ // animate position by doing a slerp and then scaling the position on the unit sphere
94
+ q1.rotateTowards(q2, step);
95
+ // animate orientation
96
+ mainCamera.position.set(0, 0, 1).applyQuaternion(q1).multiplyScalar(this.radius).add(this.focusPoint);
97
+ mainCamera.up.set(0, 1, 0).applyQuaternion(q1).normalize();
98
+ mainCamera.quaternion.copy(q1);
99
+ if (this.isCameraControls(defaultControls)) {
100
+ void defaultControls.setPosition(mainCamera.position.x, mainCamera.position.y, mainCamera.position.z);
101
+ }
102
+ if (hasListener(this.update))
103
+ this.update.emit();
104
+ else if (defaultControls)
105
+ defaultControls.update(delta);
106
+ invalidate();
107
+ }
108
+ }
109
+ // Sync Gizmo with main camera orientation
110
+ matrix.copy(mainCamera.matrix).invert();
111
+ gizmo.quaternion.setFromRotationMatrix(matrix);
112
+ });
113
+ }
114
+ tweenCamera(direction) {
115
+ const [defaultControls, invalidate, mainCamera] = [this.defaultControls(), this.invalidate(), this.mainCamera()];
116
+ this.animating = true;
117
+ if (defaultControls) {
118
+ this.focusPoint = this.isCameraControls(defaultControls)
119
+ ? defaultControls.getTarget(this.focusPoint)
120
+ : defaultControls.target;
121
+ }
122
+ this.radius = mainCamera.position.distanceTo(target);
123
+ // Rotate from current camera orientation
124
+ q1.copy(mainCamera.quaternion);
125
+ // To new current camera orientation
126
+ targetPosition.copy(direction).multiplyScalar(this.radius).add(target);
127
+ dummy.lookAt(targetPosition);
128
+ q2.copy(dummy.quaternion);
129
+ invalidate();
130
+ }
131
+ updateDefaultUpEffect() {
132
+ const mainCamera = this.mainCamera();
133
+ this.defaultUp.copy(mainCamera.up);
134
+ }
135
+ isOrbitControls(controls) {
136
+ return 'minPolarAngle' in controls;
137
+ }
138
+ isCameraControls(controls) {
139
+ return 'getTarget' in controls;
140
+ }
141
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsGizmoHelper, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
142
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "18.2.4", type: NgtsGizmoHelper, isStandalone: true, selector: "ngts-gizmo-helper", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { update: "update" }, queries: [{ propertyName: "content", first: true, predicate: NgtsGizmoHelperContent, descendants: true, read: TemplateRef, isSignal: true }], viewQueries: [{ propertyName: "gizmoRef", first: true, predicate: ["gizmo"], descendants: true, isSignal: true }, { propertyName: "virtualCameraRef", first: true, predicate: NgtsOrthographicCamera, descendants: true, isSignal: true }], ngImport: i0, template: `
143
+ <ngt-portal
144
+ [container]="scene"
145
+ [autoRender]="true"
146
+ [autoRenderPriority]="renderPriority()"
147
+ [state]="{ events: { priority: renderPriority() + 1 } }"
148
+ >
149
+ <ng-template portalContent let-injector="injector" let-container="container">
150
+ <ngts-orthographic-camera [options]="{ makeDefault: true, position: [0, 0, 200] }" />
151
+ <ngt-group #gizmo [position]="[x(), y(), 0]">
152
+ <ng-container
153
+ [ngTemplateOutlet]="content()"
154
+ [ngTemplateOutletContext]="{ container, injector }"
155
+ [ngTemplateOutletInjector]="injector"
156
+ />
157
+ </ngt-group>
158
+ </ng-template>
159
+ </ngt-portal>
160
+ `, isInline: true, dependencies: [{ kind: "component", type: NgtPortal, selector: "ngt-portal", inputs: ["container", "state", "autoRender", "autoRenderPriority"] }, { kind: "directive", type: NgtPortalContent, selector: "ng-template[portalContent]" }, { kind: "component", type: NgtsOrthographicCamera, selector: "ngts-orthographic-camera", inputs: ["options"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
161
+ }
162
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsGizmoHelper, decorators: [{
163
+ type: Component,
164
+ args: [{
165
+ selector: 'ngts-gizmo-helper',
166
+ standalone: true,
167
+ template: `
168
+ <ngt-portal
169
+ [container]="scene"
170
+ [autoRender]="true"
171
+ [autoRenderPriority]="renderPriority()"
172
+ [state]="{ events: { priority: renderPriority() + 1 } }"
173
+ >
174
+ <ng-template portalContent let-injector="injector" let-container="container">
175
+ <ngts-orthographic-camera [options]="{ makeDefault: true, position: [0, 0, 200] }" />
176
+ <ngt-group #gizmo [position]="[x(), y(), 0]">
177
+ <ng-container
178
+ [ngTemplateOutlet]="content()"
179
+ [ngTemplateOutletContext]="{ container, injector }"
180
+ [ngTemplateOutletInjector]="injector"
181
+ />
182
+ </ngt-group>
183
+ </ng-template>
184
+ </ngt-portal>
185
+ `,
186
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
187
+ changeDetection: ChangeDetectionStrategy.OnPush,
188
+ imports: [NgtPortal, NgtPortalContent, NgtsOrthographicCamera, NgTemplateOutlet],
189
+ }]
190
+ }], ctorParameters: () => [] });
191
+
192
+ const colors = { bg: '#f0f0f0', hover: '#999', text: 'black', stroke: 'black' };
193
+ const defaultFaces = ['Right', 'Left', 'Top', 'Bottom', 'Front', 'Back'];
194
+ const defaultFaceMaterialOptions = {
195
+ font: '20px Inter var, Arial, sans-serif',
196
+ faces: defaultFaces,
197
+ color: colors.bg,
198
+ hoverColor: colors.hover,
199
+ textColor: colors.text,
200
+ strokeColor: colors.stroke,
201
+ opacity: 1,
202
+ };
203
+ class FaceMaterial {
204
+ constructor() {
205
+ this.hover = input.required();
206
+ this.index = input.required();
207
+ this.options = input(defaultFaceMaterialOptions, { transform: mergeInputs(defaultFaceMaterialOptions) });
208
+ this.faces = pick(this.options, 'faces');
209
+ this.font = pick(this.options, 'font');
210
+ this.color = pick(this.options, 'color');
211
+ this.textColor = pick(this.options, 'textColor');
212
+ this.strokeColor = pick(this.options, 'strokeColor');
213
+ this.hoverColor = pick(this.options, 'hoverColor');
214
+ this.document = inject(DOCUMENT);
215
+ this.store = injectStore();
216
+ this.gl = this.store.select('gl');
217
+ this.opacity = pick(this.options, 'opacity');
218
+ this.materialColor = computed(() => (this.hover() ? this.hoverColor() : 'white'));
219
+ this.texture = computed(() => {
220
+ const [index, faces, font, color, textColor, strokeColor, gl] = [
221
+ this.index(),
222
+ this.faces(),
223
+ this.font(),
224
+ this.color(),
225
+ this.textColor(),
226
+ this.strokeColor(),
227
+ this.gl(),
228
+ ];
229
+ const canvas = this.document.createElement('canvas');
230
+ canvas.width = 128;
231
+ canvas.height = 128;
232
+ const context = canvas.getContext('2d');
233
+ context.fillStyle = color;
234
+ context.fillRect(0, 0, canvas.width, canvas.height);
235
+ context.strokeStyle = strokeColor;
236
+ context.strokeRect(0, 0, canvas.width, canvas.height);
237
+ context.font = font;
238
+ context.textAlign = 'center';
239
+ context.fillStyle = textColor;
240
+ context.fillText(faces[index].toUpperCase(), 64, 76);
241
+ const texture = new CanvasTexture(canvas);
242
+ texture.anisotropy = gl.capabilities.getMaxAnisotropy() || 1;
243
+ return texture;
244
+ });
245
+ extend({ MeshBasicMaterial });
246
+ }
247
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: FaceMaterial, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
248
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.4", type: FaceMaterial, isStandalone: true, selector: "viewcube-face-material", inputs: { hover: { classPropertyName: "hover", publicName: "hover", isSignal: true, isRequired: true, transformFunction: null }, index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: true, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
249
+ <ngt-mesh-basic-material
250
+ [attach]="['material', index()]"
251
+ [map]="texture()"
252
+ [color]="materialColor()"
253
+ [transparent]="true"
254
+ [opacity]="opacity()"
255
+ />
256
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
257
+ }
258
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: FaceMaterial, decorators: [{
259
+ type: Component,
260
+ args: [{
261
+ selector: 'viewcube-face-material',
262
+ standalone: true,
263
+ template: `
264
+ <ngt-mesh-basic-material
265
+ [attach]="['material', index()]"
266
+ [map]="texture()"
267
+ [color]="materialColor()"
268
+ [transparent]="true"
269
+ [opacity]="opacity()"
270
+ />
271
+ `,
272
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
273
+ changeDetection: ChangeDetectionStrategy.OnPush,
274
+ }]
275
+ }], ctorParameters: () => [] });
276
+ class FaceCube {
277
+ constructor() {
278
+ this.options = input({});
279
+ this.onClick = input();
280
+ this.gizmoHelper = inject(NgtsGizmoHelper);
281
+ this.hover = signal(-1);
282
+ this.count = Array.from({ length: 6 });
283
+ this.Math = Math;
284
+ extend({ Mesh, BoxGeometry });
285
+ }
286
+ internalOnClick(event) {
287
+ const onClick = this.onClick();
288
+ if (onClick)
289
+ onClick(event);
290
+ else {
291
+ event.stopPropagation();
292
+ this.gizmoHelper.tweenCamera(event.face.normal);
293
+ }
294
+ }
295
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: FaceCube, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
296
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.4", type: FaceCube, isStandalone: true, selector: "viewcube-face-cube", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, onClick: { classPropertyName: "onClick", publicName: "onClick", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
297
+ <ngt-mesh
298
+ (pointerout)="$event.stopPropagation(); hover.set(-1)"
299
+ (pointermove)="$event.stopPropagation(); hover.set(Math.floor($any($event).faceIndex / 2))"
300
+ (click)="internalOnClick($any($event))"
301
+ >
302
+ <ngt-box-geometry />
303
+ @for (face of count; track $index) {
304
+ <viewcube-face-material [index]="$index" [hover]="hover() === $index" [options]="options()" />
305
+ }
306
+ </ngt-mesh>
307
+ `, isInline: true, dependencies: [{ kind: "component", type: FaceMaterial, selector: "viewcube-face-material", inputs: ["hover", "index", "options"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
308
+ }
309
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: FaceCube, decorators: [{
310
+ type: Component,
311
+ args: [{
312
+ selector: 'viewcube-face-cube',
313
+ standalone: true,
314
+ template: `
315
+ <ngt-mesh
316
+ (pointerout)="$event.stopPropagation(); hover.set(-1)"
317
+ (pointermove)="$event.stopPropagation(); hover.set(Math.floor($any($event).faceIndex / 2))"
318
+ (click)="internalOnClick($any($event))"
319
+ >
320
+ <ngt-box-geometry />
321
+ @for (face of count; track $index) {
322
+ <viewcube-face-material [index]="$index" [hover]="hover() === $index" [options]="options()" />
323
+ }
324
+ </ngt-mesh>
325
+ `,
326
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
327
+ changeDetection: ChangeDetectionStrategy.OnPush,
328
+ imports: [FaceMaterial],
329
+ }]
330
+ }], ctorParameters: () => [] });
331
+ class EdgeCube {
332
+ constructor() {
333
+ this.dimensions = input.required();
334
+ this.position = input.required();
335
+ this.hoverColor = input(colors.hover, {
336
+ transform: (value) => {
337
+ if (value === undefined)
338
+ return colors.hover;
339
+ return value;
340
+ },
341
+ });
342
+ this.onClick = input();
343
+ this.gizmoHelper = inject(NgtsGizmoHelper);
344
+ this.hover = signal(false);
345
+ this.color = computed(() => (this.hover() ? this.hoverColor() : 'white'));
346
+ extend({ Mesh, BoxGeometry, MeshBasicMaterial });
347
+ }
348
+ internalOnClick(event) {
349
+ const onClick = this.onClick();
350
+ if (onClick)
351
+ onClick(event);
352
+ else {
353
+ event.stopPropagation();
354
+ this.gizmoHelper.tweenCamera(this.position());
355
+ }
356
+ }
357
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: EdgeCube, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
358
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.4", type: EdgeCube, isStandalone: true, selector: "viewcube-edge-cube", inputs: { dimensions: { classPropertyName: "dimensions", publicName: "dimensions", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: true, transformFunction: null }, hoverColor: { classPropertyName: "hoverColor", publicName: "hoverColor", isSignal: true, isRequired: false, transformFunction: null }, onClick: { classPropertyName: "onClick", publicName: "onClick", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
359
+ <ngt-mesh
360
+ [scale]="1.01"
361
+ [position]="position()"
362
+ (pointerout)="$event.stopPropagation(); hover.set(false)"
363
+ (pointerover)="$event.stopPropagation(); hover.set(true)"
364
+ (click)="internalOnClick($any($event))"
365
+ >
366
+ <ngt-mesh-basic-material [transparent]="true" [opacity]="0.6" [color]="color()" [visible]="hover()" />
367
+ <ngt-box-geometry *args="dimensions()" />
368
+ </ngt-mesh>
369
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgtArgs, selector: "ng-template[args]", inputs: ["args"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
370
+ }
371
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: EdgeCube, decorators: [{
372
+ type: Component,
373
+ args: [{
374
+ selector: 'viewcube-edge-cube',
375
+ standalone: true,
376
+ template: `
377
+ <ngt-mesh
378
+ [scale]="1.01"
379
+ [position]="position()"
380
+ (pointerout)="$event.stopPropagation(); hover.set(false)"
381
+ (pointerover)="$event.stopPropagation(); hover.set(true)"
382
+ (click)="internalOnClick($any($event))"
383
+ >
384
+ <ngt-mesh-basic-material [transparent]="true" [opacity]="0.6" [color]="color()" [visible]="hover()" />
385
+ <ngt-box-geometry *args="dimensions()" />
386
+ </ngt-mesh>
387
+ `,
388
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
389
+ changeDetection: ChangeDetectionStrategy.OnPush,
390
+ imports: [NgtArgs],
391
+ }]
392
+ }], ctorParameters: () => [] });
393
+ class NgtsGizmoViewcube {
394
+ constructor() {
395
+ this.options = input({});
396
+ this.click = output();
397
+ this.hoverColor = pick(this.options, 'hoverColor');
398
+ this.corners = [
399
+ [1, 1, 1],
400
+ [1, 1, -1],
401
+ [1, -1, 1],
402
+ [1, -1, -1],
403
+ [-1, 1, 1],
404
+ [-1, 1, -1],
405
+ [-1, -1, 1],
406
+ [-1, -1, -1],
407
+ ].map(this.makePositionVector);
408
+ this.cornerDimensions = [0.25, 0.25, 0.25];
409
+ this.edges = [
410
+ [1, 1, 0],
411
+ [1, 0, 1],
412
+ [1, 0, -1],
413
+ [1, -1, 0],
414
+ [0, 1, 1],
415
+ [0, 1, -1],
416
+ [0, -1, 1],
417
+ [0, -1, -1],
418
+ [-1, 1, 0],
419
+ [-1, 0, 1],
420
+ [-1, 0, -1],
421
+ [-1, -1, 0],
422
+ ].map(this.makePositionVector);
423
+ this.edgeDimensions = this.edges.map((edge) => edge.toArray().map((axis) => (axis == 0 ? 0.5 : 0.25)));
424
+ extend({ Group });
425
+ }
426
+ get onClick() {
427
+ if (hasListener(this.click))
428
+ return getEmitter(this.click);
429
+ return undefined;
430
+ }
431
+ makePositionVector(xyz) {
432
+ return new Vector3(...xyz).multiplyScalar(0.38);
433
+ }
434
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsGizmoViewcube, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
435
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.4", type: NgtsGizmoViewcube, isStandalone: true, selector: "ngts-gizmo-viewcube", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { click: "click" }, ngImport: i0, template: `
436
+ <ngt-group [scale]="60">
437
+ <viewcube-face-cube [options]="options()" [onClick]="onClick" />
438
+ @for (edge of edges; track $index) {
439
+ <viewcube-edge-cube
440
+ [position]="edge"
441
+ [dimensions]="edgeDimensions[$index]"
442
+ [onClick]="onClick"
443
+ [hoverColor]="hoverColor()"
444
+ />
445
+ }
446
+ @for (corner of corners; track $index) {
447
+ <viewcube-edge-cube
448
+ [position]="corner"
449
+ [dimensions]="cornerDimensions"
450
+ [onClick]="onClick"
451
+ [hoverColor]="hoverColor()"
452
+ />
453
+ }
454
+ </ngt-group>
455
+ `, isInline: true, dependencies: [{ kind: "component", type: FaceCube, selector: "viewcube-face-cube", inputs: ["options", "onClick"] }, { kind: "component", type: EdgeCube, selector: "viewcube-edge-cube", inputs: ["dimensions", "position", "hoverColor", "onClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
456
+ }
457
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsGizmoViewcube, decorators: [{
458
+ type: Component,
459
+ args: [{
460
+ selector: 'ngts-gizmo-viewcube',
461
+ standalone: true,
462
+ template: `
463
+ <ngt-group [scale]="60">
464
+ <viewcube-face-cube [options]="options()" [onClick]="onClick" />
465
+ @for (edge of edges; track $index) {
466
+ <viewcube-edge-cube
467
+ [position]="edge"
468
+ [dimensions]="edgeDimensions[$index]"
469
+ [onClick]="onClick"
470
+ [hoverColor]="hoverColor()"
471
+ />
472
+ }
473
+ @for (corner of corners; track $index) {
474
+ <viewcube-edge-cube
475
+ [position]="corner"
476
+ [dimensions]="cornerDimensions"
477
+ [onClick]="onClick"
478
+ [hoverColor]="hoverColor()"
479
+ />
480
+ }
481
+ </ngt-group>
482
+ `,
483
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
484
+ changeDetection: ChangeDetectionStrategy.OnPush,
485
+ imports: [FaceCube, EdgeCube],
486
+ }]
487
+ }], ctorParameters: () => [] });
488
+
489
+ class Axis {
490
+ constructor() {
491
+ this.scale = input([0.8, 0.05, 0.05], {
492
+ transform: (value) => {
493
+ if (value === undefined)
494
+ return [0.8, 0.05, 0.05];
495
+ return value;
496
+ },
497
+ });
498
+ this.color = input();
499
+ this.rotation = input([0, 0, 0]);
500
+ extend({ Group, Mesh, BoxGeometry, MeshBasicMaterial });
501
+ }
502
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: Axis, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
503
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.4", type: Axis, isStandalone: true, selector: "viewport-axis", inputs: { scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, rotation: { classPropertyName: "rotation", publicName: "rotation", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
504
+ <ngt-group [rotation]="rotation()">
505
+ <ngt-mesh [position]="[0.4, 0, 0]">
506
+ <ngt-box-geometry *args="scale()" />
507
+ <ngt-mesh-basic-material [color]="color()" [toneMapped]="false" />
508
+ </ngt-mesh>
509
+ </ngt-group>
510
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgtArgs, selector: "ng-template[args]", inputs: ["args"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
511
+ }
512
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: Axis, decorators: [{
513
+ type: Component,
514
+ args: [{
515
+ selector: 'viewport-axis',
516
+ standalone: true,
517
+ template: `
518
+ <ngt-group [rotation]="rotation()">
519
+ <ngt-mesh [position]="[0.4, 0, 0]">
520
+ <ngt-box-geometry *args="scale()" />
521
+ <ngt-mesh-basic-material [color]="color()" [toneMapped]="false" />
522
+ </ngt-mesh>
523
+ </ngt-group>
524
+ `,
525
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
526
+ changeDetection: ChangeDetectionStrategy.OnPush,
527
+ imports: [NgtArgs],
528
+ }]
529
+ }], ctorParameters: () => [] });
530
+ class AxisHead {
531
+ constructor() {
532
+ this.arcStyle = input.required();
533
+ this.position = input.required();
534
+ this.label = input();
535
+ this.labelColor = input('#000');
536
+ this.axisHeadScale = input(1);
537
+ this.disabled = input(false);
538
+ this.font = input('18px Inter var, Arial, sans-serif');
539
+ this.onClick = input();
540
+ this.document = inject(DOCUMENT);
541
+ this.gizmoHelper = inject(NgtsGizmoHelper);
542
+ this.store = injectStore();
543
+ this.gl = this.store.select('gl');
544
+ this.texture = computed(() => {
545
+ const [arcStyle, label, labelColor, font, gl] = [
546
+ this.arcStyle(),
547
+ this.label(),
548
+ this.labelColor(),
549
+ this.font(),
550
+ this.gl(),
551
+ ];
552
+ const canvas = this.document.createElement('canvas');
553
+ canvas.width = 64;
554
+ canvas.height = 64;
555
+ const context = canvas.getContext('2d');
556
+ context.beginPath();
557
+ context.arc(32, 32, 16, 0, 2 * Math.PI);
558
+ context.closePath();
559
+ context.fillStyle = arcStyle;
560
+ context.fill();
561
+ if (label) {
562
+ context.font = font;
563
+ context.textAlign = 'center';
564
+ context.fillStyle = labelColor;
565
+ context.fillText(label, 32, 41);
566
+ }
567
+ const texture = new CanvasTexture(canvas);
568
+ texture.anisotropy = gl.capabilities.getMaxAnisotropy() || 1;
569
+ return texture;
570
+ });
571
+ this.active = signal(false);
572
+ this.scale = computed(() => (this.label() ? 1 : 0.75) * (this.active() ? 1.2 : 1) * this.axisHeadScale());
573
+ extend({ Sprite, SpriteMaterial });
574
+ }
575
+ onPointerOver(event) {
576
+ if (this.disabled())
577
+ return;
578
+ event.stopPropagation();
579
+ this.active.set(true);
580
+ }
581
+ onPointerOut(event) {
582
+ if (this.disabled())
583
+ return;
584
+ const onClick = this.onClick();
585
+ if (onClick)
586
+ onClick(event);
587
+ else {
588
+ event.stopPropagation();
589
+ this.active.set(false);
590
+ }
591
+ }
592
+ onPointerDown(event) {
593
+ if (this.disabled())
594
+ return;
595
+ event.stopPropagation();
596
+ this.gizmoHelper.tweenCamera(event.object.position);
597
+ }
598
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: AxisHead, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
599
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.4", type: AxisHead, isStandalone: true, selector: "viewport-axis-head", inputs: { arcStyle: { classPropertyName: "arcStyle", publicName: "arcStyle", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelColor: { classPropertyName: "labelColor", publicName: "labelColor", isSignal: true, isRequired: false, transformFunction: null }, axisHeadScale: { classPropertyName: "axisHeadScale", publicName: "axisHeadScale", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, font: { classPropertyName: "font", publicName: "font", isSignal: true, isRequired: false, transformFunction: null }, onClick: { classPropertyName: "onClick", publicName: "onClick", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
600
+ <ngt-sprite
601
+ [scale]="scale()"
602
+ [position]="position()"
603
+ (pointerover)="onPointerOver($any($event))"
604
+ (pointerout)="onPointerOut($any($event))"
605
+ (pointerdown)="onPointerDown($any($event))"
606
+ >
607
+ <ngt-sprite-material [map]="texture()" [alphaTest]="0.3" [opacity]="label() ? 1 : 0.75" [toneMapped]="false" />
608
+ </ngt-sprite>
609
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
610
+ }
611
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: AxisHead, decorators: [{
612
+ type: Component,
613
+ args: [{
614
+ selector: 'viewport-axis-head',
615
+ standalone: true,
616
+ template: `
617
+ <ngt-sprite
618
+ [scale]="scale()"
619
+ [position]="position()"
620
+ (pointerover)="onPointerOver($any($event))"
621
+ (pointerout)="onPointerOut($any($event))"
622
+ (pointerdown)="onPointerDown($any($event))"
623
+ >
624
+ <ngt-sprite-material [map]="texture()" [alphaTest]="0.3" [opacity]="label() ? 1 : 0.75" [toneMapped]="false" />
625
+ </ngt-sprite>
626
+ `,
627
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
628
+ changeDetection: ChangeDetectionStrategy.OnPush,
629
+ }]
630
+ }], ctorParameters: () => [] });
631
+ const defaultOptions$1 = {
632
+ axisColors: ['#ff2060', '#20df80', '#2080ff'],
633
+ labels: ['X', 'Y', 'Z'],
634
+ axisHeadScale: 1,
635
+ labelColor: '#000',
636
+ hideNegativeAxes: false,
637
+ hideAxisHeads: false,
638
+ disabled: false,
639
+ font: '18px Inter var, Arial, sans-serif',
640
+ };
641
+ class NgtsGizmoViewport {
642
+ constructor() {
643
+ this.Math = Math;
644
+ this.options = input(defaultOptions$1, { transform: mergeInputs(defaultOptions$1) });
645
+ this.parameters = omit(this.options, [
646
+ 'axisColors',
647
+ 'axisScale',
648
+ 'labels',
649
+ 'axisHeadScale',
650
+ 'labelColor',
651
+ 'hideNegativeAxes',
652
+ 'hideAxisHeads',
653
+ 'disabled',
654
+ 'font',
655
+ ]);
656
+ this.click = output();
657
+ this.axisColors = pick(this.options, 'axisColors');
658
+ this.axisScale = pick(this.options, 'axisScale');
659
+ this.hideAxisHeads = pick(this.options, 'hideAxisHeads');
660
+ this.hideNegativeAxes = pick(this.options, 'hideNegativeAxes');
661
+ this.labels = pick(this.options, 'labels');
662
+ this.axisHeadScale = pick(this.options, 'axisHeadScale');
663
+ this.labelColor = pick(this.options, 'labelColor');
664
+ this.disabled = pick(this.options, 'disabled');
665
+ this.font = pick(this.options, 'font');
666
+ extend({ Group });
667
+ }
668
+ get onClick() {
669
+ if (hasListener(this.click))
670
+ return getEmitter(this.click);
671
+ return undefined;
672
+ }
673
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsGizmoViewport, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
674
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.4", type: NgtsGizmoViewport, isStandalone: true, selector: "ngts-gizmo-viewport", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { click: "click" }, ngImport: i0, template: `
675
+ <ngt-group [scale]="40" [parameters]="parameters()">
676
+ <viewport-axis [color]="axisColors()[0]" [rotation]="[0, 0, 0]" [scale]="axisScale()" />
677
+ <viewport-axis [color]="axisColors()[1]" [rotation]="[0, 0, Math.PI / 2]" [scale]="axisScale()" />
678
+ <viewport-axis [color]="axisColors()[2]" [rotation]="[0, -Math.PI / 2, 0]" [scale]="axisScale()" />
679
+
680
+ @if (!hideAxisHeads()) {
681
+ <viewport-axis-head
682
+ [arcStyle]="axisColors()[0]"
683
+ [position]="[1, 0, 0]"
684
+ [label]="labels()[0]"
685
+ [labelColor]="labelColor()"
686
+ [axisHeadScale]="axisHeadScale()"
687
+ [disabled]="disabled()"
688
+ [font]="font()"
689
+ [onClick]="onClick"
690
+ />
691
+ <viewport-axis-head
692
+ [arcStyle]="axisColors()[1]"
693
+ [position]="[0, 1, 0]"
694
+ [label]="labels()[1]"
695
+ [labelColor]="labelColor()"
696
+ [axisHeadScale]="axisHeadScale()"
697
+ [disabled]="disabled()"
698
+ [font]="font()"
699
+ [onClick]="onClick"
700
+ />
701
+ <viewport-axis-head
702
+ [arcStyle]="axisColors()[2]"
703
+ [position]="[0, 0, 1]"
704
+ [label]="labels()[2]"
705
+ [labelColor]="labelColor()"
706
+ [axisHeadScale]="axisHeadScale()"
707
+ [disabled]="disabled()"
708
+ [font]="font()"
709
+ [onClick]="onClick"
710
+ />
711
+
712
+ @if (!hideNegativeAxes()) {
713
+ <viewport-axis-head
714
+ [arcStyle]="axisColors()[0]"
715
+ [position]="[-1, 0, 0]"
716
+ [axisHeadScale]="axisHeadScale()"
717
+ [disabled]="disabled()"
718
+ [onClick]="onClick"
719
+ />
720
+ <viewport-axis-head
721
+ [arcStyle]="axisColors()[1]"
722
+ [position]="[0, -1, 0]"
723
+ [axisHeadScale]="axisHeadScale()"
724
+ [disabled]="disabled()"
725
+ [onClick]="onClick"
726
+ />
727
+ <viewport-axis-head
728
+ [arcStyle]="axisColors()[2]"
729
+ [position]="[0, 0, -1]"
730
+ [axisHeadScale]="axisHeadScale()"
731
+ [disabled]="disabled()"
732
+ [onClick]="onClick"
733
+ />
734
+ }
735
+ }
736
+ </ngt-group>
737
+ `, isInline: true, dependencies: [{ kind: "component", type: Axis, selector: "viewport-axis", inputs: ["scale", "color", "rotation"] }, { kind: "component", type: AxisHead, selector: "viewport-axis-head", inputs: ["arcStyle", "position", "label", "labelColor", "axisHeadScale", "disabled", "font", "onClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
738
+ }
739
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsGizmoViewport, decorators: [{
740
+ type: Component,
741
+ args: [{
742
+ selector: 'ngts-gizmo-viewport',
743
+ standalone: true,
744
+ template: `
745
+ <ngt-group [scale]="40" [parameters]="parameters()">
746
+ <viewport-axis [color]="axisColors()[0]" [rotation]="[0, 0, 0]" [scale]="axisScale()" />
747
+ <viewport-axis [color]="axisColors()[1]" [rotation]="[0, 0, Math.PI / 2]" [scale]="axisScale()" />
748
+ <viewport-axis [color]="axisColors()[2]" [rotation]="[0, -Math.PI / 2, 0]" [scale]="axisScale()" />
749
+
750
+ @if (!hideAxisHeads()) {
751
+ <viewport-axis-head
752
+ [arcStyle]="axisColors()[0]"
753
+ [position]="[1, 0, 0]"
754
+ [label]="labels()[0]"
755
+ [labelColor]="labelColor()"
756
+ [axisHeadScale]="axisHeadScale()"
757
+ [disabled]="disabled()"
758
+ [font]="font()"
759
+ [onClick]="onClick"
760
+ />
761
+ <viewport-axis-head
762
+ [arcStyle]="axisColors()[1]"
763
+ [position]="[0, 1, 0]"
764
+ [label]="labels()[1]"
765
+ [labelColor]="labelColor()"
766
+ [axisHeadScale]="axisHeadScale()"
767
+ [disabled]="disabled()"
768
+ [font]="font()"
769
+ [onClick]="onClick"
770
+ />
771
+ <viewport-axis-head
772
+ [arcStyle]="axisColors()[2]"
773
+ [position]="[0, 0, 1]"
774
+ [label]="labels()[2]"
775
+ [labelColor]="labelColor()"
776
+ [axisHeadScale]="axisHeadScale()"
777
+ [disabled]="disabled()"
778
+ [font]="font()"
779
+ [onClick]="onClick"
780
+ />
781
+
782
+ @if (!hideNegativeAxes()) {
783
+ <viewport-axis-head
784
+ [arcStyle]="axisColors()[0]"
785
+ [position]="[-1, 0, 0]"
786
+ [axisHeadScale]="axisHeadScale()"
787
+ [disabled]="disabled()"
788
+ [onClick]="onClick"
789
+ />
790
+ <viewport-axis-head
791
+ [arcStyle]="axisColors()[1]"
792
+ [position]="[0, -1, 0]"
793
+ [axisHeadScale]="axisHeadScale()"
794
+ [disabled]="disabled()"
795
+ [onClick]="onClick"
796
+ />
797
+ <viewport-axis-head
798
+ [arcStyle]="axisColors()[2]"
799
+ [position]="[0, 0, -1]"
800
+ [axisHeadScale]="axisHeadScale()"
801
+ [disabled]="disabled()"
802
+ [onClick]="onClick"
803
+ />
804
+ }
805
+ }
806
+ </ngt-group>
807
+ `,
808
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
809
+ changeDetection: ChangeDetectionStrategy.OnPush,
810
+ imports: [Axis, AxisHead],
811
+ }]
812
+ }], ctorParameters: () => [] });
813
+
814
+ const vec1$1 = new Vector3();
815
+ const vec2$1 = new Vector3();
816
+ function calculateOffset$1(clickPoint, normal, rayStart, rayDir) {
817
+ const e1 = normal.dot(normal);
818
+ const e2 = normal.dot(clickPoint) - normal.dot(rayStart);
819
+ const e3 = normal.dot(rayDir);
820
+ if (e3 === 0) {
821
+ return -e2 / e1;
822
+ }
823
+ vec1$1
824
+ .copy(rayDir)
825
+ .multiplyScalar(e1 / e3)
826
+ .sub(normal);
827
+ vec2$1
828
+ .copy(rayDir)
829
+ .multiplyScalar(e2 / e3)
830
+ .add(rayStart)
831
+ .sub(clickPoint);
832
+ return -vec1$1.dot(vec2$1) / vec1$1.dot(vec1$1);
833
+ }
834
+ const upV$1 = new Vector3(0, 1, 0);
835
+ const offsetMatrix$1 = new Matrix4();
836
+ class NgtsAxisArrow {
837
+ constructor() {
838
+ this.DoubleSide = DoubleSide;
839
+ this.direction = input.required();
840
+ this.axis = input.required();
841
+ this.groupRef = viewChild.required('group');
842
+ this.annotationRef = viewChild('annotation', { read: ElementRef });
843
+ this.pivotControls = inject(NgtsPivotControls);
844
+ this.store = injectStore();
845
+ this.controls = this.store.select('controls');
846
+ this.hovered = signal(false);
847
+ this.clickInfo = null;
848
+ this.offset0 = 0;
849
+ this.color = computed(() => this.hovered() ? this.pivotControls.hoveredColor() : this.pivotControls.axisColors()[this.axis()]);
850
+ this.coneWidth = computed(() => this.pivotControls.fixed()
851
+ ? (this.pivotControls.lineWidth() / this.pivotControls.scale()) * 1.6
852
+ : this.pivotControls.scale() / 20);
853
+ this.coneLength = computed(() => (this.pivotControls.fixed() ? 0.2 : this.pivotControls.scale() / 5));
854
+ this.cylinderLength = computed(() => this.pivotControls.fixed() ? 1 - this.coneLength() : this.pivotControls.scale() - this.coneLength());
855
+ this.matrixL = computed(() => {
856
+ const quaternion = new Quaternion().setFromUnitVectors(upV$1, this.direction().clone().normalize());
857
+ return new Matrix4().makeRotationFromQuaternion(quaternion);
858
+ });
859
+ extend({ Group, Mesh, ConeGeometry, CylinderGeometry, MeshBasicMaterial });
860
+ }
861
+ onPointerDown(event) {
862
+ const [group, direction, axis, controls, annotation] = [
863
+ this.groupRef().nativeElement,
864
+ this.direction(),
865
+ this.axis(),
866
+ this.controls(),
867
+ this.annotationRef()?.nativeElement,
868
+ ];
869
+ if (annotation) {
870
+ annotation.innerText = `${this.pivotControls.translation[axis].toFixed(2)}`;
871
+ annotation.style.display = 'block';
872
+ }
873
+ event.stopPropagation();
874
+ const rotation = new Matrix4().extractRotation(group.matrixWorld);
875
+ const origin = new Vector3().setFromMatrixPosition(group.matrixWorld);
876
+ const clickPoint = event.point.clone();
877
+ const dir = direction.clone().applyMatrix4(rotation).normalize();
878
+ this.clickInfo = { clickPoint, dir };
879
+ this.offset0 = this.pivotControls.translation[axis];
880
+ this.pivotControls.onDragStart({ component: 'Arrow', axis, origin, directions: [dir] });
881
+ if (controls) {
882
+ controls.enabled = false;
883
+ }
884
+ // @ts-expect-error - setPointerCapture is not in the type definition
885
+ event.target.setPointerCapture(event.pointerId);
886
+ }
887
+ onPointerUp(event) {
888
+ const [annotation, controls] = [this.annotationRef()?.nativeElement, this.controls()];
889
+ if (annotation) {
890
+ annotation.style.display = 'none';
891
+ }
892
+ event.stopPropagation();
893
+ this.clickInfo = null;
894
+ this.pivotControls.onDragEnd();
895
+ if (controls) {
896
+ controls.enabled = true;
897
+ }
898
+ // @ts-expect-error - setPointerCapture is not in the type definition
899
+ event.target.releasePointerCapture(event.pointerId);
900
+ }
901
+ onPointerMove(event) {
902
+ event.stopPropagation();
903
+ if (!this.hovered()) {
904
+ this.hovered.set(true);
905
+ }
906
+ if (this.clickInfo) {
907
+ const { clickPoint, dir } = this.clickInfo;
908
+ const [translationLimits, annotation, axis] = [
909
+ this.pivotControls.translationLimits(),
910
+ this.annotationRef()?.nativeElement,
911
+ this.axis(),
912
+ ];
913
+ const [min, max] = translationLimits?.[axis] || [undefined, undefined];
914
+ let offset = calculateOffset$1(clickPoint, dir, event.ray.origin, event.ray.direction);
915
+ if (min !== undefined) {
916
+ offset = Math.max(offset, min - this.offset0);
917
+ }
918
+ if (max !== undefined) {
919
+ offset = Math.min(offset, max - this.offset0);
920
+ }
921
+ this.pivotControls.translation[axis] = this.offset0 + offset;
922
+ if (annotation) {
923
+ annotation.innerText = `${this.pivotControls.translation[axis].toFixed(2)}`;
924
+ }
925
+ offsetMatrix$1.makeTranslation(dir.x * offset, dir.y * offset, dir.z * offset);
926
+ this.pivotControls.onDrag(offsetMatrix$1);
927
+ }
928
+ }
929
+ onPointerOut(event) {
930
+ event.stopPropagation();
931
+ this.hovered.set(false);
932
+ }
933
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsAxisArrow, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
934
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.4", type: NgtsAxisArrow, isStandalone: true, selector: "ngts-axis-arrow", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: true, transformFunction: null }, axis: { classPropertyName: "axis", publicName: "axis", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "groupRef", first: true, predicate: ["group"], descendants: true, isSignal: true }, { propertyName: "annotationRef", first: true, predicate: ["annotation"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: `
935
+ <ngt-group #group>
936
+ <ngt-group
937
+ [matrix]="matrixL()"
938
+ [matrixAutoUpdate]="false"
939
+ (pointerdown)="onPointerDown($any($event))"
940
+ (pointerup)="onPointerUp($any($event))"
941
+ (pointermove)="onPointerMove($any($event))"
942
+ (pointerout)="onPointerOut($any($event))"
943
+ >
944
+ @if (pivotControls.annotations()) {
945
+ <ngts-html [options]="{ position: [0, -coneLength(), 0] }">
946
+ <div
947
+ #annotation
948
+ ngtsHTMLContent
949
+ style="display: none; background: #151520; color: white; padding: 6px 8px; border-radius: 7px; white-space: nowrap;"
950
+ [class]="pivotControls.annotationsClass()"
951
+ ></div>
952
+ </ngts-html>
953
+ }
954
+
955
+ <ngt-mesh
956
+ [visible]="false"
957
+ [position]="[0, (cylinderLength() + coneLength()) / 2.0, 0]"
958
+ [userData]="pivotControls.userData()"
959
+ >
960
+ <ngt-cylinder-geometry
961
+ *args="[coneWidth() * 1.4, coneWidth() * 1.4, cylinderLength() + coneLength(), 8, 1]"
962
+ />
963
+ </ngt-mesh>
964
+
965
+ <ngts-line
966
+ [points]="[0, 0, 0, 0, cylinderLength(), 0]"
967
+ [options]="{
968
+ raycast: null,
969
+ side: DoubleSide,
970
+ polygonOffset: true,
971
+ polygonOffsetFactor: -10,
972
+ renderOrder: 1,
973
+ fog: false,
974
+ transparent: true,
975
+ lineWidth: pivotControls.lineWidth(),
976
+ color: color(),
977
+ opacity: pivotControls.opacity(),
978
+ depthTest: pivotControls.depthTest(),
979
+ }"
980
+ />
981
+
982
+ <ngt-mesh [raycast]="null" [position]="[0, cylinderLength() + coneLength() / 2.0, 0]" [renderOrder]="500">
983
+ <ngt-cone-geometry *args="[coneWidth(), coneLength(), 24, 1]" />
984
+ <ngt-mesh-basic-material
985
+ [transparent]="true"
986
+ [depthTest]="pivotControls.depthTest()"
987
+ [color]="color()"
988
+ [opacity]="pivotControls.opacity()"
989
+ [polygonOffset]="true"
990
+ [polygonOffsetFactor]="-10"
991
+ [fog]="false"
992
+ />
993
+ </ngt-mesh>
994
+ </ngt-group>
995
+ </ngt-group>
996
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgtArgs, selector: "ng-template[args]", inputs: ["args"] }, { kind: "component", type: NgtsLine, selector: "ngts-line", inputs: ["points", "options"] }, { kind: "component", type: NgtsHTML, selector: "ngts-html", inputs: ["options"] }, { kind: "component", type: NgtsHTMLContent, selector: "[ngtsHTMLContent]", inputs: ["ngtsHTMLContent"], outputs: ["occluded"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
997
+ }
998
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsAxisArrow, decorators: [{
999
+ type: Component,
1000
+ args: [{
1001
+ selector: 'ngts-axis-arrow',
1002
+ standalone: true,
1003
+ template: `
1004
+ <ngt-group #group>
1005
+ <ngt-group
1006
+ [matrix]="matrixL()"
1007
+ [matrixAutoUpdate]="false"
1008
+ (pointerdown)="onPointerDown($any($event))"
1009
+ (pointerup)="onPointerUp($any($event))"
1010
+ (pointermove)="onPointerMove($any($event))"
1011
+ (pointerout)="onPointerOut($any($event))"
1012
+ >
1013
+ @if (pivotControls.annotations()) {
1014
+ <ngts-html [options]="{ position: [0, -coneLength(), 0] }">
1015
+ <div
1016
+ #annotation
1017
+ ngtsHTMLContent
1018
+ style="display: none; background: #151520; color: white; padding: 6px 8px; border-radius: 7px; white-space: nowrap;"
1019
+ [class]="pivotControls.annotationsClass()"
1020
+ ></div>
1021
+ </ngts-html>
1022
+ }
1023
+
1024
+ <ngt-mesh
1025
+ [visible]="false"
1026
+ [position]="[0, (cylinderLength() + coneLength()) / 2.0, 0]"
1027
+ [userData]="pivotControls.userData()"
1028
+ >
1029
+ <ngt-cylinder-geometry
1030
+ *args="[coneWidth() * 1.4, coneWidth() * 1.4, cylinderLength() + coneLength(), 8, 1]"
1031
+ />
1032
+ </ngt-mesh>
1033
+
1034
+ <ngts-line
1035
+ [points]="[0, 0, 0, 0, cylinderLength(), 0]"
1036
+ [options]="{
1037
+ raycast: null,
1038
+ side: DoubleSide,
1039
+ polygonOffset: true,
1040
+ polygonOffsetFactor: -10,
1041
+ renderOrder: 1,
1042
+ fog: false,
1043
+ transparent: true,
1044
+ lineWidth: pivotControls.lineWidth(),
1045
+ color: color(),
1046
+ opacity: pivotControls.opacity(),
1047
+ depthTest: pivotControls.depthTest(),
1048
+ }"
1049
+ />
1050
+
1051
+ <ngt-mesh [raycast]="null" [position]="[0, cylinderLength() + coneLength() / 2.0, 0]" [renderOrder]="500">
1052
+ <ngt-cone-geometry *args="[coneWidth(), coneLength(), 24, 1]" />
1053
+ <ngt-mesh-basic-material
1054
+ [transparent]="true"
1055
+ [depthTest]="pivotControls.depthTest()"
1056
+ [color]="color()"
1057
+ [opacity]="pivotControls.opacity()"
1058
+ [polygonOffset]="true"
1059
+ [polygonOffsetFactor]="-10"
1060
+ [fog]="false"
1061
+ />
1062
+ </ngt-mesh>
1063
+ </ngt-group>
1064
+ </ngt-group>
1065
+ `,
1066
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
1067
+ changeDetection: ChangeDetectionStrategy.OnPush,
1068
+ imports: [NgtArgs, NgtsLine, NgtsHTML, NgtsHTMLContent],
1069
+ }]
1070
+ }], ctorParameters: () => [] });
1071
+
1072
+ const clickDir = new Vector3();
1073
+ const intersectionDir = new Vector3();
1074
+ function toDegrees(radians) {
1075
+ return (radians * 180) / Math.PI;
1076
+ }
1077
+ function toRadians(degrees) {
1078
+ return (degrees * Math.PI) / 180;
1079
+ }
1080
+ function calculateAngle(clickPoint, intersectionPoint, origin, e1, e2) {
1081
+ clickDir.copy(clickPoint).sub(origin);
1082
+ intersectionDir.copy(intersectionPoint).sub(origin);
1083
+ const dote1e1 = e1.dot(e1);
1084
+ const dote2e2 = e2.dot(e2);
1085
+ const uClick = clickDir.dot(e1) / dote1e1;
1086
+ const vClick = clickDir.dot(e2) / dote2e2;
1087
+ const uIntersection = intersectionDir.dot(e1) / dote1e1;
1088
+ const vIntersection = intersectionDir.dot(e2) / dote2e2;
1089
+ const angleClick = Math.atan2(vClick, uClick);
1090
+ const angleIntersection = Math.atan2(vIntersection, uIntersection);
1091
+ return angleIntersection - angleClick;
1092
+ }
1093
+ function fmod(num, denom) {
1094
+ let k = Math.floor(num / denom);
1095
+ k = k < 0 ? k + 1 : k;
1096
+ return num - k * denom;
1097
+ }
1098
+ function minimizeAngle(angle) {
1099
+ let result = fmod(angle, 2 * Math.PI);
1100
+ if (Math.abs(result) < 1e-6) {
1101
+ return 0.0;
1102
+ }
1103
+ if (result < 0.0) {
1104
+ result += 2 * Math.PI;
1105
+ }
1106
+ return result;
1107
+ }
1108
+ const rotMatrix = new Matrix4();
1109
+ const posNew = new Vector3();
1110
+ const ray$1 = new Ray();
1111
+ const intersection$1 = new Vector3();
1112
+ class NgtsAxisRotator {
1113
+ constructor() {
1114
+ this.DoubleSide = DoubleSide;
1115
+ this.dir1 = input.required();
1116
+ this.dir2 = input.required();
1117
+ this.axis = input.required();
1118
+ this.groupRef = viewChild.required('group');
1119
+ this.annotationRef = viewChild('annotation', { read: ElementRef });
1120
+ this.pivotControls = inject(NgtsPivotControls);
1121
+ this.store = injectStore();
1122
+ this.controls = this.store.select('controls');
1123
+ this.hovered = signal(false);
1124
+ this.angle = 0;
1125
+ this.angle0 = 0;
1126
+ this.clickInfo = null;
1127
+ this.matrixL = computed(() => {
1128
+ const dir1N = this.dir1().clone().normalize();
1129
+ const dir2N = this.dir2().clone().normalize();
1130
+ return new Matrix4().makeBasis(dir1N, dir2N, dir1N.clone().cross(dir2N));
1131
+ });
1132
+ this.r = computed(() => (this.pivotControls.fixed() ? 0.65 : this.pivotControls.scale() * 0.65));
1133
+ this.arc = computed(() => {
1134
+ const segments = 32;
1135
+ const points = [];
1136
+ for (let j = 0; j <= segments; j++) {
1137
+ const angle = (j * (Math.PI / 2)) / segments;
1138
+ points.push(new Vector3(Math.cos(angle) * this.r(), Math.sin(angle) * this.r(), 0));
1139
+ }
1140
+ return points;
1141
+ });
1142
+ extend({ Group });
1143
+ }
1144
+ onPointerDown(event) {
1145
+ const [annotation, group, axis, controls] = [
1146
+ this.annotationRef()?.nativeElement,
1147
+ this.groupRef().nativeElement,
1148
+ this.axis(),
1149
+ this.controls(),
1150
+ ];
1151
+ if (annotation) {
1152
+ annotation.innerText = `${toDegrees(this.angle).toFixed(0)}º`;
1153
+ annotation.style.display = 'block';
1154
+ }
1155
+ event.stopPropagation();
1156
+ const clickPoint = event.point.clone();
1157
+ const origin = new Vector3().setFromMatrixPosition(group.matrixWorld);
1158
+ const e1 = new Vector3().setFromMatrixColumn(group.matrixWorld, 0).normalize();
1159
+ const e2 = new Vector3().setFromMatrixColumn(group.matrixWorld, 1).normalize();
1160
+ const normal = new Vector3().setFromMatrixColumn(group.matrixWorld, 2).normalize();
1161
+ const plane = new Plane().setFromNormalAndCoplanarPoint(normal, origin);
1162
+ this.clickInfo = { clickPoint, origin, e1, e2, normal, plane };
1163
+ this.pivotControls.onDragStart({ component: 'Rotator', axis, origin, directions: [e1, e2, normal] });
1164
+ if (controls) {
1165
+ controls.enabled = false;
1166
+ }
1167
+ // @ts-expect-error - setPointerCapture is not a function on PointerEvent
1168
+ event.target.setPointerCapture(event.pointerId);
1169
+ }
1170
+ onPointerMove(event) {
1171
+ event.stopPropagation();
1172
+ if (!this.hovered())
1173
+ this.hovered.set(true);
1174
+ if (this.clickInfo) {
1175
+ const { clickPoint, origin, e1, e2, normal, plane } = this.clickInfo;
1176
+ const [rotationLimits, axis, annotation] = [
1177
+ this.pivotControls.rotationLimits(),
1178
+ this.axis(),
1179
+ this.annotationRef()?.nativeElement,
1180
+ ];
1181
+ const [min, max] = rotationLimits?.[axis] || [undefined, undefined];
1182
+ ray$1.copy(event.ray);
1183
+ ray$1.intersectPlane(plane, intersection$1);
1184
+ ray$1.direction.negate();
1185
+ ray$1.intersectPlane(plane, intersection$1);
1186
+ let deltaAngle = calculateAngle(clickPoint, intersection$1, origin, e1, e2);
1187
+ let degrees = toDegrees(deltaAngle);
1188
+ if (event.shiftKey) {
1189
+ degrees = Math.round(degrees / 10) * 10;
1190
+ deltaAngle = toRadians(degrees);
1191
+ }
1192
+ if (min !== undefined && max !== undefined && max - min < 2 * Math.PI) {
1193
+ deltaAngle = minimizeAngle(deltaAngle);
1194
+ deltaAngle = deltaAngle > Math.PI ? deltaAngle - 2 * Math.PI : deltaAngle;
1195
+ deltaAngle = Math.round(deltaAngle / 10) * 10;
1196
+ this.angle = this.angle0 + deltaAngle;
1197
+ }
1198
+ else {
1199
+ this.angle = minimizeAngle(this.angle0 + deltaAngle);
1200
+ this.angle = this.angle > Math.PI ? this.angle - 2 * Math.PI : this.angle;
1201
+ }
1202
+ if (annotation) {
1203
+ degrees = toDegrees(this.angle);
1204
+ annotation.innerText = `${degrees.toFixed(0)}º`;
1205
+ }
1206
+ rotMatrix.makeRotationAxis(normal, deltaAngle);
1207
+ posNew.copy(origin).applyMatrix4(rotMatrix).sub(origin).negate();
1208
+ rotMatrix.setPosition(posNew);
1209
+ this.pivotControls.onDrag(rotMatrix);
1210
+ }
1211
+ }
1212
+ onPointerUp(event) {
1213
+ const [annotation, controls] = [this.annotationRef()?.nativeElement, this.controls()];
1214
+ if (annotation) {
1215
+ annotation.style.display = 'none';
1216
+ }
1217
+ event.stopPropagation();
1218
+ this.clickInfo = null;
1219
+ this.pivotControls.onDragEnd();
1220
+ if (controls) {
1221
+ controls.enabled = true;
1222
+ }
1223
+ // @ts-expect-error - releasePointerCapture is not a function on PointerEvent
1224
+ event.target.releasePointerCapture(event.pointerId);
1225
+ }
1226
+ onPointerOut(event) {
1227
+ event.stopPropagation();
1228
+ this.hovered.set(false);
1229
+ }
1230
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsAxisRotator, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1231
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.4", type: NgtsAxisRotator, isStandalone: true, selector: "ngts-axis-rotator", inputs: { dir1: { classPropertyName: "dir1", publicName: "dir1", isSignal: true, isRequired: true, transformFunction: null }, dir2: { classPropertyName: "dir2", publicName: "dir2", isSignal: true, isRequired: true, transformFunction: null }, axis: { classPropertyName: "axis", publicName: "axis", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "groupRef", first: true, predicate: ["group"], descendants: true, isSignal: true }, { propertyName: "annotationRef", first: true, predicate: ["annotation"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: `
1232
+ <ngt-group
1233
+ #group
1234
+ [matrix]="matrixL()"
1235
+ [matrixAutoUpdate]="false"
1236
+ (pointerdown)="onPointerDown($any($event))"
1237
+ (pointermove)="onPointerMove($any($event))"
1238
+ (pointerup)="onPointerUp($any($event))"
1239
+ (pointerout)="onPointerOut($any($event))"
1240
+ >
1241
+ @if (pivotControls.annotations()) {
1242
+ <ngts-html [options]="{ position: [r(), r(), 0] }">
1243
+ <div
1244
+ #annotation
1245
+ ngtsHTMLContent
1246
+ style="display: none; background: #151520; color: white; padding: 6px 8px; border-radius: 7px; white-space: nowrap"
1247
+ [class]="pivotControls.annotationsClass()"
1248
+ ></div>
1249
+ </ngts-html>
1250
+ }
1251
+
1252
+ <ngts-line
1253
+ [points]="arc()"
1254
+ [options]="{ lineWidth: pivotControls.lineWidth() * 4, visible: false, userData: pivotControls.userData() }"
1255
+ />
1256
+
1257
+ <ngts-line
1258
+ [points]="arc()"
1259
+ [options]="{
1260
+ transparent: true,
1261
+ raycast: null,
1262
+ depthTest: pivotControls.depthTest(),
1263
+ lineWidth: pivotControls.lineWidth(),
1264
+ side: DoubleSide,
1265
+ color: hovered() ? pivotControls.hoveredColor() : pivotControls.axisColors()[axis()],
1266
+ opacity: pivotControls.opacity(),
1267
+ polygonOffset: true,
1268
+ polygonOffsetFactor: -10,
1269
+ fog: false,
1270
+ }"
1271
+ />
1272
+ </ngt-group>
1273
+ `, isInline: true, dependencies: [{ kind: "component", type: NgtsLine, selector: "ngts-line", inputs: ["points", "options"] }, { kind: "component", type: NgtsHTML, selector: "ngts-html", inputs: ["options"] }, { kind: "component", type: NgtsHTMLContent, selector: "[ngtsHTMLContent]", inputs: ["ngtsHTMLContent"], outputs: ["occluded"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1274
+ }
1275
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsAxisRotator, decorators: [{
1276
+ type: Component,
1277
+ args: [{
1278
+ selector: 'ngts-axis-rotator',
1279
+ standalone: true,
1280
+ template: `
1281
+ <ngt-group
1282
+ #group
1283
+ [matrix]="matrixL()"
1284
+ [matrixAutoUpdate]="false"
1285
+ (pointerdown)="onPointerDown($any($event))"
1286
+ (pointermove)="onPointerMove($any($event))"
1287
+ (pointerup)="onPointerUp($any($event))"
1288
+ (pointerout)="onPointerOut($any($event))"
1289
+ >
1290
+ @if (pivotControls.annotations()) {
1291
+ <ngts-html [options]="{ position: [r(), r(), 0] }">
1292
+ <div
1293
+ #annotation
1294
+ ngtsHTMLContent
1295
+ style="display: none; background: #151520; color: white; padding: 6px 8px; border-radius: 7px; white-space: nowrap"
1296
+ [class]="pivotControls.annotationsClass()"
1297
+ ></div>
1298
+ </ngts-html>
1299
+ }
1300
+
1301
+ <ngts-line
1302
+ [points]="arc()"
1303
+ [options]="{ lineWidth: pivotControls.lineWidth() * 4, visible: false, userData: pivotControls.userData() }"
1304
+ />
1305
+
1306
+ <ngts-line
1307
+ [points]="arc()"
1308
+ [options]="{
1309
+ transparent: true,
1310
+ raycast: null,
1311
+ depthTest: pivotControls.depthTest(),
1312
+ lineWidth: pivotControls.lineWidth(),
1313
+ side: DoubleSide,
1314
+ color: hovered() ? pivotControls.hoveredColor() : pivotControls.axisColors()[axis()],
1315
+ opacity: pivotControls.opacity(),
1316
+ polygonOffset: true,
1317
+ polygonOffsetFactor: -10,
1318
+ fog: false,
1319
+ }"
1320
+ />
1321
+ </ngt-group>
1322
+ `,
1323
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
1324
+ changeDetection: ChangeDetectionStrategy.OnPush,
1325
+ imports: [NgtsLine, NgtsHTML, NgtsHTMLContent],
1326
+ }]
1327
+ }], ctorParameters: () => [] });
1328
+
1329
+ function decomposeIntoBasis(e1, e2, offset) {
1330
+ const i1 = Math.abs(e1.x) >= Math.abs(e1.y) && Math.abs(e1.x) >= Math.abs(e1.z)
1331
+ ? 0
1332
+ : Math.abs(e1.y) >= Math.abs(e1.x) && Math.abs(e1.y) >= Math.abs(e1.z)
1333
+ ? 1
1334
+ : 2;
1335
+ const e2DegrowthOrder = [0, 1, 2].sort((a, b) => Math.abs(e2.getComponent(b)) - Math.abs(e2.getComponent(a)));
1336
+ const i2 = i1 === e2DegrowthOrder[0] ? e2DegrowthOrder[1] : e2DegrowthOrder[0];
1337
+ const a1 = e1.getComponent(i1);
1338
+ const a2 = e1.getComponent(i2);
1339
+ const b1 = e2.getComponent(i1);
1340
+ const b2 = e2.getComponent(i2);
1341
+ const c1 = offset.getComponent(i1);
1342
+ const c2 = offset.getComponent(i2);
1343
+ const y = (c2 - c1 * (a2 / a1)) / (b2 - b1 * (a2 / a1));
1344
+ const x = (c1 - y * b1) / a1;
1345
+ return [x, y];
1346
+ }
1347
+ const ray = new Ray();
1348
+ const intersection = new Vector3();
1349
+ const offsetMatrix = new Matrix4();
1350
+ class NgtsPlaneSlider {
1351
+ constructor() {
1352
+ this.DoubleSide = DoubleSide;
1353
+ this.dir1 = input.required();
1354
+ this.dir2 = input.required();
1355
+ this.axis = input.required();
1356
+ this.groupRef = viewChild.required('group');
1357
+ this.annotationRef = viewChild('annotation', { read: ElementRef });
1358
+ this.pivotControls = inject(NgtsPivotControls);
1359
+ this.store = injectStore();
1360
+ this.controls = this.store.select('controls');
1361
+ this.hovered = signal(false);
1362
+ this.clickInfo = null;
1363
+ this.offsetX0 = 0;
1364
+ this.offsetY0 = 0;
1365
+ this.matrixL = computed(() => {
1366
+ const dir1N = this.dir1().clone().normalize();
1367
+ const dir2N = this.dir2().clone().normalize();
1368
+ return new Matrix4().makeBasis(dir1N, dir2N, dir1N.clone().cross(dir2N));
1369
+ });
1370
+ this.pos1 = computed(() => (this.pivotControls.fixed() ? 1 / 7 : this.pivotControls.scale() / 7));
1371
+ this.length = computed(() => (this.pivotControls.fixed() ? 0.225 : this.pivotControls.scale() * 0.225));
1372
+ this.color = computed(() => this.hovered() ? this.pivotControls.hoveredColor() : this.pivotControls.axisColors()[this.axis()]);
1373
+ this.points = computed(() => {
1374
+ const length = this.length();
1375
+ return [
1376
+ new Vector3(0, 0, 0),
1377
+ new Vector3(0, length, 0),
1378
+ new Vector3(length, length, 0),
1379
+ new Vector3(length, 0, 0),
1380
+ new Vector3(0, 0, 0),
1381
+ ];
1382
+ });
1383
+ extend({ Group, Mesh, PlaneGeometry, MeshBasicMaterial });
1384
+ }
1385
+ onPointerDown(event) {
1386
+ const [annotation, axis, group, controls] = [
1387
+ this.annotationRef()?.nativeElement,
1388
+ this.axis(),
1389
+ this.groupRef().nativeElement,
1390
+ this.controls(),
1391
+ ];
1392
+ if (annotation) {
1393
+ annotation.innerText = `${this.pivotControls.translation[(axis + 1) % 3].toFixed(2)}, ${this.pivotControls.translation[(axis + 2) % 3].toFixed(2)}`;
1394
+ annotation.style.display = 'block';
1395
+ }
1396
+ event.stopPropagation();
1397
+ const clickPoint = event.point.clone();
1398
+ const origin = new Vector3().setFromMatrixPosition(group.matrixWorld);
1399
+ const e1 = new Vector3().setFromMatrixColumn(group.matrixWorld, 0).normalize();
1400
+ const e2 = new Vector3().setFromMatrixColumn(group.matrixWorld, 1).normalize();
1401
+ const normal = new Vector3().setFromMatrixColumn(group.matrixWorld, 2).normalize();
1402
+ const plane = new Plane().setFromNormalAndCoplanarPoint(normal, origin);
1403
+ this.clickInfo = { clickPoint, e1, e2, plane };
1404
+ this.offsetX0 = this.pivotControls.translation[(axis + 1) % 3];
1405
+ this.offsetY0 = this.pivotControls.translation[(axis + 2) % 3];
1406
+ this.pivotControls.onDragStart({ component: 'Slider', axis, origin, directions: [e1, e2, normal] });
1407
+ if (controls) {
1408
+ controls.enabled = false;
1409
+ }
1410
+ // @ts-expect-error - setPointerCapture is not defined on ThreeEvent
1411
+ event.target.setPointerCapture(event.pointerId);
1412
+ }
1413
+ onPointerMove(event) {
1414
+ event.stopPropagation();
1415
+ if (!this.hovered())
1416
+ this.hovered.set(true);
1417
+ if (this.clickInfo) {
1418
+ const { clickPoint, e1, e2, plane } = this.clickInfo;
1419
+ const [translationLimits, axis, annotation] = [
1420
+ this.pivotControls.translationLimits(),
1421
+ this.axis(),
1422
+ this.annotationRef()?.nativeElement,
1423
+ ];
1424
+ const [minX, maxX] = translationLimits?.[(axis + 1) % 3] || [undefined, undefined];
1425
+ const [minY, maxY] = translationLimits?.[(axis + 2) % 3] || [undefined, undefined];
1426
+ ray.copy(event.ray);
1427
+ ray.intersectPlane(plane, intersection);
1428
+ ray.direction.negate();
1429
+ ray.intersectPlane(plane, intersection);
1430
+ intersection.sub(clickPoint);
1431
+ let [offsetX, offsetY] = decomposeIntoBasis(e1, e2, intersection);
1432
+ /* let offsetY = (intersection.y - (intersection.x * e1.y) / e1.x) / (e2.y - (e2.x * e1.y) / e1.x)
1433
+ let offsetX = (intersection.x - offsetY * e2.x) / e1.x */
1434
+ if (minX !== undefined) {
1435
+ offsetX = Math.max(offsetX, minX - this.offsetX0);
1436
+ }
1437
+ if (maxX !== undefined) {
1438
+ offsetX = Math.min(offsetX, maxX - this.offsetX0);
1439
+ }
1440
+ if (minY !== undefined) {
1441
+ offsetY = Math.max(offsetY, minY - this.offsetY0);
1442
+ }
1443
+ if (maxY !== undefined) {
1444
+ offsetY = Math.min(offsetY, maxY - this.offsetY0);
1445
+ }
1446
+ this.pivotControls.translation[(axis + 1) % 3] = this.offsetX0 + offsetX;
1447
+ this.pivotControls.translation[(axis + 2) % 3] = this.offsetY0 + offsetY;
1448
+ if (annotation) {
1449
+ annotation.innerText = `${this.pivotControls.translation[(axis + 1) % 3].toFixed(2)}, ${this.pivotControls.translation[(axis + 2) % 3].toFixed(2)}`;
1450
+ }
1451
+ offsetMatrix.makeTranslation(offsetX * e1.x + offsetY * e2.x, offsetX * e1.y + offsetY * e2.y, offsetX * e1.z + offsetY * e2.z);
1452
+ this.pivotControls.onDrag(offsetMatrix);
1453
+ }
1454
+ }
1455
+ onPointerUp(event) {
1456
+ const [annotation, controls] = [this.annotationRef()?.nativeElement, this.controls()];
1457
+ if (annotation) {
1458
+ annotation.style.display = 'none';
1459
+ }
1460
+ event.stopPropagation();
1461
+ this.clickInfo = null;
1462
+ this.pivotControls.onDragEnd();
1463
+ if (controls) {
1464
+ controls.enabled = true;
1465
+ }
1466
+ // @ts-expect-error - releasePointerCapture is not defined on ThreeEvent
1467
+ event.target.releasePointerCapture(event.pointerId);
1468
+ }
1469
+ onPointerOut(event) {
1470
+ event.stopPropagation();
1471
+ this.hovered.set(false);
1472
+ }
1473
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsPlaneSlider, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1474
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.4", type: NgtsPlaneSlider, isStandalone: true, selector: "ngts-plane-slider", inputs: { dir1: { classPropertyName: "dir1", publicName: "dir1", isSignal: true, isRequired: true, transformFunction: null }, dir2: { classPropertyName: "dir2", publicName: "dir2", isSignal: true, isRequired: true, transformFunction: null }, axis: { classPropertyName: "axis", publicName: "axis", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "groupRef", first: true, predicate: ["group"], descendants: true, isSignal: true }, { propertyName: "annotationRef", first: true, predicate: ["annotation"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: `
1475
+ <ngt-group #group [matrix]="matrixL()" [matrixAutoUpdate]="false">
1476
+ @if (pivotControls.annotations()) {
1477
+ <ngts-html [options]="{ position: [0, 0, 0] }">
1478
+ <div
1479
+ #annotation
1480
+ ngtsHTMLContent
1481
+ style="display: none; background: #151520; color: white; padding: 6px 8px; border-radius: 7px; white-space: nowrap"
1482
+ [class]="pivotControls.annotationsClass()"
1483
+ ></div>
1484
+ </ngts-html>
1485
+ }
1486
+ <ngt-group [position]="[pos1() * 1.7, pos1() * 1.7, 0]">
1487
+ <ngt-mesh
1488
+ [visible]="true"
1489
+ [scale]="length()"
1490
+ [userData]="pivotControls.userData()"
1491
+ (pointerdown)="onPointerDown($any($event))"
1492
+ (pointermove)="onPointerMove($any($event))"
1493
+ (pointerup)="onPointerUp($any($event))"
1494
+ (pointerout)="onPointerOut($any($event))"
1495
+ >
1496
+ <ngt-plane-geometry />
1497
+ <ngt-mesh-basic-material
1498
+ [transparent]="true"
1499
+ [depthTest]="pivotControls.depthTest()"
1500
+ [color]="color()"
1501
+ [polygonOffset]="true"
1502
+ [polygonOffsetFactor]="-10"
1503
+ [side]="DoubleSide"
1504
+ [fog]="false"
1505
+ />
1506
+ </ngt-mesh>
1507
+ <ngts-line
1508
+ [points]="points()"
1509
+ [options]="{
1510
+ position: [-length() / 2, -length() / 2, 0],
1511
+ transparent: true,
1512
+ depthTest: pivotControls.depthTest(),
1513
+ lineWidth: pivotControls.lineWidth(),
1514
+ color: color(),
1515
+ opacity: pivotControls.opacity(),
1516
+ polygonOffset: true,
1517
+ polygonOffsetFactor: -10,
1518
+ userData: pivotControls.userData(),
1519
+ fog: false,
1520
+ }"
1521
+ />
1522
+ </ngt-group>
1523
+ </ngt-group>
1524
+ `, isInline: true, dependencies: [{ kind: "component", type: NgtsHTML, selector: "ngts-html", inputs: ["options"] }, { kind: "component", type: NgtsHTMLContent, selector: "[ngtsHTMLContent]", inputs: ["ngtsHTMLContent"], outputs: ["occluded"] }, { kind: "component", type: NgtsLine, selector: "ngts-line", inputs: ["points", "options"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1525
+ }
1526
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsPlaneSlider, decorators: [{
1527
+ type: Component,
1528
+ args: [{
1529
+ selector: 'ngts-plane-slider',
1530
+ standalone: true,
1531
+ template: `
1532
+ <ngt-group #group [matrix]="matrixL()" [matrixAutoUpdate]="false">
1533
+ @if (pivotControls.annotations()) {
1534
+ <ngts-html [options]="{ position: [0, 0, 0] }">
1535
+ <div
1536
+ #annotation
1537
+ ngtsHTMLContent
1538
+ style="display: none; background: #151520; color: white; padding: 6px 8px; border-radius: 7px; white-space: nowrap"
1539
+ [class]="pivotControls.annotationsClass()"
1540
+ ></div>
1541
+ </ngts-html>
1542
+ }
1543
+ <ngt-group [position]="[pos1() * 1.7, pos1() * 1.7, 0]">
1544
+ <ngt-mesh
1545
+ [visible]="true"
1546
+ [scale]="length()"
1547
+ [userData]="pivotControls.userData()"
1548
+ (pointerdown)="onPointerDown($any($event))"
1549
+ (pointermove)="onPointerMove($any($event))"
1550
+ (pointerup)="onPointerUp($any($event))"
1551
+ (pointerout)="onPointerOut($any($event))"
1552
+ >
1553
+ <ngt-plane-geometry />
1554
+ <ngt-mesh-basic-material
1555
+ [transparent]="true"
1556
+ [depthTest]="pivotControls.depthTest()"
1557
+ [color]="color()"
1558
+ [polygonOffset]="true"
1559
+ [polygonOffsetFactor]="-10"
1560
+ [side]="DoubleSide"
1561
+ [fog]="false"
1562
+ />
1563
+ </ngt-mesh>
1564
+ <ngts-line
1565
+ [points]="points()"
1566
+ [options]="{
1567
+ position: [-length() / 2, -length() / 2, 0],
1568
+ transparent: true,
1569
+ depthTest: pivotControls.depthTest(),
1570
+ lineWidth: pivotControls.lineWidth(),
1571
+ color: color(),
1572
+ opacity: pivotControls.opacity(),
1573
+ polygonOffset: true,
1574
+ polygonOffsetFactor: -10,
1575
+ userData: pivotControls.userData(),
1576
+ fog: false,
1577
+ }"
1578
+ />
1579
+ </ngt-group>
1580
+ </ngt-group>
1581
+ `,
1582
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
1583
+ changeDetection: ChangeDetectionStrategy.OnPush,
1584
+ imports: [NgtsHTML, NgtsHTMLContent, NgtsLine],
1585
+ }]
1586
+ }], ctorParameters: () => [] });
1587
+
1588
+ const vec1 = new Vector3();
1589
+ const vec2 = new Vector3();
1590
+ function calculateOffset(clickPoint, normal, rayStart, rayDir) {
1591
+ const e1 = normal.dot(normal);
1592
+ const e2 = normal.dot(clickPoint) - normal.dot(rayStart);
1593
+ const e3 = normal.dot(rayDir);
1594
+ if (e3 === 0) {
1595
+ return -e2 / e1;
1596
+ }
1597
+ vec1
1598
+ .copy(rayDir)
1599
+ .multiplyScalar(e1 / e3)
1600
+ .sub(normal);
1601
+ vec2
1602
+ .copy(rayDir)
1603
+ .multiplyScalar(e2 / e3)
1604
+ .add(rayStart)
1605
+ .sub(clickPoint);
1606
+ return -vec1.dot(vec2) / vec1.dot(vec1);
1607
+ }
1608
+ const upV = new Vector3(0, 1, 0);
1609
+ const scaleV = new Vector3();
1610
+ const scaleMatrix = new Matrix4();
1611
+ class NgtsScalingSphere {
1612
+ constructor() {
1613
+ this.direction = input.required();
1614
+ this.axis = input.required();
1615
+ this.groupRef = viewChild.required('group');
1616
+ this.annotationRef = viewChild('annotation', { read: ElementRef });
1617
+ this.meshRef = viewChild.required('mesh');
1618
+ this.pivotControls = inject(NgtsPivotControls);
1619
+ this.store = injectStore();
1620
+ this.controls = this.store.select('controls');
1621
+ this.size = this.store.select('size');
1622
+ this.hovered = signal(false);
1623
+ this.scale0 = 1;
1624
+ this.scaleCurrent = 1;
1625
+ this.clickInfo = null;
1626
+ this.position = computed(() => (this.pivotControls.fixed() ? 1.2 : 1.2 * this.pivotControls.scale()));
1627
+ this.radius = computed(() => this.pivotControls.fixed()
1628
+ ? (this.pivotControls.lineWidth() / this.pivotControls.scale()) * 1.8
1629
+ : this.pivotControls.scale() / 22.5);
1630
+ this.matrixL = computed(() => {
1631
+ const quaternion = new Quaternion().setFromUnitVectors(upV, this.direction().clone().normalize());
1632
+ return new Matrix4().makeRotationFromQuaternion(quaternion);
1633
+ });
1634
+ this.color = computed(() => this.hovered() ? this.pivotControls.hoveredColor() : this.pivotControls.axisColors()[this.axis()]);
1635
+ extend({ Group, Mesh, SphereGeometry, MeshBasicMaterial });
1636
+ }
1637
+ onPointerDown(event) {
1638
+ const [annotation, controls, fixed, scale, direction, axis, size, group] = [
1639
+ this.annotationRef()?.nativeElement,
1640
+ this.controls(),
1641
+ this.pivotControls.fixed(),
1642
+ this.pivotControls.scale(),
1643
+ this.direction(),
1644
+ this.axis(),
1645
+ this.size(),
1646
+ this.groupRef().nativeElement,
1647
+ ];
1648
+ if (annotation) {
1649
+ annotation.innerText = `${scale.toFixed(2)}`;
1650
+ annotation.style.display = 'block';
1651
+ }
1652
+ event.stopPropagation();
1653
+ const rotation = new Matrix4().extractRotation(group.matrixWorld);
1654
+ const clickPoint = event.point.clone();
1655
+ const origin = new Vector3().setFromMatrixPosition(group.matrixWorld);
1656
+ const dir = direction.clone().applyMatrix4(rotation).normalize();
1657
+ const mPLG = group.matrixWorld.clone();
1658
+ const mPLGInv = mPLG.clone().invert();
1659
+ const offsetMultiplier = fixed
1660
+ ? 1 / calculateScaleFactor(group.getWorldPosition(vec1), scale, event.camera, size)
1661
+ : 1;
1662
+ this.clickInfo = { clickPoint, dir, mPLG, mPLGInv, offsetMultiplier };
1663
+ this.pivotControls.onDragStart({ component: 'Sphere', axis, origin, directions: [dir] });
1664
+ if (controls) {
1665
+ controls.enabled = false;
1666
+ }
1667
+ // @ts-expect-error - setPointerCapture is not in the type definition
1668
+ event.target.setPointerCapture(event.pointerId);
1669
+ }
1670
+ onPointerMove(event) {
1671
+ event.stopPropagation();
1672
+ if (!this.hovered())
1673
+ this.hovered.set(true);
1674
+ if (this.clickInfo) {
1675
+ const { clickPoint, dir, mPLG, mPLGInv, offsetMultiplier } = this.clickInfo;
1676
+ const [scaleLimits, axis, position, annotation, fixed, scale, mesh] = [
1677
+ this.pivotControls.scaleLimits(),
1678
+ this.axis(),
1679
+ this.position(),
1680
+ this.annotationRef()?.nativeElement,
1681
+ this.pivotControls.fixed(),
1682
+ this.pivotControls.scale(),
1683
+ this.meshRef().nativeElement,
1684
+ ];
1685
+ const [min, max] = scaleLimits?.[axis] || [1e-5, undefined]; // always limit the minimal value, since setting it very low might break the transform
1686
+ const offsetW = calculateOffset(clickPoint, dir, event.ray.origin, event.ray.direction);
1687
+ const offsetL = offsetW * offsetMultiplier;
1688
+ const offsetH = fixed ? offsetL : offsetL / scale;
1689
+ let upscale = Math.pow(2, offsetH * 0.2);
1690
+ if (event.shiftKey) {
1691
+ upscale = Math.round(upscale * 10) / 10;
1692
+ }
1693
+ upscale = Math.max(upscale, min / this.scale0);
1694
+ if (max !== undefined) {
1695
+ upscale = Math.min(upscale, max / this.scale0);
1696
+ }
1697
+ this.scaleCurrent = this.scale0 * upscale;
1698
+ mesh.position.set(0, position + offsetL, 0);
1699
+ if (annotation) {
1700
+ annotation.innerText = `${this.scaleCurrent.toFixed(2)}`;
1701
+ }
1702
+ scaleV.set(1, 1, 1);
1703
+ scaleV.setComponent(axis, upscale);
1704
+ scaleMatrix.makeScale(scaleV.x, scaleV.y, scaleV.z).premultiply(mPLG).multiply(mPLGInv);
1705
+ this.pivotControls.onDrag(scaleMatrix);
1706
+ }
1707
+ }
1708
+ onPointerUp(event) {
1709
+ const [annotation, controls, position, mesh] = [
1710
+ this.annotationRef()?.nativeElement,
1711
+ this.controls(),
1712
+ this.position(),
1713
+ this.meshRef().nativeElement,
1714
+ ];
1715
+ if (annotation) {
1716
+ annotation.style.display = 'none';
1717
+ }
1718
+ event.stopPropagation();
1719
+ this.scale0 = this.scaleCurrent;
1720
+ this.clickInfo = null;
1721
+ mesh.position.set(0, position, 0);
1722
+ this.pivotControls.onDragEnd();
1723
+ if (controls) {
1724
+ controls.enabled = true;
1725
+ }
1726
+ // @ts-expect-error - releasePointerCapture is not in the type definition
1727
+ event.target.releasePointerCapture(event.pointerId);
1728
+ }
1729
+ onPointerOut(event) {
1730
+ event.stopPropagation();
1731
+ this.hovered.set(false);
1732
+ }
1733
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsScalingSphere, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1734
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.4", type: NgtsScalingSphere, isStandalone: true, selector: "ngts-scaling-sphere", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: true, transformFunction: null }, axis: { classPropertyName: "axis", publicName: "axis", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "groupRef", first: true, predicate: ["group"], descendants: true, isSignal: true }, { propertyName: "annotationRef", first: true, predicate: ["annotation"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "meshRef", first: true, predicate: ["mesh"], descendants: true, isSignal: true }], ngImport: i0, template: `
1735
+ <ngt-group #group>
1736
+ <ngt-group
1737
+ [matrix]="matrixL()"
1738
+ [matrixAutoUpdate]="false"
1739
+ (pointerdown)="onPointerDown($any($event))"
1740
+ (pointermove)="onPointerMove($any($event))"
1741
+ (pointerup)="onPointerUp($any($event))"
1742
+ (pointerout)="onPointerOut($any($event))"
1743
+ >
1744
+ @if (pivotControls.annotations()) {
1745
+ <ngts-html [options]="{ position: [0, position() / 2, 0] }">
1746
+ <div
1747
+ #annotation
1748
+ ngtsHTMLContent
1749
+ style="display: none; background: #151520; color: white; padding: 6px 8px; border-radius: 7px; white-space: nowrap;"
1750
+ [class]="pivotControls.annotationsClass()"
1751
+ ></div>
1752
+ </ngts-html>
1753
+ }
1754
+ <ngt-mesh #mesh [position]="[0, position(), 0]" [renderOrder]="500" [userData]="pivotControls.userData()">
1755
+ <ngt-sphere-geometry *args="[radius(), 12, 12]" />
1756
+ <ngt-mesh-basic-material
1757
+ [transparent]="true"
1758
+ [depthTest]="pivotControls.depthTest()"
1759
+ [color]="color()"
1760
+ [opacity]="pivotControls.opacity()"
1761
+ [polygonOffset]="true"
1762
+ [polygonOffsetFactor]="-10"
1763
+ />
1764
+ </ngt-mesh>
1765
+ </ngt-group>
1766
+ </ngt-group>
1767
+ `, isInline: true, dependencies: [{ kind: "component", type: NgtsHTML, selector: "ngts-html", inputs: ["options"] }, { kind: "component", type: NgtsHTMLContent, selector: "[ngtsHTMLContent]", inputs: ["ngtsHTMLContent"], outputs: ["occluded"] }, { kind: "directive", type: NgtArgs, selector: "ng-template[args]", inputs: ["args"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1768
+ }
1769
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsScalingSphere, decorators: [{
1770
+ type: Component,
1771
+ args: [{
1772
+ selector: 'ngts-scaling-sphere',
1773
+ standalone: true,
1774
+ template: `
1775
+ <ngt-group #group>
1776
+ <ngt-group
1777
+ [matrix]="matrixL()"
1778
+ [matrixAutoUpdate]="false"
1779
+ (pointerdown)="onPointerDown($any($event))"
1780
+ (pointermove)="onPointerMove($any($event))"
1781
+ (pointerup)="onPointerUp($any($event))"
1782
+ (pointerout)="onPointerOut($any($event))"
1783
+ >
1784
+ @if (pivotControls.annotations()) {
1785
+ <ngts-html [options]="{ position: [0, position() / 2, 0] }">
1786
+ <div
1787
+ #annotation
1788
+ ngtsHTMLContent
1789
+ style="display: none; background: #151520; color: white; padding: 6px 8px; border-radius: 7px; white-space: nowrap;"
1790
+ [class]="pivotControls.annotationsClass()"
1791
+ ></div>
1792
+ </ngts-html>
1793
+ }
1794
+ <ngt-mesh #mesh [position]="[0, position(), 0]" [renderOrder]="500" [userData]="pivotControls.userData()">
1795
+ <ngt-sphere-geometry *args="[radius(), 12, 12]" />
1796
+ <ngt-mesh-basic-material
1797
+ [transparent]="true"
1798
+ [depthTest]="pivotControls.depthTest()"
1799
+ [color]="color()"
1800
+ [opacity]="pivotControls.opacity()"
1801
+ [polygonOffset]="true"
1802
+ [polygonOffsetFactor]="-10"
1803
+ />
1804
+ </ngt-mesh>
1805
+ </ngt-group>
1806
+ </ngt-group>
1807
+ `,
1808
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
1809
+ changeDetection: ChangeDetectionStrategy.OnPush,
1810
+ imports: [NgtsHTML, NgtsHTMLContent, NgtArgs],
1811
+ }]
1812
+ }], ctorParameters: () => [] });
1813
+
1814
+ const mL0 = new Matrix4();
1815
+ const mW0 = new Matrix4();
1816
+ const mP = new Matrix4();
1817
+ const mPInv = new Matrix4();
1818
+ const mW = new Matrix4();
1819
+ const mL = new Matrix4();
1820
+ const mL0Inv = new Matrix4();
1821
+ const mdL = new Matrix4();
1822
+ const mG = new Matrix4();
1823
+ const bb = new Box3();
1824
+ const bbObj = new Box3();
1825
+ const vCenter = new Vector3();
1826
+ const vSize = new Vector3();
1827
+ const vAnchorOffset = new Vector3();
1828
+ const vPosition = new Vector3();
1829
+ const vScale = new Vector3();
1830
+ const xDir = new Vector3(1, 0, 0);
1831
+ const yDir = new Vector3(0, 1, 0);
1832
+ const zDir = new Vector3(0, 0, 1);
1833
+ const defaultOptions = {
1834
+ enabled: true,
1835
+ autoTransform: true,
1836
+ disableAxes: false,
1837
+ disableSliders: false,
1838
+ disableRotations: false,
1839
+ disableScaling: false,
1840
+ activeAxes: [true, true, true],
1841
+ offset: [0, 0, 0],
1842
+ rotation: [0, 0, 0],
1843
+ scale: 1,
1844
+ lineWidth: 4,
1845
+ fixed: false,
1846
+ depthTest: true,
1847
+ axisColors: ['#ff2060', '#20df80', '#2080ff'],
1848
+ hoveredColor: '#ffff40',
1849
+ annotations: false,
1850
+ opacity: 1,
1851
+ visible: true,
1852
+ };
1853
+ // TODO: PivotControls is not working properly with control flow
1854
+ class NgtsPivotControls {
1855
+ constructor() {
1856
+ this.options = input(defaultOptions, { transform: mergeInputs(defaultOptions) });
1857
+ this.parameters = omit(this.options, [
1858
+ 'enabled',
1859
+ 'matrix',
1860
+ 'autoTransform',
1861
+ 'anchor',
1862
+ 'disableAxes',
1863
+ 'disableSliders',
1864
+ 'disableRotations',
1865
+ 'disableScaling',
1866
+ 'activeAxes',
1867
+ 'offset',
1868
+ 'rotation',
1869
+ 'scale',
1870
+ 'lineWidth',
1871
+ 'fixed',
1872
+ 'translationLimits',
1873
+ 'rotationLimits',
1874
+ 'scaleLimits',
1875
+ 'depthTest',
1876
+ 'axisColors',
1877
+ 'hoveredColor',
1878
+ 'annotations',
1879
+ 'annotationsClass',
1880
+ 'opacity',
1881
+ 'visible',
1882
+ 'userData',
1883
+ ]);
1884
+ this.dragStarted = output();
1885
+ this.dragEnded = output();
1886
+ this.dragged = output();
1887
+ this.matrix = pick(this.options, 'matrix');
1888
+ this.annotations = pick(this.options, 'annotations');
1889
+ this.annotationsClass = pick(this.options, 'annotationsClass');
1890
+ this.translationLimits = pick(this.options, 'translationLimits');
1891
+ this.rotationLimits = pick(this.options, 'rotationLimits');
1892
+ this.scaleLimits = pick(this.options, 'scaleLimits');
1893
+ this.autoTransform = pick(this.options, 'autoTransform');
1894
+ this.fixed = pick(this.options, 'fixed');
1895
+ this.hoveredColor = pick(this.options, 'hoveredColor');
1896
+ this.axisColors = pick(this.options, 'axisColors');
1897
+ this.lineWidth = pick(this.options, 'lineWidth');
1898
+ this.scale = pick(this.options, 'scale');
1899
+ this.userData = pick(this.options, 'userData');
1900
+ this.opacity = pick(this.options, 'opacity');
1901
+ this.depthTest = pick(this.options, 'depthTest');
1902
+ this.offset = pick(this.options, 'offset');
1903
+ this.rotation = pick(this.options, 'rotation');
1904
+ this.visible = pick(this.options, 'visible');
1905
+ this.enabled = pick(this.options, 'enabled');
1906
+ this.disableAxes = pick(this.options, 'disableAxes');
1907
+ this.disableSliders = pick(this.options, 'disableSliders');
1908
+ this.disableRotations = pick(this.options, 'disableRotations');
1909
+ this.disableScaling = pick(this.options, 'disableScaling');
1910
+ this.activeAxes = pick(this.options, 'activeAxes');
1911
+ this.xDir = xDir;
1912
+ this.yDir = yDir;
1913
+ this.zDir = zDir;
1914
+ this.parentRef = viewChild.required('parent');
1915
+ this.groupRef = viewChild.required('group');
1916
+ this.gizmoRef = viewChild.required('gizmo');
1917
+ this.childrenRef = viewChild.required('children');
1918
+ this.store = injectStore();
1919
+ this.invalidate = this.store.select('invalidate');
1920
+ this.translation = [0, 0, 0];
1921
+ this.anchor = pick(this.options, 'anchor');
1922
+ this.cameraScale = new Vector3(1, 1, 1);
1923
+ this.gizmoScale = new Vector3(1, 1, 1);
1924
+ extend({ Group });
1925
+ effect(() => {
1926
+ const anchor = this.anchor();
1927
+ if (!anchor)
1928
+ return;
1929
+ const childrenContainer = this.childrenRef().nativeElement;
1930
+ const localState = getLocalState(childrenContainer);
1931
+ if (!localState)
1932
+ return;
1933
+ const [gizmo, offset, invalidate] = [
1934
+ this.gizmoRef().nativeElement,
1935
+ this.offset(),
1936
+ this.invalidate(),
1937
+ this.options(),
1938
+ [localState.objects(), localState.nonObjects()],
1939
+ ];
1940
+ childrenContainer.updateWorldMatrix(true, true);
1941
+ mPInv.copy(childrenContainer.matrixWorld).invert();
1942
+ bb.makeEmpty();
1943
+ childrenContainer.traverse((obj) => {
1944
+ if (!obj.geometry)
1945
+ return;
1946
+ if (!obj.geometry.boundingBox)
1947
+ obj.geometry.computeBoundingBox();
1948
+ mL.copy(obj.matrixWorld).premultiply(mPInv);
1949
+ const boundingBox = obj.geometry.boundingBox;
1950
+ if (boundingBox) {
1951
+ bbObj.copy(boundingBox);
1952
+ bbObj.applyMatrix4(mL);
1953
+ bb.union(bbObj);
1954
+ }
1955
+ });
1956
+ vCenter.copy(bb.max).add(bb.min).multiplyScalar(0.5);
1957
+ vSize.copy(bb.max).sub(bb.min).multiplyScalar(0.5);
1958
+ vAnchorOffset
1959
+ .copy(vSize)
1960
+ .multiply(new Vector3(...anchor))
1961
+ .add(vCenter);
1962
+ vPosition.set(...offset).add(vAnchorOffset);
1963
+ gizmo.position.copy(vPosition);
1964
+ invalidate();
1965
+ });
1966
+ const vec = new Vector3();
1967
+ injectBeforeRender(({ camera, size, invalidate }) => {
1968
+ const [{ fixed, scale, matrix }, gizmo, group] = [
1969
+ this.options(),
1970
+ this.gizmoRef().nativeElement,
1971
+ this.groupRef().nativeElement,
1972
+ ];
1973
+ if (fixed) {
1974
+ const sf = calculateScaleFactor(gizmo.getWorldPosition(vec), scale, camera, size);
1975
+ this.cameraScale.setScalar(sf);
1976
+ }
1977
+ if (matrix && matrix instanceof Matrix4) {
1978
+ group.matrix = matrix;
1979
+ }
1980
+ // Update gizmo scale in accordance with matrix changes
1981
+ // Without this, there might be noticeable turbulence if scaling happens fast enough
1982
+ gizmo.updateWorldMatrix(true, true);
1983
+ mG.makeRotationFromEuler(gizmo.rotation).setPosition(gizmo.position).premultiply(group.matrixWorld);
1984
+ this.gizmoScale.setFromMatrixScale(mG);
1985
+ vScale.copy(this.cameraScale).divide(this.gizmoScale);
1986
+ if (Math.abs(gizmo.scale.x - vScale.x) > 1e-4 ||
1987
+ Math.abs(gizmo.scale.y - vScale.y) > 1e-4 ||
1988
+ Math.abs(gizmo.scale.z - vScale.z) > 1e-4) {
1989
+ gizmo.scale.copy(vScale);
1990
+ invalidate();
1991
+ }
1992
+ });
1993
+ }
1994
+ onDragStart(parameters) {
1995
+ const group = this.groupRef().nativeElement;
1996
+ mL0.copy(group.matrix);
1997
+ mW0.copy(group.matrixWorld);
1998
+ this.dragStarted.emit(parameters);
1999
+ this.store.snapshot.invalidate();
2000
+ }
2001
+ onDrag(mdW) {
2002
+ const [parent, group, autoTransform] = [
2003
+ this.parentRef().nativeElement,
2004
+ this.groupRef().nativeElement,
2005
+ this.autoTransform(),
2006
+ ];
2007
+ mP.copy(parent.matrixWorld);
2008
+ mPInv.copy(mP).invert();
2009
+ // After applying the delta
2010
+ mW.copy(mW0).premultiply(mdW);
2011
+ mL.copy(mW).premultiply(mPInv);
2012
+ mL0Inv.copy(mL0).invert();
2013
+ mdL.copy(mL).multiply(mL0Inv);
2014
+ if (autoTransform) {
2015
+ group.matrix.copy(mL);
2016
+ }
2017
+ this.dragged.emit({ l: mL, deltaL: mdL, w: mW, deltaW: mdW });
2018
+ this.store.snapshot.invalidate();
2019
+ }
2020
+ onDragEnd() {
2021
+ this.dragEnded.emit();
2022
+ this.store.snapshot.invalidate();
2023
+ }
2024
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsPivotControls, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2025
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.4", type: NgtsPivotControls, isStandalone: true, selector: "ngts-pivot-controls", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dragStarted: "dragStarted", dragEnded: "dragEnded", dragged: "dragged" }, viewQueries: [{ propertyName: "parentRef", first: true, predicate: ["parent"], descendants: true, isSignal: true }, { propertyName: "groupRef", first: true, predicate: ["group"], descendants: true, isSignal: true }, { propertyName: "gizmoRef", first: true, predicate: ["gizmo"], descendants: true, isSignal: true }, { propertyName: "childrenRef", first: true, predicate: ["children"], descendants: true, isSignal: true }], ngImport: i0, template: `
2026
+ <ngt-group #parent>
2027
+ <ngt-group #group [matrix]="matrix()" [matrixAutoUpdate]="false" [parameters]="parameters()">
2028
+ <ngt-group #gizmo [visible]="visible()" [position]="offset()" [rotation]="rotation()">
2029
+ @if (enabled()) {
2030
+ @if (!disableAxes() && activeAxes()[0]) {
2031
+ <ngts-axis-arrow [axis]="0" [direction]="xDir" />
2032
+ }
2033
+ @if (!disableAxes() && activeAxes()[1]) {
2034
+ <ngts-axis-arrow [axis]="1" [direction]="yDir" />
2035
+ }
2036
+ @if (!disableAxes() && activeAxes()[2]) {
2037
+ <ngts-axis-arrow [axis]="2" [direction]="zDir" />
2038
+ }
2039
+
2040
+ @if (!disableSliders() && activeAxes()[0] && activeAxes()[1]) {
2041
+ <ngts-plane-slider [axis]="2" [dir1]="xDir" [dir2]="yDir" />
2042
+ }
2043
+ @if (!disableSliders() && activeAxes()[0] && activeAxes()[2]) {
2044
+ <ngts-plane-slider [axis]="1" [dir1]="zDir" [dir2]="xDir" />
2045
+ }
2046
+ @if (!disableSliders() && activeAxes()[2] && activeAxes()[1]) {
2047
+ <ngts-plane-slider [axis]="0" [dir1]="yDir" [dir2]="zDir" />
2048
+ }
2049
+
2050
+ @if (!disableRotations() && activeAxes()[0] && activeAxes()[1]) {
2051
+ <ngts-axis-rotator [axis]="2" [dir1]="xDir" [dir2]="yDir" />
2052
+ }
2053
+ @if (!disableRotations() && activeAxes()[0] && activeAxes()[2]) {
2054
+ <ngts-axis-rotator [axis]="1" [dir1]="zDir" [dir2]="xDir" />
2055
+ }
2056
+ @if (!disableRotations() && activeAxes()[2] && activeAxes()[1]) {
2057
+ <ngts-axis-rotator [axis]="0" [dir1]="yDir" [dir2]="zDir" />
2058
+ }
2059
+
2060
+ @if (!disableScaling() && activeAxes()[0]) {
2061
+ <ngts-scaling-sphere [axis]="0" [direction]="xDir" />
2062
+ }
2063
+ @if (!disableScaling() && activeAxes()[1]) {
2064
+ <ngts-scaling-sphere [axis]="1" [direction]="yDir" />
2065
+ }
2066
+ @if (!disableScaling() && activeAxes()[2]) {
2067
+ <ngts-scaling-sphere [axis]="2" [direction]="zDir" />
2068
+ }
2069
+ }
2070
+ </ngt-group>
2071
+ <ngt-group #children>
2072
+ <ng-content />
2073
+ </ngt-group>
2074
+ </ngt-group>
2075
+ </ngt-group>
2076
+ `, isInline: true, dependencies: [{ kind: "component", type: NgtsAxisArrow, selector: "ngts-axis-arrow", inputs: ["direction", "axis"] }, { kind: "component", type: NgtsPlaneSlider, selector: "ngts-plane-slider", inputs: ["dir1", "dir2", "axis"] }, { kind: "component", type: NgtsAxisRotator, selector: "ngts-axis-rotator", inputs: ["dir1", "dir2", "axis"] }, { kind: "component", type: NgtsScalingSphere, selector: "ngts-scaling-sphere", inputs: ["direction", "axis"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2077
+ }
2078
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsPivotControls, decorators: [{
2079
+ type: Component,
2080
+ args: [{
2081
+ selector: 'ngts-pivot-controls',
2082
+ standalone: true,
2083
+ template: `
2084
+ <ngt-group #parent>
2085
+ <ngt-group #group [matrix]="matrix()" [matrixAutoUpdate]="false" [parameters]="parameters()">
2086
+ <ngt-group #gizmo [visible]="visible()" [position]="offset()" [rotation]="rotation()">
2087
+ @if (enabled()) {
2088
+ @if (!disableAxes() && activeAxes()[0]) {
2089
+ <ngts-axis-arrow [axis]="0" [direction]="xDir" />
2090
+ }
2091
+ @if (!disableAxes() && activeAxes()[1]) {
2092
+ <ngts-axis-arrow [axis]="1" [direction]="yDir" />
2093
+ }
2094
+ @if (!disableAxes() && activeAxes()[2]) {
2095
+ <ngts-axis-arrow [axis]="2" [direction]="zDir" />
2096
+ }
2097
+
2098
+ @if (!disableSliders() && activeAxes()[0] && activeAxes()[1]) {
2099
+ <ngts-plane-slider [axis]="2" [dir1]="xDir" [dir2]="yDir" />
2100
+ }
2101
+ @if (!disableSliders() && activeAxes()[0] && activeAxes()[2]) {
2102
+ <ngts-plane-slider [axis]="1" [dir1]="zDir" [dir2]="xDir" />
2103
+ }
2104
+ @if (!disableSliders() && activeAxes()[2] && activeAxes()[1]) {
2105
+ <ngts-plane-slider [axis]="0" [dir1]="yDir" [dir2]="zDir" />
2106
+ }
2107
+
2108
+ @if (!disableRotations() && activeAxes()[0] && activeAxes()[1]) {
2109
+ <ngts-axis-rotator [axis]="2" [dir1]="xDir" [dir2]="yDir" />
2110
+ }
2111
+ @if (!disableRotations() && activeAxes()[0] && activeAxes()[2]) {
2112
+ <ngts-axis-rotator [axis]="1" [dir1]="zDir" [dir2]="xDir" />
2113
+ }
2114
+ @if (!disableRotations() && activeAxes()[2] && activeAxes()[1]) {
2115
+ <ngts-axis-rotator [axis]="0" [dir1]="yDir" [dir2]="zDir" />
2116
+ }
2117
+
2118
+ @if (!disableScaling() && activeAxes()[0]) {
2119
+ <ngts-scaling-sphere [axis]="0" [direction]="xDir" />
2120
+ }
2121
+ @if (!disableScaling() && activeAxes()[1]) {
2122
+ <ngts-scaling-sphere [axis]="1" [direction]="yDir" />
2123
+ }
2124
+ @if (!disableScaling() && activeAxes()[2]) {
2125
+ <ngts-scaling-sphere [axis]="2" [direction]="zDir" />
2126
+ }
2127
+ }
2128
+ </ngt-group>
2129
+ <ngt-group #children>
2130
+ <ng-content />
2131
+ </ngt-group>
2132
+ </ngt-group>
2133
+ </ngt-group>
2134
+ `,
2135
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
2136
+ changeDetection: ChangeDetectionStrategy.OnPush,
2137
+ imports: [NgtsAxisArrow, NgtsPlaneSlider, NgtsAxisRotator, NgtsScalingSphere],
2138
+ }]
2139
+ }], ctorParameters: () => [] });
2140
+
2141
+ class NgtsTransformControls {
2142
+ constructor() {
2143
+ this.object = input(null);
2144
+ this.options = input({});
2145
+ this.parameters = omit(this.options, [
2146
+ 'enabled',
2147
+ 'axis',
2148
+ 'mode',
2149
+ 'translationSnap',
2150
+ 'rotationSnap',
2151
+ 'scaleSnap',
2152
+ 'space',
2153
+ 'size',
2154
+ 'showX',
2155
+ 'showY',
2156
+ 'showZ',
2157
+ 'domElement',
2158
+ 'makeDefault',
2159
+ 'camera',
2160
+ ]);
2161
+ this.controlsOptions = pick(this.options, [
2162
+ 'enabled',
2163
+ 'axis',
2164
+ 'mode',
2165
+ 'translationSnap',
2166
+ 'rotationSnap',
2167
+ 'scaleSnap',
2168
+ 'space',
2169
+ 'size',
2170
+ 'showX',
2171
+ 'showY',
2172
+ 'showZ',
2173
+ ]);
2174
+ this.camera = pick(this.options, 'camera');
2175
+ this.domElement = pick(this.options, 'domElement');
2176
+ this.makeDefault = pick(this.options, 'makeDefault');
2177
+ this.change = output();
2178
+ this.mouseDown = output();
2179
+ this.mouseUp = output();
2180
+ this.objectChange = output();
2181
+ this.groupRef = viewChild.required('group');
2182
+ this.store = injectStore();
2183
+ this.glDomElement = this.store.select('gl', 'domElement');
2184
+ this.defaultCamera = this.store.select('camera');
2185
+ this.events = this.store.select('events');
2186
+ this.defaultControls = this.store.select('controls');
2187
+ this.invalidate = this.store.select('invalidate');
2188
+ this.controls = computed(() => {
2189
+ let camera = this.camera();
2190
+ if (!camera) {
2191
+ camera = this.defaultCamera();
2192
+ }
2193
+ let domElement = this.domElement();
2194
+ if (!domElement) {
2195
+ domElement = this.events().connected || this.glDomElement();
2196
+ }
2197
+ return new TransformControls(camera, domElement);
2198
+ });
2199
+ extend({ Group });
2200
+ effect((onCleanup) => {
2201
+ const cleanup = this.attachControlsEffect();
2202
+ onCleanup(() => cleanup?.());
2203
+ });
2204
+ effect((onCleanup) => {
2205
+ const cleanup = this.disableDefaultControlsEffect();
2206
+ onCleanup(() => cleanup?.());
2207
+ });
2208
+ effect((onCleanup) => {
2209
+ const cleanup = this.setupControlsEventsEffect();
2210
+ onCleanup(() => cleanup?.());
2211
+ });
2212
+ effect((onCleanup) => {
2213
+ const cleanup = this.updateDefaultControlsEffect();
2214
+ onCleanup(() => cleanup?.());
2215
+ });
2216
+ }
2217
+ attachControlsEffect() {
2218
+ const group = this.groupRef().nativeElement;
2219
+ if (!group)
2220
+ return;
2221
+ const localState = getLocalState(group);
2222
+ if (!localState)
2223
+ return;
2224
+ const [object, controls] = [resolveRef(this.object()), this.controls(), localState.objects()];
2225
+ if (object) {
2226
+ controls.attach(object);
2227
+ }
2228
+ else {
2229
+ controls.attach(group);
2230
+ }
2231
+ return () => controls.detach();
2232
+ }
2233
+ disableDefaultControlsEffect() {
2234
+ const defaultControls = this.defaultControls();
2235
+ if (!defaultControls)
2236
+ return;
2237
+ const controls = this.controls();
2238
+ const callback = (event) => {
2239
+ defaultControls.enabled = !event.value;
2240
+ };
2241
+ // @ts-expect-error - three-stdlib types are not up-to-date
2242
+ controls.addEventListener('dragging-changed', callback);
2243
+ return () => {
2244
+ // @ts-expect-error - three-stdlib types are not up-to-date
2245
+ controls.removeEventListener('dragging-changed', callback);
2246
+ };
2247
+ }
2248
+ setupControlsEventsEffect() {
2249
+ const [controls, invalidate] = [this.controls(), this.invalidate()];
2250
+ const onChange = (event) => {
2251
+ invalidate();
2252
+ if (!this.change['destroyed']) {
2253
+ this.change.emit(event);
2254
+ }
2255
+ };
2256
+ const onMouseDown = this.mouseDown.emit.bind(this.mouseDown);
2257
+ const onMouseUp = this.mouseUp.emit.bind(this.mouseUp);
2258
+ const onObjectChange = this.objectChange.emit.bind(this.objectChange);
2259
+ // @ts-expect-error - three-stdlib types are not up-to-date
2260
+ controls.addEventListener('change', onChange);
2261
+ // @ts-expect-error - three-stdlib types are not up-to-date
2262
+ controls.addEventListener('mouseDown', onMouseDown);
2263
+ // @ts-expect-error - three-stdlib types are not up-to-date
2264
+ controls.addEventListener('mouseUp', onMouseUp);
2265
+ // @ts-expect-error - three-stdlib types are not up-to-date
2266
+ controls.addEventListener('objectChange', onObjectChange);
2267
+ return () => {
2268
+ // @ts-expect-error - three-stdlib types are not up-to-date
2269
+ controls.removeEventListener('change', onChange);
2270
+ // @ts-expect-error - three-stdlib types are not up-to-date
2271
+ controls.removeEventListener('mouseDown', onMouseDown);
2272
+ // @ts-expect-error - three-stdlib types are not up-to-date
2273
+ controls.removeEventListener('mouseUp', onMouseUp);
2274
+ // @ts-expect-error - three-stdlib types are not up-to-date
2275
+ controls.removeEventListener('objectChange', onObjectChange);
2276
+ };
2277
+ }
2278
+ updateDefaultControlsEffect() {
2279
+ const [controls, makeDefault] = [this.controls(), this.makeDefault()];
2280
+ if (!makeDefault)
2281
+ return;
2282
+ const oldControls = this.store.snapshot.controls;
2283
+ this.store.update({ controls });
2284
+ return () => this.store.update(() => ({ controls: oldControls }));
2285
+ }
2286
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsTransformControls, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2287
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "18.2.4", type: NgtsTransformControls, isStandalone: true, selector: "ngts-transform-controls", inputs: { object: { classPropertyName: "object", publicName: "object", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { change: "change", mouseDown: "mouseDown", mouseUp: "mouseUp", objectChange: "objectChange" }, viewQueries: [{ propertyName: "groupRef", first: true, predicate: ["group"], descendants: true, isSignal: true }], ngImport: i0, template: `
2288
+ <ngt-primitive *args="[controls()]" [parameters]="controlsOptions()" />
2289
+
2290
+ <ngt-group #group [parameters]="parameters()">
2291
+ <ng-content />
2292
+ </ngt-group>
2293
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgtArgs, selector: "ng-template[args]", inputs: ["args"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2294
+ }
2295
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.4", ngImport: i0, type: NgtsTransformControls, decorators: [{
2296
+ type: Component,
2297
+ args: [{
2298
+ selector: 'ngts-transform-controls',
2299
+ standalone: true,
2300
+ template: `
2301
+ <ngt-primitive *args="[controls()]" [parameters]="controlsOptions()" />
2302
+
2303
+ <ngt-group #group [parameters]="parameters()">
2304
+ <ng-content />
2305
+ </ngt-group>
2306
+ `,
2307
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
2308
+ changeDetection: ChangeDetectionStrategy.OnPush,
2309
+ imports: [NgtArgs],
2310
+ }]
2311
+ }], ctorParameters: () => [] });
2312
+
2313
+ /**
2314
+ * Generated bundle index. Do not edit.
2315
+ */
2316
+
2317
+ export { NgtsGizmoHelper, NgtsGizmoHelperContent, NgtsGizmoViewcube, NgtsGizmoViewport, NgtsPivotControls, NgtsTransformControls };
2318
+ //# sourceMappingURL=angular-three-soba-gizmos.mjs.map