diff --git a/v3/src/paths/Path.js b/v3/src/paths/Path.js index b00330630..2ace608a4 100644 --- a/v3/src/paths/Path.js +++ b/v3/src/paths/Path.js @@ -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; } }); diff --git a/v3/src/paths/curves/Curve.js b/v3/src/paths/curves/Curve.js index da30ba89c..d2cc41b84 100644 --- a/v3/src/paths/curves/Curve.js +++ b/v3/src/paths/curves/Curve.js @@ -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; } }); diff --git a/v3/src/paths/curves/cubicbezier/CubicBezierCurve.js b/v3/src/paths/curves/cubicbezier/CubicBezierCurve.js index a17c56543..fa8c5a1b9 100644 --- a/v3/src/paths/curves/cubicbezier/CubicBezierCurve.js +++ b/v3/src/paths/curves/cubicbezier/CubicBezierCurve.js @@ -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; } }); diff --git a/v3/src/paths/curves/ellipse/EllipseCurve.js b/v3/src/paths/curves/ellipse/EllipseCurve.js index ac5ff4518..8c8925a94 100644 --- a/v3/src/paths/curves/ellipse/EllipseCurve.js +++ b/v3/src/paths/curves/ellipse/EllipseCurve.js @@ -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,8 +56,8 @@ var EllipseCurve = new Class({ if (out === undefined) { out = new Vector2(); } var twoPi = Math.PI * 2; - var deltaAngle = this.endAngle - this.startAngle; - var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; + var deltaAngle = this._endAngle - this._startAngle; + var samePoints = Math.abs(deltaAngle) < Number.EPSILON; // ensures that deltaAngle is 0 .. 2 PI while (deltaAngle < 0) @@ -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); + } } }); diff --git a/v3/src/paths/curves/line/LineCurve.js b/v3/src/paths/curves/line/LineCurve.js index c019e8aa7..735089126 100644 --- a/v3/src/paths/curves/line/LineCurve.js +++ b/v3/src/paths/curves/line/LineCurve.js @@ -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; } }); diff --git a/v3/src/paths/curves/spline/SplineCurve.js b/v3/src/paths/curves/spline/SplineCurve.js index 61f6a7401..4ee5343f2 100644 --- a/v3/src/paths/curves/spline/SplineCurve.js +++ b/v3/src/paths/curves/spline/SplineCurve.js @@ -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; @@ -40,10 +45,10 @@ var SplineCurve = new Class({ var weight = point - intPoint; - var p0 = points[ (intPoint === 0) ? intPoint : intPoint - 1 ]; - var p1 = points[ intPoint ]; - var p2 = points[ (intPoint > points.length - 2) ? points.length - 1 : intPoint + 1 ]; - var p3 = points[ (intPoint > points.length - 3) ? points.length - 1 : intPoint + 2 ]; + var p0 = points[(intPoint === 0) ? intPoint : intPoint - 1]; + var p1 = points[intPoint]; + var p2 = points[(intPoint > points.length - 2) ? points.length - 1 : intPoint + 1]; + var p3 = points[(intPoint > points.length - 3) ? points.length - 1 : intPoint + 2]; return out.set(CatmullRom(weight, p0.x, p1.x, p2.x, p3.x), CatmullRom(weight, p0.y, p1.y, p2.y, p3.y)); }