mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-08 17:33:15 +01:00
117 lines
No EOL
2.7 KiB
JavaScript
117 lines
No EOL
2.7 KiB
JavaScript
import {Tool} from './tool'
|
|
import {Ellipse} from '../shapes/ellipse'
|
|
import {EllipticalArc} from '../shapes/elliptical-arc'
|
|
|
|
export const CENTER = 0;
|
|
export const RADIUS_X = 1;
|
|
export const RADIUS_Y = 2;
|
|
|
|
|
|
export class EllipseTool extends Tool {
|
|
|
|
constructor(viewer, arc) {
|
|
super(arc ? 'elliptical arc' : 'ellipse', viewer);
|
|
this.arc = arc;
|
|
this.ellipse = null;
|
|
this.state = CENTER;
|
|
}
|
|
|
|
restart() {
|
|
this.ellipse = null;
|
|
this.state = CENTER;
|
|
this.sendHint('specify a center of the ellipse')
|
|
}
|
|
|
|
cleanup(e) {
|
|
this.viewer.cleanSnap();
|
|
}
|
|
|
|
point(e) {
|
|
return this.viewer.snapped ? this.viewer.snapped : this.viewer.screenToModel(e);
|
|
}
|
|
|
|
newEllipse(p) {
|
|
return this.arc ? new EllipticalArc(p.x, p.y, 0, 0, 0, p.x, p.y, p.x, p.y) : new Ellipse(p.x, p.y, 0, 0, 0);
|
|
}
|
|
|
|
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 CENTER: {
|
|
const p = this.point(e);
|
|
this.ellipse = this.newEllipse(p);
|
|
this.snapIfNeed(this.ellipse.c);
|
|
this.viewer.activeLayer.add(this.ellipse);
|
|
this.viewer.refresh();
|
|
this.state = RADIUS_X;
|
|
this.sendHint('specify major radius');
|
|
break;
|
|
}
|
|
case RADIUS_X: {
|
|
this.state = RADIUS_Y;
|
|
this.sendHint('specify minor radius');
|
|
break;
|
|
}
|
|
case RADIUS_Y:
|
|
if (this.arc) {
|
|
this.ellipse.stabilize(this.viewer);
|
|
}
|
|
this.viewer.toolManager.releaseControl();
|
|
}
|
|
}
|
|
|
|
mousemove(e) {
|
|
const p = this.viewer.screenToModel(e);
|
|
switch (this.state) {
|
|
case CENTER: {
|
|
this.viewer.snap(p.x, p.y, []);
|
|
break;
|
|
}
|
|
case RADIUS_X: {
|
|
|
|
const dx = p.x - this.ellipse.c.x;
|
|
const dy = p.y - this.ellipse.c.y;
|
|
|
|
const rot = Math.atan2(dy, dx);
|
|
const rx = Math.sqrt(dx*dx + dy*dy);
|
|
|
|
this.ellipse.rx.set(rx);
|
|
this.ellipse.rot.set(rot);
|
|
|
|
if (this.arc) {
|
|
this.ellipse.a.setFromPoint(p);
|
|
this.demoBPoint();
|
|
}
|
|
break;
|
|
}
|
|
case RADIUS_Y: {
|
|
|
|
const dx = p.x - this.ellipse.c.x;
|
|
const dy = p.y - this.ellipse.c.y;
|
|
|
|
const rot = this.ellipse.rotation;
|
|
const axisX = - Math.sin(rot);
|
|
const axisY = Math.cos(rot);
|
|
|
|
|
|
const ry = Math.abs(dx * axisX + dy * axisY);
|
|
|
|
this.ellipse.ry.set(ry);
|
|
|
|
if (this.arc) {
|
|
this.demoBPoint();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
this.viewer.refresh();
|
|
}
|
|
} |