awv3
Version:
⚡ AWV3 embedded CAD
121 lines (103 loc) • 4.04 kB
JavaScript
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;
}
}