Closed jonobr1 closed 2 years ago
Pseudo code:
import Two from 'two.js';
export class Arc extends Two.Path {
_flagRadius = false;
_flagStartAngle = false;
_flagEndAngle = false;
_radius = 0;
_startAngle = 0;
_endAngle = 0;
constructor(x, y, radius, startAngle, endAngle, resolution) {
if (typeof resolution !== 'number') {
resolution = Two.Resolution;
}
var points = [];
for (var i = 0; i < resolution; i++) {
points.push(new Two.Anchor());
}
super(points);
for (var j = 0; j < Arc.Properties.length; j++) {
var prop = Arc.Properties[j];
Object.defineProperty(this, prop, protos[prop]);
}
this.curved = true;
if (typeof x === 'number') {
this.position.x = x;
}
if (typeof y === 'number') {
this.position.y = y;
}
if (typeof radius === 'number') {
this.radius = radius;
}
if (typeof startAngle === 'number') {
this.startAngle = startAngle;
}
if (typeof endAngle === 'number') {
this.endAngle = endAngle;
}
this._update();
}
static Properties = ['radius', 'startAngle', 'endAngle'];
_update() {
if (this._flagVertices || this._flagRadius || this._flagStartAngle
|| this._flagEndAngle) {
var vertices = this.vertices;
var radius = this._radius;
var startAngle = this._flagStartAngle;
var endAngle = this._endAngle;
for (var i = 0; i < vertices.length; i++) {
var v = vertices[i];
var pct = i / (vertices.length - 1);
var theta = pct * (endAngle - startAngle) + startAngle;
v.x = radius * Math.cos(theta);
v.y = radius * Math.sin(theta);
}
}
super._update.call(this);
return this;
}
flagReset() {
super.flagReset.call(this);
this._flagRadius = this._flagStartAngle = this._flagEndAngle = false;
return this;
}
};
var protos = {
radius: {
enumerable: true,
get: function() {
return this._radius;
},
set: function(v) {
if (v !== this._radius) {
this._radius = v;
this._flagRadius = true;
}
}
},
startAngle: {
enumerable: true,
get: function() {
return this._startAngle;
},
set: function(v) {
if (v !== this._startAngle) {
this._startAngle = v;
this._flagStartAngle = true;
}
}
},
endAngle: {
enumerable: true,
get: function() {
return this._endAngle;
},
set: function(v) {
if (v !== this._endAngle) {
this._endAngle = v;
this._flagEndAngle = true;
}
}
}
}
I like the direction that this going. I have a suggestion to make this a little more general so that it will draw both circular arcs and elliptical arcs. If the Two.arc
command had both and x radius and y radius, then the user could draw both (and if the y radius isn't supplied it could default to the x radius). Using your pseudocode, the change appear to be small (maybe 13 lines of code, at least in the pseudocode you posted) and relatively simple.
_flagRadius = false;
_flagStartAngle = false;
_flagEndAngle = false;
_radiusX = 0; <-------------- NEW
_radiusY =0; <-------------- NEW
_startAngle = 0;
_endAngle = 0;
constructor(x, y, radiusX, startAngle, endAngle, resolution, radiusY) { <-------------- NEW
if (typeof resolution !== 'number') {
resolution = Two.Resolution;
}
var points = [];
for (var i = 0; i < resolution; i++) {
points.push(new Two.Anchor());
}
super(points);
for (var j = 0; j < Arc.Properties.length; j++) {
var prop = Arc.Properties[j];
Object.defineProperty(this, prop, protos[prop]);
}
this.curved = true;
if (typeof x === 'number') {
this.position.x = x;
}
if (typeof y === 'number') {
this.position.y = y;
}
if (typeof radiusX === 'number') { <---------- NEW
this.radiusX = radiusX; <-------------- NEW
}
------------ START NEW ------------
if (typeof radiusY === 'undefined') {
this.radiusY = radiusX;
} else if ( typeof radiusY === 'number') {
this.radiusY = radiusY;
}
------------ END NEW ------------
if (typeof startAngle === 'number') {
this.startAngle = startAngle;
}
if (typeof endAngle === 'number') {
this.endAngle = endAngle;
}
this._update();
}
Then update
would look like this
_update() {
if (this._flagVertices || this._flagRadius || this._flagStartAngle
|| this._flagEndAngle) {
var vertices = this.vertices;
var radiusX = this._radiusX; <---------------NEW
var radiusY = this._radiusY; <----------------NEW
var startAngle = this._flagStartAngle; <-------------TYPO? I think this should be this._startAngle
var endAngle = this._endAngle;
for (var i = 0; i < vertices.length; i++) {
var v = vertices[i];
var pct = i / (vertices.length - 1);
var theta = pct * (endAngle - startAngle) + startAngle;
v.x = radiusX * Math.cos(theta); <-------------- NEW
v.y = radiusY * Math.sin(theta); <---------------NEW
}
}
super._update.call(this);
return this;
}
@jonobr1 Another suggestion -- It would also be great to have a rotation parameter also, like this: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/ellipse I'm wondering if you have a timeline for when you might start implementing such feature.
Thanks for all you work on this package - it is centrally important to my application.
All objects have a rotation
property. Would this be sufficient?
@jonobr1 Yes! That would work fine for rotation. Are you going to expand to elliptical arcs instead of just circular ones? Is Two.Arc
in production in V.0.8.x? Did I miss the release?
Two.Arc
is not implemented anywhere yet, but it's not a problem to expand to elliptical arcs.
Thanks for the update. Do you have a timeline in mind?
This branch has it implemented, but not tested: https://github.com/jonobr1/two.js/tree/issue-605
Let me know if you give it a try.
This is added to the latest npm package: https://www.npmjs.com/package/two.js
Is your feature request related to a problem? Please describe. Add
Two.Arc
which draws an arc between two points or draws an arc at a specificmidpoint
with aradius
,startAngle
, andendAngle
.