elliptical arc basic support(no DXF or SVG export)

This commit is contained in:
Val Erastov 2016-12-08 01:25:28 -08:00
parent af85e3e77b
commit 787dc07925
12 changed files with 131 additions and 30 deletions

View file

@ -5,6 +5,7 @@ import {EndPoint} from './shapes/point'
import {Segment} from './shapes/segment'
import {Circle} from './shapes/circle'
import {Ellipse} from './shapes/ellipse'
import {EllipticalArc} from './shapes/elliptical-arc'
import {HDimension, VDimension, Dimension, DiameterDimension} from './shapes/dim'
import {Constraints} from './parametric'
import Vector from '../math/vector'
@ -14,7 +15,8 @@ var Types = {
SEGMENT : 'TCAD.TWO.Segment',
ARC : 'TCAD.TWO.Arc',
CIRCLE : 'TCAD.TWO.Circle',
ELLIPSE : 'TCAD.TWO.Ellipse',
ELLIPSE : 'TCAD.TWO.Ellipse',
ELL_ARC : 'TCAD.TWO.EllipticalArc',
DIM : 'TCAD.TWO.Dimension',
HDIM : 'TCAD.TWO.HDimension',
VDIM : 'TCAD.TWO.VDimension',
@ -120,6 +122,13 @@ IO.prototype._loadSketch = function(sketch) {
const ep2 = endPoint(obj['ep2']);
skobj = new Ellipse(ep1, ep2);
skobj.r.set(obj['r']);
} else if (_class === T.ELL_ARC) {
const ep1 = endPoint(obj['ep1']);
const ep2 = endPoint(obj['ep2']);
const a = endPoint(obj['a']);
const b = endPoint(obj['b']);
skobj = new EllipticalArc(ep1, ep2, a, b);
skobj.r.set(obj['r']);
} else if (_class === T.HDIM) {
skobj = new HDimension(obj['a'], obj['b']);
skobj.flip = obj['flip'];
@ -299,6 +308,12 @@ IO.prototype._serializeSketch = function() {
to['ep1'] = point(obj.ep1);
to['ep2'] = point(obj.ep2);
to['r'] = obj.r.get();
} else if (obj._class === T.ELL_ARC) {
to['ep1'] = point(obj.ep1);
to['ep2'] = point(obj.ep2);
to['a'] = point(obj.a);
to['b'] = point(obj.b);
to['r'] = obj.r.get();
} else if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) {
to['a'] = obj.a.id;
to['b'] = obj.b.id;

View file

@ -267,7 +267,7 @@ ParametricManager.prototype.lockConvex = function(objs, warnCallback) {
};
ParametricManager.prototype.tangent = function(objs) {
const ellipses = fetch.generic(objs, ['TCAD.TWO.Ellipse'], 0);
const ellipses = fetch.generic(objs, ['TCAD.TWO.Ellipse', 'TCAD.TWO.EllipticalArc'], 0);
const lines = fetch.generic(objs, ['TCAD.TWO.Segment'], 1);
if (ellipses.length > 0) {
this.add(new Constraints.EllipseTangent(lines[0], ellipses[0]));
@ -337,7 +337,7 @@ ParametricManager.prototype.pointOnArc = function(objs) {
ParametricManager.prototype.pointOnEllipse = function(objs) {
const points = fetch.generic(objs, ['TCAD.TWO.EndPoint'], 1);
const ellipses = fetch.generic(objs, ['TCAD.TWO.Ellipse'], 1);
const ellipses = fetch.generic(objs, ['TCAD.TWO.Ellipse', 'TCAD.TWO.EllipticalArc'], 1);
this.add(new Constraints.PointOnEllipse(points[0], ellipses[0]));
};
@ -1374,6 +1374,7 @@ Constraints.PointOnEllipseInternal = function(point, 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 = [];

View file

@ -44,9 +44,6 @@ export class Circle extends SketchObject {
if (alternative) {
return super.getDefaultTool(viewer, alternative);
} else {
const editTool = new EditCircleTool(viewer, null);
editTool.circle = this;
return editTool;
}
}
}

View file

@ -1,6 +1,5 @@
import {Ref} from './ref'
import {SketchObject} from './sketch-object'
import {EllipseTool, STATE_RADIUS} from '../tools/ellipse'
import {Constraints} from '../parametric'
import * as math from '../../math/math';
@ -95,10 +94,6 @@ export class Ellipse extends SketchObject {
if (alternative) {
return super.getDefaultTool(viewer, alternative);
} else {
const editTool = new EllipseTool(viewer);
editTool.ellipse = this;
editTool.state = STATE_RADIUS;
return editTool;
}
}
}

View file

@ -1,19 +1,54 @@
import {Ref} from './ref'
import {SketchObject} from './sketch-object'
import {Ellipse} from './ellipse'
import {Constraints} from '../parametric'
import * as math from '../../math/math';
import {swap} from '../../utils/utils'
export class EllipticalArc extends SketchObject {
export class EllipticalArc extends Ellipse {
constructor(ep1, ep2, a, b) {
super(ep1, ep2);
this.a = a;
this.b = b;
this.addChild(a);
this.addChild(b);
//we'd like to have angles points have higher selection order
swap(this.children, 0, this.children.length - 2);
swap(this.children, 1, this.children.length - 1);
}
stabilize(viewer) {
viewer.parametricManager._add(new Constraints.PointOnEllipseInternal(this.b, this));
viewer.parametricManager._add(new Constraints.PointOnEllipseInternal(this.a, this));
}
drawImpl(ctx, scale) {
}
normalDistance(aim) {
ctx.beginPath();
const radiusX = Math.max(this.radiusX, 1e-8);
const radiusY = Math.max(this.radiusY, 1e-8);
let aAngle = this.drawAngle(this.a);
let bAngle;
if (math.areEqual(this.a.x, this.b.x, math.TOLERANCE) &&
math.areEqual(this.a.y, this.b.y, math.TOLERANCE)) {
bAngle = aAngle + 2 * Math.PI;
} else {
bAngle = this.drawAngle(this.b)
}
ctx.ellipse(this.centerX, this.centerY, radiusX, radiusY, this.rotation, aAngle, bAngle );
ctx.stroke();
}
drawAngle(point) {
let deformScale = this.radiusY / this.radiusX;
let x = point.x - this.centerX;
let y = point.y - this.centerY;
const rotation = - this.rotation;
let xx = x * Math.cos(rotation) - y * Math.sin(rotation);
let yy = x * Math.sin(rotation) + y * Math.cos(rotation);
xx *= deformScale;
return Math.atan2(yy, xx);
}
}
EllipticalArc.prototype._class = 'TCAD.TWO.EllipticalArc';

View file

@ -35,10 +35,6 @@ export class SketchObject extends Shape {
return false;
}
getDefaultTool(viewer) {
return new DragTool(this, viewer);
}
isAuxOrLinkedTo() {
if (!!this.aux) {
return true;

View file

@ -136,7 +136,11 @@ function App2D() {
}, 'circle');
this.registerAction('addEllipse', "Add Ellipse", function () {
app.viewer.toolManager.takeControl(new EllipseTool(app.viewer));
app.viewer.toolManager.takeControl(new EllipseTool(app.viewer, false));
});
this.registerAction('addEllipticalArc', "Add Elliptical Arc", function () {
app.viewer.toolManager.takeControl(new EllipseTool(app.viewer, true));
});
this.registerAction('pan', "Pan", function () {

View file

@ -0,0 +1,24 @@
import {Ellipse} from '../shapes/ellipse'
import {EllipticalArc} from '../shapes/elliptical-arc'
import {Circle} from '../shapes/circle'
import {EditCircleTool} from './circle'
import {DragTool} from './drag'
import {EllipseTool, STATE_RADIUS} from './ellipse'
export function GetShapeEditTool(viewer, obj, alternative) {
if (obj instanceof Circle && !alternative) {
const tool = new EditCircleTool(viewer);
tool.circle = obj;
return tool;
} else if (obj instanceof Ellipse && !alternative) {
// even for an ell-arc we should act as it would be an ellipse to
// avoid stabilize constraints added and demoing B point on move
// so second arg must be FALSE!
const tool = new EllipseTool(viewer, false);
tool.ellipse = obj;
tool.state = STATE_RADIUS;
return tool;
} else {
return new DragTool(obj, viewer);
}
}

View file

@ -1,6 +1,7 @@
import {Tool} from './tool'
import {EndPoint} from '../shapes/point'
import {Ellipse} from '../shapes/ellipse'
import {EllipticalArc} from '../shapes/elliptical-arc'
import Vector from '../../math/vector'
export const STATE_POINT1 = 0;
@ -9,8 +10,9 @@ export const STATE_RADIUS = 2;
export class EllipseTool extends Tool {
constructor(viewer) {
super('ellipse', viewer);
constructor(viewer, arc) {
super(arc ? 'ellipse' : 'elliptical arc', viewer);
this.arc = arc;
this.ellipse = null;
this.state = STATE_POINT1;
}
@ -29,11 +31,25 @@ export class EllipseTool extends Tool {
return this.viewer.snapped ? this.viewer.snapped : this.viewer.screenToModel(e);
}
newEllipse(p) {
const ep = () => new EndPoint(p.x, p.y);
return this.arc ? new EllipticalArc(ep(), ep(), ep(), ep()) : new Ellipse(ep(), ep());
}
demoBPoint() {
const arc = this.ellipse;
let ang = Math.atan2(arc.a.y - arc.centerY, arc.a.x - arc.centerX) + (2 * Math.PI - 0.3);
ang %= 2 * Math.PI;
const r = arc.radiusAtAngle(ang - arc.rotation);
arc.b.x = arc.centerX + r * Math.cos(ang);
arc.b.y = arc.centerY + r * Math.sin(ang);
}
mouseup(e) {
switch (this.state) {
case STATE_POINT1: {
const p = this.point(e);
this.ellipse = new Ellipse(new EndPoint(p.x, p.y), new EndPoint(p.x, p.y));
this.ellipse = this.newEllipse(p);
this.snapIfNeed(this.ellipse.ep1);
this.viewer.activeLayer.objects.push(this.ellipse);
this.viewer.refresh();
@ -51,6 +67,9 @@ export class EllipseTool extends Tool {
break;
}
case STATE_RADIUS:
if (this.arc) {
this.ellipse.stabilize(this.viewer);
}
this.viewer.toolManager.releaseControl();
}
}
@ -64,7 +83,11 @@ export class EllipseTool extends Tool {
case STATE_POINT2:
this.ellipse.ep2.setFromPoint(this.viewer.screenToModel(e));
this.ellipse.r.value = this.ellipse.radiusX * 0.5;
this.viewer.snap(p.x, p.y, [this.ellipse.ep1, this.ellipse.ep2]);
this.viewer.snap(p.x, p.y, this.ellipse.children);
if (this.arc) {
this.ellipse.a.setFromPoint(this.ellipse.ep2);
this.demoBPoint();
}
break;
case STATE_RADIUS:
const polarPoint = this.ellipse.toEllipseCoordinateSystem(p);
@ -79,6 +102,9 @@ export class EllipseTool extends Tool {
if (!Tool.dumbMode(e)) {
this.solveRequest(true);
}
if (this.arc) {
this.demoBPoint();
}
break;
}
this.viewer.refresh();

View file

@ -1,4 +1,5 @@
import {Tool} from './tool'
import {GetShapeEditTool} from './edit-tools-map'
export class PanTool extends Tool {
constructor(viewer) {
@ -57,7 +58,7 @@ export class PanTool extends Tool {
}
this.viewer.select([toSelect], true);
if (!toSelect.isAuxOrLinkedTo()) {
var tool = toSelect.getDefaultTool(this.viewer, e.altKey);
const tool = GetShapeEditTool(this.viewer, toSelect, e.altKey);
tool.mousedown(e);
this.viewer.toolManager.switchTool(tool);
}

View file

@ -33,4 +33,10 @@ export function constRef(value) {
return function() {
return value;
};
}
}
export function swap(arr, i1, i2) {
const tmp = arr[i1];
arr[i1] = arr[i2];
arr[i2] = tmp;
}

View file

@ -29,7 +29,8 @@
--><button class="btn tbtn act-addMultiSegment" style="background-image: url(img/mline.png);" type="submit" value=""></button><!--
--><button class="btn tbtn act-addCircle" style="background-image: url(img/circle.png);" type="submit" value=""></button><!--
--><button class="btn tbtn act-addArc" style="background-image: url(img/arc.png);" type="submit" value=""></button><!--
--><button class="btn tbtn act-addEllipse sep" type="submit" value="">E</button><!--
--><button class="btn tbtn act-addEllipse" type="submit" value="">E</button><!--
--><button class="btn tbtn act-addEllipticalArc sep" type="submit" value="">EA</button><!--
--><button class="btn tbtn act-addHDim" style="background-image: url(img/hdim.png);" type="submit" value=""></button><!--
--><button class="btn tbtn act-addVDim" style="background-image: url(img/vdim.png);" type="submit" value=""></button><!--
--><button class="btn tbtn act-addDim" style="background-image: url(img/dim.png);" type="submit" value=""></button><!--