diff --git a/web/app/sketcher/actions/constraintActions.js b/web/app/sketcher/actions/constraintActions.js index 72f598b9..fc398de5 100644 --- a/web/app/sketcher/actions/constraintActions.js +++ b/web/app/sketcher/actions/constraintActions.js @@ -153,6 +153,25 @@ export default [ } }, + { + id: 'Horizontal', + shortName: 'Horizontal', + description: 'Horizontal', + selectionMatcher: (selection, sortedByType) => matchAll(sortedByType, Segment, 1), + + invoke: ctx => { + const {viewer} = ctx; + const pm = viewer.parametricManager; + + viewer.selected.forEach(obj => { + const constr = new AlgNumConstraint(ConstraintDefinitions.Horizontal, [obj]); + constr.initConstants(); + pm._add(constr); + }); + pm.commit(); + } + }, + { id: 'AngleBetween', shortName: 'Angle Between', diff --git a/web/app/sketcher/constr/ANConstraints.js b/web/app/sketcher/constr/ANConstraints.js index b59f5342..ad43c95d 100644 --- a/web/app/sketcher/constr/ANConstraints.js +++ b/web/app/sketcher/constr/ANConstraints.js @@ -165,10 +165,35 @@ export const ConstraintDefinitions = { type: 'number', description: 'line angle', initialValue: ([seg]) => { - const angleFromNormal = seg.getAngleFromNormal(); + const angleFromNormal = seg.angleDeg(); return Math.abs(270 - angleFromNormal) > Math.abs(90 - angleFromNormal) ? 90 : 270; }, - transform: degree => ( (degree ) % 360 ) * DEG_RAD + transform: degree => degree * DEG_RAD + } + }, + + defineParamsScope: (objs, cb) => { + ConstraintDefinitions.Angle.defineParamsScope(objs, cb); + }, + + collectPolynomials: (polynomials, params, constants) => { + ConstraintDefinitions.Angle.collectPolynomials(polynomials, params, constants); + } + }, + + Horizontal: { + id: 'Horizontal', + name: 'Line Horizontality', + constants: { + angle: { + readOnly: true, + type: 'number', + description: 'line angle', + initialValue: ([seg]) => { + const ang = seg.angleDeg(); + return Math.abs(180 - ang) > Math.min(Math.abs(360 - ang), Math.abs(0 - ang)) ? 0 : 180; + }, + transform: degree => degree * DEG_RAD } }, diff --git a/web/app/sketcher/constr/AlgNumSystem.js b/web/app/sketcher/constr/AlgNumSystem.js index 23a087bd..c96383ef 100644 --- a/web/app/sketcher/constr/AlgNumSystem.js +++ b/web/app/sketcher/constr/AlgNumSystem.js @@ -26,6 +26,8 @@ export class AlgNumSubSystem { interactiveParams = new Set(); + controlBounds = false; + snapshot = new Map(); constructor() { @@ -332,7 +334,7 @@ export class AlgNumSubSystem { } } if (isolation.length) { - clusters.push(new Isolation(isolation)); + clusters.push(new Isolation(isolation, this)); } } @@ -428,7 +430,8 @@ export class AlgNumSubSystem { class Isolation { - constructor(polynomials) { + constructor(polynomials, system) { + this.system = system; this.polynomials = polynomials; this.beingSolvedParams = new Set(); const residuals = []; @@ -468,8 +471,10 @@ class Isolation { this.beingSolvedParams.forEach(solverParam => { let val = solverParam.objectParam.get(); - if (solverParam.objectParam.min && val < solverParam.objectParam.min) { - val = solverParam.objectParam.min; + if (this.system.controlBounds) { + if (solverParam.objectParam.min && val < solverParam.objectParam.min) { + val = solverParam.objectParam.min; + } } solverParam.set(val); }); diff --git a/web/app/sketcher/shapes/arc.js b/web/app/sketcher/shapes/arc.js index ee615a7c..dcb59024 100644 --- a/web/app/sketcher/shapes/arc.js +++ b/web/app/sketcher/shapes/arc.js @@ -94,7 +94,9 @@ export class Arc extends SketchObject { } else { endAngle = makeAngle0_360(this.getEndAngle()); } - ctx.arc(this.c.x, this.c.y, r, startAngle, endAngle); + if (r > 0) { + ctx.arc(this.c.x, this.c.y, r, startAngle, endAngle); + } let distanceB = this.distanceB(); if (Math.abs(r - distanceB) * scale > 1) { let adj = r / distanceB; diff --git a/web/app/sketcher/shapes/circle.js b/web/app/sketcher/shapes/circle.js index 23b56c6c..db20aa46 100644 --- a/web/app/sketcher/shapes/circle.js +++ b/web/app/sketcher/shapes/circle.js @@ -32,7 +32,10 @@ export class Circle extends SketchObject { drawImpl(ctx, scale) { ctx.beginPath(); - ctx.arc(this.c.x, this.c.y, this.r.get(), 0, 2 * Math.PI); + let r = this.r.get(); + if (r > 0) { + ctx.arc(this.c.x, this.c.y, r, 0, 2 * Math.PI); + } ctx.stroke(); } diff --git a/web/app/sketcher/shapes/segment.js b/web/app/sketcher/shapes/segment.js index 3c3fdc99..1deb863c 100644 --- a/web/app/sketcher/shapes/segment.js +++ b/web/app/sketcher/shapes/segment.js @@ -46,10 +46,15 @@ export class Segment extends SketchObject { } getAngleFromNormal() { + return this.angleDeg(); + } + + angleDeg() { const degrees = this.params.ang.get() / DEG_RAD; return (degrees + 360) % 360; } + syncGeometry() { const dx = this.b.x - this.a.x; const dy = this.b.y - this.a.y; diff --git a/web/app/sketcher/tools/drag.js b/web/app/sketcher/tools/drag.js index e9862bc0..fc34f82f 100644 --- a/web/app/sketcher/tools/drag.js +++ b/web/app/sketcher/tools/drag.js @@ -37,12 +37,14 @@ export class DragTool extends Tool { this.origin.y = e.offsetY; this.viewer.screenToModel2(e.offsetX, e.offsetY, this._point); + this.viewer.parametricManager.algNumSystem.controlBounds = true; this.viewer.parametricManager.prepare([this.obj]); } mouseup(e) { this.viewer.parametricManager.solve(false); this.viewer.refresh(); + this.viewer.parametricManager.algNumSystem.controlBounds = false; this.viewer.toolManager.releaseControl(); var traveled = math.distance(this.origin.x, this.origin.y, e.offsetX, e.offsetY); if (traveled >= 10) { diff --git a/web/app/sketcher/viewer2d.js b/web/app/sketcher/viewer2d.js index 32a4f047..d07b10d7 100644 --- a/web/app/sketcher/viewer2d.js +++ b/web/app/sketcher/viewer2d.js @@ -239,7 +239,11 @@ class Viewer { obj.accept((obj) => { if (!obj.visible) return true; if (drawPredicate(obj)) { - this.__draw(ctx, layer, obj); + try { + this.__draw(ctx, layer, obj); + } catch (e) { + console.log(e); + } } return true; });