angular-three-soba 2.0.0 → 2.2.0

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