src/plugins/FaceAlignedSectionPlanesPlugin/Overview.js
import {math} from "../../viewer/scene/math/math.js";
import {Scene} from "../../viewer/scene/scene/Scene.js";
import {DirLight} from "./../../viewer/scene/lights/DirLight.js";
import {Plane} from "./Plane.js";
/**
* @desc An interactive 3D overview for navigating the {@link SectionPlane}s created by its {@link FaceAlignedSectionPlanesPlugin}.
*
* * Located at {@link FaceAlignedSectionPlanesPlugin#overview}.
* * Renders the overview on a separate canvas at a corner of the {@link Viewer}'s {@link Scene} {@link Canvas}.
* * The overview shows a 3D plane object for each {@link SectionPlane} in the {@link Scene}.
* * Click a plane object in the overview to toggle the visibility of a 3D gizmo to edit the position and orientation of its {@link SectionPlane}.
*
* @private
*/
export class Overview {
/**
* @private
*/
constructor(plugin, cfg) {
if (!cfg.onHoverEnterPlane || !cfg.onHoverLeavePlane || !cfg.onClickedNothing || !cfg.onClickedPlane) {
throw "Missing config(s): onHoverEnterPlane, onHoverLeavePlane, onClickedNothing || onClickedPlane";
}
/**
* The {@link FaceAlignedSectionPlanesPlugin} that owns this SectionPlanesOverview.
*
* @type {FaceAlignedSectionPlanesPlugin}
*/
this.plugin = plugin;
this._viewer = plugin.viewer;
this._onHoverEnterPlane = cfg.onHoverEnterPlane;
this._onHoverLeavePlane = cfg.onHoverLeavePlane;
this._onClickedNothing = cfg.onClickedNothing;
this._onClickedPlane = cfg.onClickedPlane;
this._visible = true;
this._planes = {};
//--------------------------------------------------------------------------------------------------------------
// Init canvas
//--------------------------------------------------------------------------------------------------------------
this._canvas = cfg.overviewCanvas;
//--------------------------------------------------------------------------------------------------------------
// Init scene
//--------------------------------------------------------------------------------------------------------------
this._scene = new Scene(this._viewer, {
canvasId: this._canvas.id,
transparent: true
});
this._scene.clearLights();
new DirLight(this._scene, {
dir: [0.4, -0.4, 0.8],
color: [0.8, 1.0, 1.0],
intensity: 1.0,
space: "view"
});
new DirLight(this._scene, {
dir: [-0.8, -0.3, -0.4],
color: [0.8, 0.8, 0.8],
intensity: 1.0,
space: "view"
});
new DirLight(this._scene, {
dir: [0.8, -0.6, -0.8],
color: [1.0, 1.0, 1.0],
intensity: 1.0,
space: "view"
});
this._scene.camera;
this._scene.camera.perspective.fov = 70;
this._zUp = false;
//--------------------------------------------------------------------------------------------------------------
// Synchronize overview scene camera with viewer camera
//--------------------------------------------------------------------------------------------------------------
{
const camera = this._scene.camera;
const matrix = math.rotationMat4c(-90 * math.DEGTORAD, 1, 0, 0);
const eyeLookVec = math.vec3();
const eyeLookVecOverview = math.vec3();
const upOverview = math.vec3();
this._synchCamera = () => {
const eye = this._viewer.camera.eye;
const look = this._viewer.camera.look;
const up = this._viewer.camera.up;
math.mulVec3Scalar(math.normalizeVec3(math.subVec3(eye, look, eyeLookVec)), 7);
if (this._zUp) { // +Z up
math.transformVec3(matrix, eyeLookVec, eyeLookVecOverview);
math.transformVec3(matrix, up, upOverview);
camera.look = [0, 0, 0];
camera.eye = math.transformVec3(matrix, eyeLookVec, eyeLookVecOverview);
camera.up = math.transformPoint3(matrix, up, upOverview);
} else { // +Y up
camera.look = [0, 0, 0];
camera.eye = eyeLookVec;
camera.up = up;
}
};
}
this._onViewerCameraMatrix = this._viewer.camera.on("matrix", this._synchCamera);
this._onViewerCameraWorldAxis = this._viewer.camera.on("worldAxis", this._synchCamera);
this._onViewerCameraFOV = this._viewer.camera.perspective.on("fov", (fov) => {
this._scene.camera.perspective.fov = fov;
});
//--------------------------------------------------------------------------------------------------------------
// Bind overview canvas events
//--------------------------------------------------------------------------------------------------------------
{
var hoveredEntity = null;
this._onInputMouseMove = this._scene.input.on("mousemove", (coords) => {
const hit = this._scene.pick({
canvasPos: coords
});
if (hit) {
if (!hoveredEntity || hit.entity.id !== hoveredEntity.id) {
if (hoveredEntity) {
const plane = this._planes[hoveredEntity.id];
if (plane) {
this._onHoverLeavePlane(hoveredEntity.id);
}
}
hoveredEntity = hit.entity;
const plane = this._planes[hoveredEntity.id];
if (plane) {
this._onHoverEnterPlane(hoveredEntity.id);
}
}
} else {
if (hoveredEntity) {
this._onHoverLeavePlane(hoveredEntity.id);
hoveredEntity = null;
}
}
});
this._scene.canvas.canvas.addEventListener("mouseup", this._onCanvasMouseUp = () => {
if (hoveredEntity) {
const plane = this._planes[hoveredEntity.id];
if (plane) {
this._onClickedPlane(hoveredEntity.id);
}
} else {
this._onClickedNothing();
}
});
this._scene.canvas.canvas.addEventListener("mouseout", this._onCanvasMouseOut = () => {
if (hoveredEntity) {
this._onHoverLeavePlane(hoveredEntity.id);
hoveredEntity = null;
}
});
}
//--------------------------------------------------------------------------------------------------------------
// Configure overview
//--------------------------------------------------------------------------------------------------------------
this.setVisible(cfg.overviewVisible);
}
/** Called by SectionPlanesPlugin#createSectionPlane()
* @private
*/
addSectionPlane(sectionPlane) {
this._planes[sectionPlane.id] = new Plane(this, this._scene, sectionPlane);
}
/** @private
*/
setPlaneHighlighted(id, highlighted) {
const plane = this._planes[id];
if (plane) {
plane.setHighlighted(highlighted);
}
}
/** @private
*/
setPlaneSelected(id, selected) {
const plane = this._planes[id];
if (plane) {
plane.setSelected(selected);
}
}
/** @private
*/
removeSectionPlane(sectionPlane) {
const plane = this._planes[sectionPlane.id];
if (plane) {
plane.destroy();
delete this._planes[sectionPlane.id];
}
}
/**
* Sets if this SectionPlanesOverview is visible.
*
* @param {Boolean} visible Whether or not this SectionPlanesOverview is visible.
*/
setVisible(visible = true) {
this._visible = visible;
this._canvas.style.visibility = visible ? "visible" : "hidden";
}
/**
* Gets if this SectionPlanesOverview is visible.
*
* @return {Boolean} True when this SectionPlanesOverview is visible.
*/
getVisible() {
return this._visible;
}
/** @private
*/
destroy() {
this._viewer.camera.off(this._onViewerCameraMatrix);
this._viewer.camera.off(this._onViewerCameraWorldAxis);
this._viewer.camera.perspective.off(this._onViewerCameraFOV);
this._scene.input.off(this._onInputMouseMove);
this._scene.canvas.canvas.removeEventListener("mouseup", this._onCanvasMouseUp);
this._scene.canvas.canvas.removeEventListener("mouseout", this._onCanvasMouseOut);
this._scene.destroy();
}
}