UNPKG

awv3

Version:
121 lines (103 loc) 4.04 kB
import * as THREE from 'three'; export default class Snapper { constructor(options) { this.sketch = options.sketch; this.gridStep = options.gridStep; this.pointRadius = options.pointRadius; this.ignoredIds = []; this.keyOffsets = undefined; this.maxSnapDistance = this.gridStep / 5.0; this.sketchPoints = undefined; } //note: subobjects (like endpoints of line) are also marked ignoreObject(ccrefs) { ccrefs = [].concat(ccrefs); for (let ccref of ccrefs) for (let obj of ccref.descendants) { this.ignoredIds.push(obj.id); } } //call this when dragging (or duplicating) many objects // ccrefs: set of objects which is going to be moved // mousePosition: where must cursor is currently // dragged (optional): the object we drag with mouse (note: special case if it is point) setDraggedObjects(ccrefs, mousePosition, dragged) { this.keyOffsets = []; for (var obj of ccrefs) { var subpoints = Array.from(obj.descendants).filter(obj => obj.isPoint()); for (var pnt of subpoints) { var offset = pnt.pos.clone().sub(mousePosition); if (dragged && dragged.isPoint()) offset.set(0, 0, 0); if (!this.keyOffsets.some(vec => vec.distanceTo(offset) <= 1e-9)) this.keyOffsets.push(offset); } } } //use this to snap dragged object snapDraggedObject(mousePosition) { var res = this.noneResult(); for (var key of this.keyOffsets) { var position = mousePosition.clone().add(key); var tres = this.snapPoint(position); tres.position.sub(key); if (this.compareResult(res, tres) > 0) res = tres; } return res; } //use this method for drawing things (and NOT for dragging) snapPoint(position) { var res = this.noneResult(); var resPoints = this.snapToSketchPoints(position); if (this.compareResult(res, resPoints) > 0) res = resPoints; var resGrid = this.snapToGrid(position); if (this.compareResult(res, resGrid) > 0) res = resGrid; res.position = res.displacement.clone().add(position); return res; } //internal methods noneResult() { return { cost: Infinity, displacement: new THREE.Vector3(0, 0, 0) }; } compareResult(resA, resB) { if (Math.abs(resA.cost - resB.cost) <= 1e-3) return 0; return resA.cost < resB.cost ? -1 : 1; } snapToGrid(position) { if (this.gridStep > 0) { var x = Math.round(position.x / this.gridStep) * this.gridStep; var y = Math.round(position.y / this.gridStep) * this.gridStep; var gridNode = new THREE.Vector3(x, y, 0); var dist = gridNode.distanceTo(position); if (dist < this.maxSnapDistance) { return { cost: dist, displacement: gridNode.clone().sub(position) }; } } return this.noneResult(); } snapToSketchPoints(position) { var res = this.noneResult(); //note: cache sketch points for faster multi-snapping if (this.sketchPoints === undefined) this.sketchPoints = Array.from(this.sketch.descendants).filter(obj => obj.isPoint()); for (let obj of this.sketchPoints) { if (this.ignoredIds.indexOf(obj.id) !== -1) continue; var pointPos = obj.pos; var dist = pointPos.distanceTo(position); if (dist > this.maxSnapDistance) continue; var snap = { cost: dist, displacement: pointPos.clone().sub(position), toPoint: obj }; if (this.compareResult(snap, res) < 0) res = snap; } return res; } }