mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-07 17:04:58 +01:00
409 lines
No EOL
9.9 KiB
JavaScript
409 lines
No EOL
9.9 KiB
JavaScript
TCAD.constraints = {};
|
|
|
|
TCAD.constraints.create = function(name, params, values) {
|
|
switch (name) {
|
|
case "equal":
|
|
return new TCAD.constraints.Equal(params);
|
|
case "equalsTo":
|
|
return new TCAD.constraints.EqualsTo(params, values[0]);
|
|
case "perpendicular":
|
|
return new TCAD.constraints.Perpendicular(params);
|
|
case "parallel":
|
|
return new TCAD.constraints.Parallel(params);
|
|
case "P2LDistance":
|
|
return new TCAD.constraints.P2LDistance(params, values[0]);
|
|
case "P2LDistanceV":
|
|
return new TCAD.constraints.P2LDistanceV(params);
|
|
case "P2PDistance":
|
|
return new TCAD.constraints.P2PDistance(params, values[0]);
|
|
case "P2PDistanceV":
|
|
return new TCAD.constraints.P2PDistanceV(params);
|
|
}
|
|
};
|
|
|
|
/** @constructor */
|
|
TCAD.constraints.Equal = function(params) {
|
|
|
|
this.params = params;
|
|
|
|
this.error = function() {
|
|
return this.params[0].get() - this.params[1].get();
|
|
};
|
|
|
|
this.gradient = function(out) {
|
|
out[0] = 1;
|
|
out[1] = -1;
|
|
}
|
|
|
|
};
|
|
|
|
TCAD.constraints.ConstantWrapper = function(constr, mask) {
|
|
|
|
this.params = [];
|
|
this.grad = [];
|
|
var j;
|
|
|
|
for (j = 0; j < constr.params.length; j++) {
|
|
if (!mask[j]) {
|
|
this.params.push(constr.params[j]);
|
|
}
|
|
this.grad.push(0);
|
|
}
|
|
|
|
this.error = function() {
|
|
return constr.error();
|
|
};
|
|
|
|
this.gradient = function(out) {
|
|
constr.gradient(this.grad);
|
|
var jj = 0;
|
|
for (j = 0; j < mask.length; j++) {
|
|
if (!mask[j]) {
|
|
out[jj ++] = this.grad[j];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
TCAD.constraints.Weighted = function(constr, weight) {
|
|
|
|
this.params = constr.params;
|
|
|
|
this.error = function() {
|
|
return constr.error() * weight;
|
|
};
|
|
|
|
this.gradient = function(out) {
|
|
constr.gradient(out);
|
|
for (var i = 0; i < out.length; i++) {
|
|
out[i] *= weight;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/** @constructor */
|
|
TCAD.constraints.EqualsTo = function(params, value) {
|
|
|
|
this.params = params;
|
|
this.value = value;
|
|
|
|
this.error = function() {
|
|
return this.params[0].get() - this.value;
|
|
};
|
|
|
|
|
|
this.gradient = function(out) {
|
|
out[0] = 1;
|
|
};
|
|
};
|
|
|
|
/** @constructor */
|
|
TCAD.constraints.P2LDistance = function(params, distance) {
|
|
|
|
this.params = params;
|
|
this.distance = distance;
|
|
|
|
this.tx = 0;
|
|
this.ty = 1;
|
|
this.lp1x = 2;
|
|
this.lp1y = 3;
|
|
this.lp2x = 4;
|
|
this.lp2y = 5;
|
|
|
|
this.error = function() {
|
|
var x0 = this.p0x(), x1 = this.p1x(), x2 = this.p2x();
|
|
var y0 = this.p0y(), y1 = this.p1y(), y2 = this.p2y();
|
|
var dist = this.distance;
|
|
var dx = x2 - x1;
|
|
var dy = y2 - y1;
|
|
var d = Math.sqrt(dx * dx + dy * dy);
|
|
//calculate triangle area
|
|
var area = Math.abs
|
|
(-x0 * dy + y0 * dx + x1 * y2 - x2 * y1);
|
|
if (d == 0) {
|
|
return 0;
|
|
}
|
|
return (area / d - dist);
|
|
|
|
};
|
|
|
|
this.p1x = function() {
|
|
return params[this.lp1x].get();
|
|
};
|
|
|
|
this.p1y = function() {
|
|
return params[this.lp1y].get();
|
|
};
|
|
|
|
this.p2x = function() {
|
|
return params[this.lp2x].get();
|
|
};
|
|
|
|
this.p2y = function() {
|
|
return params[this.lp2y].get();
|
|
};
|
|
|
|
this.p0x = function() {
|
|
return params[this.tx].get();
|
|
};
|
|
|
|
this.p0y = function() {
|
|
return params[this.ty].get();
|
|
};
|
|
|
|
|
|
this.gradient = function(out) {
|
|
var x0 = this.p0x(), x1 = this.p1x(), x2 = this.p2x();
|
|
var y0 = this.p0y(), y1 = this.p1y(), y2 = this.p2y();
|
|
var dx = x2 - x1;
|
|
var dy = y2 - y1;
|
|
var d2 = dx * dx + dy * dy;
|
|
var d = Math.sqrt(d2);
|
|
var area = -x0 * dy + y0 * dx + x1 * y2 - x2 * y1;
|
|
out[this.tx] = ((y1 - y2) / d);
|
|
out[this.ty] = ((x2 - x1) / d);
|
|
out[this.lp1x] = (((y2 - y0) * d + (dx / d) * area) / d2);
|
|
out[this.lp1y] = (((x0 - x2) * d + (dy / d) * area) / d2);
|
|
out[this.lp2x] = (((y0 - y1) * d - (dx / d) * area) / d2);
|
|
out[this.lp2y] = (((x1 - x0) * d - (dy / d) * area) / d2);
|
|
|
|
for (var i = 0; i < 6; i++) {
|
|
if (Number.isNaN(out[i])) {
|
|
out[i] = 0;
|
|
}
|
|
if (area < 0) {
|
|
out[i] *= -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/** @constructor */
|
|
TCAD.constraints.P2LDistanceV = function(params) {
|
|
|
|
this.params = params;//.slice(0, params.length -1);
|
|
|
|
var TX = 0;
|
|
var TY = 1;
|
|
var LP1X = 2;
|
|
var LP1Y = 3;
|
|
var LP2X = 4;
|
|
var LP2Y = 5;
|
|
var D = 6;
|
|
|
|
this.error = function() {
|
|
var x0 = this.p0x(), x1 = this.p1x(), x2 = this.p2x();
|
|
var y0 = this.p0y(), y1 = this.p1y(), y2 = this.p2y();
|
|
var dist = this.params[D].get();
|
|
var dx = x2 - x1;
|
|
var dy = y2 - y1;
|
|
var d = Math.sqrt(dx * dx + dy * dy);
|
|
var area = Math.abs
|
|
(-x0 * dy + y0 * dx + x1 * y2 - x2 * y1);
|
|
if (d == 0) {
|
|
return 0;
|
|
}
|
|
return (area / d - dist);
|
|
|
|
};
|
|
|
|
this.p1x = function() {
|
|
return params[LP1X].get();
|
|
};
|
|
|
|
this.p1y = function() {
|
|
return params[LP1Y].get();
|
|
};
|
|
|
|
this.p2x = function() {
|
|
return params[LP2X].get();
|
|
};
|
|
|
|
this.p2y = function() {
|
|
return params[LP2Y].get();
|
|
};
|
|
|
|
this.p0x = function() {
|
|
return params[TX].get();
|
|
};
|
|
|
|
this.p0y = function() {
|
|
return params[TY].get();
|
|
};
|
|
|
|
this.gradient = function(out) {
|
|
var x0 = this.p0x(), x1 = this.p1x(), x2 = this.p2x();
|
|
var y0 = this.p0y(), y1 = this.p1y(), y2 = this.p2y();
|
|
var dx = x2 - x1;
|
|
var dy = y2 - y1;
|
|
var d2 = dx * dx + dy * dy;
|
|
var d = Math.sqrt(d2);
|
|
var area = -x0 * dy + y0 * dx + x1 * y2 - x2 * y1;
|
|
out[TX] = ((y1 - y2) / d);
|
|
out[TY] = ((x2 - x1) / d);
|
|
out[LP1X] = (((y2 - y0) * d + (dx / d) * area) / d2);
|
|
out[LP1Y] = (((x0 - x2) * d + (dy / d) * area) / d2);
|
|
out[LP2X] = (((y0 - y1) * d - (dx / d) * area) / d2);
|
|
out[LP2Y] = (((x1 - x0) * d - (dy / d) * area) / d2);
|
|
out[D] = -1;
|
|
|
|
for (var i = 0; i < 6; i++) {
|
|
if (Number.isNaN(out[i])) {
|
|
out[i] = 0;
|
|
}
|
|
if (area < 0) {
|
|
out[i] *= -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
/** @constructor */
|
|
TCAD.constraints.P2PDistance = function(params, distance) {
|
|
|
|
this.params = params;
|
|
this.distance = distance;
|
|
|
|
this.p1x = 0;
|
|
this.p1y = 1;
|
|
this.p2x = 2;
|
|
this.p2y = 3;
|
|
|
|
this.get = function(i) {
|
|
return this.params[i].get();
|
|
};
|
|
|
|
this.error = function() {
|
|
var dx = this.get(this.p1x) - this.get(this.p2x);
|
|
var dy = this.get(this.p1y) - this.get(this.p2y);
|
|
var d = Math.sqrt(dx * dx + dy * dy);
|
|
return (d - this.distance);
|
|
};
|
|
|
|
this.gradient = function(out) {
|
|
|
|
var dx = this.get(this.p1x) - this.get(this.p2x);
|
|
var dy = this.get(this.p1y) - this.get(this.p2y);
|
|
var d = Math.sqrt(dx * dx + dy * dy);
|
|
out[this.p1x] = dx / d;
|
|
out[this.p1y] = dy / d;
|
|
out[this.p2x] = -dx / d;
|
|
out[this.p2y] = -dy / d;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/** @constructor */
|
|
TCAD.constraints.P2PDistanceV = function(params) {
|
|
|
|
this.params = params;
|
|
|
|
|
|
this.p1x = 0;
|
|
this.p1y = 1;
|
|
this.p2x = 2;
|
|
this.p2y = 3;
|
|
this.d = 4;
|
|
|
|
this.get = function(i) {
|
|
return this.params[i].get();
|
|
};
|
|
|
|
this.error = function() {
|
|
var dx = this.get(this.p1x) - this.get(this.p2x);
|
|
var dy = this.get(this.p1y) - this.get(this.p2y);
|
|
var d = Math.sqrt(dx * dx + dy * dy);
|
|
return (d - this.get(this.d));
|
|
};
|
|
|
|
this.gradient = function(out) {
|
|
|
|
var dx = this.get(this.p1x) - this.get(this.p2x);
|
|
var dy = this.get(this.p1y) - this.get(this.p2y);
|
|
var d = Math.sqrt(dx * dx + dy * dy);
|
|
out[this.p1x] = dx / d;
|
|
out[this.p1y] = dy / d;
|
|
out[this.p2x] = -dx / d;
|
|
out[this.p2y] = -dy / d;
|
|
out[this.d] = -1;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/** @constructor */
|
|
TCAD.constraints.Parallel = function(params) {
|
|
|
|
this.params = params;
|
|
|
|
this.l1p1x = 0;
|
|
this.l1p1y = 1;
|
|
this.l1p2x = 2;
|
|
this.l1p2y = 3;
|
|
this.l2p1x = 4;
|
|
this.l2p1y = 5;
|
|
this.l2p2x = 6;
|
|
this.l2p2y = 7;
|
|
|
|
this.error = function() {
|
|
var dx1 = (this.params[this.l1p1x].get() - this.params[this.l1p2x].get());
|
|
var dy1 = (this.params[this.l1p1y].get() - this.params[this.l1p2y].get());
|
|
var dx2 = (this.params[this.l2p1x].get() - this.params[this.l2p2x].get());
|
|
var dy2 = (this.params[this.l2p1y].get() - this.params[this.l2p2y].get());
|
|
return (dx1*dy2 - dy1*dx2);
|
|
};
|
|
|
|
this.gradient = function(out) {
|
|
out[this.l1p1x] = (this.params[this.l2p1y].get() - this.params[this.l2p2y].get());
|
|
out[this.l1p2x] = -(this.params[this.l2p1y].get() - this.params[this.l2p2y].get());
|
|
out[this.l1p1y] = -(this.params[this.l2p1x].get() - this.params[this.l2p2x].get());
|
|
out[this.l1p2y] = (this.params[this.l2p1x].get() - this.params[this.l2p2x].get());
|
|
out[this.l2p1x] = -(this.params[this.l1p1y].get() - this.params[this.l1p2y].get());
|
|
out[this.l2p2x] = (this.params[this.l1p1y].get() - this.params[this.l1p2y].get());
|
|
out[this.l2p1y] = (this.params[this.l1p1x].get() - this.params[this.l1p2x].get());
|
|
out[this.l2p2y] = -(this.params[this.l1p1x].get() - this.params[this.l1p2x].get());
|
|
}
|
|
};
|
|
|
|
/** @constructor */
|
|
TCAD.constraints.Perpendicular = function(params) {
|
|
|
|
this.params = params;
|
|
|
|
this.l1p1x = 0;
|
|
this.l1p1y = 1;
|
|
this.l1p2x = 2;
|
|
this.l1p2y = 3;
|
|
this.l2p1x = 4;
|
|
this.l2p1y = 5;
|
|
this.l2p2x = 6;
|
|
this.l2p2y = 7;
|
|
|
|
this.error = function() {
|
|
var dx1 = (this.params[this.l1p1x].get() - this.params[this.l1p2x].get());
|
|
var dy1 = (this.params[this.l1p1y].get() - this.params[this.l1p2y].get());
|
|
var dx2 = (this.params[this.l2p1x].get() - this.params[this.l2p2x].get());
|
|
var dy2 = (this.params[this.l2p1y].get() - this.params[this.l2p2y].get());
|
|
//dot product shows how the lines off to be perpendicular
|
|
return (dx1*dx2 + dy1*dy2);
|
|
};
|
|
|
|
this.gradient = function(out) {
|
|
|
|
out[this.l1p1x] = (this.params[this.l2p1x].get() - this.params[this.l2p2x].get());
|
|
out[this.l1p2x] = -(this.params[this.l2p1x].get() - this.params[this.l2p2x].get());
|
|
out[this.l1p1y] = (this.params[this.l2p1y].get() - this.params[this.l2p2y].get());
|
|
out[this.l1p2y] = -(this.params[this.l2p1y].get() - this.params[this.l2p2y].get());
|
|
out[this.l2p1x] = (this.params[this.l1p1x].get() - this.params[this.l1p2x].get());
|
|
out[this.l2p2x] = -(this.params[this.l1p1x].get() - this.params[this.l1p2x].get());
|
|
out[this.l2p1y] = (this.params[this.l1p1y].get() - this.params[this.l1p2y].get());
|
|
out[this.l2p2y] = -(this.params[this.l1p1y].get() - this.params[this.l1p2y].get());
|
|
|
|
}
|
|
|
|
}; |