mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-07 17:04:58 +01:00
fix sketcher solving problems
This commit is contained in:
parent
06a76f643d
commit
69de018f45
5 changed files with 161 additions and 82 deletions
|
|
@ -1,5 +1,7 @@
|
|||
optim = {};
|
||||
|
||||
optim.DEBUG_HANDLER = function() {};
|
||||
|
||||
//Added strong wolfe condition to numeric's uncmin
|
||||
optim.bfgs_ = function(f,x0,tol,gradient,maxit,callback,options) {
|
||||
var grad = numeric.gradient;
|
||||
|
|
@ -335,6 +337,7 @@ optim.dog_leg = function (subsys, rough) {
|
|||
var iter = 0, stop = 0, reduce = 0;
|
||||
//var log = [];
|
||||
while (stop === 0) {
|
||||
optim.DEBUG_HANDLER(iter, err);
|
||||
|
||||
// check if finished
|
||||
if (fx_inf <= tolf ) // Success
|
||||
|
|
@ -365,14 +368,12 @@ optim.dog_leg = function (subsys, rough) {
|
|||
|
||||
var hitBoundary = false;
|
||||
|
||||
var stepKind;
|
||||
// compute the dogleg step
|
||||
var gnorm = n.norm2(g);
|
||||
if (n.norm2(h_gn) < delta) {
|
||||
var gnNorm = n.norm2(h_gn);
|
||||
if (gnNorm < delta) {
|
||||
h_dl = h_gn;
|
||||
stepKind = 1;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
var Jt = n.transpose(Jx);
|
||||
var B = n.dot(Jt, Jx);
|
||||
var gBg = n.dot(g, n.dot(B, g));
|
||||
|
|
@ -380,24 +381,26 @@ optim.dog_leg = function (subsys, rough) {
|
|||
if (alpha * gnorm >= delta) {
|
||||
h_dl = n.mul(g, - delta / gnorm);
|
||||
hitBoundary = true;
|
||||
stepKind = 2;
|
||||
} else {
|
||||
var h_sd = n.mul(g, - alpha);
|
||||
if (isNaN(gnNorm)) {
|
||||
h_dl = h_sd;
|
||||
} else {
|
||||
|
||||
var d = n.sub(h_gn, h_sd);
|
||||
var d = n.sub(h_gn, h_sd);
|
||||
|
||||
var a = n.dot(d, d);
|
||||
var b = 2 * n.dot(h_sd, d);
|
||||
var c = n.dot(h_sd, h_sd) - delta * delta
|
||||
var a = n.dot(d, d);
|
||||
var b = 2 * n.dot(h_sd, d);
|
||||
var c = n.dot(h_sd, h_sd) - delta * delta;
|
||||
|
||||
var sqrt_discriminant = Math.sqrt(b * b - 4 * a * c)
|
||||
var sqrt_discriminant = Math.sqrt(b * b - 4 * a * c);
|
||||
|
||||
var beta = (-b + sqrt_discriminant) / (2 * a)
|
||||
var beta = (-b + sqrt_discriminant) / (2 * a);
|
||||
|
||||
// and update h_dl and dL with beta
|
||||
h_dl = n.add(h_sd, n.mul(beta, d));
|
||||
hitBoundary = true;
|
||||
stepKind = 3;
|
||||
// and update h_dl and dL with beta
|
||||
h_dl = n.add(h_sd, n.mul(beta, d));
|
||||
hitBoundary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -839,11 +839,9 @@ TCAD.TWO.DragTool = function(obj, viewer) {
|
|||
this._point = {x: 0, y: 0};
|
||||
this.origin = {x: 0, y: 0};
|
||||
this.ref = this.obj.getReferencePoint();
|
||||
this.errorX = 0;
|
||||
this.errorY = 0;
|
||||
this.solver = null;
|
||||
};
|
||||
|
||||
TCAD.TWO.DragTool.prototype.snapshots = []
|
||||
TCAD.TWO.DragTool.prototype.keydown = function(e) {};
|
||||
TCAD.TWO.DragTool.prototype.keypress = function(e) {};
|
||||
TCAD.TWO.DragTool.prototype.keyup = function(e) {};
|
||||
|
|
@ -852,29 +850,27 @@ TCAD.TWO.DragTool.prototype.cleanup = function(e) {};
|
|||
TCAD.TWO.DragTool.prototype.mousemove = function(e) {
|
||||
var x = this._point.x;
|
||||
var y = this._point.y;
|
||||
this.viewer.screenToModel2(e.x, e.y, this._point);
|
||||
var dx = this._point.x - x - this.errorX;
|
||||
var dy = this._point.y - y - this.errorY;
|
||||
var checkX = this.ref.x;
|
||||
var checkY = this.ref.y;
|
||||
this.obj.translate(dx, dy);
|
||||
this.viewer.screenToModel2(e.offsetX, e.offsetY, this._point);
|
||||
var dx = this._point.x - x;
|
||||
var dy = this._point.y - y;
|
||||
if (!e.altKey && !e.ctrlKey) {
|
||||
for (var i = 0; i < this.lockedShifts.length; i += 2) {
|
||||
this.lockedValues[i] = this._point.x - this.lockedShifts[i];
|
||||
this.lockedValues[i + 1] = this._point.y - this.lockedShifts[i + 1];
|
||||
}
|
||||
this.solver.updateLock(this.lockedValues);
|
||||
this.solveRequest(true);
|
||||
} else {
|
||||
this.obj.translate(dx, dy);
|
||||
}
|
||||
|
||||
this.errorX = (this.ref.x - dx) - checkX;
|
||||
this.errorY = (this.ref.y - dy) - checkY;
|
||||
|
||||
// console.log("accumulated error X = " + this.errorX);
|
||||
// console.log("accumulated error Y = " + this.errorY);
|
||||
|
||||
this.viewer.refresh();
|
||||
};
|
||||
|
||||
TCAD.TWO.DragTool.prototype.mousedown = function(e) {
|
||||
this.origin.x = e.x;
|
||||
this.origin.y = e.y;
|
||||
this.viewer.screenToModel2(e.x, e.y, this._point);
|
||||
this.origin.x = e.offsetX;
|
||||
this.origin.y = e.offsetY;
|
||||
this.viewer.screenToModel2(e.offsetX, e.offsetY, this._point);
|
||||
this.prepareSolver();
|
||||
};
|
||||
|
||||
|
|
@ -882,10 +878,11 @@ TCAD.TWO.DragTool.prototype.mouseup = function(e) {
|
|||
this.solveRequest(false);
|
||||
this.viewer.refresh();
|
||||
this.viewer.toolManager.releaseControl();
|
||||
var traveled = TCAD.math.distance(this.origin.x, this.origin.y, e.x, e.y);
|
||||
var traveled = TCAD.math.distance(this.origin.x, this.origin.y, e.offsetX, e.offsetY);
|
||||
if (traveled >= 10) {
|
||||
this.viewer.historyManager.lightCheckpoint(10);
|
||||
}
|
||||
//this.animateSolution();
|
||||
};
|
||||
|
||||
TCAD.TWO.DragTool.prototype.mousewheel = function(e) {
|
||||
|
|
@ -896,20 +893,70 @@ TCAD.TWO.DragTool.prototype.solveRequest = function(rough) {
|
|||
this.solver.sync();
|
||||
};
|
||||
|
||||
TCAD.TWO.DragTool.prototype.getParamsToLock = function() {
|
||||
var params = [];
|
||||
this.obj.accept(function(obj) {
|
||||
if (obj._class === 'TCAD.TWO.EndPoint') {
|
||||
params.push(obj._x);
|
||||
params.push(obj._y);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return params;
|
||||
};
|
||||
|
||||
TCAD.TWO.DragTool.prototype.prepareSolver = function() {
|
||||
var locked;
|
||||
if (this.obj._class === 'TCAD.TWO.EndPoint') {
|
||||
locked = [this.obj._x, this.obj._y];
|
||||
// if (this.obj.parent != null
|
||||
// && this.obj.parent._class === 'TCAD.TWO.Arc') {
|
||||
//
|
||||
// if (this.obj.id != this.obj.parent.c.id) {
|
||||
// locked.push(this.obj.parent.c._x);
|
||||
// locked.push(this.obj.parent.c._y);
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
locked = [];
|
||||
var locked = this.getParamsToLock();
|
||||
this.lockedShifts = [];
|
||||
this.lockedValues = [];
|
||||
for (var i = 0; i < locked.length; i += 2) {
|
||||
this.lockedShifts[i] = this._point.x - locked[i].get();
|
||||
this.lockedShifts[i + 1] = this._point.y - locked[i + 1].get();
|
||||
}
|
||||
this.solver = this.viewer.parametricManager.prepare(locked);
|
||||
//this.enableRecording();
|
||||
};
|
||||
|
||||
TCAD.TWO.DragTool.prototype.enableRecording = function() {
|
||||
var solver = this.solver;
|
||||
var snapshots = this.snapshots = [];
|
||||
optim.DEBUG_HANDLER = function() {
|
||||
snapshots.push([]);
|
||||
for (var i = 0; i < solver.solvers.length; i++) {
|
||||
var sys = solver.solvers[i].system;
|
||||
snapshots[i].push(sys.params.map(function(p) {return p.get()}))
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
TCAD.TWO.DragTool.prototype.animateSolution = function() {
|
||||
if (this.snapshots.length === 0) return;
|
||||
var stepNum = 0;
|
||||
var scope = this;
|
||||
var then = Date.now();
|
||||
var speed = 3000;
|
||||
function step() {
|
||||
var now = Date.now();
|
||||
var elapsed = now - then;
|
||||
|
||||
if (elapsed > speed) {
|
||||
for (var i = 0; i < scope.solver.solvers.length; i++) {
|
||||
var sys = scope.solver.solvers[i].system;
|
||||
if (stepNum >= scope.snapshots[i].length) continue;
|
||||
var values = scope.snapshots[i][stepNum];
|
||||
for (var k = 0; k < values.length; k++) {
|
||||
sys.params[k]._backingParam.set(values[k]);
|
||||
}
|
||||
}
|
||||
stepNum ++;
|
||||
|
||||
then = now;
|
||||
scope.viewer.repaint();
|
||||
}
|
||||
|
||||
if (stepNum < scope.snapshots[0].length) {
|
||||
window.requestAnimationFrame(step);
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(step);
|
||||
};
|
||||
|
|
@ -236,6 +236,7 @@ TCAD.constraints.P2PDistance = function(params, distance) {
|
|||
out[p1y] = dy / d;
|
||||
out[p2x] = -dx / d;
|
||||
out[p2y] = -dy / d;
|
||||
for (var i = 0; i < 4; i++) if (Number.isNaN(out[i])) out[i] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -267,6 +268,7 @@ TCAD.constraints.P2PDistanceV = function(params) {
|
|||
out[p2x] = -dx / d;
|
||||
out[p2y] = -dy / d;
|
||||
out[D] = -1;
|
||||
for (var i = 0; i < 4; i++) if (Number.isNaN(out[i])) out[i] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ TCAD.parametric.prepare = function(constrs, locked, aux, alg) {
|
|||
returnCode : 1
|
||||
};
|
||||
|
||||
var conflict = TCAD.parametric.diagnose(sys).conflict;
|
||||
var conflict = false;//TCAD.parametric.diagnose(sys).conflict;
|
||||
if (conflict) {
|
||||
console.log("Conflicting or redundant constraints. Please fix your system.");
|
||||
}
|
||||
|
|
@ -271,6 +271,7 @@ TCAD.parametric.prepare = function(constrs, locked, aux, alg) {
|
|||
diagnose : function() {return TCAD.parametric.diagnose(sys)},
|
||||
error : function() {return sys.error()},
|
||||
solveSystem : solve,
|
||||
system : sys,
|
||||
updateLock : function(values) {
|
||||
for (var i = 0; i < values.length; ++i) {
|
||||
lockingConstrs[i].constr.value = values[i];
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ TCAD.TWO.ParametricManager.prototype._add = function(constr) {
|
|||
};
|
||||
|
||||
TCAD.TWO.ParametricManager.prototype.checkRedundancy = function (subSystem, constr) {
|
||||
var solver = this.prepareForSubSystem([], subSystem);
|
||||
var solver = this.prepareForSubSystem([], subSystem.constraints);
|
||||
if (solver.diagnose().conflict) {
|
||||
alert("Most likely this "+constr.NAME + " constraint is CONFLICTING!")
|
||||
}
|
||||
|
|
@ -295,14 +295,14 @@ TCAD.TWO.ParametricManager.prototype.coincident = function(objs) {
|
|||
TCAD.TWO.ParametricManager.prototype.getSolveData = function() {
|
||||
var sdata = [];
|
||||
for (var i = 0; i < this.subSystems.length; i++) {
|
||||
this.__getSolveData(this.subSystems[i], sdata);
|
||||
this.__getSolveData(this.subSystems[i].constraints, sdata);
|
||||
}
|
||||
return sdata;
|
||||
};
|
||||
|
||||
TCAD.TWO.ParametricManager.prototype.__getSolveData = function(subSystem, out) {
|
||||
for (var i = 0; i < subSystem.constraints.length; ++i) {
|
||||
var constraint = subSystem.constraints[i];
|
||||
TCAD.TWO.ParametricManager.prototype.__getSolveData = function(constraints, out) {
|
||||
for (var i = 0; i < constraints.length; ++i) {
|
||||
var constraint = constraints[i];
|
||||
var data = constraint.getSolveData();
|
||||
for (var j = 0; j < data.length; ++j) {
|
||||
data[j].push(constraint.reducible !== undefined);
|
||||
|
|
@ -324,21 +324,24 @@ TCAD.TWO.ParametricManager.prototype.solveWithLock = function(lock) {
|
|||
solver.sync();
|
||||
};
|
||||
|
||||
TCAD.TWO.ParametricManager.prototype.prepare = function(locked) {
|
||||
return this._prepare(locked, this.subSystems);
|
||||
TCAD.TWO.ParametricManager.prototype.prepare = function(locked, extraConstraints) {
|
||||
return this._prepare(locked, this.subSystems, extraConstraints);
|
||||
};
|
||||
|
||||
TCAD.TWO.ParametricManager.prototype._prepare = function(locked, subSystems) {
|
||||
TCAD.TWO.ParametricManager.prototype._prepare = function(locked, subSystems, extraConstraints) {
|
||||
var solvers = [];
|
||||
for (var i = 0; i < subSystems.length; i++) {
|
||||
solvers.push(this.prepareForSubSystem(locked, subSystems[i]));
|
||||
solvers.push(this.prepareForSubSystem(locked, subSystems[i].constraints, extraConstraints));
|
||||
}
|
||||
if (subSystems.length == 0 && locked.length != 0) {
|
||||
solvers.push(this.prepareForSubSystem(locked, [], extraConstraints));
|
||||
}
|
||||
return {
|
||||
solvers : solvers,
|
||||
|
||||
solve : function(rough) {
|
||||
for (var i = 0; i < solvers.length; i++) {
|
||||
var alg = subSystems[i].alg;
|
||||
var alg = i < subSystems.length ? subSystems[i].alg : 1;
|
||||
var res = solvers[i].solve(rough, alg);
|
||||
if (res.returnCode !== 1) {
|
||||
alg = alg == 1 ? 2 : 1;
|
||||
|
|
@ -354,10 +357,10 @@ TCAD.TWO.ParametricManager.prototype._prepare = function(locked, subSystems) {
|
|||
solvers[i].sync();
|
||||
}
|
||||
},
|
||||
|
||||
updateLock : function() {
|
||||
|
||||
updateLock : function(values) {
|
||||
for (var i = 0; i < solvers.length; i++) {
|
||||
solvers[i].updateLock();
|
||||
solvers[i].updateLock(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -393,7 +396,7 @@ TCAD.TWO.ParametricManager.__toId = function(v) {
|
|||
return v.id;
|
||||
};
|
||||
|
||||
TCAD.TWO.ParametricManager.prototype.prepareForSubSystem = function(locked, subSystem) {
|
||||
TCAD.TWO.ParametricManager.prototype.prepareForSubSystem = function(locked, subSystemConstraints, extraConstraints) {
|
||||
|
||||
var pdict = {};
|
||||
var params;
|
||||
|
|
@ -401,12 +404,17 @@ TCAD.TWO.ParametricManager.prototype.prepareForSubSystem = function(locked, subS
|
|||
|
||||
var equalsDict = {};
|
||||
var equalsIndex = [];
|
||||
var eqcElimination = [];
|
||||
var eqcElimination = {};
|
||||
|
||||
var lockedIds = locked.map(function(p) {return p.id});
|
||||
|
||||
function peq(p1, p2) {
|
||||
return Math.abs(p1.get() - p2.get()) <= 0.000001
|
||||
}
|
||||
var system = this.__getSolveData(subSystem, []);
|
||||
var system = [];
|
||||
this.__getSolveData(subSystemConstraints, system);
|
||||
if (!!extraConstraints) this.__getSolveData(extraConstraints, system);
|
||||
|
||||
// system.sort(function(a, b){
|
||||
// a = a[0] === 'equal' ? 1 : 2;
|
||||
// b = b[0] === 'equal' ? 1 : 2;
|
||||
|
|
@ -417,18 +425,49 @@ TCAD.TWO.ParametricManager.prototype.prepareForSubSystem = function(locked, subS
|
|||
|
||||
var tuples = [];
|
||||
if (TCAD.EQUALS_ELIMINATION_ENABLED) {
|
||||
var c, pi, paramIndex = {};
|
||||
|
||||
function intersect(array1, array2) {
|
||||
if (!array1 || !array2) return false;
|
||||
return array1.filter(function(n) {
|
||||
return array2.indexOf(n) != -1
|
||||
}).length != 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < system.length; ++i) {
|
||||
var c = system[i];
|
||||
c = system[i];
|
||||
if (c[3] !== true) {
|
||||
var sameParams = {};
|
||||
for (pi = 0; pi < c[1].length; pi++) {
|
||||
var param = c[1][pi];
|
||||
var paramConstrs = paramIndex[param.id];
|
||||
if (paramConstrs === undefined) {
|
||||
paramConstrs = [];
|
||||
paramIndex[param.id] = paramConstrs;
|
||||
}
|
||||
paramConstrs.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < system.length; ++i) {
|
||||
c = system[i];
|
||||
if (c[3] === true) { //Reduce flag
|
||||
|
||||
var cp1 = c[1][0];
|
||||
var cp2 = c[1][1];
|
||||
//if (!peq(cp1, cp2)) continue;
|
||||
var p0 = cp1.id;
|
||||
var p1 = cp2.id;
|
||||
eqcElimination.push(i);
|
||||
|
||||
var assoc0 = paramIndex[p0];
|
||||
var assoc1 = paramIndex[p1];
|
||||
if (intersect(assoc0, assoc1)) {
|
||||
continue;
|
||||
}
|
||||
equalsDict[p0] = cp1;
|
||||
equalsDict[p1] = cp2;
|
||||
tuples.push([p0, p1]);
|
||||
eqcElimination[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -518,14 +557,10 @@ TCAD.TWO.ParametricManager.prototype.prepareForSubSystem = function(locked, subS
|
|||
var _p;
|
||||
var ei;
|
||||
|
||||
var ii = 0;
|
||||
var aux = [];
|
||||
for (i = 0; i < system.length; ++i) {
|
||||
|
||||
if (eqcElimination[ii] === i) {
|
||||
ii++;
|
||||
continue;
|
||||
}
|
||||
if (eqcElimination[i] === true) continue;
|
||||
|
||||
var sdata = system[i];
|
||||
params = [];
|
||||
|
|
@ -542,23 +577,14 @@ TCAD.TWO.ParametricManager.prototype.prepareForSubSystem = function(locked, subS
|
|||
}
|
||||
|
||||
var _locked = [];
|
||||
var lockedIds = {};
|
||||
if (locked !== undefined) {
|
||||
for (p = 0; p < locked.length; ++p) {
|
||||
_locked[p] = getParam(locked[p]);
|
||||
lockedIds[locked[p]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
var lockedValues = [];
|
||||
var solver = TCAD.parametric.prepare(_constrs, _locked, aux);
|
||||
function solve(rough, alg) {
|
||||
if (_locked.length != 0) {
|
||||
for (p = 0; p < locked.length; ++p) {
|
||||
lockedValues[p] = locked[p].get() ;
|
||||
}
|
||||
solver.updateLock(lockedValues);
|
||||
}
|
||||
for (p in pdict) {
|
||||
_p = pdict[p];
|
||||
_p.set(_p._backingParam.get());
|
||||
|
|
|
|||
Loading…
Reference in a new issue