diff --git a/web/app/sketcher/constr/constraints.js b/web/app/sketcher/constr/constraints.js index e60684f4..ccf30e2e 100644 --- a/web/app/sketcher/constr/constraints.js +++ b/web/app/sketcher/constr/constraints.js @@ -23,6 +23,8 @@ function createByConstraintName(name, params, values) { return new P2PDistance(params, values[0]); case "P2PDistanceV": return new P2PDistanceV(params); + case "PointOnEllipse": + return new PointOnEllipse(params); case "angle": return new Angle(params); case "angleConst": @@ -367,7 +369,6 @@ function P2PDistanceV(params) { } } - /** @constructor */ function Parallel(params) { @@ -499,6 +500,62 @@ function Angle(params) { } } +/** @constructor */ +function PointOnEllipse(params) { + + this.params = params; + + const PX = 0; + const PY = 1; + const EP1X = 2; + const EP1Y = 3; + const EP2X = 4; + const EP2Y = 5; + const R = 6; + + this.error = function() { + const sq = x => x * x; + const px = params[PX].get(); + const py = params[PY].get(); + const ep1x = params[EP1X].get(); + const ep1y = params[EP1Y].get(); + const ep2x = params[EP2X].get(); + const ep2y = params[EP2Y].get(); + const radiusY = params[R].get(); + + const centerX = ep1x + (ep2x - ep1x) * 0.5; + const centerY = ep1y + (ep2y - ep1y) * 0.5; + const rotation = Math.atan2(ep2y - ep1y, ep2x - ep1x); + let x = px - centerX; + let y = py - centerY; + const polarAngle = Math.atan2(y, x) - rotation; + const polarRadius = Math.sqrt(x*x + y*y); + const radiusX = Math.sqrt(sq(ep1x - ep2x) + sq(ep1y - ep2y)) * 0.5; + + const L = Math.sqrt(1/( sq(Math.cos(polarAngle)/radiusX) + sq(Math.sin(polarAngle)/radiusY))); + return L - polarRadius + }; + + this.gradient = function(out) { + const h = 1; + const approx = (param) => { + const fx = this.error(); + params[param].set(params[param].get() + h); + const fhx = this.error(); + params[param].set(params[param].get() - h); + return (fhx - fx) / h; + }; + + out[PX] = approx(PX); + out[PY] = approx(PY); + out[EP1X] = approx(EP1X); + out[EP1Y] = approx(EP1Y); + out[EP2X] = approx(EP2X); + out[EP2Y] = approx(EP2Y); + out[R] = approx(R); + } +} + function _fixNaN(grad) { for (var i = 0; i < grad.length; i++) { if (isNaN(grad[i])) { diff --git a/web/app/sketcher/parametric.js b/web/app/sketcher/parametric.js index a9eac5c2..b447ed3e 100644 --- a/web/app/sketcher/parametric.js +++ b/web/app/sketcher/parametric.js @@ -331,6 +331,12 @@ ParametricManager.prototype.pointOnArc = function(objs) { this.add(new Constraints.PointOnArc(points[0], arcs[0])); }; +ParametricManager.prototype.pointOnEllipse = function(objs) { + const points = fetch.generic(objs, ['TCAD.TWO.EndPoint'], 1); + const ellipses = fetch.generic(objs, ['TCAD.TWO.Ellipse'], 1); + this.add(new Constraints.PointOnEllipse(points[0], ellipses[0])); +}; + ParametricManager.prototype.pointOnLine = function(objs) { var pl = fetch.pointAndLine(objs); var target = pl[0]; @@ -1340,6 +1346,38 @@ Constraints.PointOnArc.prototype.getObjects = function() { // ------------------------------------------------------------------------------------------------------------------ // +/** @constructor */ +Constraints.PointOnEllipse = function(point, ellipse) { + this.point = point; + this.ellipse= ellipse; +}; + +Constraints.PointOnEllipse.prototype.NAME = 'PointOnEllipse'; +Constraints.PointOnEllipse.prototype.UI_NAME = 'Point On Ellipse'; + +Constraints.PointOnEllipse.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, []]]; +}; + +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.PointInMiddle = function(point, line) { this.point = point;