mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-09 18:02:50 +01:00
607 lines
No EOL
14 KiB
JavaScript
607 lines
No EOL
14 KiB
JavaScript
import {AlgNumConstraint, ConstraintDefinitions} from "../constr/ANConstraints";
|
|
import {EndPoint} from "../shapes/point";
|
|
import {Circle} from "../shapes/circle";
|
|
import {Segment} from "../shapes/segment";
|
|
import {isInstanceOf, matchAll, matchTypes} from "./matchUtils";
|
|
import {Arc} from "../shapes/arc";
|
|
import {FilletTool} from "../tools/fillet";
|
|
import {editConstraint as _editConstraint} from "../components/ConstraintEditor";
|
|
import {BezierCurve} from "../shapes/bezier-curve";
|
|
|
|
export default [
|
|
|
|
|
|
{
|
|
id: 'Coincident',
|
|
shortName: 'Coincident',
|
|
kind: 'Constraint',
|
|
description: 'Point Coincident',
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [EndPoint],
|
|
minQuantity: 2
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
const [first, ...others] = matchedObjects;
|
|
let pm = viewer.parametricManager;
|
|
for (let obj of others) {
|
|
pm._add(
|
|
new AlgNumConstraint(ConstraintDefinitions.PCoincident, [first, obj])
|
|
);
|
|
}
|
|
pm.commit();
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Tangent',
|
|
shortName: 'Tangent',
|
|
kind: 'Constraint',
|
|
description: 'Tangent Between Line And Circle',
|
|
selectionMatcher: {
|
|
selector: 'matchSequence',
|
|
sequence: [
|
|
{
|
|
types: [Circle, Arc],
|
|
quantity: 1
|
|
},
|
|
{
|
|
types: [Segment],
|
|
quantity: 1
|
|
},
|
|
]
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
|
|
const {viewer} = ctx;
|
|
const [circle, line] = matchedObjects;
|
|
|
|
const constraint = new AlgNumConstraint(ConstraintDefinitions.TangentLC, [line, circle]);
|
|
constraint.initConstants();
|
|
const pm = viewer.parametricManager;
|
|
pm.add(constraint);
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
id: 'EqualRadius',
|
|
shortName: 'Equal Radius',
|
|
kind: 'Constraint',
|
|
description: 'Equal Radius Between Two Circle',
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Circle, Arc],
|
|
minQuantity: 2
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
|
|
const {viewer} = ctx;
|
|
|
|
const pm = viewer.parametricManager;
|
|
for (let i = 1; i < matchedObjects.length; ++i) {
|
|
pm._add(new AlgNumConstraint(ConstraintDefinitions.EqualRadius, [matchedObjects[i-1], matchedObjects[i]]));
|
|
}
|
|
pm.commit();
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
id: 'EqualLength',
|
|
shortName: 'Equal Length',
|
|
kind: 'Constraint',
|
|
description: 'Equal Length Between Two Segments',
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Segment],
|
|
minQuantity: 2
|
|
},
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
const pm = viewer.parametricManager;
|
|
for (let i = 1; i < matchedObjects.length; ++i) {
|
|
pm._add(new AlgNumConstraint(ConstraintDefinitions.EqualLength, [matchedObjects[i-1], matchedObjects[i]]));
|
|
}
|
|
pm.commit();
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
id: 'PointOnLine',
|
|
shortName: 'Point On Line',
|
|
kind: 'Constraint',
|
|
description: 'Point On Line',
|
|
selectionMatcher: {
|
|
selector: 'matchSequence',
|
|
sequence: [
|
|
{
|
|
types: [EndPoint],
|
|
quantity: 1
|
|
},
|
|
{
|
|
types: [Segment],
|
|
quantity: 1
|
|
},
|
|
]
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
const [pt, line] = matchedObjects;
|
|
let pm = viewer.parametricManager;
|
|
pm.add(new AlgNumConstraint(ConstraintDefinitions.PointOnLine, [pt, line]));
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'PointOnCircle',
|
|
shortName: 'Point On Circle',
|
|
kind: 'Constraint',
|
|
description: 'Point On Circle',
|
|
selectionMatcher: {
|
|
selector: 'matchSequence',
|
|
sequence: [
|
|
{
|
|
types: [EndPoint],
|
|
quantity: 1
|
|
},
|
|
{
|
|
types: [Circle, Arc],
|
|
quantity: 1
|
|
},
|
|
]
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
const [pt, circle] = matchedObjects;
|
|
let pm = viewer.parametricManager;
|
|
pm.add(new AlgNumConstraint(ConstraintDefinitions.PointOnCircle, [pt, circle]));
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'PointOnCurve',
|
|
shortName: 'Point On Curve',
|
|
kind: 'Constraint',
|
|
description: 'Point On Curve',
|
|
selectionMatcher: {
|
|
selector: 'matchSequence',
|
|
sequence: [
|
|
{
|
|
types: [EndPoint],
|
|
quantity: 1
|
|
},
|
|
{
|
|
types: [BezierCurve],
|
|
quantity: 1
|
|
},
|
|
]
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
const [pt, curve] = matchedObjects;
|
|
let pm = viewer.parametricManager;
|
|
pm.add(new AlgNumConstraint(ConstraintDefinitions.PointOnBezier, [pt, curve]));
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'PointInMiddle',
|
|
shortName: 'Middle Point',
|
|
kind: 'Constraint',
|
|
description: 'Point In The Middle',
|
|
selectionMatcher: {
|
|
selector: 'matchSequence',
|
|
sequence: [
|
|
{
|
|
types: [EndPoint],
|
|
quantity: 1
|
|
},
|
|
{
|
|
types: [Segment],
|
|
quantity: 1
|
|
},
|
|
]
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
viewer.parametricManager.add(new AlgNumConstraint(ConstraintDefinitions.PointInMiddle, matchedObjects));
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Symmetry',
|
|
shortName: 'Symmetry',
|
|
kind: 'Constraint',
|
|
description: 'Symmetry of two points against middle point',
|
|
selectionMatcher: {
|
|
selector: 'matchSequence',
|
|
sequence: [
|
|
{
|
|
types: [EndPoint],
|
|
quantity: 1
|
|
},
|
|
{
|
|
types: [Segment],
|
|
quantity: 1
|
|
},
|
|
]
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
viewer.parametricManager.add(new AlgNumConstraint(ConstraintDefinitions.Symmetry, matchedObjects));
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Angle',
|
|
shortName: 'Angle',
|
|
kind: 'Constraint',
|
|
description: 'Angle',
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Segment],
|
|
minQuantity: 1
|
|
},
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
|
|
const firstSegment = matchedObjects[0];
|
|
|
|
const firstConstr = new AlgNumConstraint(ConstraintDefinitions.Angle, [firstSegment]);
|
|
firstConstr.initConstants();
|
|
|
|
editConstraint(ctx, firstConstr, () => {
|
|
const pm = viewer.parametricManager;
|
|
pm._add(firstConstr);
|
|
for (let i = 1; i < matchedObjects.length; ++i) {
|
|
pm._add(new AlgNumConstraint(ConstraintDefinitions.Angle, [matchedObjects[i]], {...firstConstr.constants}));
|
|
}
|
|
pm.commit();
|
|
});
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Vertical',
|
|
shortName: 'Vertical',
|
|
kind: 'Constraint',
|
|
description: 'Vertical',
|
|
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Segment],
|
|
minQuantity: 1
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
const pm = viewer.parametricManager;
|
|
|
|
matchedObjects.forEach(obj => {
|
|
const constr = new AlgNumConstraint(ConstraintDefinitions.Vertical, [obj]);
|
|
constr.initConstants();
|
|
pm._add(constr);
|
|
});
|
|
pm.commit();
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Horizontal',
|
|
shortName: 'Horizontal',
|
|
kind: 'Constraint',
|
|
description: 'Horizontal',
|
|
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Segment],
|
|
minQuantity: 1
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
const pm = viewer.parametricManager;
|
|
|
|
matchedObjects.forEach(obj => {
|
|
const constr = new AlgNumConstraint(ConstraintDefinitions.Horizontal, [obj]);
|
|
constr.initConstants();
|
|
pm._add(constr);
|
|
});
|
|
pm.commit();
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'AngleBetween',
|
|
shortName: 'Angle Between',
|
|
kind: 'Constraint',
|
|
description: 'Angle Between Lines',
|
|
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Segment],
|
|
minQuantity: 2
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
|
|
const [firstSegment, secondSegment] = matchedObjects;
|
|
|
|
const firstConstr = new AlgNumConstraint(ConstraintDefinitions.AngleBetween, [firstSegment, secondSegment]);
|
|
firstConstr.initConstants();
|
|
|
|
editConstraint(ctx, firstConstr, () => {
|
|
const pm = viewer.parametricManager;
|
|
pm._add(firstConstr);
|
|
for (let i = 2; i < matchedObjects.length; ++i) {
|
|
pm._add(new AlgNumConstraint(ConstraintDefinitions.Angle,
|
|
[matchedObjects[i-1], matchedObjects[i]], {...firstConstr.constants}));
|
|
}
|
|
pm.commit();
|
|
});
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Perpendicular',
|
|
shortName: 'Perpendicular',
|
|
kind: 'Constraint',
|
|
description: 'Perpendicularity between two or more lines',
|
|
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Segment],
|
|
minQuantity: 2
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
|
|
const pm = viewer.parametricManager;
|
|
|
|
for (let i = 1; i < matchedObjects.length; ++i) {
|
|
const constr = new AlgNumConstraint(ConstraintDefinitions.Perpendicular, [matchedObjects[i-1], matchedObjects[i]]);
|
|
constr.initConstants();
|
|
pm._add(constr);
|
|
}
|
|
pm.commit();
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Parallel',
|
|
shortName: 'Parallel',
|
|
kind: 'Constraint',
|
|
description: 'Parallelism between two or more lines',
|
|
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Segment],
|
|
minQuantity: 2
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
|
|
const pm = viewer.parametricManager;
|
|
|
|
for (let i = 1; i < matchedObjects.length; ++i) {
|
|
const constr = new AlgNumConstraint(ConstraintDefinitions.Parallel, [matchedObjects[i-1], matchedObjects[i]]);
|
|
constr.initConstants();
|
|
pm._add(constr);
|
|
}
|
|
pm.commit();
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Length',
|
|
shortName: 'Length',
|
|
kind: 'Constraint',
|
|
description: 'Segment Length',
|
|
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Segment],
|
|
minQuantity: 1
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
|
|
const [firstSegment, ...others] = matchedObjects;
|
|
|
|
const firstConstr = new AlgNumConstraint(ConstraintDefinitions.SegmentLength, [firstSegment]);
|
|
firstConstr.initConstants();
|
|
|
|
editConstraint(ctx, firstConstr, () => {
|
|
const pm = viewer.parametricManager;
|
|
pm._add(firstConstr);
|
|
for (let other of others) {
|
|
pm._add(new AlgNumConstraint(ConstraintDefinitions.SegmentLength, [other], {...firstConstr.constants}));
|
|
}
|
|
pm.commit();
|
|
});
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'RadiusLength',
|
|
shortName: 'Radius Length',
|
|
kind: 'Constraint',
|
|
description: 'Radius Length',
|
|
|
|
selectionMatcher: {
|
|
selector: 'matchAll',
|
|
types: [Circle, Arc],
|
|
minQuantity: 1
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
|
|
const [firstCircle, ...others] = matchedObjects;
|
|
|
|
const firstConstr = new AlgNumConstraint(ConstraintDefinitions.RadiusLength, [firstCircle]);
|
|
firstConstr.initConstants();
|
|
|
|
editConstraint(ctx, firstConstr, () => {
|
|
const pm = viewer.parametricManager;
|
|
pm._add(firstConstr);
|
|
for (let other of others) {
|
|
pm._add(new AlgNumConstraint(ConstraintDefinitions.RadiusLength, [other], {...firstConstr.constants}));
|
|
}
|
|
pm.commit();
|
|
});
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'DistancePL',
|
|
shortName: 'Point to Line Distance',
|
|
kind: 'Constraint',
|
|
description: 'Distance between Point and Line',
|
|
|
|
selectionMatcher: {
|
|
selector: 'matchSequence',
|
|
sequence: [
|
|
{
|
|
types: [EndPoint],
|
|
quantity: 1
|
|
},
|
|
{
|
|
types: [Segment],
|
|
quantity: 1
|
|
},
|
|
]
|
|
},
|
|
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
|
|
const [pt, seg] = matchedObjects;
|
|
|
|
const constr = new AlgNumConstraint(ConstraintDefinitions.DistancePL, [pt, seg]);
|
|
constr.initConstants();
|
|
|
|
editConstraint(ctx, constr, () => {
|
|
const pm = viewer.parametricManager;
|
|
pm.add(constr);
|
|
});
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'DistancePP',
|
|
shortName: 'Two Point Distance',
|
|
kind: 'Constraint',
|
|
description: 'Distance between two Points',
|
|
|
|
selectionMatcher: {
|
|
selector: 'matchSequence',
|
|
sequence: [
|
|
{
|
|
types: [EndPoint],
|
|
quantity: 2
|
|
}
|
|
]
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
|
|
const [p1, p2] = matchedObjects;
|
|
|
|
const constr = new AlgNumConstraint(ConstraintDefinitions.DistancePP, [p1, p2]);
|
|
constr.initConstants();
|
|
|
|
editConstraint(ctx, constr, () => {
|
|
const pm = viewer.parametricManager;
|
|
pm.add(constr);
|
|
});
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Lock',
|
|
shortName: 'Lock Point',
|
|
kind: 'Constraint',
|
|
description: 'Lock Point',
|
|
selectionMatcher: {
|
|
selector: 'matchSequence',
|
|
sequence: [
|
|
{
|
|
types: [EndPoint],
|
|
quantity: 1
|
|
}
|
|
]
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
|
|
const [point] = matchedObjects;
|
|
|
|
const constr = new AlgNumConstraint(ConstraintDefinitions.LockPoint, [point]);
|
|
constr.initConstants();
|
|
editConstraint(ctx, constr, () => viewer.parametricManager.add(constr));
|
|
}
|
|
},
|
|
|
|
{
|
|
id: 'Fillet',
|
|
shortName: 'Fillet',
|
|
kind: 'Tool',
|
|
description: 'Add a Fillet',
|
|
selectionMatcher: {
|
|
selector: 'function',
|
|
match: (selection) => {
|
|
if (matchTypes(selection, EndPoint, 1)) {
|
|
const [point] = selection;
|
|
if (isInstanceOf(point.parent, Segment)) {
|
|
let pair = null;
|
|
point.visitLinked(l => {
|
|
if (l !== point && isInstanceOf(l.parent, Segment)) {
|
|
pair = l;
|
|
return true;
|
|
}
|
|
});
|
|
if (pair) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
description: 'a point linking two segment'
|
|
},
|
|
|
|
invoke: (ctx, matchedObjects) => {
|
|
const {viewer} = ctx;
|
|
const filletTool = new FilletTool(ctx.viewer);
|
|
const cands = filletTool.getCandidateFromSelection(viewer.selected);
|
|
if (cands) {
|
|
filletTool.breakLinkAndMakeFillet(cands[0], cands[1]);
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
];
|
|
|
|
function editConstraint(ctx, constraint, onApply) {
|
|
_editConstraint(ctx.ui.$constraintEditRequest, constraint, onApply)
|
|
} |