mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-09 09:52:34 +01:00
174 lines
4.6 KiB
JavaScript
174 lines
4.6 KiB
JavaScript
import Vector from 'math/vector';
|
|
import * as fetch from '../fetchers'
|
|
import {Arc} from '../shapes/arc'
|
|
import {Tool} from './tool'
|
|
import {Segment} from "../shapes/segment";
|
|
import {AlgNumConstraint, ConstraintDefinitions} from "../constr/ANConstraints";
|
|
import {distanceAB} from "math/distance";
|
|
|
|
export class FilletTool extends Tool {
|
|
|
|
constructor(viewer) {
|
|
super('fillet', viewer);
|
|
this.viewer = viewer;
|
|
}
|
|
|
|
restart() {
|
|
const cands = this.getCandidateFromSelection(this.viewer.selected);
|
|
if (cands) {
|
|
const [c1, c2] = cands;
|
|
if (this.breakLinkAndMakeFillet(c1, c2)) {
|
|
this.viewer.toolManager.releaseControl();
|
|
}
|
|
}
|
|
}
|
|
|
|
makeFillet(point1, point2) {
|
|
function shrink(point1) {
|
|
let a, b;
|
|
if (point1.id === point1.parent.a.id) {
|
|
a = point1.parent.b;
|
|
b = point1.parent.a;
|
|
} else {
|
|
a = point1.parent.a;
|
|
b = point1.parent.b;
|
|
}
|
|
const d = distanceAB(a, b);
|
|
const k = 4 / 5;
|
|
b.x = a.x + (b.x - a.x) * k;
|
|
b.y = a.y + (b.y - a.y) * k;
|
|
return new Vector(a.x - b.x, a.y - b.y, 0);
|
|
}
|
|
|
|
const v1 = shrink(point1);
|
|
const v2 = shrink(point2);
|
|
|
|
if (v1.cross(v2).z > 0) {
|
|
const _ = point1;
|
|
point1 = point2;
|
|
point2 = _;
|
|
}
|
|
|
|
const vec = new Vector();
|
|
vec.setV(point2);
|
|
vec._minus(point1);
|
|
vec._multiply(0.5);
|
|
vec._plus(point1);
|
|
|
|
const arc = new Arc(
|
|
point1.x, point1.y,
|
|
point2.x, point2.y,
|
|
vec.x, vec.y);
|
|
point1.parent.layer.add(arc);
|
|
const pm = this.viewer.parametricManager;
|
|
|
|
const s1 = point1.parent;
|
|
const s2 = point2.parent;
|
|
|
|
const inverted1 = s1.nx * arc.c.x + s1.ny * arc.c.y < s1.w;
|
|
const inverted2 = s2.nx * arc.c.x + s2.ny * arc.c.y < s2.w;
|
|
arc.stabilize(this.viewer);
|
|
|
|
pm.add(new AlgNumConstraint(ConstraintDefinitions.Fillet, [point1.parent, point2.parent, arc], {
|
|
inverted1,
|
|
inverted2
|
|
}));
|
|
|
|
pm.add(new AlgNumConstraint(ConstraintDefinitions.PCoincident, [point1, arc.a]));
|
|
pm.add(new AlgNumConstraint(ConstraintDefinitions.PCoincident, [point2, arc.b]));
|
|
|
|
//function otherEnd(point) {
|
|
// if (point.parent.a.id === point.id) {
|
|
// return point.parent.b;
|
|
// } else {
|
|
// return point.parent.a;
|
|
// }
|
|
//}
|
|
//
|
|
//pm._add(new Constraints.LockConvex(arc.c, arc.a, otherEnd(point1)));
|
|
//pm._add(new Constraints.LockConvex(otherEnd(point2), arc.b, arc.c));
|
|
|
|
// var solver = pm.solve();
|
|
// var solver = pm.solve([point1._x, point1._y, point2._x, point2._y]);
|
|
// pm.notify();
|
|
// this.viewer.refresh();
|
|
}
|
|
|
|
mouseup(e) {
|
|
let candi = this.getCandidate(e);
|
|
if (candi == null) return;
|
|
const point1 = candi[0];
|
|
const point2 = candi[1];
|
|
this.breakLinkAndMakeFillet(point1, point2)
|
|
}
|
|
breakLinkAndMakeFillet(point1, point2) {
|
|
const pm = this.viewer.parametricManager;
|
|
let coi = null;
|
|
for (let c of point1.constraints) {
|
|
if (c.schema.id === ConstraintDefinitions.PCoincident.id) {
|
|
if (c.objects.indexOf(point2) !== -1) {
|
|
coi = c;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (coi != null) {
|
|
pm.remove(coi);
|
|
this.makeFillet(point1, point2);
|
|
this.viewer.withdrawAll('tool');
|
|
this.viewer.deselectAll();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static isLine(line) {
|
|
return line != null && line.TYPE === 'Segment';
|
|
}
|
|
|
|
getCandidate(e) {
|
|
const picked = this.viewer.pick(e);
|
|
return this.getCandidateFromSelection(picked);
|
|
}
|
|
|
|
getCandidateFromSelection(picked) {
|
|
|
|
let preferSketchLayer = (a, b) => (a.effectiveLayer === b.effectiveLayer)? 0 : a.effectiveLayer.name === 'sketch' ? -1 : 1;
|
|
|
|
if (picked.length > 0) {
|
|
let res = fetch.sketchObjects(picked, true, ['TCAD.TWO.EndPoint']);
|
|
if (res == null) return null;
|
|
let point1 = res.sort(preferSketchLayer)[0];
|
|
if (!FilletTool.isLine(point1.parent)) return;
|
|
|
|
const linked = [];
|
|
point1.visitLinked(l => {
|
|
if (l !== point1 && FilletTool.isLine(l.parent)) {
|
|
linked.push(l);
|
|
}
|
|
});
|
|
|
|
if (linked.length) {
|
|
linked.sort(preferSketchLayer);
|
|
return [point1, linked[0]];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
mousemove(e) {
|
|
let needRefresh = false;
|
|
if (this.viewer.captured.tool.length !== 0) {
|
|
this.viewer.withdrawAll('tool');
|
|
needRefresh = true;
|
|
}
|
|
let candi = this.getCandidate(e);
|
|
if (candi != null) {
|
|
this.viewer.capture('tool', [candi[0]], true);
|
|
needRefresh = true;
|
|
}
|
|
if (needRefresh) {
|
|
this.viewer.refresh();
|
|
}
|
|
}
|
|
}
|