123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /*
- * PlaceTool.js
- *
- * @author realor
- */
- import { Tool } from './Tool.js'
- import { Controls } from '../ui/Controls.js'
- import { I18N } from '../i18n/I18N.js'
- import { GeometryUtils } from '../utils/GeometryUtils.js'
- import * as THREE from '../lib/three.module.js'
- class PlaceTool extends Tool {
- static CHANGED_PROPERTIES = ['position', 'rotation']
- static GLOBAL_MODE = 0
- static LOCAL_MODE = 1
- static PERPENDICULAR_MODE = 2
- constructor(application, options) {
- super(application)
- this.name = 'place'
- this.label = 'tool.place.label'
- this.help = 'tool.place.help'
- this.className = 'place'
- this.setOptions(options)
- this.stage = 0
- this.snap = null
- this.mode = 0
- this.localMatrix = new THREE.Matrix4()
- this.axisMatrixWorld = new THREE.Matrix4()
- this._onPointerDown = this.onPointerDown.bind(this)
- this._onPointerUp = this.onPointerUp.bind(this)
- this._onPointerMove = this.onPointerMove.bind(this)
- this._onContextMenu = this.onContextMenu.bind(this)
- this.createPanel()
- }
- createPanel() {
- this.panel = this.application.createPanel(this.label, 'left', 'panel_place')
- this.panel.preferredHeight = 140
- this.helpElem = document.createElement('div')
- this.panel.bodyElem.appendChild(this.helpElem)
- I18N.set(this.helpElem, 'innerHTML', 'tool.place.help')
- this.modeElem = Controls.addSelectField(this.panel.bodyElem, 'place_mode', 'label.place_mode', [
- [PlaceTool.GLOBAL_MODE, 'Global'],
- [PlaceTool.LOCAL_MODE, 'Local'],
- [PlaceTool.PERPENDICULAR_MODE, 'Perpendicular']
- ])
- this.modeElem.addEventListener('change', event => {
- this.mode = parseInt(this.modeElem.value)
- this.placeObject()
- })
- }
- activate() {
- this.panel.visible = true
- const application = this.application
- const container = application.container
- container.addEventListener('contextmenu', this._onContextMenu, false)
- container.addEventListener('pointerdown', this._onPointerDown, false)
- container.addEventListener('pointerup', this._onPointerUp, false)
- container.addEventListener('pointermove', this._onPointerMove, false)
- this.setStage(this.stage)
- application.pointSelector.auxiliaryLines = []
- application.pointSelector.activate()
- application.pointSelector.excludeSelection = true
- application.pointSelector.clearAxisGuides()
- this.preparePlacement()
- }
- deactivate() {
- this.panel.visible = false
- const application = this.application
- const container = application.container
- container.removeEventListener('contextmenu', this._onContextMenu, false)
- container.removeEventListener('pointerdown', this._onPointerDown, false)
- container.removeEventListener('pointerup', this._onPointerUp, false)
- container.removeEventListener('pointermove', this._onPointerMove, false)
- application.pointSelector.deactivate()
- }
- onPointerDown(event) {
- const pointSelector = this.application.pointSelector
- if (!pointSelector.isPointSelectionEvent(event)) return
- event.preventDefault()
- this.preparePlacement()
- this.snap = pointSelector.snap
- this.placeObject()
- this.setStage(1)
- }
- onPointerMove(event) {
- if (this.stage === 0) return
- const pointSelector = this.application.pointSelector
- if (!pointSelector.isPointSelectionEvent(event)) return
- event.preventDefault()
- this.snap = pointSelector.snap
- this.placeObject()
- }
- onPointerUp(event) {
- if (this.stage === 1) {
- event.preventDefault()
- this.setStage(0)
- }
- }
- onContextMenu(event) {
- const pointSelector = this.application.pointSelector
- if (!pointSelector.isPointSelectionEvent(event)) return
- event.preventDefault()
- }
- setStage(stage) {
- this.stage = stage
- }
- preparePlacement() {
- const application = this.application
- const object = application.selection.object
- if (application.selection.size > 1) {
- application.selection.set(object)
- }
- }
- placeObject() {
- const application = this.application
- const object = application.selection.object
- const snap = this.snap
- if (object === null || object.parent === null || snap === null) return
- const axisMatrixWorld = this.axisMatrixWorld
- switch (this.mode) {
- case PlaceTool.GLOBAL_MODE:
- axisMatrixWorld.identity()
- break
- case PlaceTool.LOCAL_MODE:
- axisMatrixWorld.copy(snap.object.matrixWorld)
- break
- case PlaceTool.PERPENDICULAR_MODE:
- if (snap.normalWorld) {
- this.setPerpendicularMatrix(snap, axisMatrixWorld)
- } else {
- axisMatrixWorld.identity()
- }
- break
- }
- axisMatrixWorld.setPosition(snap.positionWorld)
- const matrix = this.localMatrix
- matrix.copy(object.parent.matrixWorld).invert()
- matrix.multiply(axisMatrixWorld)
- matrix.decompose(object.position, object.rotation, new THREE.Vector3())
- object.updateMatrix()
- application.notifyObjectsChanged(object, this, 'nodeChanged', PlaceTool.CHANGED_PROPERTIES)
- }
- setPerpendicularMatrix(snap, axisMatrixWorld) {
- const objectMatrixWorld = snap.object.matrixWorld
- const xAxis = new THREE.Vector3()
- const yAxis = new THREE.Vector3()
- const zAxis = new THREE.Vector3()
- const upVector = new THREE.Vector3(0, 0, 1)
- zAxis.copy(snap.normalWorld)
- if (Math.abs(upVector.dot(zAxis)) < 0.999) {
- xAxis.crossVectors(upVector, zAxis)
- yAxis.crossVectors(zAxis, xAxis)
- } else {
- GeometryUtils.orthogonalVector(zAxis, yAxis)
- xAxis.crossVectors(yAxis, zAxis).normalize()
- }
- xAxis.normalize()
- yAxis.normalize()
- zAxis.normalize()
- axisMatrixWorld.makeBasis(xAxis, yAxis, zAxis)
- }
- vectorToGlobal(vector, matrixWorld) {
- vector.applyMatrix4(matrixWorld)
- let origin = new THREE.Vector3()
- origin.setFromMatrixPosition(matrixWorld)
- vector.sub(origin)
- }
- }
- export { PlaceTool }
|