UNPKG

awv3

Version:
226 lines (200 loc) 9.15 kB
import cloneDeep from 'lodash/cloneDeep' import * as THREE from 'three' import Object3 from '../../three/object3' export class Handle extends THREE.Mesh { constructor(geometry, material) { super(geometry, material) this.createInteraction({ priority: 1000, types: ['DimensionHandle'] }) for (let category of Object.values(Object3.Events)) for (let event of Object.values(category)) if (this[event]) this.on(event, this[event].bind(this), { sync: true }) this.text = undefined } [Object3.Events.Interaction.Hovered](hitObject) { this.view.setCursor('grab') if (this.parent.plugin.selector) this.parent.plugin.selector.hover(hitObject) else this.animate({ material: { color: new THREE.Color(this.colors.accent), opacity: 0.6 } }).start(0) } [Object3.Events.Interaction.Unhovered](hitObject) { if (this.parent.plugin.selector) this.parent.plugin.selector.unhover(hitObject) else this.animate({ material: { color: new THREE.Color(this.colors.primary), opacity: 0.3 } }).start(1000) } [Object3.Events.Interaction.Picked](hitObject) { this.view.controls.enabled = false } [Object3.Events.Interaction.Dragged](hitObject) { this.view.setCursor('grabbing') const ray = hitObject.ray.clone().applyMatrix4(new THREE.Matrix4().getInverse(this.parent.matrixWorld)) const position = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1))) this.onDrag(this.info, position) this.parent.updateFromState(this.info) } [Object3.Events.Interaction.Dropped](hitObject) { this.view.setCursor('grab') this.view.controls.enabled = true this.onDrop(this.info) this.parent.plugin.afterSetCallback() } [Object3.Events.Interaction.Clicked](hitObject) { if (this.parent.plugin.selector) this.parent.plugin.selector.clicked(hitObject) } [Object3.Events.Interaction.Missed](hitObject) { if (this.parent.plugin.selector) this.parent.plugin.selector.missed(hitObject) } [Object3.Events.Lifecycle.Rendered]() { const scale = this.view.calculateScaleFactor(this.getWorldPosition(), 1) this.onScale(scale) } // called when the dimension state changes, should update meshes updateFromState(info) { this.info = info this.colors = this.parent.plugin.session.globals.colors this.material.color = new THREE.Color(this.colors.primary) this.visible = info.visible let textParts = [] if (!info.dimension.members.paramName.value.startsWith('_')) textParts.push(info.dimension.members.paramName.value) const num = info.dimension.previewValue !== undefined ? info.dimension.previewValue : info.dimension.id ? info.value : undefined if (num !== undefined) textParts.push(Number.isInteger(num) ? String(num) : num.toFixed(2)) this.text = textParts.join(' ') } // called from Object3.Events.Interaction.Dragged/Dropped, should update state from position onDrag(info, position) {} // called from Object3.Events.Interaction.Dropped, should send state update to the server onDrop(info) {} // called from Object3.Events.Lifecycle.Rendered, should scale meshes onScale(scale) {} } export class PositionHandle extends Handle { constructor(plugin) { const colors = plugin.session.globals.colors super( new THREE.SphereBufferGeometry(1, 16, 16), new THREE.MeshBasicMaterial({ color: colors.primary, transparent: true, opacity: 0.3 }), ) this.colors = colors } updateFromState(info) { super.updateFromState(info) this.position.fromArray(info.dimension.members.dimPt.value) } onDrag(info, position) { position.toArray(info.dimension.members.dimPt.value) } onDrop(info) { info.dimPt = `{${info.dimension.members.dimPt.value.join(', ')}}` } onScale(scale) { this.scale.setScalar(7 * scale) } } export class ValueHandle extends Handle { constructor(plugin) { const colors = plugin.session.globals.colors super( new THREE.SphereBufferGeometry(1.5, 16, 16), new THREE.MeshBasicMaterial({ color: colors.primary, transparent: true, opacity: 0.3 }), ) this.colors = colors } updateFromState(info) { super.updateFromState(info) const dimension = info.dimension const [start, end, dim, corner, center] = ['startPt', 'endPt', 'dimPt', 'cornerPt', 'center'].map(x => new THREE.Vector3().fromArray((dimension.members[x] || { value: [0, 0, 0] }).value), ) const nearend = (dimension.members.valHandlePos || {}).value ? start : end switch (dimension.class) { case 'CC_AngularDimension': case 'CC_AngularFeatureDimension': this.position.copy(nearend).sub(corner).setLength(corner.distanceTo(dim)).add(corner) break case 'CC_LinearDimension': case 'CC_LinearFeatureDimension': let d = new THREE.Vector3( Math.cos(dimension.members.angle.value), Math.sin(dimension.members.angle.value), 0, ) this.position.copy(nearend).sub(dim).projectOnVector(d).add(dim) break case 'CC_RadialDimension': case 'CC_RadialFeatureDimension': case 'CC_DiameterDimension': case 'CC_DiameterFeatureDimension': this.position.copy(dim).sub(center).setLength(dimension.members.radius.value).add(center) break } this.visible = (dimension.members.isDriven || { value: 0 }).value === 0 } onDrag({ dimension, angle: hasAngle }, position) { const [start, end, dim, corner, center] = ['startPt', 'endPt', 'dimPt', 'cornerPt', 'center'].map(x => new THREE.Vector3().fromArray((dimension.members[x] || { value: [0, 0, 0] }).value), ) const [nearend, farend] = (dimension.members.valHandlePos || {}).value ? [start, end] : [end, start] switch (dimension.class) { case 'CC_AngularDimension': case 'CC_AngularFeatureDimension': const toPolar = v => v.sub(corner).set(Math.atan2(v.y, v.x), v.length(), 0) const fromPolar = v => v.set(v.y * Math.cos(v.x), v.y * Math.sin(v.x), 0).add(corner) toPolar(nearend) toPolar(farend) const diffAng = toPolar(position).x - nearend.x nearend.x += diffAng if (dimension.members.valHandleBehaviour.value) farend.x -= diffAng let angle = (nearend.x - farend.x) % (2 * Math.PI) fromPolar(nearend) fromPolar(farend) start.toArray(dimension.members.startPt.value) end.toArray(dimension.members.endPt.value) if (!Boolean(dimension.members.ccw.value) ^ Boolean(dimension.members.valHandlePos.value)) angle = -angle if (angle < 0) angle += 2 * Math.PI if (hasAngle) angle = THREE.Math.radToDeg(angle) dimension.previewValue = angle break case 'CC_LinearDimension': case 'CC_LinearFeatureDimension': let d = new THREE.Vector3( Math.cos(dimension.members.angle.value), Math.sin(dimension.members.angle.value), 0, ) const diff = position.clone().sub(nearend).projectOnVector(d) nearend.add(diff) if (dimension.members.valHandleBehaviour.value) farend.sub(diff) start.toArray(dimension.members.startPt.value) end.toArray(dimension.members.endPt.value) dimension.previewValue = Math.abs(end.clone().sub(start).dot(d)) break case 'CC_RadialDimension': case 'CC_RadialFeatureDimension': dimension.members.radius.value = center.distanceTo(position) dimension.previewValue = dimension.members.radius.value break case 'CC_DiameterDimension': case 'CC_DiameterFeatureDimension': dimension.members.radius.value = center.distanceTo(position) dimension.previewValue = 2 * dimension.members.radius.value break } } onDrop(info) { info.expression = info.dimension.previewValue.toFixed(2) } onScale(scale) { this.scale.setScalar(7 * scale) } } export class PositionValueHandle extends ValueHandle { onDrag(info, position) { position.toArray(info.dimension.members.dimPt.value) super.onDrag(info, position) } onDrop(info) { info.dimPt = `{${info.members.dimPt.value.join(', ')}}` super.onDrop(info) } }