UNPKG

awv3

Version:
147 lines (131 loc) 6.22 kB
import * as THREE from 'three' import Object3 from '../../../three/object3' import View from '../../../core/view' export default class BaseGraphics extends THREE.Object3D { constructor(plugin, nLines = 0, nArcs = 0, nArrows = 0) { super() const colors = plugin.session.globals.colors this.lineGeometry = new THREE.CylinderBufferGeometry(1, 1, 1) this.lineMaterial = new THREE.MeshBasicMaterial({ color: colors.primary }) this.arcSegmentGeometry = new THREE.CylinderBufferGeometry(1, 1, 1, 4, 1) this.arcSegmentMaterial = new THREE.MeshBasicMaterial({ color: colors.primary }) this.arrowGeometry = new THREE.ConeBufferGeometry(1, 1) this.arrowGeometry.translate(0, -0.5, 0) this.arrowMaterial = new THREE.MeshBasicMaterial({ color: colors.primary }) this.arcSegments = 32 this.plugin = plugin this.handles = plugin.handlePrototypes.map(handlePrototype => new handlePrototype(plugin)) this.add(...this.handles) if (nLines) { this.lines = [] for (let i = 0; i < nLines; ++i) this.lines.push(new THREE.Mesh(this.lineGeometry, this.lineMaterial)) this.add(...this.lines) } if (nArcs) { this.arcs = [] for (let i = 0; i < nArcs; ++i) { this.arcs.push([]) for (let j = 0; j < this.arcSegments; ++j) this.arcs[i].push(new THREE.Mesh(this.arcSegmentGeometry, this.arcSegmentMaterial)) } this.add(...this.arcs) } if (nArrows) { this.arrows = [] for (let i = 0; i < nArrows; ++i) this.arrows.push(new THREE.Mesh(this.arrowGeometry, this.arrowMaterial)) this.add(...this.arrows) } this.dimPos2 = new THREE.Vector2() this.text = '' this.textNode = document.createElement('div') this.textNode.setAttribute( 'style', `position: absolute; display: inline-block; top: 0; left: 0; padding: 1px 2px; color: ${colors.primary}; font-size: 9px; pointer-events: none;`, ) this.userData.meta = {} for (let hdl of this.handles) hdl.type = 'DimensionHandle' this.handles[0].material.meta = {} this.destroyed = false this.viewFound().then(view => { if (this.destroyed) return view.dom.appendChild(this.textNode) this.createInteraction({ priority: 1000 }).on(Object3.Events.Lifecycle.Rendered, this.onRender.bind(this), { sync: false, }) }) } destroy() { this.destroyed = true if (this.textNode.parentElement) this.textNode.parentElement.removeChild(this.textNode) super.destroy() } onRender() { const position = this.handles[0].getWorldPosition() const scale = this.view.calculateScaleFactor(position, 1.0) for (let line of this.lines || []) line.scale.x = line.scale.z = scale for (let arc of this.arcs || []) for (let arcSegment of arc) arcSegment.scale.x = arcSegment.scale.z = scale for (let arrow of this.arrows || []) arrow.scale.set(7 * scale, 15 * scale, 7 * scale) const pos2 = this.view.getPoint2(position.clone()) if (!this.dimPos2.equals(pos2)) { this.dimPos2.copy(pos2) this.textNode.style.transform = `translate3d(${pos2.x + 15}px, calc(-50% + ${pos2.y - 15}px), 0)` } if (this.textNode.innerHTML !== this.handles[0].text) this.textNode.innerHTML = this.handles[0].text } updateLine(i, start, end) { const line = Number.isInteger(i) ? this.lines[i] : i // line.geometry describes a cylinder with axis from [0, -0.5, 0] to [0, 0.5, 0] and raidus 1 line.position.lerpVectors(start, end, 0.5) line.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), end.clone().sub(start).normalize()) line.scale.y = start.distanceTo(end) } updateArc(i, center, radius, startAngle, endAngle) { const arc = this.arcs[i] for (let j = 0; j < this.arcSegments; ++j) { const arcSegment = arc[j] const [sStartAngle, sEndAngle] = [j, j + 1].map(k => THREE.Math.lerp(startAngle, endAngle, k / this.arcSegments), ) const [start, end] = [sStartAngle, sEndAngle].map(angle => new THREE.Vector3(Math.cos(angle), Math.sin(angle), 0).multiplyScalar(radius).add(center), ) this.updateLine(arcSegment, start, end) } } updateArrow(i, end, dir) { const arrow = this.arrows[i] // arrow.geometry describes a cone with axis from [0, -1, 0] (r=1) to [0, 0, 0] (r=0) arrow.position.copy(end) arrow.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir.clone().normalize()) } updateCoordinateSystem(csys) { csys = csys.map(row => new THREE.Vector3().fromArray(row)) this.matrix.makeBasis(csys[1], csys[2], csys[3]) this.matrix.setPosition(csys[0]) this.matrix.decompose(this.position, this.quaternion, this.scale) this.matrixWorldNeedsUpdate = true this.updateMatrixWorld() } updateFromState(info) { this.textNode.style.display = info.visible ? 'inline-block' : 'none' this.visible = info.visible this.lastState = info this.userData.meta.id = info.dimension.id this.updateCoordinateSystem(info.dimension.coordinateSystem) for (let handle of this.handles) handle.updateFromState(info) this.handles[0].material.meta.id = info.dimension.id this.handles[0].material.meta.box = this.handles[0].updateBounds().bounds.box const colors = this.plugin.session.globals.colors this.lineMaterial.color = new THREE.Color(colors.primary) this.arcSegmentMaterial.color = new THREE.Color(colors.primary) this.arrowMaterial.color = new THREE.Color(colors.primary) this.textNode.style.color = colors.primary this.onRender() this.view.invalidate() } }