@aura3d/controls 1.3.3 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/package.json +35 -3
- package/src/ControlState.ts +0 -24
- package/src/DragControls.ts +0 -17
- package/src/FirstPersonControls.ts +0 -8
- package/src/FlyControls.ts +0 -14
- package/src/InteractionControls.ts +0 -224
- package/src/MapControls.ts +0 -10
- package/src/NativeControlTypes.ts +0 -93
- package/src/OrbitControls.ts +0 -25
- package/src/Picking.ts +0 -234
- package/src/PickingAnnotations.ts +0 -391
- package/src/PointerLockControls.ts +0 -15
- package/src/SelectionManager.ts +0 -18
- package/src/TrackballControls.ts +0 -116
- package/src/TransformControls.ts +0 -19
- package/src/index.ts +0 -58
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @aura3d/controls
|
|
2
|
+
|
|
3
|
+
`@aura3d/controls` owns camera controls, transform controls, picking,
|
|
4
|
+
selection, annotations, hotspots, and interaction helpers for Aura3D and
|
|
5
|
+
Three.js-compatibility workflows.
|
|
6
|
+
|
|
7
|
+
## Public API
|
|
8
|
+
|
|
9
|
+
- `OrbitControls`, `TrackballControls`, `FlyControls`, `FirstPersonControls`,
|
|
10
|
+
`MapControls`, and `PointerLockControls`: camera/navigation controls.
|
|
11
|
+
- `DragControls`, `TransformControls`: object manipulation controls.
|
|
12
|
+
- `SelectionManager`: selection ownership for interactive scenes.
|
|
13
|
+
- `InteractionControls`: interaction modes, rays, listeners, and hotspot
|
|
14
|
+
handling.
|
|
15
|
+
- `Picking`: picking reports and diagnostics.
|
|
16
|
+
- Picking annotation helpers such as `createRobotPickingAnnotations`,
|
|
17
|
+
`createDistrictPickingAnnotations`, `pickAnnotation`, and
|
|
18
|
+
`pickScreenSpaceAnnotation`.
|
|
19
|
+
- Shared control state and native control type helpers.
|
|
20
|
+
|
|
21
|
+
## Package Boundary
|
|
22
|
+
|
|
23
|
+
This package provides control and picking primitives. It does not claim that a
|
|
24
|
+
public root `createAuraApp` route has a particular interaction unless that route
|
|
25
|
+
imports the controls or root interaction helpers and verifies the behavior in a
|
|
26
|
+
browser test.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aura3d/controls",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -11,6 +11,38 @@
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@aura3d/input": "1.
|
|
15
|
-
}
|
|
14
|
+
"@aura3d/input": "1.4.1"
|
|
15
|
+
},
|
|
16
|
+
"description": "Orbit, trackball, fly, first-person, map, pointer-lock, drag, transform, picking, hotspot, and selection controls for Aura3D.",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"aura3d",
|
|
19
|
+
"3d",
|
|
20
|
+
"browser-3d",
|
|
21
|
+
"web-3d",
|
|
22
|
+
"typescript",
|
|
23
|
+
"controls",
|
|
24
|
+
"orbit-controls",
|
|
25
|
+
"camera-controls",
|
|
26
|
+
"transform-controls",
|
|
27
|
+
"picking",
|
|
28
|
+
"hotspots",
|
|
29
|
+
"interaction"
|
|
30
|
+
],
|
|
31
|
+
"homepage": "https://aura3d.auraone.ai",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/auraoneai/aura3d.git",
|
|
35
|
+
"directory": "packages/controls"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/auraoneai/aura3d/issues"
|
|
39
|
+
},
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"README.md",
|
|
46
|
+
"dist"
|
|
47
|
+
]
|
|
16
48
|
}
|
package/src/ControlState.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { ControlVector3 } from "./NativeControlTypes";
|
|
2
|
-
|
|
3
|
-
export interface ThreeCompatControlEvent {
|
|
4
|
-
readonly type: string;
|
|
5
|
-
readonly delta?: ControlVector3;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface ThreeCompatControlState {
|
|
9
|
-
readonly target: ControlVector3;
|
|
10
|
-
readonly position: ControlVector3;
|
|
11
|
-
readonly rotation: ControlVector3;
|
|
12
|
-
readonly zoom: number;
|
|
13
|
-
readonly enabled: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function createDefaultControlState(): ThreeCompatControlState {
|
|
17
|
-
return {
|
|
18
|
-
target: new ControlVector3(),
|
|
19
|
-
position: new ControlVector3(0, 0, 5),
|
|
20
|
-
rotation: new ControlVector3(),
|
|
21
|
-
zoom: 1,
|
|
22
|
-
enabled: true
|
|
23
|
-
};
|
|
24
|
-
}
|
package/src/DragControls.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { addVector3, type ControlObject3DLike, type Vector3Like } from "./NativeControlTypes";
|
|
2
|
-
|
|
3
|
-
export class DragControls {
|
|
4
|
-
dragging: ControlObject3DLike | null = null;
|
|
5
|
-
|
|
6
|
-
start(object: ControlObject3DLike): void {
|
|
7
|
-
this.dragging = object;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
drag(delta: Vector3Like): void {
|
|
11
|
-
addVector3(this.dragging?.position, delta);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
end(): void {
|
|
15
|
-
this.dragging = null;
|
|
16
|
-
}
|
|
17
|
-
}
|
package/src/FlyControls.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { createDefaultControlState, type ThreeCompatControlState } from "./ControlState";
|
|
2
|
-
|
|
3
|
-
export class FlyControls {
|
|
4
|
-
readonly state: ThreeCompatControlState = createDefaultControlState();
|
|
5
|
-
movementSpeed = 1;
|
|
6
|
-
|
|
7
|
-
moveForward(distance: number): void {
|
|
8
|
-
this.state.position.z -= distance * this.movementSpeed;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
strafe(distance: number): void {
|
|
12
|
-
this.state.position.x += distance * this.movementSpeed;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
import { InputSnapshot } from "@aura3d/input";
|
|
2
|
-
import { FlyControls } from "./FlyControls";
|
|
3
|
-
import { OrbitControls } from "./OrbitControls";
|
|
4
|
-
import { Picking, type PickingOptions, type PickingReport, type ThreeCompatPickResult } from "./Picking";
|
|
5
|
-
import { ControlVector3, type ControlObject3DLike, type Vector3Like } from "./NativeControlTypes";
|
|
6
|
-
|
|
7
|
-
export type InteractionControlMode = "orbit" | "fly";
|
|
8
|
-
export type InteractionControlsEventType =
|
|
9
|
-
| "mode-change"
|
|
10
|
-
| "hover-enter"
|
|
11
|
-
| "hover-exit"
|
|
12
|
-
| "pick"
|
|
13
|
-
| "hotspot-click";
|
|
14
|
-
|
|
15
|
-
export interface InteractionRay {
|
|
16
|
-
readonly origin: Vector3Like;
|
|
17
|
-
readonly direction: Vector3Like;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export type InteractionRayProvider = (snapshot: InputSnapshot) => InteractionRay;
|
|
21
|
-
export type InteractionRootProvider = () => ControlObject3DLike | undefined;
|
|
22
|
-
export type InteractionControlsListener = (event: InteractionControlsEvent) => void;
|
|
23
|
-
export type HotspotHandler = (event: InteractionControlsEvent & { readonly hit: ThreeCompatPickResult }) => void;
|
|
24
|
-
|
|
25
|
-
export interface InteractionControlsOptions {
|
|
26
|
-
readonly mode?: InteractionControlMode;
|
|
27
|
-
readonly orbit?: OrbitControls;
|
|
28
|
-
readonly fly?: FlyControls;
|
|
29
|
-
readonly picking?: Picking;
|
|
30
|
-
readonly root?: ControlObject3DLike | InteractionRootProvider;
|
|
31
|
-
readonly rayProvider?: InteractionRayProvider;
|
|
32
|
-
readonly pickOptions?: PickingOptions;
|
|
33
|
-
readonly rotateButton?: number;
|
|
34
|
-
readonly panButton?: number;
|
|
35
|
-
readonly rotateSpeed?: number;
|
|
36
|
-
readonly panSpeed?: number;
|
|
37
|
-
readonly dollySpeed?: number;
|
|
38
|
-
readonly flyMoveSpeed?: number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface InteractionControlsEvent {
|
|
42
|
-
readonly type: InteractionControlsEventType;
|
|
43
|
-
readonly mode: InteractionControlMode;
|
|
44
|
-
readonly snapshot: InputSnapshot;
|
|
45
|
-
readonly hit?: ThreeCompatPickResult;
|
|
46
|
-
readonly previousHit?: ThreeCompatPickResult;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface InteractionControlsUpdate {
|
|
50
|
-
readonly mode: InteractionControlMode;
|
|
51
|
-
readonly pickReport?: PickingReport;
|
|
52
|
-
readonly hit: ThreeCompatPickResult | null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export class InteractionControls {
|
|
56
|
-
readonly orbit: OrbitControls;
|
|
57
|
-
readonly fly: FlyControls;
|
|
58
|
-
readonly picking: Picking;
|
|
59
|
-
|
|
60
|
-
enabled = true;
|
|
61
|
-
|
|
62
|
-
private controlMode: InteractionControlMode;
|
|
63
|
-
private rootRef?: ControlObject3DLike | InteractionRootProvider;
|
|
64
|
-
private rayProvider?: InteractionRayProvider;
|
|
65
|
-
private pickOptions: PickingOptions;
|
|
66
|
-
private readonly listeners = new Set<InteractionControlsListener>();
|
|
67
|
-
private readonly hotspotHandlers = new Map<string, Set<HotspotHandler>>();
|
|
68
|
-
private hoverHit: ThreeCompatPickResult | null = null;
|
|
69
|
-
private disposed = false;
|
|
70
|
-
|
|
71
|
-
private readonly rotateButton: number;
|
|
72
|
-
private readonly panButton: number;
|
|
73
|
-
private readonly rotateSpeed: number;
|
|
74
|
-
private readonly panSpeed: number;
|
|
75
|
-
private readonly dollySpeed: number;
|
|
76
|
-
private readonly flyMoveSpeed: number;
|
|
77
|
-
|
|
78
|
-
constructor(options: InteractionControlsOptions = {}) {
|
|
79
|
-
this.orbit = options.orbit ?? new OrbitControls();
|
|
80
|
-
this.fly = options.fly ?? new FlyControls();
|
|
81
|
-
this.picking = options.picking ?? new Picking();
|
|
82
|
-
this.controlMode = options.mode ?? "orbit";
|
|
83
|
-
this.rootRef = options.root;
|
|
84
|
-
this.rayProvider = options.rayProvider;
|
|
85
|
-
this.pickOptions = options.pickOptions ?? {};
|
|
86
|
-
this.rotateButton = options.rotateButton ?? 0;
|
|
87
|
-
this.panButton = options.panButton ?? 1;
|
|
88
|
-
this.rotateSpeed = options.rotateSpeed ?? 0.005;
|
|
89
|
-
this.panSpeed = options.panSpeed ?? 0.01;
|
|
90
|
-
this.dollySpeed = options.dollySpeed ?? 0.001;
|
|
91
|
-
this.flyMoveSpeed = options.flyMoveSpeed ?? 1;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
get mode(): InteractionControlMode {
|
|
95
|
-
return this.controlMode;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
setMode(mode: InteractionControlMode, snapshot = new InputSnapshot()): void {
|
|
99
|
-
if (this.controlMode === mode) return;
|
|
100
|
-
this.controlMode = mode;
|
|
101
|
-
this.emit({ type: "mode-change", mode, snapshot });
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
setRoot(root: ControlObject3DLike | InteractionRootProvider | undefined): void {
|
|
105
|
-
this.rootRef = root;
|
|
106
|
-
this.hoverHit = null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
setRayProvider(provider: InteractionRayProvider | undefined): void {
|
|
110
|
-
this.rayProvider = provider;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
setPickOptions(options: PickingOptions): void {
|
|
114
|
-
this.pickOptions = options;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
subscribe(listener: InteractionControlsListener): () => void {
|
|
118
|
-
this.listeners.add(listener);
|
|
119
|
-
return () => this.listeners.delete(listener);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
onHotspot(id: string, handler: HotspotHandler): () => void {
|
|
123
|
-
const handlers = this.hotspotHandlers.get(id) ?? new Set<HotspotHandler>();
|
|
124
|
-
handlers.add(handler);
|
|
125
|
-
this.hotspotHandlers.set(id, handlers);
|
|
126
|
-
return () => {
|
|
127
|
-
handlers.delete(handler);
|
|
128
|
-
if (handlers.size === 0) this.hotspotHandlers.delete(id);
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
update(snapshot: InputSnapshot): InteractionControlsUpdate {
|
|
133
|
-
if (this.disposed || !this.enabled) {
|
|
134
|
-
return { mode: this.controlMode, hit: this.hoverHit };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (this.controlMode === "orbit") {
|
|
138
|
-
this.updateOrbit(snapshot);
|
|
139
|
-
} else {
|
|
140
|
-
this.updateFly(snapshot);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const pickReport = this.updatePicking(snapshot);
|
|
144
|
-
return { mode: this.controlMode, pickReport, hit: pickReport?.hit ?? null };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
pick(snapshot: InputSnapshot): PickingReport | undefined {
|
|
148
|
-
const root = this.resolveRoot();
|
|
149
|
-
if (!root) return undefined;
|
|
150
|
-
const ray = this.resolveRay(snapshot);
|
|
151
|
-
return this.picking.report(root, ray.origin, ray.direction, this.pickOptions);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
dispose(): void {
|
|
155
|
-
this.disposed = true;
|
|
156
|
-
this.listeners.clear();
|
|
157
|
-
this.hotspotHandlers.clear();
|
|
158
|
-
this.hoverHit = null;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
private updateOrbit(snapshot: InputSnapshot): void {
|
|
162
|
-
if (snapshot.button(this.rotateButton).down) {
|
|
163
|
-
this.orbit.rotate(snapshot.pointer.deltaX * this.rotateSpeed, snapshot.pointer.deltaY * this.rotateSpeed);
|
|
164
|
-
}
|
|
165
|
-
if (snapshot.button(this.panButton).down) {
|
|
166
|
-
this.orbit.pan(snapshot.pointer.deltaX * this.panSpeed, -snapshot.pointer.deltaY * this.panSpeed);
|
|
167
|
-
}
|
|
168
|
-
if (snapshot.pointer.wheelY !== 0) {
|
|
169
|
-
this.orbit.dolly(Math.max(0.01, 1 + snapshot.pointer.wheelY * this.dollySpeed));
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private updateFly(snapshot: InputSnapshot): void {
|
|
174
|
-
const distance = this.flyMoveSpeed;
|
|
175
|
-
if (snapshot.key("KeyW").down || snapshot.key("ArrowUp").down) this.fly.moveForward(distance);
|
|
176
|
-
if (snapshot.key("KeyS").down || snapshot.key("ArrowDown").down) this.fly.moveForward(-distance);
|
|
177
|
-
if (snapshot.key("KeyA").down || snapshot.key("ArrowLeft").down) this.fly.strafe(-distance);
|
|
178
|
-
if (snapshot.key("KeyD").down || snapshot.key("ArrowRight").down) this.fly.strafe(distance);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
private updatePicking(snapshot: InputSnapshot): PickingReport | undefined {
|
|
182
|
-
const pickReport = this.pick(snapshot);
|
|
183
|
-
const hit = pickReport?.hit ?? null;
|
|
184
|
-
const previousHit = this.hoverHit;
|
|
185
|
-
if (previousHit?.object !== hit?.object) {
|
|
186
|
-
if (previousHit) this.emit({ type: "hover-exit", mode: this.controlMode, snapshot, previousHit });
|
|
187
|
-
if (hit) this.emit({ type: "hover-enter", mode: this.controlMode, snapshot, hit, previousHit: previousHit ?? undefined });
|
|
188
|
-
this.hoverHit = hit;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (hit && snapshot.button(0).released) {
|
|
192
|
-
const event = { type: "pick" as const, mode: this.controlMode, snapshot, hit, previousHit: previousHit ?? undefined };
|
|
193
|
-
this.emit(event);
|
|
194
|
-
this.emitHotspot(event);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return pickReport;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
private emitHotspot(event: InteractionControlsEvent & { readonly hit: ThreeCompatPickResult }): void {
|
|
201
|
-
const id = event.hit.metadata?.id ?? event.hit.object.name;
|
|
202
|
-
if (!id) return;
|
|
203
|
-
const hotspotEvent = { ...event, type: "hotspot-click" as const };
|
|
204
|
-
this.emit(hotspotEvent);
|
|
205
|
-
for (const handler of [...(this.hotspotHandlers.get(id) ?? [])]) {
|
|
206
|
-
handler(hotspotEvent);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private emit(event: InteractionControlsEvent): void {
|
|
211
|
-
for (const listener of [...this.listeners]) listener(event);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
private resolveRoot(): ControlObject3DLike | undefined {
|
|
215
|
-
return typeof this.rootRef === "function" ? this.rootRef() : this.rootRef;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
private resolveRay(snapshot: InputSnapshot): InteractionRay {
|
|
219
|
-
return this.rayProvider?.(snapshot) ?? {
|
|
220
|
-
origin: new ControlVector3(),
|
|
221
|
-
direction: new ControlVector3(0, 0, -1)
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
}
|
package/src/MapControls.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { OrbitControls } from "./OrbitControls";
|
|
2
|
-
|
|
3
|
-
export class MapControls extends OrbitControls {
|
|
4
|
-
readonly screenSpacePanning = false;
|
|
5
|
-
|
|
6
|
-
truck(deltaX: number, deltaZ: number): void {
|
|
7
|
-
this.state.target.x += deltaX;
|
|
8
|
-
this.state.target.z += deltaZ;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
export interface Vector3Like {
|
|
2
|
-
x: number;
|
|
3
|
-
y: number;
|
|
4
|
-
z: number;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface ControlPickMetadata {
|
|
8
|
-
readonly id?: string;
|
|
9
|
-
readonly label?: string;
|
|
10
|
-
readonly kind?: string;
|
|
11
|
-
readonly group?: string;
|
|
12
|
-
readonly routeId?: string;
|
|
13
|
-
readonly source?: string;
|
|
14
|
-
readonly targetId?: string;
|
|
15
|
-
readonly selectable?: boolean;
|
|
16
|
-
readonly highlightable?: boolean;
|
|
17
|
-
readonly pickRadius?: number;
|
|
18
|
-
readonly priority?: number;
|
|
19
|
-
readonly payload?: unknown;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class ControlVector3 implements Vector3Like {
|
|
23
|
-
constructor(public x = 0, public y = 0, public z = 0) {}
|
|
24
|
-
|
|
25
|
-
set(x: number, y: number, z: number): this {
|
|
26
|
-
this.x = x;
|
|
27
|
-
this.y = y;
|
|
28
|
-
this.z = z;
|
|
29
|
-
return this;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
copy(value: Vector3Like): this {
|
|
33
|
-
return this.set(value.x, value.y, value.z);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
clone(): ControlVector3 {
|
|
37
|
-
return new ControlVector3(this.x, this.y, this.z);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
add(value: Vector3Like): this {
|
|
41
|
-
this.x += value.x;
|
|
42
|
-
this.y += value.y;
|
|
43
|
-
this.z += value.z;
|
|
44
|
-
return this;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
sub(value: Vector3Like): this {
|
|
48
|
-
this.x -= value.x;
|
|
49
|
-
this.y -= value.y;
|
|
50
|
-
this.z -= value.z;
|
|
51
|
-
return this;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
length(): number {
|
|
55
|
-
return Math.hypot(this.x, this.y, this.z);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
normalize(): this {
|
|
59
|
-
const length = this.length();
|
|
60
|
-
return length > 0 ? this.set(this.x / length, this.y / length, this.z / length) : this;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface ControlObject3DLike {
|
|
65
|
-
readonly name?: string;
|
|
66
|
-
readonly type?: string;
|
|
67
|
-
readonly children?: readonly ControlObject3DLike[];
|
|
68
|
-
readonly position: Vector3Like;
|
|
69
|
-
readonly rotation?: Vector3Like;
|
|
70
|
-
readonly scale?: Vector3Like;
|
|
71
|
-
readonly visible?: boolean;
|
|
72
|
-
readonly pickRadius?: number;
|
|
73
|
-
readonly pickPriority?: number;
|
|
74
|
-
readonly picking?: ControlPickMetadata;
|
|
75
|
-
readonly userData?: Record<string, unknown>;
|
|
76
|
-
traverse?(callback: (object: ControlObject3DLike) => void): void;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function addVector3(target: Vector3Like | undefined, delta: Vector3Like): void {
|
|
80
|
-
if (!target) return;
|
|
81
|
-
target.x += delta.x;
|
|
82
|
-
target.y += delta.y;
|
|
83
|
-
target.z += delta.z;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function traverseControlObject(root: ControlObject3DLike, callback: (object: ControlObject3DLike) => void): void {
|
|
87
|
-
if (typeof root.traverse === "function") {
|
|
88
|
-
root.traverse(callback);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
callback(root);
|
|
92
|
-
for (const child of root.children ?? []) traverseControlObject(child, callback);
|
|
93
|
-
}
|
package/src/OrbitControls.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { createDefaultControlState, type ThreeCompatControlState } from "./ControlState";
|
|
2
|
-
|
|
3
|
-
export class OrbitControls {
|
|
4
|
-
readonly state: ThreeCompatControlState = createDefaultControlState();
|
|
5
|
-
enablePan = true;
|
|
6
|
-
enableZoom = true;
|
|
7
|
-
enableRotate = true;
|
|
8
|
-
|
|
9
|
-
rotate(deltaX: number, deltaY: number): void {
|
|
10
|
-
if (!this.enableRotate) return;
|
|
11
|
-
this.state.rotation.x += deltaY;
|
|
12
|
-
this.state.rotation.y += deltaX;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pan(deltaX: number, deltaY: number): void {
|
|
16
|
-
if (!this.enablePan) return;
|
|
17
|
-
this.state.target.x += deltaX;
|
|
18
|
-
this.state.target.y += deltaY;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
dolly(scale: number): void {
|
|
22
|
-
if (!this.enableZoom) return;
|
|
23
|
-
this.state.position.z *= scale;
|
|
24
|
-
}
|
|
25
|
-
}
|
package/src/Picking.ts
DELETED
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ControlVector3,
|
|
3
|
-
traverseControlObject,
|
|
4
|
-
type ControlObject3DLike,
|
|
5
|
-
type ControlPickMetadata,
|
|
6
|
-
type Vector3Like
|
|
7
|
-
} from "./NativeControlTypes";
|
|
8
|
-
|
|
9
|
-
export interface ThreeCompatPickResult {
|
|
10
|
-
readonly object: ControlObject3DLike;
|
|
11
|
-
readonly distance: number;
|
|
12
|
-
readonly distanceAlongRay: number;
|
|
13
|
-
readonly perpendicularDistance: number;
|
|
14
|
-
readonly point: ControlVector3;
|
|
15
|
-
readonly radius: number;
|
|
16
|
-
readonly metadata?: ControlPickMetadata;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface PickingOptions {
|
|
20
|
-
readonly near?: number;
|
|
21
|
-
readonly far?: number;
|
|
22
|
-
readonly tolerance?: number;
|
|
23
|
-
readonly includeInvisible?: boolean;
|
|
24
|
-
readonly includeNonRenderableMetadata?: boolean;
|
|
25
|
-
readonly metadata?: (object: ControlObject3DLike) => ControlPickMetadata | undefined;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface PickingDiagnostics {
|
|
29
|
-
readonly testedObjects: number;
|
|
30
|
-
readonly candidateObjects: number;
|
|
31
|
-
readonly hitCount: number;
|
|
32
|
-
readonly skippedInvisible: number;
|
|
33
|
-
readonly skippedNonPickable: number;
|
|
34
|
-
readonly skippedDisabled: number;
|
|
35
|
-
readonly skippedOutOfRange: number;
|
|
36
|
-
readonly skippedMissedRadius: number;
|
|
37
|
-
readonly nearestMissPerpendicularDistance: number | null;
|
|
38
|
-
readonly nearestHitLabel: string | null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface PickingReport {
|
|
42
|
-
readonly hit: ThreeCompatPickResult | null;
|
|
43
|
-
readonly hits: readonly ThreeCompatPickResult[];
|
|
44
|
-
readonly diagnostics: PickingDiagnostics;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export class Picking {
|
|
48
|
-
pick(
|
|
49
|
-
root: ControlObject3DLike,
|
|
50
|
-
origin: Vector3Like = new ControlVector3(),
|
|
51
|
-
direction: Vector3Like = new ControlVector3(0, 0, -1),
|
|
52
|
-
options: PickingOptions = {}
|
|
53
|
-
): ThreeCompatPickResult | null {
|
|
54
|
-
return this.report(root, origin, direction, options).hit;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
pickAll(
|
|
58
|
-
root: ControlObject3DLike,
|
|
59
|
-
origin: Vector3Like = new ControlVector3(),
|
|
60
|
-
direction: Vector3Like = new ControlVector3(0, 0, -1),
|
|
61
|
-
options: PickingOptions = {}
|
|
62
|
-
): readonly ThreeCompatPickResult[] {
|
|
63
|
-
return this.report(root, origin, direction, options).hits;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
report(
|
|
67
|
-
root: ControlObject3DLike,
|
|
68
|
-
origin: Vector3Like = new ControlVector3(),
|
|
69
|
-
direction: Vector3Like = new ControlVector3(0, 0, -1),
|
|
70
|
-
options: PickingOptions = {}
|
|
71
|
-
): PickingReport {
|
|
72
|
-
const normalizedDirection = normalizedRayDirection(direction);
|
|
73
|
-
const near = finiteRange(options.near ?? 0, "near", 0);
|
|
74
|
-
const far = finiteRange(options.far ?? Number.POSITIVE_INFINITY, "far", near);
|
|
75
|
-
const tolerance = finiteRange(options.tolerance ?? 0, "tolerance", 0);
|
|
76
|
-
const hits: ThreeCompatPickResult[] = [];
|
|
77
|
-
const counters = {
|
|
78
|
-
testedObjects: 0,
|
|
79
|
-
candidateObjects: 0,
|
|
80
|
-
skippedInvisible: 0,
|
|
81
|
-
skippedNonPickable: 0,
|
|
82
|
-
skippedDisabled: 0,
|
|
83
|
-
skippedOutOfRange: 0,
|
|
84
|
-
skippedMissedRadius: 0
|
|
85
|
-
};
|
|
86
|
-
let nearestMissPerpendicularDistance = Number.POSITIVE_INFINITY;
|
|
87
|
-
|
|
88
|
-
traverseControlObject(root, (object) => {
|
|
89
|
-
counters.testedObjects += 1;
|
|
90
|
-
if (object.visible === false && options.includeInvisible !== true) {
|
|
91
|
-
counters.skippedInvisible += 1;
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const metadata = resolvePickMetadata(object, options);
|
|
95
|
-
if (metadata?.selectable === false) {
|
|
96
|
-
counters.skippedDisabled += 1;
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (!isPickableObject(object, metadata, options)) {
|
|
100
|
-
counters.skippedNonPickable += 1;
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
counters.candidateObjects += 1;
|
|
104
|
-
const toObject = new ControlVector3(
|
|
105
|
-
object.position.x - origin.x,
|
|
106
|
-
object.position.y - origin.y,
|
|
107
|
-
object.position.z - origin.z
|
|
108
|
-
);
|
|
109
|
-
const distanceAlongRay = dot(toObject, normalizedDirection);
|
|
110
|
-
if (distanceAlongRay < near || distanceAlongRay > far) {
|
|
111
|
-
counters.skippedOutOfRange += 1;
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
const closestPoint = pointOnRay(origin, normalizedDirection, distanceAlongRay);
|
|
115
|
-
const perpendicularDistance = new ControlVector3(
|
|
116
|
-
object.position.x - closestPoint.x,
|
|
117
|
-
object.position.y - closestPoint.y,
|
|
118
|
-
object.position.z - closestPoint.z
|
|
119
|
-
).length();
|
|
120
|
-
const radius = resolvePickRadius(object, metadata) + tolerance;
|
|
121
|
-
if (perpendicularDistance > radius) {
|
|
122
|
-
counters.skippedMissedRadius += 1;
|
|
123
|
-
nearestMissPerpendicularDistance = Math.min(nearestMissPerpendicularDistance, perpendicularDistance);
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const rayEntryDistance = Math.max(near, distanceAlongRay - Math.sqrt(Math.max(0, radius * radius - perpendicularDistance * perpendicularDistance)));
|
|
127
|
-
hits.push({
|
|
128
|
-
object,
|
|
129
|
-
distance: rayEntryDistance,
|
|
130
|
-
distanceAlongRay,
|
|
131
|
-
perpendicularDistance,
|
|
132
|
-
point: pointOnRay(origin, normalizedDirection, rayEntryDistance),
|
|
133
|
-
radius,
|
|
134
|
-
metadata
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
hits.sort(compareHits);
|
|
139
|
-
const hit = hits[0] ?? null;
|
|
140
|
-
return {
|
|
141
|
-
hit,
|
|
142
|
-
hits,
|
|
143
|
-
diagnostics: {
|
|
144
|
-
...counters,
|
|
145
|
-
hitCount: hits.length,
|
|
146
|
-
nearestMissPerpendicularDistance: Number.isFinite(nearestMissPerpendicularDistance) ? nearestMissPerpendicularDistance : null,
|
|
147
|
-
nearestHitLabel: hit ? pickLabel(hit.object, hit.metadata) : null
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function normalizedRayDirection(direction: Vector3Like): ControlVector3 {
|
|
154
|
-
const normalized = new ControlVector3(direction.x, direction.y, direction.z);
|
|
155
|
-
const length = normalized.length();
|
|
156
|
-
if (!Number.isFinite(length) || length <= 1e-8) {
|
|
157
|
-
throw new RangeError("Picking ray direction must be finite and non-zero.");
|
|
158
|
-
}
|
|
159
|
-
return normalized.set(normalized.x / length, normalized.y / length, normalized.z / length);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function finiteRange(value: number, label: string, minimum: number): number {
|
|
163
|
-
if (value === Number.POSITIVE_INFINITY && label === "far") return value;
|
|
164
|
-
if (!Number.isFinite(value) || value < minimum) {
|
|
165
|
-
throw new RangeError(`Picking ${label} must be finite and >= ${minimum}.`);
|
|
166
|
-
}
|
|
167
|
-
return value;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function resolvePickMetadata(object: ControlObject3DLike, options: PickingOptions): ControlPickMetadata | undefined {
|
|
171
|
-
return options.metadata?.(object)
|
|
172
|
-
?? object.picking
|
|
173
|
-
?? readUserDataMetadata(object.userData);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function readUserDataMetadata(userData: Record<string, unknown> | undefined): ControlPickMetadata | undefined {
|
|
177
|
-
const value = userData?.a3dPicking ?? userData?.picking;
|
|
178
|
-
if (!value || typeof value !== "object") return undefined;
|
|
179
|
-
return value as ControlPickMetadata;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function isPickableObject(
|
|
183
|
-
object: ControlObject3DLike,
|
|
184
|
-
metadata: ControlPickMetadata | undefined,
|
|
185
|
-
options: PickingOptions
|
|
186
|
-
): boolean {
|
|
187
|
-
if (metadata && options.includeNonRenderableMetadata !== false) return true;
|
|
188
|
-
return object.type === "Mesh" || object.type === "Sprite" || object.type === "Points" || object.type === "LineSegments";
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function resolvePickRadius(object: ControlObject3DLike, metadata: ControlPickMetadata | undefined): number {
|
|
192
|
-
const explicit = metadata?.pickRadius ?? object.pickRadius ?? readUserDataRadius(object.userData);
|
|
193
|
-
if (explicit !== undefined) return positiveFinite(explicit, "pickRadius");
|
|
194
|
-
const scale = object.scale;
|
|
195
|
-
if (!scale) return 0.5;
|
|
196
|
-
const radius = Math.max(Math.abs(scale.x), Math.abs(scale.y), Math.abs(scale.z)) * 0.5;
|
|
197
|
-
return Number.isFinite(radius) && radius > 0 ? radius : 0.5;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function readUserDataRadius(userData: Record<string, unknown> | undefined): number | undefined {
|
|
201
|
-
const value = userData?.a3dPickRadius;
|
|
202
|
-
return typeof value === "number" ? value : undefined;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function positiveFinite(value: number, label: string): number {
|
|
206
|
-
if (!Number.isFinite(value) || value <= 0) throw new RangeError(`Picking ${label} must be finite and positive.`);
|
|
207
|
-
return value;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function dot(left: Vector3Like, right: Vector3Like): number {
|
|
211
|
-
return left.x * right.x + left.y * right.y + left.z * right.z;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function pointOnRay(origin: Vector3Like, direction: Vector3Like, distance: number): ControlVector3 {
|
|
215
|
-
return new ControlVector3(
|
|
216
|
-
origin.x + direction.x * distance,
|
|
217
|
-
origin.y + direction.y * distance,
|
|
218
|
-
origin.z + direction.z * distance
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function compareHits(left: ThreeCompatPickResult, right: ThreeCompatPickResult): number {
|
|
223
|
-
const distanceDelta = left.distance - right.distance;
|
|
224
|
-
if (Math.abs(distanceDelta) > 1e-8) return distanceDelta;
|
|
225
|
-
return pickPriority(right) - pickPriority(left);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function pickPriority(hit: ThreeCompatPickResult): number {
|
|
229
|
-
return hit.metadata?.priority ?? hit.object.pickPriority ?? 0;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function pickLabel(object: ControlObject3DLike, metadata: ControlPickMetadata | undefined): string | null {
|
|
233
|
-
return metadata?.label ?? metadata?.id ?? object.name ?? null;
|
|
234
|
-
}
|
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
import { Picking, type PickingOptions, type PickingReport, type ThreeCompatPickResult } from "./Picking";
|
|
2
|
-
import { ControlVector3, type ControlObject3DLike, type ControlPickMetadata, type Vector3Like } from "./NativeControlTypes";
|
|
3
|
-
|
|
4
|
-
export type PickingAnnotationKind = "hotspot" | "label" | "district" | "building" | "robot" | "entity";
|
|
5
|
-
export type PickingAnnotationSource = "imported-gltf" | "procedural" | "screen-space";
|
|
6
|
-
export type PickingAnnotationHitPolicy = "nearest" | "priority";
|
|
7
|
-
|
|
8
|
-
export interface PickingAnnotation<TPayload = unknown> {
|
|
9
|
-
readonly id: string;
|
|
10
|
-
readonly label: string;
|
|
11
|
-
readonly kind: PickingAnnotationKind;
|
|
12
|
-
readonly position: Vector3Like | readonly [number, number, number];
|
|
13
|
-
readonly radius: number;
|
|
14
|
-
readonly priority?: number;
|
|
15
|
-
readonly group?: string;
|
|
16
|
-
readonly routeId?: string;
|
|
17
|
-
readonly source?: PickingAnnotationSource;
|
|
18
|
-
readonly selectable?: boolean;
|
|
19
|
-
readonly highlightable?: boolean;
|
|
20
|
-
readonly targetId?: string;
|
|
21
|
-
readonly payload?: TPayload;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface PickingAnnotationRoot<TPayload = unknown> extends ControlObject3DLike {
|
|
25
|
-
readonly type: "PickingAnnotationRoot";
|
|
26
|
-
readonly name: string;
|
|
27
|
-
readonly children: readonly PickingAnnotationObject<TPayload>[];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface PickingAnnotationObject<TPayload = unknown> extends ControlObject3DLike {
|
|
31
|
-
readonly type: "PickingAnnotation";
|
|
32
|
-
readonly name: string;
|
|
33
|
-
readonly picking: ControlPickMetadata;
|
|
34
|
-
readonly userData: {
|
|
35
|
-
readonly a3dPicking: ControlPickMetadata;
|
|
36
|
-
readonly a3dPickingAnnotation: PickingAnnotation<TPayload>;
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface PickingAnnotationReport<TPayload = unknown> extends PickingReport {
|
|
41
|
-
readonly annotation: PickingAnnotation<TPayload> | null;
|
|
42
|
-
readonly annotations: readonly PickingAnnotation<TPayload>[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface PickingAnnotationOptions extends PickingOptions {
|
|
46
|
-
readonly hitPolicy?: PickingAnnotationHitPolicy;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface ImportedGlbHotspotDescriptor<TPayload = unknown> {
|
|
50
|
-
readonly id?: string;
|
|
51
|
-
readonly nodeName?: string;
|
|
52
|
-
readonly label?: string;
|
|
53
|
-
readonly focusId?: string;
|
|
54
|
-
readonly position: Vector3Like | readonly [number, number, number];
|
|
55
|
-
readonly radius?: number;
|
|
56
|
-
readonly priority?: number;
|
|
57
|
-
readonly selectable?: boolean;
|
|
58
|
-
readonly highlightable?: boolean;
|
|
59
|
-
readonly payload?: TPayload;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface DistrictPickingDescriptor<TPayload = unknown> {
|
|
63
|
-
readonly id: string;
|
|
64
|
-
readonly label?: string;
|
|
65
|
-
readonly center: Vector3Like | readonly [number, number, number];
|
|
66
|
-
readonly radius: number;
|
|
67
|
-
readonly priority?: number;
|
|
68
|
-
readonly routeId?: string;
|
|
69
|
-
readonly payload?: TPayload;
|
|
70
|
-
readonly buildings?: readonly BuildingPickingDescriptor<TPayload>[];
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface BuildingPickingDescriptor<TPayload = unknown> {
|
|
74
|
-
readonly id: string;
|
|
75
|
-
readonly label?: string;
|
|
76
|
-
readonly position: Vector3Like | readonly [number, number, number];
|
|
77
|
-
readonly radius: number;
|
|
78
|
-
readonly priority?: number;
|
|
79
|
-
readonly payload?: TPayload;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export interface EntityPickingDescriptor<TPayload = unknown> {
|
|
83
|
-
readonly id: string;
|
|
84
|
-
readonly label?: string;
|
|
85
|
-
readonly kind?: "robot" | "entity";
|
|
86
|
-
readonly position: Vector3Like | readonly [number, number, number];
|
|
87
|
-
readonly radius: number;
|
|
88
|
-
readonly priority?: number;
|
|
89
|
-
readonly group?: string;
|
|
90
|
-
readonly routeId?: string;
|
|
91
|
-
readonly payload?: TPayload;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface ScreenPickingAnnotation<TPayload = unknown> {
|
|
95
|
-
readonly id: string;
|
|
96
|
-
readonly label: string;
|
|
97
|
-
readonly kind: PickingAnnotationKind;
|
|
98
|
-
readonly x: number;
|
|
99
|
-
readonly y: number;
|
|
100
|
-
readonly radius: number;
|
|
101
|
-
readonly priority?: number;
|
|
102
|
-
readonly group?: string;
|
|
103
|
-
readonly routeId?: string;
|
|
104
|
-
readonly source?: PickingAnnotationSource;
|
|
105
|
-
readonly selectable?: boolean;
|
|
106
|
-
readonly highlightable?: boolean;
|
|
107
|
-
readonly targetId?: string;
|
|
108
|
-
readonly payload?: TPayload;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export interface ScreenPickingHit<TPayload = unknown> {
|
|
112
|
-
readonly annotation: ScreenPickingAnnotation<TPayload>;
|
|
113
|
-
readonly distance: number;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export interface ScreenPickingReport<TPayload = unknown> {
|
|
117
|
-
readonly hit: ScreenPickingHit<TPayload> | null;
|
|
118
|
-
readonly hits: readonly ScreenPickingHit<TPayload>[];
|
|
119
|
-
readonly diagnostics: {
|
|
120
|
-
readonly testedAnnotations: number;
|
|
121
|
-
readonly candidateAnnotations: number;
|
|
122
|
-
readonly hitCount: number;
|
|
123
|
-
readonly skippedDisabled: number;
|
|
124
|
-
readonly skippedOutOfRadius: number;
|
|
125
|
-
readonly nearestHitLabel: string | null;
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export interface ScreenPickingOptions {
|
|
130
|
-
readonly tolerance?: number;
|
|
131
|
-
readonly hitPolicy?: PickingAnnotationHitPolicy;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function createPickingAnnotationRoot<TPayload = unknown>(
|
|
135
|
-
name: string,
|
|
136
|
-
annotations: readonly PickingAnnotation<TPayload>[]
|
|
137
|
-
): PickingAnnotationRoot<TPayload> {
|
|
138
|
-
return {
|
|
139
|
-
type: "PickingAnnotationRoot",
|
|
140
|
-
name,
|
|
141
|
-
position: new ControlVector3(),
|
|
142
|
-
children: annotations.map(createPickingAnnotationObject)
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export function createPickingAnnotationObject<TPayload = unknown>(
|
|
147
|
-
annotation: PickingAnnotation<TPayload>
|
|
148
|
-
): PickingAnnotationObject<TPayload> {
|
|
149
|
-
const radius = positiveFinite(annotation.radius, "annotation radius");
|
|
150
|
-
const metadata: ControlPickMetadata = {
|
|
151
|
-
id: annotation.id,
|
|
152
|
-
label: annotation.label,
|
|
153
|
-
kind: annotation.kind,
|
|
154
|
-
group: annotation.group,
|
|
155
|
-
selectable: annotation.selectable,
|
|
156
|
-
highlightable: annotation.highlightable,
|
|
157
|
-
pickRadius: radius,
|
|
158
|
-
priority: annotation.priority,
|
|
159
|
-
routeId: annotation.routeId,
|
|
160
|
-
source: annotation.source,
|
|
161
|
-
targetId: annotation.targetId,
|
|
162
|
-
payload: annotation.payload
|
|
163
|
-
};
|
|
164
|
-
return {
|
|
165
|
-
type: "PickingAnnotation",
|
|
166
|
-
name: annotation.label,
|
|
167
|
-
position: toVector3(annotation.position),
|
|
168
|
-
scale: new ControlVector3(radius * 2, radius * 2, radius * 2),
|
|
169
|
-
visible: annotation.selectable === false ? false : true,
|
|
170
|
-
pickRadius: radius,
|
|
171
|
-
pickPriority: annotation.priority,
|
|
172
|
-
picking: metadata,
|
|
173
|
-
userData: {
|
|
174
|
-
a3dPicking: metadata,
|
|
175
|
-
a3dPickingAnnotation: annotation
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export function pickAnnotation<TPayload = unknown>(
|
|
181
|
-
root: ControlObject3DLike,
|
|
182
|
-
origin: Vector3Like = new ControlVector3(),
|
|
183
|
-
direction: Vector3Like = new ControlVector3(0, 0, -1),
|
|
184
|
-
options: PickingAnnotationOptions = {}
|
|
185
|
-
): PickingAnnotationReport<TPayload> {
|
|
186
|
-
const report = new Picking().report(root, origin, direction, options);
|
|
187
|
-
const hits = options.hitPolicy === "priority"
|
|
188
|
-
? [...report.hits].sort(compareAnnotationHitsByPriority)
|
|
189
|
-
: report.hits;
|
|
190
|
-
const hit = hits[0] ?? null;
|
|
191
|
-
return {
|
|
192
|
-
...report,
|
|
193
|
-
hit,
|
|
194
|
-
hits,
|
|
195
|
-
annotation: hit ? annotationFromPickHit<TPayload>(hit) : null,
|
|
196
|
-
annotations: hits.map((candidate) => annotationFromPickHit<TPayload>(candidate)).filter((annotation): annotation is PickingAnnotation<TPayload> => Boolean(annotation))
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export function annotationFromPickHit<TPayload = unknown>(
|
|
201
|
-
hit: ThreeCompatPickResult | null | undefined
|
|
202
|
-
): PickingAnnotation<TPayload> | null {
|
|
203
|
-
const value = hit?.object.userData?.a3dPickingAnnotation;
|
|
204
|
-
return isPickingAnnotation(value) ? value as PickingAnnotation<TPayload> : null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export function createImportedGlbHotspotAnnotations<TPayload = unknown>(
|
|
208
|
-
assetId: string,
|
|
209
|
-
hotspots: readonly ImportedGlbHotspotDescriptor<TPayload>[],
|
|
210
|
-
routeId?: string
|
|
211
|
-
): readonly PickingAnnotation<TPayload>[] {
|
|
212
|
-
return hotspots.map((hotspot, index) => {
|
|
213
|
-
const targetId = hotspot.focusId ?? hotspot.nodeName ?? hotspot.id ?? `hotspot-${index}`;
|
|
214
|
-
return {
|
|
215
|
-
id: hotspot.id ?? `${assetId}:${targetId}`,
|
|
216
|
-
label: hotspot.label ?? readableLabel(targetId),
|
|
217
|
-
kind: "hotspot",
|
|
218
|
-
position: hotspot.position,
|
|
219
|
-
radius: hotspot.radius ?? 0.18,
|
|
220
|
-
priority: hotspot.priority ?? 100,
|
|
221
|
-
group: assetId,
|
|
222
|
-
routeId,
|
|
223
|
-
source: "imported-gltf",
|
|
224
|
-
selectable: hotspot.selectable,
|
|
225
|
-
highlightable: hotspot.highlightable ?? true,
|
|
226
|
-
targetId,
|
|
227
|
-
payload: hotspot.payload
|
|
228
|
-
};
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
export function createDistrictPickingAnnotations<TPayload = unknown>(
|
|
233
|
-
districts: readonly DistrictPickingDescriptor<TPayload>[]
|
|
234
|
-
): readonly PickingAnnotation<TPayload>[] {
|
|
235
|
-
const annotations: PickingAnnotation<TPayload>[] = [];
|
|
236
|
-
for (const district of districts) {
|
|
237
|
-
annotations.push({
|
|
238
|
-
id: district.id,
|
|
239
|
-
label: district.label ?? readableLabel(district.id),
|
|
240
|
-
kind: "district",
|
|
241
|
-
position: district.center,
|
|
242
|
-
radius: district.radius,
|
|
243
|
-
priority: district.priority ?? 10,
|
|
244
|
-
group: "district",
|
|
245
|
-
routeId: district.routeId,
|
|
246
|
-
source: "procedural",
|
|
247
|
-
highlightable: true,
|
|
248
|
-
payload: district.payload
|
|
249
|
-
});
|
|
250
|
-
for (const building of district.buildings ?? []) {
|
|
251
|
-
annotations.push({
|
|
252
|
-
id: building.id,
|
|
253
|
-
label: building.label ?? readableLabel(building.id),
|
|
254
|
-
kind: "building",
|
|
255
|
-
position: building.position,
|
|
256
|
-
radius: building.radius,
|
|
257
|
-
priority: building.priority ?? 40,
|
|
258
|
-
group: district.id,
|
|
259
|
-
routeId: district.routeId,
|
|
260
|
-
source: "procedural",
|
|
261
|
-
highlightable: true,
|
|
262
|
-
payload: building.payload
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return annotations;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
export function createRobotPickingAnnotations<TPayload = unknown>(
|
|
270
|
-
robots: readonly EntityPickingDescriptor<TPayload>[]
|
|
271
|
-
): readonly PickingAnnotation<TPayload>[] {
|
|
272
|
-
return createEntityPickingAnnotations(robots.map((robot) => ({ ...robot, kind: "robot" as const })), {
|
|
273
|
-
defaultGroup: "robot",
|
|
274
|
-
defaultPriority: 70
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
export function createEntityPickingAnnotations<TPayload = unknown>(
|
|
279
|
-
entities: readonly EntityPickingDescriptor<TPayload>[],
|
|
280
|
-
options: { readonly defaultGroup?: string; readonly defaultPriority?: number } = {}
|
|
281
|
-
): readonly PickingAnnotation<TPayload>[] {
|
|
282
|
-
return entities.map((entity) => ({
|
|
283
|
-
id: entity.id,
|
|
284
|
-
label: entity.label ?? readableLabel(entity.id),
|
|
285
|
-
kind: entity.kind ?? "entity",
|
|
286
|
-
position: entity.position,
|
|
287
|
-
radius: entity.radius,
|
|
288
|
-
priority: entity.priority ?? options.defaultPriority ?? 50,
|
|
289
|
-
group: entity.group ?? options.defaultGroup,
|
|
290
|
-
routeId: entity.routeId,
|
|
291
|
-
source: "procedural",
|
|
292
|
-
highlightable: true,
|
|
293
|
-
targetId: entity.id,
|
|
294
|
-
payload: entity.payload
|
|
295
|
-
}));
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
export function pickScreenSpaceAnnotation<TPayload = unknown>(
|
|
299
|
-
pointer: { readonly x: number; readonly y: number },
|
|
300
|
-
annotations: readonly ScreenPickingAnnotation<TPayload>[],
|
|
301
|
-
options: ScreenPickingOptions = {}
|
|
302
|
-
): ScreenPickingReport<TPayload> {
|
|
303
|
-
validateScreenPoint(pointer, "pointer");
|
|
304
|
-
const tolerance = options.tolerance ?? 0;
|
|
305
|
-
if (!Number.isFinite(tolerance) || tolerance < 0) throw new RangeError("Screen picking tolerance must be finite and non-negative.");
|
|
306
|
-
const hits: ScreenPickingHit<TPayload>[] = [];
|
|
307
|
-
let skippedDisabled = 0;
|
|
308
|
-
let skippedOutOfRadius = 0;
|
|
309
|
-
|
|
310
|
-
for (const annotation of annotations) {
|
|
311
|
-
if (annotation.selectable === false) {
|
|
312
|
-
skippedDisabled += 1;
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
validateScreenPoint(annotation, annotation.id);
|
|
316
|
-
const radius = positiveFinite(annotation.radius, `${annotation.id} screen radius`) + tolerance;
|
|
317
|
-
const distance = Math.hypot(pointer.x - annotation.x, pointer.y - annotation.y);
|
|
318
|
-
if (distance > radius) {
|
|
319
|
-
skippedOutOfRadius += 1;
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
hits.push({ annotation, distance });
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
hits.sort(options.hitPolicy === "priority" ? compareScreenHitsByPriority : compareScreenHitsByDistance);
|
|
326
|
-
const hit = hits[0] ?? null;
|
|
327
|
-
return {
|
|
328
|
-
hit,
|
|
329
|
-
hits,
|
|
330
|
-
diagnostics: {
|
|
331
|
-
testedAnnotations: annotations.length,
|
|
332
|
-
candidateAnnotations: annotations.length - skippedDisabled,
|
|
333
|
-
hitCount: hits.length,
|
|
334
|
-
skippedDisabled,
|
|
335
|
-
skippedOutOfRadius,
|
|
336
|
-
nearestHitLabel: hit?.annotation.label ?? null
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function toVector3(value: Vector3Like | readonly [number, number, number]): ControlVector3 {
|
|
342
|
-
const tuple = value as readonly number[];
|
|
343
|
-
const vector = value as Vector3Like;
|
|
344
|
-
const x = Array.isArray(value) ? tuple[0] : vector.x;
|
|
345
|
-
const y = Array.isArray(value) ? tuple[1] : vector.y;
|
|
346
|
-
const z = Array.isArray(value) ? tuple[2] : vector.z;
|
|
347
|
-
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z)) {
|
|
348
|
-
throw new RangeError("Picking annotation position must contain three finite values.");
|
|
349
|
-
}
|
|
350
|
-
return new ControlVector3(x, y, z);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function positiveFinite(value: number, label: string): number {
|
|
354
|
-
if (!Number.isFinite(value) || value <= 0) throw new RangeError(`Picking ${label} must be finite and positive.`);
|
|
355
|
-
return value;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
function readableLabel(value: string): string {
|
|
359
|
-
return value.replace(/[_:-]+/g, " ").replace(/\s+/g, " ").trim() || "Picking target";
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
function compareAnnotationHitsByPriority(left: ThreeCompatPickResult, right: ThreeCompatPickResult): number {
|
|
363
|
-
const priorityDelta = (right.metadata?.priority ?? 0) - (left.metadata?.priority ?? 0);
|
|
364
|
-
if (Math.abs(priorityDelta) > 1e-8) return priorityDelta;
|
|
365
|
-
return left.distance - right.distance;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
function isPickingAnnotation(value: unknown): value is PickingAnnotation {
|
|
369
|
-
return Boolean(value)
|
|
370
|
-
&& typeof value === "object"
|
|
371
|
-
&& typeof (value as { readonly id?: unknown }).id === "string"
|
|
372
|
-
&& typeof (value as { readonly label?: unknown }).label === "string";
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
function validateScreenPoint(point: { readonly x: number; readonly y: number }, label: string): void {
|
|
376
|
-
if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) {
|
|
377
|
-
throw new RangeError(`Screen picking ${label} must contain finite x/y values.`);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
function compareScreenHitsByDistance(left: ScreenPickingHit, right: ScreenPickingHit): number {
|
|
382
|
-
const distanceDelta = left.distance - right.distance;
|
|
383
|
-
if (Math.abs(distanceDelta) > 1e-8) return distanceDelta;
|
|
384
|
-
return (right.annotation.priority ?? 0) - (left.annotation.priority ?? 0);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function compareScreenHitsByPriority(left: ScreenPickingHit, right: ScreenPickingHit): number {
|
|
388
|
-
const priorityDelta = (right.annotation.priority ?? 0) - (left.annotation.priority ?? 0);
|
|
389
|
-
if (Math.abs(priorityDelta) > 1e-8) return priorityDelta;
|
|
390
|
-
return left.distance - right.distance;
|
|
391
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { createDefaultControlState, type ThreeCompatControlState } from "./ControlState";
|
|
2
|
-
|
|
3
|
-
export class PointerLockControls {
|
|
4
|
-
readonly state: ThreeCompatControlState = createDefaultControlState();
|
|
5
|
-
locked = false;
|
|
6
|
-
|
|
7
|
-
lock(): void { this.locked = true; }
|
|
8
|
-
unlock(): void { this.locked = false; }
|
|
9
|
-
|
|
10
|
-
look(deltaX: number, deltaY: number): void {
|
|
11
|
-
if (!this.locked) return;
|
|
12
|
-
this.state.rotation.y += deltaX;
|
|
13
|
-
this.state.rotation.x += deltaY;
|
|
14
|
-
}
|
|
15
|
-
}
|
package/src/SelectionManager.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { ControlObject3DLike } from "./NativeControlTypes";
|
|
2
|
-
|
|
3
|
-
export class SelectionManager {
|
|
4
|
-
readonly selected = new Set<ControlObject3DLike>();
|
|
5
|
-
|
|
6
|
-
select(object: ControlObject3DLike, additive = false): void {
|
|
7
|
-
if (!additive) this.clear();
|
|
8
|
-
this.selected.add(object);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
deselect(object: ControlObject3DLike): void {
|
|
12
|
-
this.selected.delete(object);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
clear(): void {
|
|
16
|
-
this.selected.clear();
|
|
17
|
-
}
|
|
18
|
-
}
|
package/src/TrackballControls.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { OrbitControls } from "./OrbitControls";
|
|
2
|
-
|
|
3
|
-
export type TrackballKey =
|
|
4
|
-
| "ArrowUp"
|
|
5
|
-
| "ArrowDown"
|
|
6
|
-
| "ArrowLeft"
|
|
7
|
-
| "ArrowRight"
|
|
8
|
-
| "KeyQ"
|
|
9
|
-
| "KeyE"
|
|
10
|
-
| "NumpadAdd"
|
|
11
|
-
| "NumpadSubtract"
|
|
12
|
-
| "+"
|
|
13
|
-
| "-"
|
|
14
|
-
| "="
|
|
15
|
-
| "_";
|
|
16
|
-
|
|
17
|
-
export class TrackballControls extends OrbitControls {
|
|
18
|
-
enableDamping = false;
|
|
19
|
-
dampingFactor = 0.08;
|
|
20
|
-
keyPanSpeed = 0.12;
|
|
21
|
-
keyRollSpeed = 0.06;
|
|
22
|
-
|
|
23
|
-
private rotationVelocity = { x: 0, y: 0, z: 0 };
|
|
24
|
-
private panVelocity = { x: 0, y: 0 };
|
|
25
|
-
private dollyVelocity = 0;
|
|
26
|
-
|
|
27
|
-
roll(delta: number): void {
|
|
28
|
-
if (!this.state.enabled || !this.enableRotate) return;
|
|
29
|
-
this.state.rotation.z += delta;
|
|
30
|
-
this.rotationVelocity.z += delta;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
override rotate(deltaX: number, deltaY: number): void {
|
|
34
|
-
if (!this.state.enabled || !this.enableRotate) return;
|
|
35
|
-
super.rotate(deltaX, deltaY);
|
|
36
|
-
this.rotationVelocity.x += deltaY;
|
|
37
|
-
this.rotationVelocity.y += deltaX;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
override pan(deltaX: number, deltaY: number): void {
|
|
41
|
-
if (!this.state.enabled || !this.enablePan) return;
|
|
42
|
-
super.pan(deltaX, deltaY);
|
|
43
|
-
this.panVelocity.x += deltaX;
|
|
44
|
-
this.panVelocity.y += deltaY;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
override dolly(scale: number): void {
|
|
48
|
-
if (!this.state.enabled || !this.enableZoom) return;
|
|
49
|
-
super.dolly(scale);
|
|
50
|
-
this.dollyVelocity += scale - 1;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
handleKey(code: TrackballKey): void {
|
|
54
|
-
switch (code) {
|
|
55
|
-
case "ArrowUp":
|
|
56
|
-
this.pan(0, this.keyPanSpeed);
|
|
57
|
-
break;
|
|
58
|
-
case "ArrowDown":
|
|
59
|
-
this.pan(0, -this.keyPanSpeed);
|
|
60
|
-
break;
|
|
61
|
-
case "ArrowLeft":
|
|
62
|
-
this.pan(-this.keyPanSpeed, 0);
|
|
63
|
-
break;
|
|
64
|
-
case "ArrowRight":
|
|
65
|
-
this.pan(this.keyPanSpeed, 0);
|
|
66
|
-
break;
|
|
67
|
-
case "KeyQ":
|
|
68
|
-
this.roll(-this.keyRollSpeed);
|
|
69
|
-
break;
|
|
70
|
-
case "KeyE":
|
|
71
|
-
this.roll(this.keyRollSpeed);
|
|
72
|
-
break;
|
|
73
|
-
case "NumpadAdd":
|
|
74
|
-
case "+":
|
|
75
|
-
case "=":
|
|
76
|
-
this.dolly(0.95);
|
|
77
|
-
break;
|
|
78
|
-
case "NumpadSubtract":
|
|
79
|
-
case "-":
|
|
80
|
-
case "_":
|
|
81
|
-
this.dolly(1.05);
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
update(deltaSeconds = 1 / 60): boolean {
|
|
87
|
-
if (!this.enableDamping) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
const damping = Math.max(0, Math.min(1, this.dampingFactor * deltaSeconds * 60));
|
|
91
|
-
const rotationStep = {
|
|
92
|
-
x: this.rotationVelocity.x * damping,
|
|
93
|
-
y: this.rotationVelocity.y * damping,
|
|
94
|
-
z: this.rotationVelocity.z * damping
|
|
95
|
-
};
|
|
96
|
-
const panStep = {
|
|
97
|
-
x: this.panVelocity.x * damping,
|
|
98
|
-
y: this.panVelocity.y * damping
|
|
99
|
-
};
|
|
100
|
-
const dollyStep = this.dollyVelocity * damping;
|
|
101
|
-
this.state.rotation.x += rotationStep.x;
|
|
102
|
-
this.state.rotation.y += rotationStep.y;
|
|
103
|
-
this.state.rotation.z += rotationStep.z;
|
|
104
|
-
this.state.target.x += panStep.x;
|
|
105
|
-
this.state.target.y += panStep.y;
|
|
106
|
-
this.state.position.z *= 1 + dollyStep;
|
|
107
|
-
this.rotationVelocity.x -= rotationStep.x;
|
|
108
|
-
this.rotationVelocity.y -= rotationStep.y;
|
|
109
|
-
this.rotationVelocity.z -= rotationStep.z;
|
|
110
|
-
this.panVelocity.x -= panStep.x;
|
|
111
|
-
this.panVelocity.y -= panStep.y;
|
|
112
|
-
this.dollyVelocity -= dollyStep;
|
|
113
|
-
return Math.abs(this.rotationVelocity.x) + Math.abs(this.rotationVelocity.y) + Math.abs(this.rotationVelocity.z) +
|
|
114
|
-
Math.abs(this.panVelocity.x) + Math.abs(this.panVelocity.y) + Math.abs(this.dollyVelocity) > 1e-6;
|
|
115
|
-
}
|
|
116
|
-
}
|
package/src/TransformControls.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { addVector3, type ControlObject3DLike, type Vector3Like } from "./NativeControlTypes";
|
|
2
|
-
|
|
3
|
-
export type TransformControlMode = "translate" | "rotate" | "scale";
|
|
4
|
-
|
|
5
|
-
export class TransformControls {
|
|
6
|
-
object: ControlObject3DLike | null = null;
|
|
7
|
-
mode: TransformControlMode = "translate";
|
|
8
|
-
|
|
9
|
-
attach(object: ControlObject3DLike): void { this.object = object; }
|
|
10
|
-
detach(): void { this.object = null; }
|
|
11
|
-
setMode(mode: TransformControlMode): void { this.mode = mode; }
|
|
12
|
-
|
|
13
|
-
apply(delta: Vector3Like): void {
|
|
14
|
-
if (!this.object) return;
|
|
15
|
-
if (this.mode === "translate") addVector3(this.object.position, delta);
|
|
16
|
-
if (this.mode === "rotate") addVector3(this.object.rotation, delta);
|
|
17
|
-
if (this.mode === "scale") addVector3(this.object.scale, delta);
|
|
18
|
-
}
|
|
19
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
export { OrbitControls } from "./OrbitControls";
|
|
2
|
-
export { TrackballControls } from "./TrackballControls";
|
|
3
|
-
export { FlyControls } from "./FlyControls";
|
|
4
|
-
export { FirstPersonControls } from "./FirstPersonControls";
|
|
5
|
-
export { MapControls } from "./MapControls";
|
|
6
|
-
export { PointerLockControls } from "./PointerLockControls";
|
|
7
|
-
export { DragControls } from "./DragControls";
|
|
8
|
-
export { TransformControls } from "./TransformControls";
|
|
9
|
-
export type { TransformControlMode } from "./TransformControls";
|
|
10
|
-
export { SelectionManager } from "./SelectionManager";
|
|
11
|
-
export { InteractionControls } from "./InteractionControls";
|
|
12
|
-
export type {
|
|
13
|
-
HotspotHandler,
|
|
14
|
-
InteractionControlMode,
|
|
15
|
-
InteractionControlsEvent,
|
|
16
|
-
InteractionControlsEventType,
|
|
17
|
-
InteractionControlsListener,
|
|
18
|
-
InteractionControlsOptions,
|
|
19
|
-
InteractionControlsUpdate,
|
|
20
|
-
InteractionRay,
|
|
21
|
-
InteractionRayProvider,
|
|
22
|
-
InteractionRootProvider
|
|
23
|
-
} from "./InteractionControls";
|
|
24
|
-
export { Picking } from "./Picking";
|
|
25
|
-
export type { PickingDiagnostics, PickingOptions, PickingReport, ThreeCompatPickResult } from "./Picking";
|
|
26
|
-
export {
|
|
27
|
-
annotationFromPickHit,
|
|
28
|
-
createDistrictPickingAnnotations,
|
|
29
|
-
createEntityPickingAnnotations,
|
|
30
|
-
createImportedGlbHotspotAnnotations,
|
|
31
|
-
createPickingAnnotationObject,
|
|
32
|
-
createPickingAnnotationRoot,
|
|
33
|
-
createRobotPickingAnnotations,
|
|
34
|
-
pickAnnotation,
|
|
35
|
-
pickScreenSpaceAnnotation
|
|
36
|
-
} from "./PickingAnnotations";
|
|
37
|
-
export type {
|
|
38
|
-
BuildingPickingDescriptor,
|
|
39
|
-
DistrictPickingDescriptor,
|
|
40
|
-
EntityPickingDescriptor,
|
|
41
|
-
ImportedGlbHotspotDescriptor,
|
|
42
|
-
PickingAnnotation,
|
|
43
|
-
PickingAnnotationHitPolicy,
|
|
44
|
-
PickingAnnotationKind,
|
|
45
|
-
PickingAnnotationObject,
|
|
46
|
-
PickingAnnotationOptions,
|
|
47
|
-
PickingAnnotationReport,
|
|
48
|
-
PickingAnnotationRoot,
|
|
49
|
-
PickingAnnotationSource,
|
|
50
|
-
ScreenPickingAnnotation,
|
|
51
|
-
ScreenPickingHit,
|
|
52
|
-
ScreenPickingOptions,
|
|
53
|
-
ScreenPickingReport
|
|
54
|
-
} from "./PickingAnnotations";
|
|
55
|
-
export { ControlVector3 } from "./NativeControlTypes";
|
|
56
|
-
export type { ControlObject3DLike, ControlPickMetadata, Vector3Like } from "./NativeControlTypes";
|
|
57
|
-
export { createDefaultControlState } from "./ControlState";
|
|
58
|
-
export type { ThreeCompatControlEvent, ThreeCompatControlState } from "./ControlState";
|