diff --git a/web/app/sketcher/id-generator.js b/web/app/sketcher/id-generator.js new file mode 100644 index 00000000..770f01a3 --- /dev/null +++ b/web/app/sketcher/id-generator.js @@ -0,0 +1,13 @@ + +let ID_COUNTER = 0; + +export const Generator = { + genID : function() { + return ID_COUNTER ++; + }, + + resetIDGenerator : function(value) { + ID_COUNTER = value; + } +}; + diff --git a/web/app/sketcher/io.js b/web/app/sketcher/io.js index f0dd89d2..67428255 100644 --- a/web/app/sketcher/io.js +++ b/web/app/sketcher/io.js @@ -1,5 +1,8 @@ -import {EndPoint, Layer, Styles, Segment, SketchObject} from './viewer2d' +import {Generator} from './id-generator' +import {Layer, Styles} from './viewer2d' import {Arc} from './shapes/arc' +import {EndPoint} from './shapes/point' +import {Segment} from './shapes/segment' import {Circle} from './shapes/circle' import {HDimension, VDimension, Dimension, DiameterDimension} from './shapes/dim' import {Constraints} from './parametric' @@ -248,7 +251,7 @@ IO.prototype.cleanUpData = function() { } } this.viewer.deselectAll(); - SketchObject.resetIDGenerator(0); + Generator.resetIDGenerator(0); if (this.viewer.parametricManager.subSystems.length != 0) { this.viewer.parametricManager.subSystems = []; this.viewer.parametricManager.notify(); diff --git a/web/app/sketcher/parametric.js b/web/app/sketcher/parametric.js index 63ba83cc..a9eac5c2 100644 --- a/web/app/sketcher/parametric.js +++ b/web/app/sketcher/parametric.js @@ -1,5 +1,5 @@ import * as utils from '../utils/utils' -import {Ref} from './viewer2d' +import {Ref} from './shapes/ref' import {Param, prepare} from './constr/solver' import {createByConstraintName} from './constr/constraints' import Vector from '../math/vector' diff --git a/web/app/sketcher/shapes/arc.js b/web/app/sketcher/shapes/arc.js index 44781af2..3f6c6a06 100644 --- a/web/app/sketcher/shapes/arc.js +++ b/web/app/sketcher/shapes/arc.js @@ -1,132 +1,132 @@ import * as utils from '../../utils/utils'; import * as math from '../../math/math'; import Vector from '../../math/vector' -import {SketchObject, Ref} from '../viewer2d' +import {Ref} from './ref' import {Constraints} from '../parametric' +import {SketchObject} from './sketch-object' -/** @constructor */ -export function Arc(a, b, c) { - SketchObject.call(this); - this.a = a; - this.b = b; - this.c = c; - a.parent = this; - b.parent = this; - c.parent = this; - this.children.push(a, b, c); - this.r = new Ref(0); - this.r.value = this.distanceA(); - this.r.obj = this; +export class Arc extends SketchObject { + + constructor(a, b, c) { + super(); + this.a = a; + this.b = b; + this.c = c; + a.parent = this; + b.parent = this; + c.parent = this; + this.children.push(a, b, c); + this.r = new Ref(0); + this.r.value = this.distanceA(); + this.r.obj = this; + } + + collectParams(params) { + this.a.collectParams(params); + this.b.collectParams(params); + this.c.collectParams(params); + params.push(this.r); + } + + getReferencePoint() { + return this.c; + } + + translateImpl(dx, dy) { + this.a.translate(dx, dy); + this.b.translate(dx, dy); + this.c.translate(dx, dy); + } + + + radiusForDrawing() { + return this.distanceA(); + } + + distanceA() { + return math.distance(this.a.x, this.a.y, this.c.x, this.c.y); + } + + distanceB() { + return math.distance(this.b.x, this.b.y, this.c.x, this.c.y); + } + + getStartAngle() { + return Math.atan2(this.a.y - this.c.y, this.a.x - this.c.x); + } + + getEndAngle() { + return Math.atan2(this.b.y - this.c.y, this.b.x - this.c.x); + } + + drawImpl(ctx, scale) { + ctx.beginPath(); + var r = this.radiusForDrawing(); + var startAngle = this.getStartAngle(); + var endAngle; + if (math.areEqual(this.a.x, this.b.x, math.TOLERANCE) && + math.areEqual(this.a.y, this.b.y, math.TOLERANCE)) { + endAngle = startAngle + 2 * Math.PI; + } else { + endAngle = this.getEndAngle(); + } + ctx.arc(this.c.x, this.c.y, r, startAngle, endAngle); + var distanceB = this.distanceB(); + if (Math.abs(r - distanceB) * scale > 1) { + var adj = r / distanceB; + ctx.save(); + ctx.setLineDash([7 / scale]); + ctx.lineTo(this.b.x, this.b.y); + ctx.moveTo(this.b.x + (this.b.x - this.c.x) / adj, this.b.y + (this.b.y - this.c.y) / adj); + ctx.stroke(); + ctx.restore(); + } else { + ctx.stroke(); + } + } + + isPointInsideSector(x, y) { + var ca = new Vector(this.a.x - this.c.x, this.a.y - this.c.y); + var cb = new Vector(this.b.x - this.c.x, this.b.y - this.c.y); + var ct = new Vector(x - this.c.x, y - this.c.y); + + ca._normalize(); + cb._normalize(); + ct._normalize(); + var cosAB = ca.dot(cb); + var cosAT = ca.dot(ct); + + var isInside = cosAT >= cosAB; + var abInverse = ca.cross(cb).z < 0; + var atInverse = ca.cross(ct).z < 0; + + var result; + if (abInverse) { + result = !atInverse || !isInside; + } else { + result = !atInverse && isInside; + } + return result; + } + + normalDistance(aim) { + + var isInsideSector = this.isPointInsideSector(aim.x, aim.y); + if (isInsideSector) { + return Math.abs(math.distance(aim.x, aim.y, this.c.x, this.c.y) - this.radiusForDrawing()); + } else { + return Math.min( + math.distance(aim.x, aim.y, this.a.x, this.a.y), + math.distance(aim.x, aim.y, this.b.x, this.b.y) + ); + } + } + + stabilize(viewer) { + this.r.set(this.distanceA()); + viewer.parametricManager._add(new Constraints.P2PDistanceV(this.b, this.c, this.r)); + viewer.parametricManager._add(new Constraints.P2PDistanceV(this.a, this.c, this.r)); + } } -utils.extend(Arc, SketchObject); - Arc.prototype._class = 'TCAD.TWO.Arc'; - -Arc.prototype.collectParams = function(params) { - this.a.collectParams(params); - this.b.collectParams(params); - this.c.collectParams(params); - params.push(this.r); -}; - -Arc.prototype.getReferencePoint = function() { - return this.c; -}; - -Arc.prototype.translateImpl = function(dx, dy) { - this.a.translate(dx, dy); - this.b.translate(dx, dy); - this.c.translate(dx, dy); -}; - - -Arc.prototype.radiusForDrawing = function() { - return this.distanceA(); -}; - -Arc.prototype.distanceA = function() { - return math.distance(this.a.x, this.a.y, this.c.x, this.c.y); -}; - -Arc.prototype.distanceB = function() { - return math.distance(this.b.x, this.b.y, this.c.x, this.c.y); -}; - -Arc.prototype.getStartAngle = function() { - return Math.atan2(this.a.y - this.c.y, this.a.x - this.c.x); -}; - -Arc.prototype.getEndAngle = function() { - return Math.atan2(this.b.y - this.c.y, this.b.x - this.c.x); -}; - -Arc.prototype.drawImpl = function(ctx, scale) { - ctx.beginPath(); - var r = this.radiusForDrawing(); - var startAngle = this.getStartAngle(); - var endAngle; - if (math.areEqual(this.a.x, this.b.x, math.TOLERANCE) && - math.areEqual(this.a.y, this.b.y, math.TOLERANCE)) { - endAngle = startAngle + 2 * Math.PI; - } else { - endAngle = this.getEndAngle(); - } - ctx.arc(this.c.x, this.c.y, r, startAngle, endAngle); - var distanceB = this.distanceB(); - if (Math.abs(r - distanceB) * scale > 1) { - var adj = r / distanceB; - ctx.save(); - ctx.setLineDash([7 / scale]); - ctx.lineTo(this.b.x, this.b.y); - ctx.moveTo(this.b.x + (this.b.x - this.c.x) / adj, this.b.y + (this.b.y - this.c.y) / adj); - ctx.stroke(); - ctx.restore(); - } else { - ctx.stroke(); - } -}; - -Arc.prototype.isPointInsideSector = function(x, y) { - var ca = new Vector(this.a.x - this.c.x, this.a.y - this.c.y); - var cb = new Vector(this.b.x - this.c.x, this.b.y - this.c.y); - var ct = new Vector(x - this.c.x, y - this.c.y); - - ca._normalize(); - cb._normalize(); - ct._normalize(); - var cosAB = ca.dot(cb); - var cosAT = ca.dot(ct); - - var isInside = cosAT >= cosAB; - var abInverse = ca.cross(cb).z < 0; - var atInverse = ca.cross(ct).z < 0; - - var result; - if (abInverse) { - result = !atInverse || !isInside; - } else { - result = !atInverse && isInside; - } - return result; -}; - -Arc.prototype.normalDistance = function(aim) { - - var isInsideSector = this.isPointInsideSector(aim.x, aim.y); - if (isInsideSector) { - return Math.abs(math.distance(aim.x, aim.y, this.c.x, this.c.y) - this.radiusForDrawing()); - } else { - return Math.min( - math.distance(aim.x, aim.y, this.a.x, this.a.y), - math.distance(aim.x, aim.y, this.b.x, this.b.y) - ); - } -}; - -Arc.prototype.stabilize = function(viewer) { - this.r.set(this.distanceA()); - viewer.parametricManager._add(new Constraints.P2PDistanceV(this.b, this.c, this.r)); - viewer.parametricManager._add(new Constraints.P2PDistanceV(this.a, this.c, this.r)); -}; - diff --git a/web/app/sketcher/shapes/circle.js b/web/app/sketcher/shapes/circle.js index 5cdec137..9f90dec2 100644 --- a/web/app/sketcher/shapes/circle.js +++ b/web/app/sketcher/shapes/circle.js @@ -2,50 +2,49 @@ import * as utils from '../../utils/utils'; import * as math from '../../math/math'; import {EditCircleTool} from '../tools/circle' -import {SketchObject, EndPoint, Ref} from '../viewer2d' +import {EndPoint} from './point' +import {Ref} from './ref' +import {SketchObject} from './sketch-object' -/** @constructor */ -function Circle(c) { - SketchObject.call(this); - this.c = c; - c.parent = this; - this.children.push(c); - this.r = new Ref(0); - this.r.obj = this; +export class Circle extends SketchObject { + + constructor(c) { + super(); + this.c = c; + c.parent = this; + this.children.push(c); + this.r = new Ref(0); + this.r.obj = this; + } + + collectParams(params) { + this.c.collectParams(params); + params.push(this.r); + } + + getReferencePoint() { + return this.c; + } + + translateImpl(dx, dy) { + this.c.translate(dx, dy); + } + + drawImpl(ctx, scale) { + ctx.beginPath(); + ctx.arc(this.c.x, this.c.y, this.r.get(), 0, 2 * Math.PI); + ctx.stroke(); + } + + normalDistance(aim) { + return Math.abs(math.distance(aim.x, aim.y, this.c.x, this.c.y) - this.r.get()); + } + + getDefaultTool(viewer) { + var editTool = new EditCircleTool(viewer, null); + editTool.circle = this; + return editTool; + } } -utils.extend(Circle, SketchObject); - Circle.prototype._class = 'TCAD.TWO.Circle'; - -Circle.prototype.collectParams = function(params) { - this.c.collectParams(params); - params.push(this.r); -}; - -Circle.prototype.getReferencePoint = function() { - return this.c; -}; - -Circle.prototype.translateImpl = function(dx, dy) { - this.c.translate(dx, dy); -}; - -Circle.prototype.drawImpl = function(ctx, scale) { - ctx.beginPath(); - ctx.arc(this.c.x, this.c.y, this.r.get(), 0, 2 * Math.PI); - ctx.stroke(); -}; - -Circle.prototype.normalDistance = function(aim) { - return Math.abs(math.distance(aim.x, aim.y, this.c.x, this.c.y) - this.r.get()); -}; - -Circle.prototype.getDefaultTool = function(viewer) { - var editTool = new EditCircleTool(viewer, null); - editTool.circle = this; - return editTool; -}; - - -export {Circle} \ No newline at end of file diff --git a/web/app/sketcher/shapes/dim.js b/web/app/sketcher/shapes/dim.js index 98e7085a..f3e6d246 100644 --- a/web/app/sketcher/shapes/dim.js +++ b/web/app/sketcher/shapes/dim.js @@ -1,300 +1,306 @@ import * as utils from '../../utils/utils' import * as math from '../../math/math' -import {SketchObject} from '../viewer2d' import Vector from '../../math/vector' +import {SketchObject} from './sketch-object' -/** @constructor */ -function LinearDimension(a, b) { - SketchObject.call(this); - this.a = a; - this.b = b; - this.flip = false; -} - -utils.extend(LinearDimension, SketchObject); - -LinearDimension.prototype.collectParams = function(params) { -}; - -LinearDimension.prototype.getReferencePoint = function() { - return this.a; -}; - -LinearDimension.prototype.translateImpl = function(dx, dy) { -}; - -LinearDimension.prototype.getA = function() { return this.a }; -LinearDimension.prototype.getB = function() { return this.b }; - -LinearDimension.getTextOff = function(scale) { - return 3 * scale; -}; - -LinearDimension.prototype.drawImpl = function(ctx, scale, viewer) { - - var off = 30 * viewer.dimScale; - var textOff = LinearDimension.getTextOff(viewer.dimScale); - - var a, b, startA, startB; - if (this.flip) { - a = this.getB(); - b = this.getA(); - startA = this.b; - startB = this.a; - } else { - a = this.getA(); - b = this.getB(); - startA = this.a; - startB = this.b; +class LinearDimension extends SketchObject { + + constructor(a, b) { + super(); + this.a = a; + this.b = b; + this.flip = false; } - var d = math.distanceAB(a, b); - - var _vx = - (b.y - a.y); - var _vy = b.x - a.x; - - //normalize - var _vxn = _vx / d; - var _vyn = _vy / d; - - _vx = _vxn * off; - _vy = _vyn * off; - - ctx.beginPath(); - - var _ax = a.x + _vx; - var _ay = a.y + _vy; - var _bx = b.x + _vx; - var _by = b.y + _vy; - - ctx.moveTo(_ax, _ay); - ctx.lineTo(_bx, _by); - - - function drawRef(start, x, y) { - var vec = new Vector(x - start.x, y - start.y); - vec._normalize(); - vec._multiply(7 * viewer.dimScale); - - ctx.moveTo(start.x, start.y ); - ctx.lineTo(x, y); - ctx.lineTo(x + vec.x, y + vec.y); - } - - drawRef(startA, _ax, _ay); - drawRef(startB, _bx, _by); - - ctx.closePath(); - ctx.stroke(); - - function drawArrow(x, y) { - var s1 = 50; - var s2 = 20; - ctx.lineCap = 'round'; - ctx.beginPath(); - ctx.moveTo(x, y); - ctx.lineTo(x - s1, y - s2); - ctx.closePath(); - ctx.stroke(); - } - -// drawArrow(_ax, _ay); -// drawArrow(_bx, _by); - - ctx.font= (12 * viewer.dimScale) + "px Arial"; - var txt = d.toFixed(2); - var h = d / 2 - ctx.measureText(txt).width / 2; - - if (h > 0) { - var tx = (_ax + _vxn * textOff) - (- _vyn) * h; - var ty = (_ay + _vyn * textOff) - ( _vxn) * h; - ctx.save(); - ctx.translate(tx, ty); - ctx.rotate( - Math.atan2(_vxn, _vyn)); - ctx.scale(1, -1); - ctx.fillText(txt, 0, 0); - ctx.restore(); - } -}; - -LinearDimension.prototype.normalDistance = function(aim) { - return -1; -}; - -/** @constructor */ -function Dimension(a, b) { - LinearDimension.call(this, a, b); -} - -utils.extend(Dimension, LinearDimension); - -Dimension.prototype._class = 'TCAD.TWO.Dimension'; - -/** @constructor */ -function HDimension(a, b) { - LinearDimension.call(this, a, b); -} - -utils.extend(HDimension, LinearDimension); - -HDimension.prototype._class = 'TCAD.TWO.HDimension'; - -HDimension.prototype.getA = function() { return this.a }; -HDimension.prototype.getB = function() { return {x : this.b.x, y : this.a.y} }; - -/** @constructor */ -function VDimension(a, b) { - LinearDimension.call(this, a, b); -} - -utils.extend(VDimension, LinearDimension); - -VDimension.prototype._class = 'TCAD.TWO.VDimension'; - -VDimension.prototype.getA = function() { return this.a }; -VDimension.prototype.getB = function() { return {x : this.a.x, y : this.b.y} }; - - -/** @constructor */ -function DiameterDimension(obj) { - SketchObject.call(this); - this.obj = obj; - this.angle = Math.PI / 4; -} - -DiameterDimension.prototype._class = 'TCAD.TWO.DiameterDimension'; - -utils.extend(DiameterDimension, SketchObject); - -DiameterDimension.prototype.collectParams = function(params) { -}; - -DiameterDimension.prototype.getReferencePoint = function() { -}; - -DiameterDimension.prototype.translateImpl = function(dx, dy) { -}; - -DiameterDimension.prototype.drawImpl = function(ctx, scale, viewer) { - if (this.obj == null) return; - if (this.obj._class === 'TCAD.TWO.Circle') { - this.drawForCircle(ctx, scale, viewer); - } else if (this.obj._class === 'TCAD.TWO.Arc') { - this.drawForArc(ctx, scale, viewer); - } -}; - -DiameterDimension.prototype.drawForCircle = function(ctx, scale, viewer) { - var c = new Vector().setV(this.obj.c); - var r = this.obj.r.get(); - var angled = new Vector(r * Math.cos(this.angle), r * Math.sin(this.angle), 0); - var a = c.minus(angled); - var b = c.plus(angled); - var textOff = LinearDimension.getTextOff(viewer.dimScale); - - var d = 2 * r; - - ctx.beginPath(); - ctx.moveTo(a.x, a.y); - ctx.lineTo(b.x, b.y); - ctx.closePath(); - ctx.stroke(); - - var fontSize = 12 * viewer.dimScale; - ctx.font = (fontSize) + "px Arial"; - var txt = String.fromCharCode(216) + ' ' + d.toFixed(2); - var textWidth = ctx.measureText(txt).width; - var h = d / 2 - textWidth / 2; - - var _vx = - (b.y - a.y); - var _vy = b.x - a.x; - - //normalize - var _vxn = _vx / d; - var _vyn = _vy / d; - - function drawText(tx, ty) { - ctx.save(); - ctx.translate(tx, ty); - ctx.rotate(-Math.atan2(_vxn, _vyn)); - ctx.scale(1, -1); - ctx.fillText(txt, 0, 0); - ctx.restore(); + collectParams(params) { } - var tx, ty; - if (h - fontSize * .3 > 0) { // take into account font size to not have circle overlap symbols - tx = (a.x + _vxn * textOff) - (-_vyn) * h; - ty = (a.y + _vyn * textOff) - ( _vxn) * h; - drawText(tx, ty); - } else { - var off = 2 * viewer.dimScale; - angled._normalize(); - var extraLine = angled.multiply(textWidth + off * 2); - ctx.beginPath(); - ctx.moveTo(b.x, b.y); - ctx.lineTo(b.x + extraLine.x, b.y + extraLine.y); - ctx.closePath(); - ctx.stroke(); - angled._multiply(off); - - tx = (b.x + _vxn * textOff) + angled.x; - ty = (b.y + _vyn * textOff) + angled.y; - drawText(tx, ty); + getReferencePoint() { + return this.a; } -}; - -DiameterDimension.prototype.drawForArc = function(ctx, scale, viewer) { - - var r = this.obj.distanceA(); - - var hxn = Math.cos(this.angle); - var hyn = Math.sin(this.angle); - - var vxn = - hyn; - var vyn = hxn; - - //fix angle if needed - if (!this.obj.isPointInsideSector(this.obj.c.x + hxn, this.obj.c.y + hyn)) { - var cosA = hxn * (this.obj.a.x - this.obj.c.x) + hyn * (this.obj.a.y - this.obj.c.y); - var cosB = hxn * (this.obj.b.x - this.obj.c.x) + hyn * (this.obj.b.y - this.obj.c.y); - if (cosA - hxn > cosB - hxn) { - this.angle = this.obj.getStartAngle(); + + translateImpl(dx, dy) { + } + + getA() { return this.a } + getB() { return this.b } + + drawImpl(ctx, scale, viewer) { + + var off = 30 * viewer.dimScale; + var textOff = getTextOff(viewer.dimScale); + + var a, b, startA, startB; + if (this.flip) { + a = this.getB(); + b = this.getA(); + startA = this.b; + startB = this.a; } else { - this.angle = this.obj.getEndAngle(); + a = this.getA(); + b = this.getB(); + startA = this.a; + startB = this.b; + } + + var d = math.distanceAB(a, b); + + var _vx = - (b.y - a.y); + var _vy = b.x - a.x; + + //normalize + var _vxn = _vx / d; + var _vyn = _vy / d; + + _vx = _vxn * off; + _vy = _vyn * off; + + ctx.beginPath(); + + var _ax = a.x + _vx; + var _ay = a.y + _vy; + var _bx = b.x + _vx; + var _by = b.y + _vy; + + ctx.moveTo(_ax, _ay); + ctx.lineTo(_bx, _by); + + + function drawRef(start, x, y) { + var vec = new Vector(x - start.x, y - start.y); + vec._normalize(); + vec._multiply(7 * viewer.dimScale); + + ctx.moveTo(start.x, start.y ); + ctx.lineTo(x, y); + ctx.lineTo(x + vec.x, y + vec.y); + } + + drawRef(startA, _ax, _ay); + drawRef(startB, _bx, _by); + + ctx.closePath(); + ctx.stroke(); + + function drawArrow(x, y) { + var s1 = 50; + var s2 = 20; + ctx.lineCap = 'round'; + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x - s1, y - s2); + ctx.closePath(); + ctx.stroke(); + } + + // drawArrow(_ax, _ay); + // drawArrow(_bx, _by); + + ctx.font= (12 * viewer.dimScale) + "px Arial"; + var txt = d.toFixed(2); + var h = d / 2 - ctx.measureText(txt).width / 2; + + if (h > 0) { + var tx = (_ax + _vxn * textOff) - (- _vyn) * h; + var ty = (_ay + _vyn * textOff) - ( _vxn) * h; + ctx.save(); + ctx.translate(tx, ty); + ctx.rotate( - Math.atan2(_vxn, _vyn)); + ctx.scale(1, -1); + ctx.fillText(txt, 0, 0); + ctx.restore(); } } + + normalDistance(aim) { + return -1; + } +} - var vertOff = LinearDimension.getTextOff(viewer.dimScale); - var horOff = 5 * viewer.dimScale; +export class Dimension extends LinearDimension { + constructor(a, b) { + super(a, b); + } +} +Dimension.prototype._class = 'TCAD.TWO.Dimension'; - var fontSize = 12 * viewer.dimScale; - ctx.font = (fontSize) + "px Arial"; - var txt = 'R ' + r.toFixed(2); - var textWidth = ctx.measureText(txt).width; - var startX = this.obj.c.x + hxn * r; - var startY = this.obj.c.y + hyn * r; - var lineLength = textWidth + horOff * 2; +export class HDimension extends LinearDimension { + constructor(a, b) { + super(a, b); + } - ctx.beginPath(); - ctx.moveTo(startX, startY); - ctx.lineTo(startX + hxn * lineLength, startY + hyn * lineLength); - ctx.closePath(); - ctx.stroke(); + getA() { + return this.a; + } + + getB() { + return {x: this.b.x, y: this.a.y}; + } +} +HDimension.prototype._class = 'TCAD.TWO.HDimension'; - var tx = startX + vxn * vertOff + hxn * horOff; - var ty = startY + vyn * vertOff + hyn * horOff; - ctx.save(); - ctx.translate(tx, ty); - ctx.rotate(-Math.atan2(vxn, vyn)); - ctx.scale(1, -1); - ctx.fillText(txt, 0, 0); - ctx.restore(); -}; +export class VDimension extends LinearDimension { + + constructor(a, b) { + super(a, b); + } + + getA() { + return this.a; + } + + getB() { + return {x: this.a.x, y: this.b.y}; + } +} +VDimension.prototype._class = 'TCAD.TWO.VDimension'; + + +export class DiameterDimension extends SketchObject { + + constructor(obj) { + super(); + this.obj = obj; + this.angle = Math.PI / 4; + } + + collectParams(params) { + } + + getReferencePoint() { + } + + translateImpl(dx, dy) { + } + + drawImpl(ctx, scale, viewer) { + if (this.obj == null) return; + if (this.obj._class === 'TCAD.TWO.Circle') { + this.drawForCircle(ctx, scale, viewer); + } else if (this.obj._class === 'TCAD.TWO.Arc') { + this.drawForArc(ctx, scale, viewer); + } + } + + drawForCircle(ctx, scale, viewer) { + var c = new Vector().setV(this.obj.c); + var r = this.obj.r.get(); + var angled = new Vector(r * Math.cos(this.angle), r * Math.sin(this.angle), 0); + var a = c.minus(angled); + var b = c.plus(angled); + var textOff = getTextOff(viewer.dimScale); + + var d = 2 * r; + + ctx.beginPath(); + ctx.moveTo(a.x, a.y); + ctx.lineTo(b.x, b.y); + ctx.closePath(); + ctx.stroke(); + + var fontSize = 12 * viewer.dimScale; + ctx.font = (fontSize) + "px Arial"; + var txt = String.fromCharCode(216) + ' ' + d.toFixed(2); + var textWidth = ctx.measureText(txt).width; + var h = d / 2 - textWidth / 2; + + var _vx = - (b.y - a.y); + var _vy = b.x - a.x; + + //normalize + var _vxn = _vx / d; + var _vyn = _vy / d; + + function drawText(tx, ty) { + ctx.save(); + ctx.translate(tx, ty); + ctx.rotate(-Math.atan2(_vxn, _vyn)); + ctx.scale(1, -1); + ctx.fillText(txt, 0, 0); + ctx.restore(); + } + + var tx, ty; + if (h - fontSize * .3 > 0) { // take into account font size to not have circle overlap symbols + tx = (a.x + _vxn * textOff) - (-_vyn) * h; + ty = (a.y + _vyn * textOff) - ( _vxn) * h; + drawText(tx, ty); + } else { + var off = 2 * viewer.dimScale; + angled._normalize(); + var extraLine = angled.multiply(textWidth + off * 2); + ctx.beginPath(); + ctx.moveTo(b.x, b.y); + ctx.lineTo(b.x + extraLine.x, b.y + extraLine.y); + ctx.closePath(); + ctx.stroke(); + angled._multiply(off); + + tx = (b.x + _vxn * textOff) + angled.x; + ty = (b.y + _vyn * textOff) + angled.y; + drawText(tx, ty); + } + } + + drawForArc(ctx, scale, viewer) { + + var r = this.obj.distanceA(); + + var hxn = Math.cos(this.angle); + var hyn = Math.sin(this.angle); + + var vxn = - hyn; + var vyn = hxn; + + //fix angle if needed + if (!this.obj.isPointInsideSector(this.obj.c.x + hxn, this.obj.c.y + hyn)) { + var cosA = hxn * (this.obj.a.x - this.obj.c.x) + hyn * (this.obj.a.y - this.obj.c.y); + var cosB = hxn * (this.obj.b.x - this.obj.c.x) + hyn * (this.obj.b.y - this.obj.c.y); + if (cosA - hxn > cosB - hxn) { + this.angle = this.obj.getStartAngle(); + } else { + this.angle = this.obj.getEndAngle(); + } + } + + var vertOff = getTextOff(viewer.dimScale); + var horOff = 5 * viewer.dimScale; + + var fontSize = 12 * viewer.dimScale; + ctx.font = (fontSize) + "px Arial"; + var txt = 'R ' + r.toFixed(2); + var textWidth = ctx.measureText(txt).width; + + var startX = this.obj.c.x + hxn * r; + var startY = this.obj.c.y + hyn * r; + var lineLength = textWidth + horOff * 2; + + ctx.beginPath(); + ctx.moveTo(startX, startY); + ctx.lineTo(startX + hxn * lineLength, startY + hyn * lineLength); + ctx.closePath(); + ctx.stroke(); + + var tx = startX + vxn * vertOff + hxn * horOff; + var ty = startY + vyn * vertOff + hyn * horOff; + ctx.save(); + ctx.translate(tx, ty); + ctx.rotate(-Math.atan2(vxn, vyn)); + ctx.scale(1, -1); + ctx.fillText(txt, 0, 0); + ctx.restore(); + } + + normalDistance(aim) { + return -1; + } +} +DiameterDimension.prototype._class = 'TCAD.TWO.DiameterDimension'; + + +function getTextOff(scale) { + return 3 * scale; +} -DiameterDimension.prototype.normalDistance = function(aim) { - return -1; -}; -export {HDimension, VDimension, Dimension, DiameterDimension} diff --git a/web/app/sketcher/shapes/draw-utils.js b/web/app/sketcher/shapes/draw-utils.js new file mode 100644 index 00000000..a3c7229d --- /dev/null +++ b/web/app/sketcher/shapes/draw-utils.js @@ -0,0 +1,12 @@ + +export function DrawPoint(ctx, x, y, rad, scale) { + ctx.beginPath(); + ctx.arc(x, y, rad / scale, 0, 2 * Math.PI, false); + ctx.fill(); +} + +export function SetStyle(style, ctx, scale) { + ctx.lineWidth = style.lineWidth / scale; + ctx.strokeStyle = style.strokeStyle; + ctx.fillStyle = style.fillStyle; +} diff --git a/web/app/sketcher/shapes/point.js b/web/app/sketcher/shapes/point.js new file mode 100644 index 00000000..934fe7a2 --- /dev/null +++ b/web/app/sketcher/shapes/point.js @@ -0,0 +1,55 @@ +import {SketchObject} from './sketch-object' +import {DrawPoint} from './draw-utils' +import {Generator} from '../id-generator' +import Vector from '../../math/vector' + +export class EndPoint extends SketchObject { + + constructor(x, y) { + super(); + this.x = x; + this.y = y; + this.parent = null; + this._x = new Param(this, 'x'); + this._y = new Param(this, 'y'); + } + + collectParams(params) { + params.push(this._x); + params.push(this._y); + } + + normalDistance(aim) { + return aim.minus(new Vector(this.x, this.y)).length(); + } + + getReferencePoint() { + return this; + } + + translateImpl(dx, dy) { + this.x += dx; + this.y += dy; + } + + drawImpl(ctx, scale) { + DrawPoint(ctx, this.x, this.y, 3, scale) + } +} +EndPoint.prototype._class = 'TCAD.TWO.EndPoint'; + +export class Param { + constructor(obj, prop) { + this.id = Generator.genID(); + this.obj = obj; + this.prop = prop; + } + + set(value) { + this.obj[this.prop] = value; + } + + get() { + return this.obj[this.prop]; + } +} diff --git a/web/app/sketcher/shapes/ref.js b/web/app/sketcher/shapes/ref.js new file mode 100644 index 00000000..f580f3a4 --- /dev/null +++ b/web/app/sketcher/shapes/ref.js @@ -0,0 +1,14 @@ +import {Generator} from '../id-generator' + +export function Ref(value) { + this.id = Generator.genID(); + this.value = value; +} + +Ref.prototype.set = function(value) { + this.value = value; +}; + +Ref.prototype.get = function() { + return this.value; +}; diff --git a/web/app/sketcher/shapes/segment.js b/web/app/sketcher/shapes/segment.js new file mode 100644 index 00000000..ee5445f5 --- /dev/null +++ b/web/app/sketcher/shapes/segment.js @@ -0,0 +1,74 @@ +import {SketchObject} from './sketch-object' +import Vector from '../../math/vector' +import * as math from '../../math/math' + +export class Segment extends SketchObject { + + constructor(a, b) { + super(); + this.a = a; + this.b = b; + a.parent = this; + b.parent = this; + this.children.push(a, b); + } + + validate() { + return math.distanceAB(this.a, this.b) > math.TOLERANCE; + } + + recover() { + var recoverLength = 100; + this.a.translate(-recoverLength, -recoverLength); + this.b.translate( recoverLength, recoverLength); + } + + collectParams(params) { + this.a.collectParams(params); + this.b.collectParams(params); + } + + normalDistance(aim) { + var x = aim.x; + var y = aim.y; + + var ab = new Vector(this.b.x - this.a.x, this.b.y - this.a.y) + var e = ab.normalize(); + var a = new Vector(aim.x - this.a.x, aim.y - this.a.y); + var b = e.multiply(a.dot(e)); + var n = a.minus(b); + + //Check if vector b lays on the vector ab + if (b.length() > ab.length()) { + return -1; + } + + if (b.dot(ab) < 0) { + return -1; + } + + return n.length(); + } + + getReferencePoint() { + return this.a; + } + + translateImpl(dx, dy) { + this.a.translate(dx, dy); + this.b.translate(dx, dy); + } + + drawImpl(ctx, scale) { + ctx.beginPath(); + ctx.moveTo(this.a.x, this.a.y); + ctx.lineTo(this.b.x, this.b.y); + // ctx.save(); + // ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.stroke(); + // ctx.restore(); + } +} + +Segment.prototype._class = 'TCAD.TWO.Segment'; + diff --git a/web/app/sketcher/shapes/sketch-object.js b/web/app/sketcher/shapes/sketch-object.js new file mode 100644 index 00000000..b0bd6fa7 --- /dev/null +++ b/web/app/sketcher/shapes/sketch-object.js @@ -0,0 +1,85 @@ +import {Generator} from '../id-generator' +import {SetStyle} from './draw-utils' +import {DragTool} from '../tools/drag' + +export class SketchObject { + constructor() { + this.id = Generator.genID(); + this.aux = false; + this.marked = null; + this.visible = true; + this.children = []; + this.linked = []; + this.layer = null; + } + + accept(visitor) { + return this.acceptV(false, visitor); + } + + acceptV(onlyVisible, visitor) { + if (onlyVisible && !this.visible) return true; + for (var i = 0; i < this.children.length; i++) { + var child = this.children[i]; + if (!child.acceptV(onlyVisible, visitor)) { + return false; + } + } + return visitor(this); + } + + validate() { + return true; + } + + recover() { + } + + getDefaultTool(viewer) { + return new DragTool(this, viewer); + } + + isAuxOrLinkedTo() { + if (!!this.aux) { + return true; + } + for (var i = 0; i < this.linked.length; ++i) { + if (!!this.linked[i].aux) { + return true; + } + } + return false; + } + + _translate(dx, dy, translated) { + translated[this.id] = 'x'; + for (var i = 0; i < this.linked.length; ++i) { + if (translated[this.linked[i].id] != 'x') { + this.linked[i]._translate(dx, dy, translated); + } + } + this.translateImpl(dx, dy); + }; + + translate(dx, dy) { + // this.translateImpl(dx, dy); + if (this.isAuxOrLinkedTo()) { + return; + } + this._translate(dx, dy, {}); + } + + draw(ctx, scale, viewer) { + if (!this.visible) return; + if (this.marked != null) { + ctx.save(); + SetStyle(this.marked, ctx, scale); + } + this.drawImpl(ctx, scale, viewer); + if (this.marked != null) ctx.restore(); + for (var i = 0; i < this.children.length; i++) { + this.children[i].draw(ctx, scale); + } + } +} + diff --git a/web/app/sketcher/viewer2d.js b/web/app/sketcher/viewer2d.js index dfb4d4fe..f61dbf9b 100644 --- a/web/app/sketcher/viewer2d.js +++ b/web/app/sketcher/viewer2d.js @@ -1,11 +1,15 @@ +import {Generator} from './id-generator' import {Parameters, Bus} from '../ui/toolkit' import {ParametricManager} from './parametric' import {HistoryManager} from './history' import {ToolManager} from './tools/manager' import {PanTool} from './tools/pan' import {DragTool} from './tools/drag' +import {Segment} from './shapes/segment' +import {EndPoint} from './shapes/point' import Vector from '../math/vector' -import * as utils from '../utils/utils' + +import * as draw_utils from './shapes/draw-utils' import * as math from '../math/math' var Styles = { @@ -53,18 +57,6 @@ var Styles = { }; -function _drawPoint(ctx, x, y, rad, scale) { - ctx.beginPath(); - ctx.arc(x, y, rad / scale, 0, 2 * Math.PI, false); - ctx.fill(); -} - -function setStyle(style, ctx, scale) { - ctx.lineWidth = style.lineWidth / scale; - ctx.strokeStyle = style.strokeStyle; - ctx.fillStyle = style.fillStyle; -} - /** @constructor */ function Viewer(canvas, IO) { @@ -264,7 +256,7 @@ Viewer.prototype.repaint = function() { for (var o = 0; o < layer.objects.length; o++) { var obj = layer.objects[o]; style = obj.style != null ? obj.style : layer.style; - if (style != prevStyle) setStyle(style, ctx, this.scale / this.retinaPxielRatio); + if (style != prevStyle) draw_utils.SetStyle(style, ctx, this.scale / this.retinaPxielRatio); obj.draw(ctx, this.scale / this.retinaPxielRatio, this); } } @@ -477,231 +469,6 @@ Polyline.prototype.draw = function(ctx) { ctx.stroke(); }; -var ID_COUNTER = 0; - -/** @constructor */ -function SketchObject() { - this.id = SketchObject.genID(); - this.aux = false; - this.marked = null; - this.visible = true; - this.children = []; - this.linked = []; - this.layer = null; -} - -SketchObject.genID = function() { - return ID_COUNTER ++; -}; - -SketchObject.resetIDGenerator = function(value) { - ID_COUNTER = value; -}; - -SketchObject.prototype.accept = function(visitor) { - return this.acceptV(false, visitor); -}; - -SketchObject.prototype.acceptV = function(onlyVisible, visitor) { - if (onlyVisible && !this.visible) return true; - for (var i = 0; i < this.children.length; i++) { - var child = this.children[i]; - if (!child.acceptV(onlyVisible, visitor)) { - return false; - } - } - return visitor(this); -}; - -SketchObject.prototype.validate = function() { - return true; -}; - -SketchObject.prototype.recover = function() { -}; - -SketchObject.prototype.getDefaultTool = function(viewer) { - return new DragTool(this, viewer); -}; - -SketchObject.prototype.isAuxOrLinkedTo = function() { - if (!!this.aux) { - return true; - } - for (var i = 0; i < this.linked.length; ++i) { - if (!!this.linked[i].aux) { - return true; - } - } - return false; -}; - -SketchObject.prototype._translate = function(dx, dy, translated) { - translated[this.id] = 'x'; - for (var i = 0; i < this.linked.length; ++i) { - if (translated[this.linked[i].id] != 'x') { - this.linked[i]._translate(dx, dy, translated); - } - } - this.translateImpl(dx, dy); -}; - -SketchObject.prototype.translate = function(dx, dy) { -// this.translateImpl(dx, dy); - if (this.isAuxOrLinkedTo()) { - return; - } - this._translate(dx, dy, {}); -}; - -SketchObject.prototype.draw = function(ctx, scale, viewer) { - if (!this.visible) return; - if (this.marked != null) { - ctx.save(); - setStyle(this.marked, ctx, scale); - } - this.drawImpl(ctx, scale, viewer); - if (this.marked != null) ctx.restore(); - for (var i = 0; i < this.children.length; i++) { - this.children[i].draw(ctx, scale); - } -}; - -/** @constructor */ -function Ref(value) { - this.id = SketchObject.genID(); - this.value = value; -} - -Ref.prototype.set = function(value) { - this.value = value; -}; - -Ref.prototype.get = function() { - return this.value; -}; - -/** @constructor */ -function Param(obj, prop) { - this.id = SketchObject.genID(); - this.obj = obj; - this.prop = prop; -} - -Param.prototype.set = function(value) { - this.obj[this.prop] = value; -}; - -Param.prototype.get = function() { - return this.obj[this.prop]; -}; - -/** @constructor */ -function EndPoint(x, y) { - SketchObject.call(this); - this.x = x; - this.y = y; - this.parent = null; - this._x = new Param(this, 'x'); - this._y = new Param(this, 'y'); -} - -utils.extend(EndPoint, SketchObject); - -EndPoint.prototype._class = 'TCAD.TWO.EndPoint'; - -EndPoint.prototype.collectParams = function(params) { - params.push(this._x); - params.push(this._y); -}; - -EndPoint.prototype.normalDistance = function(aim) { - return aim.minus(new Vector(this.x, this.y)).length(); -}; - -EndPoint.prototype.getReferencePoint = function() { - return this; -}; - -EndPoint.prototype.translateImpl = function(dx, dy) { - this.x += dx; - this.y += dy; -}; - -EndPoint.prototype.drawImpl = function(ctx, scale) { - _drawPoint(ctx, this.x, this.y, 3, scale) -}; - -/** @constructor */ -function Segment(a, b) { - SketchObject.call(this); - this.a = a; - this.b = b; - a.parent = this; - b.parent = this; - this.children.push(a, b); -} - -utils.extend(Segment, SketchObject); - -Segment.prototype._class = 'TCAD.TWO.Segment'; - -Segment.prototype.validate = function() { - return math.distanceAB(this.a, this.b) > math.TOLERANCE; -}; - -Segment.prototype.recover = function() { - var recoverLength = 100; - this.a.translate(-recoverLength, -recoverLength); - this.b.translate( recoverLength, recoverLength); -}; - -Segment.prototype.collectParams = function(params) { - this.a.collectParams(params); - this.b.collectParams(params); -}; - -Segment.prototype.normalDistance = function(aim) { - var x = aim.x; - var y = aim.y; - - var ab = new Vector(this.b.x - this.a.x, this.b.y - this.a.y) - var e = ab.normalize(); - var a = new Vector(aim.x - this.a.x, aim.y - this.a.y); - var b = e.multiply(a.dot(e)); - var n = a.minus(b); - - //Check if vector b lays on the vector ab - if (b.length() > ab.length()) { - return -1; - } - - if (b.dot(ab) < 0) { - return -1; - } - - return n.length(); -}; - -Segment.prototype.getReferencePoint = function() { - return this.a; -}; - -Segment.prototype.translateImpl = function(dx, dy) { - this.a.translate(dx, dy); - this.b.translate(dx, dy); -}; - -Segment.prototype.drawImpl = function(ctx, scale) { - ctx.beginPath(); - ctx.moveTo(this.a.x, this.a.y); - ctx.lineTo(this.b.x, this.b.y); -// ctx.save(); -// ctx.setTransform(1, 0, 0, 1, 0, 0); - ctx.stroke(); -// ctx.restore(); -}; - /** @constructor */ function Point(x, y, rad) { this.x = x; @@ -711,7 +478,7 @@ function Point(x, y, rad) { } Point.prototype.draw = function(ctx, scale) { - _drawPoint(ctx, this.x, this.y, this.rad, scale); + draw_utils.DrawPoint(ctx, this.x, this.y, this.rad, scale); }; /** @constructor */ @@ -825,4 +592,4 @@ ReferencePoint.prototype.draw = function(ctx, scale) { ctx.stroke(); }; -export {Styles, Viewer, Layer, SketchObject, EndPoint, Point, Segment, Ref} \ No newline at end of file +export {Viewer, Layer, Styles} \ No newline at end of file