jsketcher/web/app/sketcher/tools/offset.js
2020-07-18 22:18:03 -07:00

125 lines
No EOL
3.7 KiB
JavaScript

import {LoopPickTool} from './loop-pick'
import {Constraints} from '../parametric'
import * as math from '../../../../modules/math/commons';
import Vector from 'math/vector';
import {swap} from '../../utils/utils'
import {EndPoint} from '../shapes/point'
import {Arc} from '../shapes/arc'
export class OffsetTool extends LoopPickTool {
constructor(viewer) {
super('offset', viewer);
}
onMousedown(e) {
const loopPoints = this.pickedLoop.points;
const loopEdges = this.pickedLoop.edges;
const length = loopEdges.length;
for (let obj of loopEdges) {
if (!SUPPORTED_OBJECTS.has(obj.TYPE)) {
alert(obj._class + " isn't supported for offsets");
return;
}
}
let delta = parseInt(prompt('offset distance?', 100));
if (isNaN(delta)) {
return;
}
const edges = loopEdges.map(e => e.copy());
const lowestPoint = findLowestPoint(loopPoints);
const low = loopPoints.indexOf(lowestPoint);
function pos(i) {
return (i + low) % length;
}
const mainInverse = !this.twoConnectedArcs() && math.isCCW([loopPoints[pos(0)], loopPoints[pos(1)], loopPoints[pos(length - 1)]]);
const pm = this.viewer.parametricManager;
const offsetConstant = createOffsetConstant(pm, delta);
for (let i = 0; i < length; ++i) {
const edge = edges[i];
const origEdge = loopEdges[i];
const edgeInverse = loopPoints[i] !== origEdge.a;
const inverse = mainInverse !== edgeInverse;
this.viewer.activeLayer.add(edge);
if (edge.TYPE === 'Segment') {
pm._add(new Constraints.Parallel(origEdge, edge));
pm._add(new Constraints.P2LDistanceSigned(origEdge.a, inverse?edge.b:edge.a, inverse?edge.a:edge.b, offsetConstant));
} else if (edge.TYPE === 'Arc') {
edge.stabilize(this.viewer);
pm._linkObjects([edge.c, origEdge.c]);
pm._add(new Constraints.RadiusOffset(inverse?origEdge:edge, inverse?edge:origEdge, offsetConstant));
}
}
for (let i = 0; i < edges.length; i++) {
const next = ((i + 1) % edges.length);
if (loopEdges[i].a.linked.indexOf(loopEdges[next].a) !== -1) {
pm._linkObjects([edges[i].a, edges[next].a]);
} else if (loopEdges[i].a.linked.indexOf(loopEdges[next].b) !== -1) {
pm._linkObjects([edges[i].a, edges[next].b]);
} else if (loopEdges[i].b.linked.indexOf(loopEdges[next].a) !== -1) {
pm._linkObjects([edges[i].b, edges[next].a]);
} else if (loopEdges[i].b.linked.indexOf(loopEdges[next].b) !== -1) {
pm._linkObjects([edges[i].b, edges[next].b]);
}
}
pm.solve(undefined, undefined, loopEdges);
pm.refresh();
this.viewer.toolManager.releaseControl();
}
twoConnectedArcs() {
function isArc(edge) {
return edge._class === 'Arc';
}
const edges = this.pickedLoop.edges;
return edges.length === 2 && isArc(edges[0]) && isArc(edges[1]);
}
}
function segmentToVector(segment) {
return new Vector(segment.b.x - segment.a.x, segment.b.y - segment.a.y);
}
const SUPPORTED_OBJECTS = new Set();
SUPPORTED_OBJECTS.add('Segment');
SUPPORTED_OBJECTS.add('Arc');
function SimpleEdge(a, b) {
this.a = a;
this.b = b;
this.reverse = function() {
return new SimpleEdge(b, a);
}
}
function findLowestPoint(poly) {
let hero = {x: Number.MAX_VALUE, y: Number.MAX_VALUE};
for (let point of poly) {
if (point.y < hero.y) {
hero = point;
} else if (hero.y == hero.y) { // TODO: revisit and fix bug
if (point.x < hero.x) {
hero = point;
}
}
}
return hero;
}
function createOffsetConstant(pm, value) {
let constant;
let i = 0;
do {
constant = 'OFFSET' + i++;
} while (pm.constantTable[constant]);
pm.defineNewConstant(constant, value);
return constant;
}