awv3
Version:
⚡ AWV3 embedded CAD
147 lines (131 loc) • 6.22 kB
JavaScript
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()
}
}