awv3
Version:
⚡ AWV3 embedded CAD
120 lines (108 loc) • 4.15 kB
JavaScript
import * as THREE from 'three';
import Object3 from '../../../three/object3';
import Ccref from '../ccref';
import { getArcAngles } from '../geomutils';
import ConstraintGraphics from '../graphics/constraint';
const Mode = Object.freeze({
Never: 0,
Hover: 1,
Always: 2,
});
export default class Visualizer {
constructor(sketcher, textures) {
this.mode = Mode.Hover;
this.sketcher = sketcher;
// Set of constraint ids to avoid iterating and filtering sketch.children
this.constraints = new Set();
// Reverse mapping from entities to constraints
this.entityFor = new Map();
// Used to track constraint positions in all modes
this.visiblePositions = new Set();
}
addConstraint(constraint) {
if (!(constraint.graphics instanceof ConstraintGraphics)) return;
this.constraints.add(constraint.id);
for (let entity of constraint.entities) {
if (!this.entityFor.has(entity.id)) this.entityFor.set(entity.id, []);
this.entityFor.get(entity.id).push(constraint.id);
}
}
removeConstraint(constraint, state = constraint.state) {
if (!(constraint.graphics instanceof ConstraintGraphics)) return;
for (let {value: id} of state.members.entities.members) {
const constraints = this.entityFor.get(id);
constraints.splice(constraints.indexOf(constraint.id), 1);
if (constraints.length === 0) this.entityFor.delete(id);
}
this.constraints.delete(constraint.id);
}
updateConstraint(constraint) {
this.place(constraint, constraint.entities[0], this.mode === Mode.Always);
}
updateEntity(entity) {
for (let id of this.entityFor.get(entity.id) || []) {
const constraint = new Ccref(this.sketcher, id);
if (!constraint.state) continue; // if entity is updated just before constraint is deleted (e.g. fillet point)
this.updateConstraint(constraint);
}
}
hover(entity, first) {
if (this.mode !== Mode.Hover) return;
if (entity.isConstraint()) return;
if (first) this.unhoverAll();
for (let id of this.entityFor.get(entity.id) || [])
this.place(new Ccref(this.sketcher, id), entity, true);
}
unhover(entity, first) {
if (this.mode !== Mode.Hover) return;
if (entity.isConstraint()) return;
// do nothing
}
unhoverAll() {
if (this.mode !== Mode.Hover) return;
if (this.visiblePositions.size === 0) return;
this.updateAll();
}
place(constraint, entity, visible) {
const graphics = constraint.graphics, position = graphics.localMesh.position, gp = entity.geomParams;
this.visiblePositions.delete(position);
graphics.visible = visible;
if (!visible) return;
switch (entity.class) {
case 'CC_Point':
position.copy(gp.start);
break;
case 'CC_Line':
position.lerpVectors(gp.start, gp.end, 0.5);
break;
case 'CC_Arc':
position.copy(getArcAngles(gp).mid);
break;
case 'CC_Circle':
position.copy(gp.center);
break;
default:
position.set(0, 0, 0);
break;
}
const s = graphics.localMesh.scale.y;
position.x -= s;
position.y += s;
triesLoop: for (let tries = 0; tries < 10; ++tries) {
for (let visiblePosition of this.visiblePositions)
if (position.distanceToSquared(visiblePosition) < s * s) {
position.x += s * (1 + 1e-6);
continue triesLoop;
}
break;
}
this.visiblePositions.add(position);
}
updateAll(mode = this.mode) {
this.mode = mode;
this.visiblePositions.clear();
for (let id of this.constraints)
this.updateConstraint(new Ccref(this.sketcher, id));
this.sketcher.refresh();
}
}