@speckle/viewer
Version:
A 3d viewer for Speckle, based on threejs.
220 lines (219 loc) • 7.6 kB
TypeScript
import { Group, Box3, BufferGeometry, Mesh, Vector3, Plane, Raycaster, Object3D, Matrix4, Vector2, Face, PlaneGeometry } from 'three';
import { TransformControls } from '../TransformControls.js';
import { OBB } from 'three/examples/jsm/math/OBB.js';
import { type IViewer } from '../../../IViewer.js';
import { CameraController } from '../CameraController.js';
import { Vector3Like } from '../../batching/BatchObject.js';
import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2.js';
import SpeckleStandardMaterial from '../../materials/SpeckleStandardMaterial.js';
import { Extension } from '../Extension.js';
export declare enum SectionToolEvent {
DragStart = "section-box-drag-start",
DragEnd = "section-box-drag-end",
Updated = "section-box-changed"
}
export interface SectionToolEventPayload {
[]: void;
[]: void;
[]: Plane[];
}
export declare class SectionTool extends Extension {
protected cameraProvider: CameraController;
get inject(): (typeof CameraController)[];
/** This is our data model. All we need is an OBB */
protected obb: OBB;
/** The planes that will send out as clipping planes */
protected planes: Plane[];
/** The six planes of the unit cube */
protected localPlanes: Plane[];
/** Convenience LUT for when clicking on the box faces */
protected cubeFaces: {
'256': {
verts: number[];
axis: string;
normal: Vector3;
};
'152': {
verts: number[];
axis: string;
normal: Vector3;
};
'407': {
verts: number[];
axis: string;
normal: Vector3;
};
'703': {
verts: number[];
axis: string;
normal: Vector3;
};
'327': {
verts: number[];
axis: string;
normal: Vector3;
};
'726': {
verts: number[];
axis: string;
normal: Vector3;
};
'450': {
verts: number[];
axis: string;
normal: Vector3;
};
'051': {
verts: number[];
axis: string;
normal: Vector3;
};
'312': {
verts: number[];
axis: string;
normal: Vector3;
};
'013': {
verts: number[];
axis: string;
normal: Vector3;
};
'546': {
verts: number[];
axis: string;
normal: Vector3;
};
'647': {
verts: number[];
axis: string;
normal: Vector3;
};
};
/** The root object */
protected display: Group;
/** We only use this for hit testing to select it's faces */
protected boxHitMesh: Mesh;
/** The displayed box as an outline */
protected boxOutline: LineSegments2;
/** Mesh that gets shown across a box face when it gets selected */
protected facePlane: Mesh;
/** Anchor objects for the controls. Not displayable */
protected translationRotationAnchor: Object3D;
protected scaleAnchor: Object3D;
/** Controls instances */
protected translateControls: TransformControls;
protected rotateControls: TransformControls;
protected scaleControls: TransformControls;
/** Sum state */
protected lastScale: Vector3 | null;
protected lastObbTransform: Matrix4;
protected draggingFace: Face | null;
/** Hit testing related */
protected raycaster: Raycaster;
protected dragging: boolean;
/** Manadatory property for all extensions */
get enabled(): boolean;
set enabled(value: boolean);
/** Hides all controls and the box outline but keeps the sections enabled */
get visible(): boolean;
set visible(value: boolean);
/** Gets the up to date section planes */
get sectionPlanes(): Plane[];
/**
*
*/
constructor(viewer: IViewer, cameraProvider: CameraController);
/**
*
*/
/** We use the viewer's frame update to enable/disable the translate and rotate controls
* The controls were not meant to be overlayed and working in multiple instance setups
* so their input events overlap. It's not the best solution in the world, but it's one
* that requires little to no source change
*/
onEarlyUpdate(): void;
/** Explicit events for the selection tool */
on<T extends SectionToolEvent>(eventType: T, listener: (arg: SectionToolEventPayload[T]) => void): void;
/** Gets the OBB model */
getBox(): OBB;
/**
* Sets the OBB model and updates the tool gizmos and box
* @param targetBox The box to set. It accepts an aabb as well
* @param offset Optional offset
*/
setBox(targetBox: OBB | Box3 | {
min: Vector3Like;
max: Vector3Like;
}, offset?: number): void;
/**
* Convenience method
*/
toggle(): void;
/** Gets the transformation defined by the OBB */
getObbTransform(): Matrix4;
/**
* Creates the controls and all their gizmos
*/
protected setupControls(): void;
/**
* Controls, outline and hitbox update based on the OBB model
*/
protected updateVisual(): void;
/**
* Triggers when dragging starts/stops
* @param event Controls event
*/
protected draggingHandler(event: any): void;
/** Triggers whenever there is a change in the controls and their gizmos
* This is where the model OBB gets updated according to controls changes.
* Each control type writes it's data in the anchor's matching property. So:
* - Translate control write to it's anchor 'position'
* - Rotate control writes to it's anchor 'quaternion'
* - Scale control writes to it's anchor 'scale
*/
protected changeHandler(): void;
/**
* Handler used for detecting when we click on the box faces
* @param args NDC pointer coords + original event + multiselect
* @returns
*/
protected clickHandler(args: Vector2 & {
event: PointerEvent;
multiSelect: boolean;
}): void;
/**
* Computes the final box planes from the unit cube planes
* transformed against the current OBB model
*/
protected updatePlanes(): void;
/**
* Creates the plane mesh that will be shown when selecting a box face
* It's RTE enabled
*/
protected createFacePlane(): Mesh<PlaneGeometry, SpeckleStandardMaterial>;
/**
* Updates the scale control and plane mesh when a cube face is selected
* @param face The face we're pulling/pushing
* @returns void
*/
protected updateFaceControls(face: Face | null): void;
/** Creates the geometry for the visible outline of the section tool */
protected createOutline(): LineSegments2;
/** Updates the section tool outline by updating it's vertices
* We chose to do it this way in order have RTE working
*/
protected updateOutline(): void;
/** Creates a unit cube geometry instance*/
protected createCubeGeometry(): BufferGeometry;
/** Restes the gizmos. Honestly not sure if it does anything meaningfull */
protected reset(): void;
/** Type guards */
protected isAABB(box: Box3 | {
min: Vector3Like;
max: Vector3Like;
} | OBB): box is Box3;
protected isOBB(box: Box3 | {
min: Vector3Like;
max: Vector3Like;
} | OBB): box is OBB;
}