UNPKG

web-ifc-viewer

Version:
253 lines 8.82 kB
import { ConeGeometry, LineDashedMaterial, MeshBasicMaterial, Vector3 } from 'three'; import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'; import { IfcComponent } from '../../../base-types'; import { IfcDimensionLine } from './dimension-line'; export class IfcDimensions extends IfcComponent { constructor(context) { super(context); this.dimensions = []; this.labelClassName = 'ifcjs-dimension-label'; this.previewClassName = 'ifcjs-dimension-preview'; // State this.enabled = false; this.preview = false; this.dragging = false; this.snapDistance = 0.25; // Measures this.baseScale = new Vector3(1, 1, 1); // Materials this.lineMaterial = new LineDashedMaterial({ color: 0x000000, linewidth: 2, depthTest: false, dashSize: 0.2, gapSize: 0.2 }); this.endpointsMaterial = new MeshBasicMaterial({ color: 0x000000, depthTest: false }); // Temp variables this.startPoint = new Vector3(); this.endPoint = new Vector3(); this.context = context; this.endpoint = IfcDimensions.getDefaultEndpointGeometry(); const htmlPreview = document.createElement('div'); htmlPreview.className = this.previewClassName; this.previewElement = new CSS2DObject(htmlPreview); this.previewElement.visible = false; } dispose() { this.context = null; this.dimensions.forEach((dim) => dim.dispose()); this.dimensions = null; this.currentDimension = null; this.endpoint.dispose(); this.endpoint = null; this.previewElement.removeFromParent(); this.previewElement.element.remove(); this.previewElement = null; } update(_delta) { if (this.enabled && this.preview) { const intersects = this.context.castRayIfc(); this.previewElement.visible = !!intersects; if (!intersects) return; this.previewElement.visible = true; const closest = this.getClosestVertex(intersects); this.previewElement.visible = !!closest; if (!closest) return; this.previewElement.position.set(closest.x, closest.y, closest.z); if (this.dragging) { this.drawInProcess(); } } } // TODO: This causes a memory leak, and it's a bit confusing setArrow(height, radius) { this.endpoint = IfcDimensions.getDefaultEndpointGeometry(height, radius); } setPreviewElement(element) { this.previewElement = new CSS2DObject(element); } get active() { return this.enabled; } get previewActive() { return this.preview; } get previewObject() { return this.previewElement; } set previewActive(state) { this.preview = state; const scene = this.context.getScene(); if (this.preview) { scene.add(this.previewElement); } else { scene.remove(this.previewElement); } } set active(state) { this.enabled = state; this.dimensions.forEach((dim) => { dim.visibility = state; }); } set dimensionsColor(color) { this.endpointsMaterial.color = color; this.lineMaterial.color = color; } set dimensionsWidth(width) { this.lineMaterial.linewidth = width; } set endpointGeometry(geometry) { this.dimensions.forEach((dim) => { dim.endpointGeometry = geometry; }); } set endpointScaleFactor(factor) { IfcDimensionLine.scaleFactor = factor; } set endpointScale(scale) { this.baseScale = scale; this.dimensions.forEach((dim) => { dim.endpointScale = scale; }); } create() { if (!this.enabled) return; if (!this.dragging) { this.drawStart(); return; } this.drawEnd(); } createInPlane(plane) { if (!this.enabled) return; if (!this.dragging) { this.drawStartInPlane(plane); return; } this.drawEnd(); } delete() { if (!this.enabled || this.dimensions.length === 0) return; const boundingBoxes = this.getBoundingBoxes(); const intersects = this.context.castRay(boundingBoxes); if (intersects.length === 0) return; const selected = this.dimensions.find((dim) => dim.boundingBox === intersects[0].object); if (!selected) return; const index = this.dimensions.indexOf(selected); this.dimensions.splice(index, 1); selected.removeFromScene(); } deleteAll() { this.dimensions.forEach((dim) => { dim.removeFromScene(); }); this.dimensions = []; } cancelDrawing() { var _a; if (!this.currentDimension) return; this.dragging = false; (_a = this.currentDimension) === null || _a === void 0 ? void 0 : _a.removeFromScene(); this.currentDimension = undefined; } drawStart() { this.dragging = true; const intersects = this.context.castRayIfc(); if (!intersects) return; const found = this.getClosestVertex(intersects); if (!found) return; this.startPoint = found; } drawStartInPlane(plane) { this.dragging = true; const intersects = this.context.castRay([plane]); if (!intersects || intersects.length < 1) return; this.startPoint = intersects[0].point; } drawInProcess() { const intersects = this.context.castRayIfc(); if (!intersects) return; const found = this.getClosestVertex(intersects); if (!found) return; this.endPoint = found; if (!this.currentDimension) this.currentDimension = this.drawDimension(); this.currentDimension.endPoint = this.endPoint; } drawEnd() { if (!this.currentDimension) return; this.currentDimension.createBoundingBox(); this.dimensions.push(this.currentDimension); this.currentDimension = undefined; this.dragging = false; } get getDimensionsLines() { return this.dimensions; } drawDimension() { return new IfcDimensionLine(this.context, this.startPoint, this.endPoint, this.lineMaterial, this.endpointsMaterial, this.endpoint, this.labelClassName, this.baseScale); } getBoundingBoxes() { return this.dimensions .map((dim) => dim.boundingBox) .filter((box) => box !== undefined); } static getDefaultEndpointGeometry(height = 0.1, radius = 0.03) { const coneGeometry = new ConeGeometry(radius, height); coneGeometry.translate(0, -height / 2, 0); coneGeometry.rotateX(-Math.PI / 2); return coneGeometry; } getClosestVertex(intersects) { let closestVertex = new Vector3(); let vertexFound = false; let closestDistance = Number.MAX_SAFE_INTEGER; const vertices = this.getVertices(intersects); vertices === null || vertices === void 0 ? void 0 : vertices.forEach((vertex) => { if (!vertex) return; const distance = intersects.point.distanceTo(vertex); if (distance > closestDistance || distance > this.snapDistance) return; vertexFound = true; closestVertex = vertex; closestDistance = intersects.point.distanceTo(vertex); }); return vertexFound ? closestVertex : intersects.point; } getVertices(intersects) { const mesh = intersects.object; if (!intersects.face || !mesh) return null; const geom = mesh.geometry; return [ this.getVertex(intersects.face.a, geom), this.getVertex(intersects.face.b, geom), this.getVertex(intersects.face.c, geom) ]; } getVertex(index, geom) { if (index === undefined) return null; const vertices = geom.attributes.position; return new Vector3(vertices.getX(index), vertices.getY(index), vertices.getZ(index)); } } //# sourceMappingURL=dimensions.js.map