mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-09 18:02:50 +01:00
142 lines
3.6 KiB
JavaScript
142 lines
3.6 KiB
JavaScript
import * as utils from '../../utils/utils';
|
|
import * as math from '../../math/math';
|
|
import Vector from 'math/vector';
|
|
import {Ref} from './ref'
|
|
import {Constraints} from '../parametric'
|
|
import {pointIterator, SketchObject} from './sketch-object';
|
|
|
|
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;
|
|
}
|
|
|
|
visitParams(callback) {
|
|
this.a.visitParams(callback);
|
|
this.b.visitParams(callback);
|
|
this.c.visitParams(callback);
|
|
callback(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));
|
|
}
|
|
|
|
copy() {
|
|
return new Arc(this.a.copy(), this.b.copy(), this.c.copy());
|
|
}
|
|
|
|
mirror(dest, mirroringFunc) {
|
|
this.a.mirror(dest.b, mirroringFunc);
|
|
this.b.mirror(dest.a, mirroringFunc);
|
|
this.c.mirror(dest.c, mirroringFunc);
|
|
}
|
|
}
|
|
|
|
Arc.prototype._class = 'TCAD.TWO.Arc';
|