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 LineCurve = require('./curves/line/LineCurve');
var SplineCurve = require('./curves/spline/SplineCurve');
var CubicBezierCurve = require('./curves/cubicbezier/CubicBezierCurve');
var Vector2 = require('../math/Vector2');
// Local cache vars
var tmpVec2A = new Vector2();
// var tmpVec2B = new Vector2();
var tmpVec2B = new Vector2();
var Path = new Class({
initialize:
function Path ()
function Path (x, y)
{
this.curves = [];
@ -21,29 +23,66 @@ var Path = new Class({
// Automatically closes the path
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
addLineCurve: function (x1, y1, x2, y2)
// Creates a line curve from the previous end point to x/y
lineTo: function (x, y)
{
if (x2 === undefined && y2 === undefined)
if (x instanceof Vector2)
{
// Create a line from the previous end point to x1/y1
x2 = x1;
y2 = y1;
var end = this.getEndPoint(tmpVec2A);
this.curves.push(new LineCurve([ end.x, end.y, x2, y2 ]));
tmpVec2B.copy(x);
}
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)
{
this.curves.push(curve);
@ -61,7 +100,7 @@ var Path = new Class({
}
else
{
out.set(0, 0);
out.copy(this.startPoint);
}
return out;
@ -227,6 +266,16 @@ var Path = new Class({
}
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)
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 Vector2 = require('../../math/Vector2');
// Local cache vars
@ -237,6 +234,29 @@ var Curve = new Class({
var t = this.getUtoTmapping(u);
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:
function CubicBezierCurve (v0, v1, v2, v3)
function CubicBezierCurve (p0, p1, p2, p3)
{
Curve.call(this);
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
if (Array.isArray(p0))
{
p3 = new Vector2(p0[6], p0[7]);
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)
@ -32,12 +45,33 @@ var CubicBezierCurve = new Class({
{
if (out === undefined) { out = new Vector2(); }
var v0 = this.v0;
var v1 = this.v1;
var v2 = this.v2;
var v3 = this.v3;
var p0 = this.p0;
var p1 = this.p1;
var p2 = this.p2;
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);
this.x = x;
this.y = y;
this.p0 = new Vector2(x, y);
this.xRadius = xRadius;
this.yRadius = yRadius;
this._xRadius = xRadius;
this._yRadius = yRadius;
// Radians
this.startAngle = DegToRad(startAngle);
this.endAngle = DegToRad(endAngle);
this._startAngle = DegToRad(startAngle);
this._endAngle = DegToRad(endAngle);
// Boolean (anti-clockwise direction)
this.clockwise = clockwise;
this._clockwise = clockwise;
// 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)
@ -50,7 +56,7 @@ var EllipseCurve = new Class({
if (out === undefined) { out = new Vector2(); }
var twoPi = Math.PI * 2;
var deltaAngle = this.endAngle - this.startAngle;
var deltaAngle = this._endAngle - this._startAngle;
var samePoints = Math.abs(deltaAngle) < Number.EPSILON;
// 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)
{
@ -88,24 +94,126 @@ var EllipseCurve = new Class({
}
}
var angle = this.startAngle + t * deltaAngle;
var x = this.x + this.xRadius * Math.cos(angle);
var y = this.y + this.yRadius * Math.sin(angle);
var angle = this._startAngle + t * deltaAngle;
var x = this.p0.x + this._xRadius * Math.cos(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 sin = Math.sin(this.rotation);
var cos = Math.cos(this._rotation);
var sin = Math.sin(this._rotation);
var tx = x - this.x;
var ty = y - this.y;
var tx = x - this.p0.x;
var ty = y - this.p0.y;
// Rotate the point about the center of the ellipse.
x = tx * cos - ty * sin + this.x;
y = tx * sin + ty * cos + this.y;
x = tx * cos - ty * sin + this.p0.x;
y = tx * sin + ty * cos + this.p0.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:
// vec2s
function LineCurve (v1, v2)
// vec2s or array
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);
this.v1 = v1;
this.v2 = v2;
if (Array.isArray(p0))
{
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;
},
@ -40,10 +45,10 @@ var LineCurve = new Class({
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;
},
@ -56,9 +61,18 @@ var LineCurve = new Class({
getTangent: function ()
{
var tangent = tmpVec2.copy(this.v2).sub(this.v1);
var tangent = tmpVec2.copy(this.p1).sub(this.p0);
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;
},
getStartPoint: function ()
{
return this.points[0];
},
getResolution: function (divisions)
{
return divisions * this.points.length;