Added getStartPoint and draw methods to all curves and paths.

This commit is contained in:
Richard Davey 2017-09-22 16:41:11 +01:00
parent 6631985a3e
commit 8a4fff945c
6 changed files with 298 additions and 68 deletions

View file

@ -2,18 +2,20 @@
var Class = require('../utils/Class'); var Class = require('../utils/Class');
var LineCurve = require('./curves/line/LineCurve'); var LineCurve = require('./curves/line/LineCurve');
var SplineCurve = require('./curves/spline/SplineCurve');
var CubicBezierCurve = require('./curves/cubicbezier/CubicBezierCurve');
var Vector2 = require('../math/Vector2'); var Vector2 = require('../math/Vector2');
// Local cache vars // Local cache vars
var tmpVec2A = new Vector2(); var tmpVec2A = new Vector2();
// var tmpVec2B = new Vector2(); var tmpVec2B = new Vector2();
var Path = new Class({ var Path = new Class({
initialize: initialize:
function Path () function Path (x, y)
{ {
this.curves = []; this.curves = [];
@ -21,29 +23,66 @@ var Path = new Class({
// Automatically closes the path // Automatically closes the path
this.autoClose = false; this.autoClose = false;
this.startPoint = new Vector2(x, y);
}, },
// If x2/y2 are not given then it creates a line between the previous curve end point (or 0x0) and x1,y1 // Creates a line curve from the previous end point to x/y
addLineCurve: function (x1, y1, x2, y2) lineTo: function (x, y)
{ {
if (x2 === undefined && y2 === undefined) if (x instanceof Vector2)
{ {
// Create a line from the previous end point to x1/y1 tmpVec2B.copy(x);
x2 = x1;
y2 = y1;
var end = this.getEndPoint(tmpVec2A);
this.curves.push(new LineCurve([ end.x, end.y, x2, y2 ]));
} }
else else
{ {
this.curves.push(new LineCurve([ x1, y1, x2, y2 ])); tmpVec2B.set(x, y);
} }
return this; var end = this.getEndPoint(tmpVec2A);
return this.add(new LineCurve([ end.x, end.y, tmpVec2B.x, tmpVec2B.y ]));
}, },
// Creates a spline curve starting at the previous end point, using the given parameters
splineTo: function (points)
{
points.shift(this.getEndPoint());
return this.add(new SplineCurve(points));
},
// Creates a cubic bezier curve starting at the previous end point and ending at p3, using p1 and p2 as control points
cubicBezierTo: function (x, y, control1X, control1Y, control2X, control2Y)
{
var p0 = this.getEndPoint();
var p1;
var p2;
var p3;
// Assume they're all vec2s
if (x instanceof Vector2)
{
p1 = x;
p2 = y;
p3 = control1X;
}
else
{
p1 = new Vector2(control1X, control1Y);
p2 = new Vector2(control2X, control2Y);
p3 = new Vector2(x, y);
}
return this.add(new CubicBezierCurve(p0, p1, p2, p3));
},
// Creates an ellipse curve positioned at the previous end point, using the given parameters
// ellipseTo: function (xRadius, yRadius, startAngle, endAngle, clockwise, rotation)
// {
// function EllipseCurve (x, y, xRadius, yRadius, startAngle, endAngle, clockwise, rotation)
// },
add: function (curve) add: function (curve)
{ {
this.curves.push(curve); this.curves.push(curve);
@ -61,7 +100,7 @@ var Path = new Class({
} }
else else
{ {
out.set(0, 0); out.copy(this.startPoint);
} }
return out; return out;
@ -227,6 +266,16 @@ var Path = new Class({
} }
return points; return points;
},
draw: function (graphics, pointsTotal)
{
for (var i = 0; i < this.curves.length; i++)
{
this.curves[i].draw(graphics, pointsTotal);
}
return graphics;
} }
}); });

View file

@ -1,10 +1,7 @@
// Based on the three.js Curve classes created by [zz85](http://www.lab4games.net/zz85/blog) // Based on the three.js Curve classes created by [zz85](http://www.lab4games.net/zz85/blog)
var Clamp = require('../../math/Clamp');
var Vector2 = require('../../math/Vector2');
var Vector3 = require('../../math/Vector3');
var Matrix4 = require('../../math/Matrix4');
var Class = require('../../utils/Class'); var Class = require('../../utils/Class');
var Vector2 = require('../../math/Vector2');
// Local cache vars // Local cache vars
@ -237,6 +234,29 @@ var Curve = new Class({
var t = this.getUtoTmapping(u); var t = this.getUtoTmapping(u);
return this.getTangent(t, out); return this.getTangent(t, out);
},
draw: function (graphics, pointsTotal)
{
if (pointsTotal === undefined) { pointsTotal = 32; }
var start = this.getStartPoint();
var points = this.getPoints(pointsTotal);
graphics.beginPath();
graphics.moveTo(start.x, start.y);
for (var i = 1; i < points.length; i++)
{
graphics.lineTo(points[i].x, points[i].y);
}
graphics.strokePath();
graphics.closePath();
// So you can chain graphics calls
return graphics;
} }
}); });

View file

@ -13,14 +13,27 @@ var CubicBezierCurve = new Class({
initialize: initialize:
function CubicBezierCurve (v0, v1, v2, v3) function CubicBezierCurve (p0, p1, p2, p3)
{ {
Curve.call(this); Curve.call(this);
this.v0 = v0; if (Array.isArray(p0))
this.v1 = v1; {
this.v2 = v2; p3 = new Vector2(p0[6], p0[7]);
this.v3 = v3; p2 = new Vector2(p0[4], p0[5]);
p1 = new Vector2(p0[2], p0[3]);
p0 = new Vector2(p0[0], p0[1]);
}
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
},
getStartPoint: function ()
{
return this.p0;
}, },
getResolution: function (divisions) getResolution: function (divisions)
@ -32,12 +45,33 @@ var CubicBezierCurve = new Class({
{ {
if (out === undefined) { out = new Vector2(); } if (out === undefined) { out = new Vector2(); }
var v0 = this.v0; var p0 = this.p0;
var v1 = this.v1; var p1 = this.p1;
var v2 = this.v2; var p2 = this.p2;
var v3 = this.v3; var p3 = this.p3;
return out.set(CubicBezier(t, v0.x, v1.x, v2.x, v3.x), CubicBezier(t, v0.y, v1.y, v2.y, v3.y)); return out.set(CubicBezier(t, p0.x, p1.x, p2.x, p3.x), CubicBezier(t, p0.y, p1.y, p2.y, p3.y));
},
draw: function (graphics, pointsTotal)
{
if (pointsTotal === undefined) { pointsTotal = 32; }
var points = this.getPoints(pointsTotal);
graphics.beginPath();
graphics.moveTo(this.p0.x, this.p0.y);
for (var i = 1; i < points.length; i++)
{
graphics.lineTo(points[i].x, points[i].y);
}
graphics.strokePath();
graphics.closePath();
// So you can chain graphics calls
return graphics;
} }
}); });

View file

@ -23,21 +23,27 @@ var EllipseCurve = new Class({
Curve.call(this); Curve.call(this);
this.x = x; this.p0 = new Vector2(x, y);
this.y = y;
this.xRadius = xRadius; this._xRadius = xRadius;
this.yRadius = yRadius; this._yRadius = yRadius;
// Radians // Radians
this.startAngle = DegToRad(startAngle); this._startAngle = DegToRad(startAngle);
this.endAngle = DegToRad(endAngle); this._endAngle = DegToRad(endAngle);
// Boolean (anti-clockwise direction) // Boolean (anti-clockwise direction)
this.clockwise = clockwise; this._clockwise = clockwise;
// The rotation of the arc // The rotation of the arc
this.rotation = DegToRad(rotation); this._rotation = DegToRad(rotation);
this._startPoint = this.getPoint(0);
},
getStartPoint: function ()
{
return this._startPoint;
}, },
getResolution: function (divisions) getResolution: function (divisions)
@ -50,7 +56,7 @@ var EllipseCurve = new Class({
if (out === undefined) { out = new Vector2(); } if (out === undefined) { out = new Vector2(); }
var twoPi = Math.PI * 2; var twoPi = Math.PI * 2;
var deltaAngle = this.endAngle - this.startAngle; var deltaAngle = this._endAngle - this._startAngle;
var samePoints = Math.abs(deltaAngle) < Number.EPSILON; var samePoints = Math.abs(deltaAngle) < Number.EPSILON;
// ensures that deltaAngle is 0 .. 2 PI // ensures that deltaAngle is 0 .. 2 PI
@ -76,7 +82,7 @@ var EllipseCurve = new Class({
} }
} }
if (this.clockwise && ! samePoints) if (this._clockwise && !samePoints)
{ {
if (deltaAngle === twoPi) if (deltaAngle === twoPi)
{ {
@ -88,24 +94,126 @@ var EllipseCurve = new Class({
} }
} }
var angle = this.startAngle + t * deltaAngle; var angle = this._startAngle + t * deltaAngle;
var x = this.x + this.xRadius * Math.cos(angle); var x = this.p0.x + this._xRadius * Math.cos(angle);
var y = this.y + this.yRadius * Math.sin(angle); var y = this.p0.y + this._yRadius * Math.sin(angle);
if (this.rotation !== 0) if (this._rotation !== 0)
{ {
var cos = Math.cos(this.rotation); var cos = Math.cos(this._rotation);
var sin = Math.sin(this.rotation); var sin = Math.sin(this._rotation);
var tx = x - this.x; var tx = x - this.p0.x;
var ty = y - this.y; var ty = y - this.p0.y;
// Rotate the point about the center of the ellipse. // Rotate the point about the center of the ellipse.
x = tx * cos - ty * sin + this.x; x = tx * cos - ty * sin + this.p0.x;
y = tx * sin + ty * cos + this.y; y = tx * sin + ty * cos + this.p0.y;
} }
return out.set(x, y); return out.set(x, y);
},
x: {
get: function ()
{
return this.p0.x;
},
set: function (value)
{
this.p0.x = value;
}
},
y: {
get: function ()
{
return this.p0.y;
},
set: function (value)
{
this.p0.y = value;
}
},
xRadius: {
get: function ()
{
return this._xRadius;
},
set: function (value)
{
this._xRadius = value;
this.getPoint(0, this._startPoint);
}
},
yRadius: {
get: function ()
{
return this._yRadius;
},
set: function (value)
{
this._yRadius = value;
this.getPoint(0, this._startPoint);
}
},
startAngle: {
get: function ()
{
return this._startAngle;
},
set: function (value)
{
this._startAngle = DegToRad(value);
this.getPoint(0, this._startPoint);
}
},
endAngle: {
get: function ()
{
return this._endAngle;
},
set: function (value)
{
this._endAngle = DegToRad(value);
this.getPoint(0, this._startPoint);
}
},
clockwise: {
get: function ()
{
return this._clockwise;
},
set: function (value)
{
this._clockwise = value;
this.getPoint(0, this._startPoint);
}
},
rotation: {
get: function ()
{
return this._rotation;
},
set: function (value)
{
this._rotation = DegToRad(value);
this.getPoint(0, this._startPoint);
}
} }
}); });

View file

@ -14,22 +14,27 @@ var LineCurve = new Class({
initialize: initialize:
// vec2s // vec2s or array
function LineCurve (v1, v2) function LineCurve (p0, p1)
{ {
if (Array.isArray(v1))
{
v2 = new Vector2(v1[2], v1[3]);
v1 = new Vector2(v1[0], v1[1]);
}
Curve.call(this); Curve.call(this);
this.v1 = v1; if (Array.isArray(p0))
this.v2 = v2; {
p1 = new Vector2(p0[2], p0[3]);
p0 = new Vector2(p0[0], p0[1]);
}
this.p0 = p0;
this.p1 = p1;
}, },
getResolution: function (divisions) getStartPoint: function ()
{
return this.p0;
},
getResolution: function ()
{ {
return 1; return 1;
}, },
@ -40,10 +45,10 @@ var LineCurve = new Class({
if (t === 1) if (t === 1)
{ {
return out.copy(this.v2); return out.copy(this.p1);
} }
out.copy(this.v2).sub(this.v1).scale(t).add(this.v1); out.copy(this.p1).sub(this.p0).scale(t).add(this.p0);
return out; return out;
}, },
@ -56,9 +61,18 @@ var LineCurve = new Class({
getTangent: function () getTangent: function ()
{ {
var tangent = tmpVec2.copy(this.v2).sub(this.v1); var tangent = tmpVec2.copy(this.p1).sub(this.p0);
return tangent.normalize(); return tangent.normalize();
},
// Override default Curve.draw because this is better than calling getPoints on a line!
draw: function (graphics)
{
graphics.lineBetween(this.p0.x, this.p0.y, this.p1.x, this.p1.y);
// So you can chain graphics calls
return graphics;
} }
}); });

View file

@ -23,6 +23,11 @@ var SplineCurve = new Class({
this.points = points; this.points = points;
}, },
getStartPoint: function ()
{
return this.points[0];
},
getResolution: function (divisions) getResolution: function (divisions)
{ {
return divisions * this.points.length; return divisions * this.points.length;