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

1133 lines
33 KiB
JavaScript

import {Ref} from './shapes/ref';
import * as math from '../../../modules/math/commons';
import Vector from '../../../modules/math/vector';
class AbstractConstraint {
}
export const Constraints = {
Factory: {}
};
// ------------------------------------------------------------------------------------------------------------------ //
export class Coincident extends AbstractConstraint {
reducible = true;
static deserialize(refs, data) {
return new Coincident(refs(data[0]), refs(data[1]));
};
constructor(a, b) {
super();
this.a = a;
this.b = b;
a.linked.push(b);
b.linked.push(a);
};
getSolveData() {
return [
['equal', [this.a._x, this.b._x], []],
['equal', [this.a._y, this.b._y], []]
];
}
serialize() {
return [this.NAME, [this.a.id, this.b.id]];
}
getObjects() {
return [this.a, this.b];
}
}
Constraints.Coincident = Coincident;
Constraints.Coincident.prototype.NAME = 'coi';
Constraints.Coincident.prototype.UI_NAME = 'Coincident';
Constraints.Factory[Coincident.prototype.NAME] = Coincident.deserialize;
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.RadiusOffset = function(arc1, arc2, offset) {
this.arc1 = arc1;
this.arc2 = arc2;
this.offset = offset;
};
Constraints.RadiusOffset.prototype.NAME = 'RadiusOffset';
Constraints.RadiusOffset.prototype.UI_NAME = 'Radius Offset';
Constraints.RadiusOffset.prototype.getSolveData = function(resolver) {
return [
['Diff', [this.arc1.r, this.arc2.r], [resolver(this.offset)]]
];
};
Constraints.RadiusOffset.prototype.serialize = function() {
return [this.NAME, [this.arc1.id, this.arc2.id, this.offset]];
};
Constraints.Factory[Constraints.RadiusOffset.prototype.NAME] = function(refs, data) {
return new Constraints.RadiusOffset(refs(data[0]), refs(data[1]), data[2]);
};
Constraints.RadiusOffset.prototype.getObjects = function() {
return [this.arc1, this.arc2];
};
Constraints.RadiusOffset.prototype.SettableFields = {'offset' : "Enter the offset"};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Lock = function(p, c) {
this.p = p;
this.c = c;
};
Constraints.Lock.prototype.NAME = 'lock';
Constraints.Lock.prototype.UI_NAME = 'Lock';
Constraints.Lock.prototype.getSolveData = function() {
return [
['equalsTo', [this.p._x], [this.c.x]],
['equalsTo', [this.p._y], [this.c.y]]
];
};
Constraints.Lock.prototype.serialize = function() {
return [this.NAME, [this.p.id, this.c]];
};
Constraints.Factory[Constraints.Lock.prototype.NAME] = function(refs, data) {
return new Constraints.Lock(refs(data[0]), data[1]);
};
Constraints.Lock.prototype.getObjects = function() {
return [this.p];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Parallel = function(l1, l2) {
this.l1 = l1;
this.l2 = l2;
};
Constraints.Parallel.prototype.NAME = 'parallel';
Constraints.Parallel.prototype.UI_NAME = 'Parallel';
Constraints.Parallel.prototype.getSolveData = function() {
var params = [];
this.l1.collectParams(params);
this.l2.collectParams(params);
return [[this.NAME, params, []]];
};
Constraints.Parallel.prototype.serialize = function() {
return [this.NAME, [this.l1.id, this.l2.id]];
};
Constraints.Factory[Constraints.Parallel.prototype.NAME] = function(refs, data) {
return new Constraints.Parallel(refs(data[0]), refs(data[1]));
};
Constraints.Parallel.prototype.getObjects = function() {
return [this.l1, this.l2];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Perpendicular = function(l1, l2) {
this.l1 = l1;
this.l2 = l2;
};
Constraints.Perpendicular.prototype.NAME = 'perpendicular';
Constraints.Perpendicular.prototype.UI_NAME = 'Perpendicular';
Constraints.Perpendicular.prototype.getSolveData = function() {
var params = [];
this.l1.collectParams(params);
this.l2.collectParams(params);
return [[this.NAME, params, []]];
};
Constraints.Perpendicular.prototype.serialize = function() {
return [this.NAME, [this.l1.id, this.l2.id]];
};
Constraints.Factory[Constraints.Perpendicular.prototype.NAME] = function(refs, data) {
return new Constraints.Perpendicular(refs(data[0]), refs(data[1]));
};
Constraints.Perpendicular.prototype.getObjects = function() {
return [this.l1, this.l2];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.P2LDistanceSigned = function(p, a, b, d) {
this.p = p;
this.a = a;
this.b = b;
this.d = d;
};
Constraints.P2LDistanceSigned.prototype.NAME = 'P2LDistanceSigned';
Constraints.P2LDistanceSigned.prototype.UI_NAME = 'Distance P & L';
Constraints.P2LDistanceSigned.prototype.getSolveData = function(resolver) {
var params = [];
this.p.collectParams(params);
this.a.collectParams(params);
this.b.collectParams(params);
return [[this.NAME, params, [resolver(this.d)]]];
};
Constraints.P2LDistanceSigned.prototype.serialize = function() {
return [this.NAME, [this.p.id, this.a.id, this.b.id, this.d]];
};
Constraints.Factory[Constraints.P2LDistanceSigned.prototype.NAME] = function(refs, data) {
return new Constraints.P2LDistanceSigned(refs(data[0]), refs(data[1]), refs(data[2]), data[3]);
};
Constraints.P2LDistanceSigned.prototype.getObjects = function() {
const collector = new Constraints.ParentsCollector();
collector.check(this.a);
collector.check(this.b);
collector.parents.push(this.p);
return collector.parents;
};
Constraints.P2LDistanceSigned.prototype.SettableFields = {'d' : "Enter the distance"};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.P2LDistance = function(p, l, d) {
this.p = p;
this.l = l;
this.d = d;
};
Constraints.P2LDistance.prototype.NAME = 'P2LDistance';
Constraints.P2LDistance.prototype.UI_NAME = 'Distance P & L';
Constraints.P2LDistance.prototype.getSolveData = function(resolver) {
var params = [];
this.p.collectParams(params);
this.l.collectParams(params);
return [[this.NAME, params, [resolver(this.d)]]];
};
Constraints.P2LDistance.prototype.serialize = function() {
return [this.NAME, [this.p.id, this.l.id, this.d]];
};
Constraints.Factory[Constraints.P2LDistance.prototype.NAME] = function(refs, data) {
return new Constraints.P2LDistance(refs(data[0]), refs(data[1]), data[2]);
};
Constraints.P2LDistance.prototype.getObjects = function() {
return [this.p, this.l];
};
Constraints.P2LDistance.prototype.SettableFields = {'d' : "Enter the distance"};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.MinLength = function(a, b, min) {
this.a = a;
this.b = b;
this.min = min;
};
Constraints.MinLength.prototype.aux = true;
Constraints.MinLength.prototype.NAME = 'MinLength';
Constraints.MinLength.prototype.UI_NAME = 'MinLength';
Constraints.MinLength.prototype.getSolveData = function() {
var params = [];
this.a.collectParams(params);
this.b.collectParams(params);
return [[this.NAME, params, [this.min]]];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.P2LDistanceV = function(p, l, d) {
this.p = p;
this.l = l;
this.d = d;
};
Constraints.P2LDistanceV.prototype.aux = true;
Constraints.P2LDistanceV.prototype.NAME = 'P2LDistanceV';
Constraints.P2LDistanceV.prototype.UI_NAME = 'Distance P & L';
Constraints.P2LDistanceV.prototype.getSolveData = function() {
var params = [];
this.p.collectParams(params);
this.l.collectParams(params);
params.push(this.d);
return [[this.NAME, params]];
};
// We don't serialize auxiliary constraints
//
//Constraints.P2LDistanceV.prototype.serialize = function() {
// return [this.NAME, [this.p.id, this.l.id, this.d.id]];
//};
//
//Constraints.Factory[Constraints.P2LDistanceV.prototype.NAME] = function(refs, data) {
// return new Constraints.P2LDistanceV(refs(data[0]), refs(data[1]), refs(data[2]));
//};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.P2PDistance = function(p1, p2, d) {
this.p1 = p1;
this.p2 = p2;
this.d = d;
};
Constraints.P2PDistance.prototype.NAME = 'P2PDistance';
Constraints.P2PDistance.prototype.UI_NAME = 'Distance Points';
Constraints.P2PDistance.prototype.getSolveData = function(resolver) {
var params = [];
this.p1.collectParams(params);
this.p2.collectParams(params);
return [[this.NAME, params, [resolver(this.d)]]];
};
Constraints.P2PDistance.prototype.serialize = function() {
return [this.NAME, [this.p1.id, this.p2.id, this.d]];
};
Constraints.Factory[Constraints.P2PDistance.prototype.NAME] = function(refs, data) {
return new Constraints.P2PDistance(refs(data[0]), refs(data[1]), data[2]);
};
Constraints.P2PDistance.prototype.getObjects = function() {
return [this.p1, this.p2];
};
Constraints.P2PDistance.prototype.SettableFields = {'d' : "Enter the distance"};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.P2PDistanceV = function(p1, p2, d) {
this.p1 = p1;
this.p2 = p2;
this.d = d;
};
Constraints.P2PDistanceV.prototype.aux = true;
Constraints.P2PDistanceV.prototype.NAME = 'P2PDistanceV';
Constraints.P2PDistanceV.prototype.UI_NAME = 'Distance Points';
Constraints.P2PDistanceV.prototype.getSolveData = function() {
var params = [];
this.p1.collectParams(params);
this.p2.collectParams(params);
params.push(this.d);
return [[this.NAME, params]];
};
// We don't serialize auxiliary constraints
//
//Constraints.P2PDistanceV.prototype.serialize = function() {
// return [this.NAME, [this.p1.id, this.p2.id, this.d.id]];
//};
//
//Constraints.Factory[Constraints.P2PDistanceV.prototype.NAME] = function(refs, data) {
// return new Constraints.P2PDistanceV(refs(data[0]), refs(data[1]), refs(data[2]));
//};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.GreaterThan = function(p, limit) {
this.p = p;
this.limit = limit;
};
Constraints.GreaterThan.prototype.aux = true;
Constraints.GreaterThan.prototype.NAME = 'GreaterThan';
Constraints.GreaterThan.prototype.UI_NAME = 'Greater Than';
Constraints.GreaterThan.prototype.getSolveData = function() {
return [[this.NAME, [this.p], [this.limit]]];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Radius = function(arc, d) {
this.arc = arc;
this.d = d;
};
Constraints.Radius.prototype.NAME = 'Radius';
Constraints.Radius.prototype.UI_NAME = 'Radius Value';
Constraints.Radius.prototype.getSolveData = function(resolver) {
return [['equalsTo', [this.arc.r], [resolver(this.d)]]];
};
Constraints.Radius.prototype.serialize = function() {
return [this.NAME, [this.arc.id, this.d]];
};
Constraints.Factory[Constraints.Radius.prototype.NAME] = function(refs, data) {
return new Constraints.Radius(refs(data[0]), data[1]);
};
Constraints.Radius.prototype.getObjects = function() {
return [this.arc];
};
Constraints.Radius.prototype.SettableFields = {'d' : "Enter the radius value"};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.RR = function(arc1, arc2) {
this.arc1 = arc1;
this.arc2 = arc2;
};
Constraints.RR.prototype.NAME = 'RR';
Constraints.RR.prototype.UI_NAME = 'Radius Equality';
//Constraints.RR.prototype.reducible = true;
Constraints.RR.prototype.getSolveData = function() {
return [['equal', [this.arc1.r, this.arc2.r], []]];
};
Constraints.RR.prototype.serialize = function() {
return [this.NAME, [this.arc1.id, this.arc2.id]];
};
Constraints.Factory[Constraints.RR.prototype.NAME] = function(refs, data) {
return new Constraints.RR(refs(data[0]), refs(data[1]));
};
Constraints.RR.prototype.getObjects = function() {
return [this.arc1, this.arc2];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.LL = function(line1, line2) {
this.line1 = line1;
this.line2 = line2;
this.length = new Ref(math.distanceAB(line1.a, line1.b));
};
Constraints.LL.prototype.NAME = 'LL';
Constraints.LL.prototype.UI_NAME = 'Lines Equality';
Constraints.LL.prototype.getSolveData = function() {
var params1 = [];
var params2 = [];
this.line1.collectParams(params1);
this.line2.collectParams(params2);
params1.push(this.length);
params2.push(this.length);
return [
['P2PDistanceV', params1, []],
['P2PDistanceV', params2, []]
];
};
Constraints.LL.prototype.serialize = function() {
return [this.NAME, [this.line1.id, this.line2.id]];
};
Constraints.Factory[Constraints.LL.prototype.NAME] = function(refs, data) {
return new Constraints.LL(refs(data[0]), refs(data[1]));
};
Constraints.LL.prototype.getObjects = function() {
return [this.line1, this.line2];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Vertical = function(line) {
this.line = line;
};
Constraints.Vertical.prototype.NAME = 'Vertical';
Constraints.Vertical.prototype.UI_NAME = 'Vertical';
//Constraints.Vertical.prototype.reducible = true;
Constraints.Vertical.prototype.getSolveData = function() {
return [['equal', [this.line.a._x, this.line.b._x], []]];
};
Constraints.Vertical.prototype.serialize = function() {
return [this.NAME, [this.line.id]];
};
Constraints.Factory[Constraints.Vertical.prototype.NAME] = function(refs, data) {
return new Constraints.Vertical(refs(data[0]));
};
Constraints.Vertical.prototype.getObjects = function() {
return [this.line];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Horizontal = function(line) {
this.line = line;
};
Constraints.Horizontal.prototype.NAME = 'Horizontal';
Constraints.Horizontal.prototype.UI_NAME = 'Horizontal';
//Constraints.Horizontal.prototype.reducible = true;
Constraints.Horizontal.prototype.getSolveData = function() {
return [['equal', [this.line.a._y, this.line.b._y], []]];
};
Constraints.Horizontal.prototype.serialize = function() {
return [this.NAME, [this.line.id]];
};
Constraints.Factory[Constraints.Horizontal.prototype.NAME] = function(refs, data) {
return new Constraints.Horizontal(refs(data[0]));
};
Constraints.Horizontal.prototype.getObjects = function() {
return [this.line];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Tangent = function(arc, line) {
this.arc = arc;
this.line = line;
};
Constraints.Tangent.prototype.NAME = 'Tangent';
Constraints.Tangent.prototype.UI_NAME = 'Tangent';
Constraints.Tangent.prototype.getSolveData = function() {
var params = [];
this.arc.c.collectParams(params);
this.line.collectParams(params);
params.push(this.arc.r);
return [['P2LDistanceV', params, []]];
};
Constraints.Tangent.prototype.serialize = function() {
return [this.NAME, [this.arc.id, this.line.id]];
};
Constraints.Factory[Constraints.Tangent.prototype.NAME] = function(refs, data) {
return new Constraints.Tangent(refs(data[0]), refs(data[1]));
};
Constraints.Tangent.prototype.getObjects = function() {
return [this.arc, this.line];
};
// ------------------------------------------------------------------------------------------------------------------ //
export class SignedPerpendicular extends AbstractConstraint {
static deserialize(refs, data) {
return new SignedPerpendicular(refs(data[0]), refs(data[1]), refs(data[2]), refs(data[3]));
};
constructor(p1, p2, p3, p4) {
super();
this.points = [p1, p2, p3, p4];
};
getSolveData() {
const params = [];
this.points.forEach(p => p.collectParams(params));
return [['signedPerpendicular', params, []]];
}
serialize() {
return [this.NAME, this.points.map(p => p.id)];
}
getObjects() {
const collector = new Constraints.ParentsCollector();
this.points.forEach(p => collector.check(p));
return collector.parents;
}
}
Constraints.SignedPerpendicular = SignedPerpendicular;
Constraints.SignedPerpendicular.prototype.NAME = 'SignedPerpendicular';
Constraints.SignedPerpendicular.prototype.UI_NAME = 'SignedPerpendicular';
Constraints.Factory[SignedPerpendicular.prototype.NAME] = Coincident.deserialize;
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.PointOnLine = function(point, line) {
this.point = point;
this.line = line;
};
Constraints.PointOnLine.prototype.NAME = 'PointOnLine';
Constraints.PointOnLine.prototype.UI_NAME = 'Point On Line';
Constraints.PointOnLine.prototype.getSolveData = function() {
var params = [];
this.point.collectParams(params);
this.line.collectParams(params);
return [['P2LDistance', params, [0]]];
};
Constraints.PointOnLine.prototype.serialize = function() {
return [this.NAME, [this.point.id, this.line.id]];
};
Constraints.Factory[Constraints.PointOnLine.prototype.NAME] = function(refs, data) {
return new Constraints.PointOnLine(refs(data[0]), refs(data[1]));
};
Constraints.PointOnLine.prototype.getObjects = function() {
return [this.point, this.line];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.PointOnArc = function(point, arc) {
this.point = point;
this.arc = arc;
};
Constraints.PointOnArc.prototype.NAME = 'PointOnArc';
Constraints.PointOnArc.prototype.UI_NAME = 'Point On Arc';
Constraints.PointOnArc.prototype.getSolveData = function() {
var params = [];
this.point.collectParams(params);
this.arc.c.collectParams(params);
params.push(this.arc.r);
return [['P2PDistanceV', params, []]];
};
Constraints.PointOnArc.prototype.serialize = function() {
return [this.NAME, [this.point.id, this.arc.id]];
};
Constraints.Factory[Constraints.PointOnArc.prototype.NAME] = function(refs, data) {
return new Constraints.PointOnArc(refs(data[0]), refs(data[1]));
};
Constraints.PointOnArc.prototype.getObjects = function() {
return [this.point, this.arc];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.PointOnCurve = function(point, curveObject) {
this.point = point;
this.curveObject = curveObject;
};
Constraints.PointOnCurve.prototype.NAME = 'PointOnCurve';
Constraints.PointOnCurve.prototype.UI_NAME = 'Point On Curve';
Constraints.PointOnCurve.prototype.getSolveData = function() {
const params = [];
this.point.collectParams(params);
return [['PointOnCurve', params, [this.curveObject.curve]]];
};
Constraints.PointOnCurve.prototype.serialize = function() {
return [this.NAME, [this.point.id, this.curveObject.id]];
};
Constraints.Factory[Constraints.PointOnCurve.prototype.NAME] = function(refs, data) {
return new Constraints.PointOnCurve(refs(data[0]), refs(data[1]));
};
Constraints.PointOnCurve.prototype.getObjects = function() {
return [this.point, this.curveObject];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.PointOnEllipseInternal = function(point, ellipse) {
this.point = point;
this.ellipse= ellipse;
};
Constraints.PointOnEllipseInternal.prototype.NAME = 'PointOnEllipseI';
Constraints.PointOnEllipseInternal.prototype.UI_NAME = 'Point On Ellipse';
Constraints.PointOnEllipseInternal.prototype.aux = true;
Constraints.PointOnEllipseInternal.prototype.getSolveData = function() {
var params = [];
this.point.collectParams(params);
this.ellipse.ep1.collectParams(params);
this.ellipse.ep2.collectParams(params);
params.push(this.ellipse.r);
return [['PointOnEllipse', params, []]];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.PointOnEllipse = function(point, ellipse) {
Constraints.PointOnEllipseInternal.call(this, point, ellipse);
};
Constraints.PointOnEllipse.prototype.NAME = 'PointOnEllipse';
Constraints.PointOnEllipse.prototype.UI_NAME = 'Point On Ellipse';
Constraints.PointOnEllipse.prototype.getSolveData = function() {
return Constraints.PointOnEllipseInternal.prototype.getSolveData.call(this);
};
Constraints.PointOnEllipse.prototype.serialize = function() {
return [this.NAME, [this.point.id, this.ellipse.id]];
};
Constraints.Factory[Constraints.PointOnEllipse.prototype.NAME] = function(refs, data) {
return new Constraints.PointOnEllipse(refs(data[0]), refs(data[1]));
};
Constraints.PointOnEllipse.prototype.getObjects = function() {
return [this.point, this.ellipse];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.EllipseTangent = function(line, ellipse) {
this.line = line;
this.ellipse = ellipse;
};
Constraints.EllipseTangent.prototype.NAME = 'EllipseTangent';
Constraints.EllipseTangent.prototype.UI_NAME = 'Tangent Ellipse';
Constraints.EllipseTangent.prototype.getSolveData = function() {
const params = [];
this.line.collectParams(params);
this.ellipse.ep1.collectParams(params);
this.ellipse.ep2.collectParams(params);
params.push(this.ellipse.r);
return [['EllipseTangent', params, []]];
};
Constraints.EllipseTangent.prototype.serialize = function() {
return [this.NAME, [this.line.id, this.ellipse.id]];
};
Constraints.Factory[Constraints.EllipseTangent.prototype.NAME] = function(refs, data) {
return new Constraints.EllipseTangent(refs(data[0]), refs(data[1]));
};
Constraints.EllipseTangent.prototype.getObjects = function() {
return [this.line, this.ellipse];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.CurveTangent = function(line, curveObject) {
this.line = line;
this.curveObject = curveObject;
let [uMin, uMax] = this.curveObject.curve.domain();
let initPoint = this.curveObject.curve.point(0.5 * (uMin + uMax));
this.tx = new Ref(initPoint[0]);
this.ty = new Ref(initPoint[1]);
};
Constraints.CurveTangent.prototype.NAME = 'CurveTangent';
Constraints.CurveTangent.prototype.UI_NAME = 'Curve Curve';
Constraints.CurveTangent.prototype.getSolveData = function() {
const params = [];
this.line.collectParams(params);
params.push(this.tx);
params.push(this.ty);
return [['CurveTangent', params, [this.curveObject.curve]]];
};
Constraints.CurveTangent.prototype.serialize = function() {
return [this.NAME, [this.line.id, this.curveObject.id]];
};
Constraints.Factory[Constraints.CurveTangent.prototype.NAME] = function(refs, data) {
return new Constraints.CurveTangent(refs(data[0]), refs(data[1]));
};
Constraints.CurveTangent.prototype.getObjects = function() {
return [this.line, this.curveObject];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.PointInMiddle = function(point, line) {
this.point = point;
this.line = line;
this.length = new Ref(math.distanceAB(line.a, line.b) / 2);
};
Constraints.PointInMiddle.prototype.NAME = 'PointInMiddle';
Constraints.PointInMiddle.prototype.UI_NAME = 'Point In the Middle';
Constraints.PointInMiddle.prototype.getSolveData = function() {
var params1 = [];
var params2 = [];
this.line.a.collectParams(params1);
this.point.collectParams(params1);
params1.push(this.length);
this.line.b.collectParams(params2);
this.point.collectParams(params2);
params2.push(this.length);
return [
['P2PDistanceV', params1, []],
['P2PDistanceV', params2, []]
];
};
Constraints.PointInMiddle.prototype.serialize = function() {
return [this.NAME, [this.point.id, this.line.id]];
};
Constraints.Factory[Constraints.PointInMiddle.prototype.NAME] = function(refs, data) {
return new Constraints.PointInMiddle(refs(data[0]), refs(data[1]));
};
Constraints.PointInMiddle.prototype.getObjects = function() {
return [this.point, this.line];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Symmetry = function(point, line) {
this.point = point;
this.line = line;
this.length = new Ref(math.distanceAB(line.a, line.b) / 2);
};
Constraints.Symmetry.prototype.NAME = 'Symmetry';
Constraints.Symmetry.prototype.UI_NAME = 'Symmetry';
Constraints.Symmetry.prototype.getSolveData = function(resolver) {
var pointInMiddleData = Constraints.PointInMiddle.prototype.getSolveData.call(this, [resolver]);
var pointOnLineData = Constraints.PointOnLine.prototype.getSolveData.call(this, [resolver]);
return pointInMiddleData.concat(pointOnLineData);
};
Constraints.Symmetry.prototype.serialize = function() {
return [this.NAME, [this.point.id, this.line.id]];
};
Constraints.Factory[Constraints.Symmetry.prototype.NAME] = function(refs, data) {
return new Constraints.Symmetry(refs(data[0]), refs(data[1]));
};
Constraints.Symmetry.prototype.getObjects = function() {
return [this.point, this.line];
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Angle = function(p1, p2, p3, p4, angle) {
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
this.p4 = p4;
this._angle = new Ref(0);
this.angle = angle;
};
Constraints.Angle.prototype.NAME = 'Angle';
Constraints.Angle.prototype.UI_NAME = 'Lines Angle';
Constraints.Angle.prototype.getSolveData = function(resolver) {
this._angle.set(resolver(this.angle) / 180 * Math.PI);
var params = [];
this.p1.collectParams(params);
this.p2.collectParams(params);
this.p3.collectParams(params);
this.p4.collectParams(params);
params.push(this._angle);
return [['angleConst', params, []]];
};
Constraints.Angle.prototype.serialize = function() {
return [this.NAME, [this.p1.id, this.p2.id, this.p3.id, this.p4.id, this.angle]];
};
Constraints.Factory[Constraints.Angle.prototype.NAME] = function(refs, data) {
return new Constraints.Angle( refs(data[0]), refs(data[1]), refs(data[2]), refs(data[3]), data[4] );
};
Constraints.Angle.prototype.getObjects = function() {
var collector = new Constraints.ParentsCollector();
collector.check(this.p1);
collector.check(this.p2);
collector.check(this.p3);
collector.check(this.p4);
return collector.parents;
};
Constraints.Angle.prototype.SettableFields = {'angle' : "Enter the angle value"};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.LockConvex = function(c, a, t) {
this.c = c;
this.a = a;
this.t = t;
};
Constraints.LockConvex.prototype.NAME = 'LockConvex';
Constraints.LockConvex.prototype.UI_NAME = 'Lock Convexity';
Constraints.LockConvex.prototype.getSolveData = function() {
var params = [];
this.c.collectParams(params);
this.a.collectParams(params);
this.t.collectParams(params);
return [['LockConvex', params, []]];
};
Constraints.LockConvex.prototype.serialize = function() {
return [this.NAME, [this.c.id, this.a.id, this.t.id]];
};
Constraints.Factory[Constraints.LockConvex.prototype.NAME] = function(refs, data) {
return new Constraints.LockConvex(refs(data[0]), refs(data[1]), refs(data[2]));
};
Constraints.LockConvex.prototype.getObjects = function() {
var collector = new Constraints.ParentsCollector();
collector.check(this.c);
collector.check(this.a);
collector.check(this.t);
return collector.parents;
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Mirror = function(reflectionLine, objects, reflectedObjects) {
this.reflectionLine = reflectionLine;
this.objects = objects;
this.dir = new Vector();
this.updateDir();
if (!reflectedObjects) {
reflectedObjects = objects.map(o => {
let copy = o.copy();
copy.virtualOf = o.id;
copy.aux = true;
copy.role = 'virtual';
o.layer.add(copy);
this.reflect(o, copy);
return copy;
});
}
reflectedObjects.forEach((copy, i) => {
copy.virtualOf = this.objects[i].id;
copy.aux = true;
copy.role = 'virtual';
});
this.reflectedObjects = reflectedObjects;
};
Constraints.Mirror.prototype.NAME = 'Mirror';
Constraints.Mirror.prototype.UI_NAME = 'Mirror';
Constraints.Mirror.prototype.GENERATOR = true;
Constraints.Mirror.prototype.updateDir = function() {
this.dir.set(-(this.reflectionLine.b._y.get() - this.reflectionLine.a._y.get()), this.reflectionLine.b._x.get() - this.reflectionLine.a._x.get(), 0)._normalize();
};
Constraints.Mirror.prototype.reflect = function(source, dest) {
let origin = this.reflectionLine.a.toVector();
const pointMirroring = (x, y) => {
let pt = new Vector(x, y, 0);
let proj = this.dir.dot(pt.minus(origin));
return this.dir.multiply(- proj * 2)._plus(pt);
};
source.mirror(dest, pointMirroring);
};
Constraints.Mirror.prototype.getSolveData = function() {
return [];
};
Constraints.Mirror.prototype.serialize = function() {
let ids = [this.reflectionLine.id];
for (let i = 0; i < this.objects.length; i++) {
ids.push(this.objects[i].id);
ids.push(this.reflectedObjects[i].id);
}
return [this.NAME, ids];
};
Constraints.Factory[Constraints.Mirror.prototype.NAME] = function(refs, data) {
let [rlId, ...objectIds] = data;
let objects = [];
let reflectedObjects = [];
for (let i = 0; i < objectIds.length; i += 2) {
objects.push(refs(objectIds[i]));
reflectedObjects.push(refs(objectIds[i + 1]));
}
return new Constraints.Mirror(refs(rlId), objects, reflectedObjects);
};
Constraints.Mirror.prototype.getObjects = function() {
return [this.reflectionLine, ...this.objects];
};
Constraints.Mirror.prototype.visitParams = function(callback) {
this.reflectionLine.visitParams(callback);
this.objects.forEach(o => o.visitParams(callback));
};
Constraints.Mirror.prototype.visitGeneratedParams = function(callback) {
this.reflectedObjects.forEach(o => o.visitParams(callback));
};
Constraints.Mirror.prototype.updateGeneratedObjects = function() {
this.updateDir();
for (let i = 0; i < this.objects.length; i++) {
this.reflect(this.objects[i], this.reflectedObjects[i]);
}
};
Constraints.Mirror.prototype.getGeneratedObjects = function() {
return this.reflectedObjects;
};
// ------------------------------------------------------------------------------------------------------------------ //
/** @constructor */
Constraints.Fillet = function(point1, point2, arc) {
this.point1 = point1;
this.point2 = point2;
this.arc = arc;
const line1 = point1.parent;
const line2 = point2.parent;
this.contraints = [
new Constraints.SignedPerpendicular( arc.a, arc.c, point1, line1.opposite(point1)),
new Constraints.SignedPerpendicular( arc.b, arc.c, line2.opposite(point2), point2),
new Constraints.Coincident( arc.a, point1),
new Constraints.Coincident( arc.b, point2)
];
};
Constraints.Fillet.prototype.NAME = 'Fillet';
Constraints.Fillet.prototype.UI_NAME = 'Fillet';
Constraints.Fillet.prototype.getSolveData = function() {
let solveData = [];
this.contraints.forEach(c => c.getSolveData().forEach(d => solveData.push(d)));
return solveData;
};
Constraints.Fillet.prototype.serialize = function() {
return [this.NAME, [this.point1.id, this.point2.id, this.arc.id]];
};
Constraints.Factory[Constraints.Fillet.prototype.NAME] = function(refs, data) {
return new Constraints.Fillet(refs(data[0]), refs(data[1]), refs(data[2]));
};
Constraints.Fillet.prototype.getObjects = function() {
let objects = [];
this.contraints.forEach(c => c.getObjects().forEach(o => objects.push(o)));
return objects;
};
Constraints.Fillet.prototype.validate = function() {
function validOn(p, arc, left) {
let op = p.parent.opposite(p);
let opV = op.toVector();
let dir = p.toVector()._minus(opV)._normalize();
let centerDir = arc.c.toVector()._minus(opV)._normalize();
let z = centerDir.cross(dir).z;
return left === z < 0;
}
return validOn(this.point1, this.arc, true) && validOn(this.point2, this.arc, false);
};
Constraints.ParentsCollector = function() {
this.parents = [];
var parents = this.parents;
var index = {};
function add(obj) {
if (index[obj.id] === undefined) {
index[obj.id] = obj;
parents.push(obj);
}
}
this.check = function(obj) {
if (obj.parent !== null) {
add(obj.parent);
} else {
add(obj);
}
};
};