angular-3d-viewer
Version:
274 lines (237 loc) • 7.06 kB
JavaScript
import { RGBColor } from '../model/color.js';
import { ConvertColorToThreeColor, DisposeThreeObjects } from '../threejs/threeutils.js';
import * as THREE from 'three';
export function SetThreeMeshPolygonOffset (mesh, offset)
{
function SetMaterialsPolygonOffset (materials, offset)
{
for (let material of materials) {
material.polygonOffset = offset;
material.polygonOffsetUnit = 1;
material.polygonOffsetFactor = 1;
}
}
SetMaterialsPolygonOffset (mesh.material, offset);
if (mesh.userData.threeMaterials) {
SetMaterialsPolygonOffset (mesh.userData.threeMaterials, offset);
}
}
export class ViewerModel
{
constructor (scene)
{
this.scene = scene;
this.rootObject = null;
}
IsEmpty ()
{
return this.rootObject === null;
}
SetRootObject (rootObject)
{
if (this.rootObject !== null) {
this.Clear ();
}
this.rootObject = rootObject;
this.scene.add (this.rootObject);
}
GetRootObject ()
{
return this.rootObject;
}
AddObject (object)
{
if (this.rootObject === null) {
let newRootObject = new THREE.Object3D ();
this.SetRootObject (newRootObject);
}
this.rootObject.add (object);
}
Traverse (enumerator)
{
if (this.rootObject === null) {
return;
}
this.rootObject.traverse ((obj) => {
enumerator (obj);
});
}
UpdateWorldMatrix ()
{
if (this.rootObject !== null) {
this.rootObject.updateWorldMatrix (true, true);
}
}
Clear ()
{
DisposeThreeObjects (this.rootObject);
this.scene.remove (this.rootObject);
this.rootObject = null;
}
}
/**
* Edge settings object.
*/
export class EdgeSettings
{
/**
* @param {boolean} showEdges Show edges.
* @param {RGBColor} edgeColor Color of the edges.
* @param {number} edgeThreshold Minimum angle between faces to show edges between them in.
* The value must be in degrees.
*/
constructor (showEdges, edgeColor, edgeThreshold)
{
this.showEdges = showEdges;
this.edgeColor = edgeColor;
this.edgeThreshold = edgeThreshold;
}
/**
* Creates a clone of the object.
* @returns {EdgeSettings}
*/
Clone ()
{
return new EdgeSettings (this.showEdges, this.edgeColor.Clone (), this.edgeThreshold);
}
}
export class ViewerMainModel
{
constructor (scene)
{
this.scene = scene;
this.mainModel = new ViewerModel (this.scene);
this.edgeModel = new ViewerModel (this.scene);
this.edgeSettings = new EdgeSettings (false, new RGBColor (0, 0, 0), 1);
}
SetMainObject (mainObject)
{
this.mainModel.SetRootObject (mainObject);
if (this.edgeSettings.showEdges) {
this.GenerateEdgeModel ();
}
}
UpdateWorldMatrix ()
{
this.mainModel.UpdateWorldMatrix ();
this.edgeModel.UpdateWorldMatrix ();
}
SetEdgeSettings (edgeSettings)
{
let needToGenerate = false;
if (edgeSettings.showEdges && (!this.edgeSettings.showEdges || this.edgeSettings.edgeThreshold !== edgeSettings.edgeThreshold)) {
needToGenerate = true;
}
this.edgeSettings = edgeSettings;
if (this.mainModel.IsEmpty ()) {
return;
}
if (this.edgeSettings.showEdges) {
if (needToGenerate) {
this.ClearEdgeModel ();
this.GenerateEdgeModel ();
} else {
let edgeColor = ConvertColorToThreeColor (this.edgeSettings.edgeColor);
this.EnumerateEdges ((edge) => {
edge.material.color = edgeColor;
});
}
} else {
this.ClearEdgeModel ();
}
}
GenerateEdgeModel ()
{
let edgeColor = ConvertColorToThreeColor (this.edgeSettings.edgeColor);
this.UpdateWorldMatrix ();
this.EnumerateMeshes ((mesh) => {
SetThreeMeshPolygonOffset (mesh, true);
let edges = new THREE.EdgesGeometry (mesh.geometry, this.edgeSettings.edgeThreshold);
let line = new THREE.LineSegments (edges, new THREE.LineBasicMaterial ({
color: edgeColor
}));
line.applyMatrix4 (mesh.matrixWorld);
line.userData = mesh.userData;
line.visible = mesh.visible;
this.edgeModel.AddObject (line);
});
}
GetBoundingBox (needToProcess)
{
let hasMesh = false;
let boundingBox = new THREE.Box3 ();
this.EnumerateMeshes ((mesh) => {
if (needToProcess (mesh.userData)) {
boundingBox.union (new THREE.Box3 ().setFromObject (mesh));
hasMesh = true;
}
});
if (!hasMesh) {
return null;
}
return boundingBox;
}
GetBoundingSphere (needToProcess)
{
let boundingBox = this.GetBoundingBox (needToProcess);
if (boundingBox === null) {
return null;
}
let boundingSphere = new THREE.Sphere ();
boundingBox.getBoundingSphere (boundingSphere);
return boundingSphere;
}
Clear ()
{
this.mainModel.Clear ();
this.ClearEdgeModel ();
}
ClearEdgeModel ()
{
if (this.edgeModel.IsEmpty ()) {
return;
}
this.EnumerateMeshes ((mesh) => {
SetThreeMeshPolygonOffset (mesh, false);
});
this.edgeModel.Clear ();
}
EnumerateMeshes (enumerator)
{
this.mainModel.Traverse ((obj) => {
if (obj.isMesh) {
enumerator (obj);
}
});
}
EnumerateEdges (enumerator)
{
this.edgeModel.Traverse ((obj) => {
if (obj.isLineSegments) {
enumerator (obj);
}
});
}
GetMeshIntersectionUnderMouse (mouseCoords, camera, width, height)
{
if (this.mainModel.IsEmpty ()) {
return null;
}
if (mouseCoords.x < 0.0 || mouseCoords.x > width || mouseCoords.y < 0.0 || mouseCoords.y > height) {
return null;
}
let raycaster = new THREE.Raycaster ();
let mousePos = new THREE.Vector2 ();
mousePos.x = (mouseCoords.x / width) * 2 - 1;
mousePos.y = -(mouseCoords.y / height) * 2 + 1;
raycaster.setFromCamera (mousePos, camera);
let iSectObjects = raycaster.intersectObject (this.mainModel.GetRootObject (), true);
for (let i = 0; i < iSectObjects.length; i++) {
let iSectObject = iSectObjects[i];
if (iSectObject.object.isMesh && iSectObject.object.visible) {
return iSectObject;
}
}
return null;
}
}