From 32870092e0390353e5968f567b0202f98bc3fd49 Mon Sep 17 00:00:00 2001 From: Richard Tingle <6330028+richardTingle@users.noreply.github.com> Date: Sat, 18 Dec 2021 15:22:19 +0000 Subject: [PATCH 1/8] #6 Add a builder for the curve class that allows it to be specified as a series of anchor and control points --- .../com/epaga/particles/valuetypes/Curve.java | 35 +++++++++++++++ .../curvebuilder/CurveBuilderAtAnchor.java | 45 +++++++++++++++++++ .../CurveBuilderAtControlPoint1.java | 25 +++++++++++ .../CurveBuilderAtControlPoint2.java | 26 +++++++++++ .../curvebuilder/CurveBuilderStart.java | 19 ++++++++ 5 files changed, 150 insertions(+) create mode 100644 src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java create mode 100644 src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java create mode 100644 src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java create mode 100644 src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java diff --git a/src/main/java/com/epaga/particles/valuetypes/Curve.java b/src/main/java/com/epaga/particles/valuetypes/Curve.java index 831c6a6..94045ac 100644 --- a/src/main/java/com/epaga/particles/valuetypes/Curve.java +++ b/src/main/java/com/epaga/particles/valuetypes/Curve.java @@ -31,6 +31,8 @@ */ package com.epaga.particles.valuetypes; +import com.epaga.particles.valuetypes.curvebuilder.CurveBuilderAtAnchor; +import com.epaga.particles.valuetypes.curvebuilder.CurveBuilderStart; import com.jme3.export.*; import com.jme3.math.Vector2f; @@ -158,4 +160,37 @@ public boolean equals(Object o) { return true; } + + + /** + * Produces a builder that can be used to fluently build a curve. A Curve will always be continuous (And should + * move in a positive X direction) but the gradient may change sharply. + * + * It is a series of anchor points connected either by straight line sections or cubic besier curves (defined by + * 2 control points). + * + * In normal usage the first anchor point should be at x = 0, all further points should advance in the X axis and + * the final anchor point should have x at 1. This is because usually X is the fractional life of the particle + * + * Example usage: + * + *
{@code
+   *     Curve curve = Curve.builder()
+   *             .anchorPoint(new Vector2f(0,0))
+   *             .anchorPoint(new Vector2f(0.5f,0.5f))
+   *             .controlPoint1(new Vector2f(0.6f,0.5f))
+   *             .controlPoint2(new Vector2f(0.8f,2f))
+   *             .anchorPoint(new Vector2f(1,2f))
+   *             .build();
+   * }
+ * + * This example produces a straight line from (0,0) -> (0.5,0.5), then a cubic Besier curves between (0.5,0.5) -> (1,2) with control points (0.6,0.5) and (0.8,2) + * + * Note that a builder should not be reused. + * + * @return a CurveBuilderStart + */ + public static CurveBuilderStart builder(){ + return new CurveBuilderStart(); + } } diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java new file mode 100644 index 0000000..80aba70 --- /dev/null +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java @@ -0,0 +1,45 @@ +package com.epaga.particles.valuetypes.curvebuilder; + +import com.epaga.particles.valuetypes.Curve; +import com.jme3.math.Vector2f; + +public class CurveBuilderAtAnchor{ + + Curve curveBeingBuilt; + Vector2f controlPointIn; + Vector2f currentAnchor; + + public CurveBuilderAtAnchor(Curve curveBeingBuilt, Vector2f controlPointIn, Vector2f currentAnchor){ + this.curveBeingBuilt = curveBeingBuilt; + this.controlPointIn = controlPointIn; + this.currentAnchor = currentAnchor; + } + + /** + * Adds a point that the curve will attempt to move towards but may not actually touch. + * + * The 2 control points are used to define a cubic Bézier curve between 2 anchors + * @param nextControlPoint the control point + * @return a CurveBuilderAtControlPoint1 a part of the curve builder system + */ + public CurveBuilderAtControlPoint1 controlPoint1( Vector2f nextControlPoint ){ + return new CurveBuilderAtControlPoint1(curveBeingBuilt, controlPointIn, currentAnchor, nextControlPoint); + } + + /** + * Produces a straight line between 2 anchor points + * @param nextAnchor the next anchor point + * @return a CurveBuilderAtAnchor a part of the curve builder system + */ + public CurveBuilderAtAnchor anchorPoint(Vector2f nextAnchor ){ + //simulate a straight line using a Bézier curve + Vector2f midOne = currentAnchor.mult(2f/3).add(nextAnchor.mult(1f/3)); + Vector2f midTwo = currentAnchor.mult(1f/3).add(nextAnchor.mult(2f/3)); + return controlPoint1(midOne).controlPoint2(midTwo).nextAnchor(nextAnchor); + } + + public Curve end(){ + curveBeingBuilt.addControlPoint(controlPointIn, currentAnchor, null); + return curveBeingBuilt; + } +} \ No newline at end of file diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java new file mode 100644 index 0000000..353c470 --- /dev/null +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java @@ -0,0 +1,25 @@ +package com.epaga.particles.valuetypes.curvebuilder; + +import com.epaga.particles.valuetypes.Curve; +import com.jme3.math.Vector2f; + +public class CurveBuilderAtControlPoint1{ + + Curve curveBeingBuilt; + + public CurveBuilderAtControlPoint1(Curve curveBeingBuilt, Vector2f controlPointIn, Vector2f currentAnchor, Vector2f controlPointOut){ + this.curveBeingBuilt = curveBeingBuilt; + this.curveBeingBuilt.addControlPoint(controlPointIn, currentAnchor, controlPointOut); + } + + /** + * Adds a point that the curve will attempt to move towards but may not actually touch. + * + * The 2 control points are used to define a cubic Bézier curve between 2 anchors + * @param nextControlPoint the control point + * @return a CurveBuilderAtControlPoint1 a part of the curve builder system + */ + public CurveBuilderAtControlPoint2 controlPoint2( Vector2f nextControlPoint ){ + return new CurveBuilderAtControlPoint2(curveBeingBuilt, nextControlPoint); + } +} diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java new file mode 100644 index 0000000..4e1f926 --- /dev/null +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java @@ -0,0 +1,26 @@ +package com.epaga.particles.valuetypes.curvebuilder; + +import com.epaga.particles.valuetypes.Curve; +import com.jme3.math.Vector2f; + +public class CurveBuilderAtControlPoint2{ + + Curve curveBeingBuilt; + Vector2f inControlPoint; + + public CurveBuilderAtControlPoint2(Curve curveBeingBuilt, Vector2f inControlPoint){ + this.curveBeingBuilt = curveBeingBuilt; + this.inControlPoint = inControlPoint; + } + + /** + * Adds a point that the curve go through. + * + * Anchors are the starts and ends of cubic Bézier curves + * @param nextAnchor the anchor point + * @return a CurveBuilderAtAnchor a part of the curve builder system + */ + public CurveBuilderAtAnchor anchorPoint(Vector2f nextAnchor ){ + return new CurveBuilderAtAnchor(curveBeingBuilt, inControlPoint, nextAnchor); + } +} diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java new file mode 100644 index 0000000..eec04db --- /dev/null +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java @@ -0,0 +1,19 @@ +package com.epaga.particles.valuetypes.curvebuilder; + +import com.epaga.particles.valuetypes.Curve; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; + +public class CurveBuilderStart{ + + Curve curveBeingBuilt = new Curve(); + + /** + * Adds the first anchor point, where the line will start + * @return CurveBuilderAtAnchor a part of the curve builder system + */ + public CurveBuilderAtAnchor anchorPoint(Vector2f start){ + return new CurveBuilderAtAnchor(curveBeingBuilt, null, start); + } + +} From 1b30a2485d2f02164ced36068d55e0c49916106d Mon Sep 17 00:00:00 2001 From: Richard Tingle <6330028+richardTingle@users.noreply.github.com> Date: Sat, 18 Dec 2021 15:33:25 +0000 Subject: [PATCH 2/8] #6 Allow direct passing of floats and add to size influencer javadoc --- .../epaga/particles/influencers/SizeInfluencer.java | 7 +++++++ .../curvebuilder/CurveBuilderAtAnchor.java | 12 +++++++++++- .../valuetypes/curvebuilder/CurveBuilderStart.java | 4 ++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/epaga/particles/influencers/SizeInfluencer.java b/src/main/java/com/epaga/particles/influencers/SizeInfluencer.java index 4f71ee4..ebff8b5 100644 --- a/src/main/java/com/epaga/particles/influencers/SizeInfluencer.java +++ b/src/main/java/com/epaga/particles/influencers/SizeInfluencer.java @@ -44,6 +44,13 @@ * Size Module * The size module controls the particle size over time * + * To create a size inflencer that linearly changes the particle size from 0.3 to 0.1 over its lifetime create like: + *
{@code
+ *         ValueType sizeOverTime = new ValueType(Curve.builder().anchorPoint(0f, 0.03f).anchorPoint(1f, 0.01f).end());
+ *         SizeInfluencer sizeInfluencer = new SizeInfluencer();
+ *         sizeInfluencer.setSizeOverTime(sizeOverTime);
+ * }
+ * * @author t0neg0d * @author Jeddic */ diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java index 80aba70..999ff35 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java @@ -26,6 +26,16 @@ public CurveBuilderAtControlPoint1 controlPoint1( Vector2f nextControlPoint ){ return new CurveBuilderAtControlPoint1(curveBeingBuilt, controlPointIn, currentAnchor, nextControlPoint); } + /** + * Produces a straight line between 2 anchor points + * @param x the x of the next anchor point + * @param y the y of the next anchor point + * @return a CurveBuilderAtAnchor a part of the curve builder system + */ + public CurveBuilderAtAnchor anchorPoint(float x, float y){ + return anchorPoint(new Vector2f(x,y)); + } + /** * Produces a straight line between 2 anchor points * @param nextAnchor the next anchor point @@ -35,7 +45,7 @@ public CurveBuilderAtAnchor anchorPoint(Vector2f nextAnchor ){ //simulate a straight line using a Bézier curve Vector2f midOne = currentAnchor.mult(2f/3).add(nextAnchor.mult(1f/3)); Vector2f midTwo = currentAnchor.mult(1f/3).add(nextAnchor.mult(2f/3)); - return controlPoint1(midOne).controlPoint2(midTwo).nextAnchor(nextAnchor); + return controlPoint1(midOne).controlPoint2(midTwo).anchorPoint(nextAnchor); } public Curve end(){ diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java index eec04db..8e45793 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java @@ -8,6 +8,10 @@ public class CurveBuilderStart{ Curve curveBeingBuilt = new Curve(); + public CurveBuilderAtAnchor anchorPoint(float x, float y){ + return anchorPoint(new Vector2f(x,y)); + } + /** * Adds the first anchor point, where the line will start * @return CurveBuilderAtAnchor a part of the curve builder system From 751f43a7ded0d1801e33bed9068a9c5da733871e Mon Sep 17 00:00:00 2001 From: Richard Tingle <6330028+richardTingle@users.noreply.github.com> Date: Sat, 18 Dec 2021 16:40:45 +0000 Subject: [PATCH 3/8] #6 Add unit tests for the curve builder (and so implicitly the curve) --- .../curvebuilder/CurveBuilderAtAnchor.java | 12 +++ .../CurveBuilderAtControlPoint1.java | 12 +++ .../CurveBuilderAtControlPoint2.java | 12 +++ .../epaga/particles/valuetypes/CurveTest.java | 74 +++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 src/test/java/com/epaga/particles/valuetypes/CurveTest.java diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java index 999ff35..f17d8dd 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java @@ -15,6 +15,18 @@ public CurveBuilderAtAnchor(Curve curveBeingBuilt, Vector2f controlPointIn, Vect this.currentAnchor = currentAnchor; } + /** + * Adds a point that the curve will attempt to move towards but may not actually touch. + * + * The 2 control points are used to define a cubic Bézier curve between 2 anchors + * @param x the next control point's x + * @param y the next control point's y + * @return a CurveBuilderAtControlPoint1 a part of the curve builder system + */ + public CurveBuilderAtControlPoint1 controlPoint1( float x, float y ){ + return controlPoint1(new Vector2f(x,y)); + } + /** * Adds a point that the curve will attempt to move towards but may not actually touch. * diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java index 353c470..07c939f 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java @@ -16,6 +16,18 @@ public CurveBuilderAtControlPoint1(Curve curveBeingBuilt, Vector2f controlPointI * Adds a point that the curve will attempt to move towards but may not actually touch. * * The 2 control points are used to define a cubic Bézier curve between 2 anchors + * @param x the control point's x + * @param y the control point's y + * @return a CurveBuilderAtControlPoint1 a part of the curve builder system + */ + public CurveBuilderAtControlPoint2 controlPoint2( float x, float y ){ + return controlPoint2(new Vector2f(x, y)); + } + + /** + * Adds a point that the curve will attempt to move towards (but may not actually touch). + * + * The 2 control points are used to define a cubic Bézier curve between 2 anchors * @param nextControlPoint the control point * @return a CurveBuilderAtControlPoint1 a part of the curve builder system */ diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java index 4e1f926..c0e242e 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java @@ -13,6 +13,18 @@ public CurveBuilderAtControlPoint2(Curve curveBeingBuilt, Vector2f inControlPoin this.inControlPoint = inControlPoint; } + /** + * Adds a point that the curve go through. + * + * Anchors are the starts and ends of cubic Bézier curves + * @param x the anchor point's x + * @param y the anchor point's y + * @return a CurveBuilderAtAnchor a part of the curve builder system + */ + public CurveBuilderAtAnchor anchorPoint(float x, float y){ + return anchorPoint(new Vector2f(x, y)); + } + /** * Adds a point that the curve go through. * diff --git a/src/test/java/com/epaga/particles/valuetypes/CurveTest.java b/src/test/java/com/epaga/particles/valuetypes/CurveTest.java new file mode 100644 index 0000000..10c1b75 --- /dev/null +++ b/src/test/java/com/epaga/particles/valuetypes/CurveTest.java @@ -0,0 +1,74 @@ +package com.epaga.particles.valuetypes; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class CurveTest{ + + @Test + public void builder_straightLine(){ + Curve curve = Curve.builder() + .anchorPoint(0,0) + .anchorPoint(1,10) + .end(); + + assertEquals(0, curve.getValue(0f), 0.001); + assertEquals(4, curve.getValue(0.4f), 0.001); + assertEquals(10, curve.getValue(1f), 0.001); + } + + /** + * Tests that 2 straight lines joined together functions correctly + */ + @Test + public void builder_doubleStraightLine(){ + Curve curve = Curve.builder() + .anchorPoint(0,0) + .anchorPoint(0.4f,10) + .anchorPoint(1f, 10) + .end(); + + assertEquals(0, curve.getValue(0f), 0.001); + assertEquals(5, curve.getValue(0.2f), 0.001); + assertEquals(10, curve.getValue(0.8f), 0.001); + } + + /** + * Tests that a Bézier-like curve functions correctly + * + * (Its not actually a true Bézier curve becuse a Bézier curve can "go backwards" and follows a + * slightly different path + */ + @Test + public void builder_curve(){ + + Curve curve = Curve.builder() + .anchorPoint(0,0) + .controlPoint1(0.2f, 1) + .controlPoint2(0.8f, 0) + .anchorPoint(1,1) + .end(); + + //expected values obtained using https://www.desmos.com/calculator/ebdtbxgbq0 + + assertEquals(0, curve.getValue(0f), 0.001); + + //value obtained as 0.1 along using the following + // along line 1 = 0.9 * 0 + 0.1 * 1 = 0.1 + // along line 2 = 0.9 * 1 + 0.1 * 0 = 0.9 + // along line 3 = 0.9 * 0 + 0.1 * 1 = 0.1 + + //obtain 2 new lines between along line 1 -> along line 2 and along line 2 -> along line 3. Get 0.1 along each one + //along second order 1 = 0.9 * 0.1 + 0.1 * 0.9 = 0.18 + //along second order 2 = 0.9 * 0.9 + 0.1 * 0.1 = 0.82 + + //final result is 0.1 along the line between the second order points + // 0.9 * 0.18 + 0.1 * 0.82 + + assertEquals(0.244, curve.getValue(0.1f), 0.001); + + assertEquals(0.5, curve.getValue(0.5f), 0.001); + assertEquals(1, curve.getValue(1), 0.001); + } +} \ No newline at end of file From e08906dd0501c81ce0ba48f6de8d2ba3296d7170 Mon Sep 17 00:00:00 2001 From: Richard Tingle <6330028+richardTingle@users.noreply.github.com> Date: Sat, 18 Dec 2021 16:42:41 +0000 Subject: [PATCH 4/8] #6 Correct javadoc as these are not actual bezier curves --- src/main/java/com/epaga/particles/valuetypes/Curve.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/epaga/particles/valuetypes/Curve.java b/src/main/java/com/epaga/particles/valuetypes/Curve.java index 94045ac..0a7787c 100644 --- a/src/main/java/com/epaga/particles/valuetypes/Curve.java +++ b/src/main/java/com/epaga/particles/valuetypes/Curve.java @@ -166,8 +166,9 @@ public boolean equals(Object o) { * Produces a builder that can be used to fluently build a curve. A Curve will always be continuous (And should * move in a positive X direction) but the gradient may change sharply. * - * It is a series of anchor points connected either by straight line sections or cubic besier curves (defined by - * 2 control points). + * It is a series of anchor points connected either by straight line sections or cubic Bézier-like curves (defined by + * 2 control points). They are bezier-like curves not Bézier curves because of the requirement that X (often + * representing time) can only be allowed to move forward * * In normal usage the first anchor point should be at x = 0, all further points should advance in the X axis and * the final anchor point should have x at 1. This is because usually X is the fractional life of the particle From 5f964880b8758d32dda2350a3048461171611e3e Mon Sep 17 00:00:00 2001 From: Richard Tingle <6330028+richardTingle@users.noreply.github.com> Date: Sat, 18 Dec 2021 16:58:07 +0000 Subject: [PATCH 5/8] #6 Prevent illegal reuse of the curve builder (which would cause very weird behaviour) --- .../curvebuilder/CurveBuilderAtAnchor.java | 22 +++++++++++-------- .../CurveBuilderAtControlPoint1.java | 3 ++- .../CurveBuilderAtControlPoint2.java | 3 ++- .../curvebuilder/CurveBuilderPiece.java | 13 +++++++++++ .../curvebuilder/CurveBuilderStart.java | 3 ++- .../epaga/particles/valuetypes/CurveTest.java | 19 ++++++++++++---- 6 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderPiece.java diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java index f17d8dd..6cb3144 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java @@ -3,11 +3,11 @@ import com.epaga.particles.valuetypes.Curve; import com.jme3.math.Vector2f; -public class CurveBuilderAtAnchor{ +public class CurveBuilderAtAnchor extends CurveBuilderPiece{ - Curve curveBeingBuilt; - Vector2f controlPointIn; - Vector2f currentAnchor; + private final Curve curveBeingBuilt; + private final Vector2f controlPointIn; + private final Vector2f currentAnchor; public CurveBuilderAtAnchor(Curve curveBeingBuilt, Vector2f controlPointIn, Vector2f currentAnchor){ this.curveBeingBuilt = curveBeingBuilt; @@ -16,9 +16,9 @@ public CurveBuilderAtAnchor(Curve curveBeingBuilt, Vector2f controlPointIn, Vect } /** - * Adds a point that the curve will attempt to move towards but may not actually touch. + * Adds a point that the curve will attempt to move towards (but may not actually touch). * - * The 2 control points are used to define a cubic Bézier curve between 2 anchors + * The 2 control points are used to define a cubic Bézier-like curve between 2 anchors * @param x the next control point's x * @param y the next control point's y * @return a CurveBuilderAtControlPoint1 a part of the curve builder system @@ -28,13 +28,14 @@ public CurveBuilderAtControlPoint1 controlPoint1( float x, float y ){ } /** - * Adds a point that the curve will attempt to move towards but may not actually touch. + * Adds a point that the curve will attempt to move towards (but may not actually touch) * - * The 2 control points are used to define a cubic Bézier curve between 2 anchors + * The 2 control points are used to define a cubic Bézier-like curve between 2 anchors * @param nextControlPoint the control point * @return a CurveBuilderAtControlPoint1 a part of the curve builder system */ public CurveBuilderAtControlPoint1 controlPoint1( Vector2f nextControlPoint ){ + checkReuse(); return new CurveBuilderAtControlPoint1(curveBeingBuilt, controlPointIn, currentAnchor, nextControlPoint); } @@ -54,14 +55,17 @@ public CurveBuilderAtAnchor anchorPoint(float x, float y){ * @return a CurveBuilderAtAnchor a part of the curve builder system */ public CurveBuilderAtAnchor anchorPoint(Vector2f nextAnchor ){ + //no checkReuse() as the call to controlPoint1 will do that //simulate a straight line using a Bézier curve Vector2f midOne = currentAnchor.mult(2f/3).add(nextAnchor.mult(1f/3)); Vector2f midTwo = currentAnchor.mult(1f/3).add(nextAnchor.mult(2f/3)); return controlPoint1(midOne).controlPoint2(midTwo).anchorPoint(nextAnchor); } - public Curve end(){ + public Curve build(){ + checkReuse(); curveBeingBuilt.addControlPoint(controlPointIn, currentAnchor, null); return curveBeingBuilt; } + } \ No newline at end of file diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java index 07c939f..741f192 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java @@ -3,7 +3,7 @@ import com.epaga.particles.valuetypes.Curve; import com.jme3.math.Vector2f; -public class CurveBuilderAtControlPoint1{ +public class CurveBuilderAtControlPoint1 extends CurveBuilderPiece{ Curve curveBeingBuilt; @@ -32,6 +32,7 @@ public CurveBuilderAtControlPoint2 controlPoint2( float x, float y ){ * @return a CurveBuilderAtControlPoint1 a part of the curve builder system */ public CurveBuilderAtControlPoint2 controlPoint2( Vector2f nextControlPoint ){ + checkReuse(); return new CurveBuilderAtControlPoint2(curveBeingBuilt, nextControlPoint); } } diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java index c0e242e..bd1053f 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java @@ -3,7 +3,7 @@ import com.epaga.particles.valuetypes.Curve; import com.jme3.math.Vector2f; -public class CurveBuilderAtControlPoint2{ +public class CurveBuilderAtControlPoint2 extends CurveBuilderPiece{ Curve curveBeingBuilt; Vector2f inControlPoint; @@ -33,6 +33,7 @@ public CurveBuilderAtAnchor anchorPoint(float x, float y){ * @return a CurveBuilderAtAnchor a part of the curve builder system */ public CurveBuilderAtAnchor anchorPoint(Vector2f nextAnchor ){ + checkReuse(); return new CurveBuilderAtAnchor(curveBeingBuilt, inControlPoint, nextAnchor); } } diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderPiece.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderPiece.java new file mode 100644 index 0000000..3323106 --- /dev/null +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderPiece.java @@ -0,0 +1,13 @@ +package com.epaga.particles.valuetypes.curvebuilder; + +public class CurveBuilderPiece{ + + boolean used = false; + + protected void checkReuse(){ + if (used){ + throw new IllegalStateException("Curve builders must not be reused (As they actually build a single curve as they go along)"); + } + used = true; + } +} diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java index 8e45793..e275066 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderStart.java @@ -4,7 +4,7 @@ import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; -public class CurveBuilderStart{ +public class CurveBuilderStart extends CurveBuilderPiece{ Curve curveBeingBuilt = new Curve(); @@ -17,6 +17,7 @@ public CurveBuilderAtAnchor anchorPoint(float x, float y){ * @return CurveBuilderAtAnchor a part of the curve builder system */ public CurveBuilderAtAnchor anchorPoint(Vector2f start){ + checkReuse(); return new CurveBuilderAtAnchor(curveBeingBuilt, null, start); } diff --git a/src/test/java/com/epaga/particles/valuetypes/CurveTest.java b/src/test/java/com/epaga/particles/valuetypes/CurveTest.java index 10c1b75..d8cf4fa 100644 --- a/src/test/java/com/epaga/particles/valuetypes/CurveTest.java +++ b/src/test/java/com/epaga/particles/valuetypes/CurveTest.java @@ -1,5 +1,6 @@ package com.epaga.particles.valuetypes; +import com.epaga.particles.valuetypes.curvebuilder.CurveBuilderAtAnchor; import org.junit.Test; import static org.junit.Assert.*; @@ -11,7 +12,7 @@ public void builder_straightLine(){ Curve curve = Curve.builder() .anchorPoint(0,0) .anchorPoint(1,10) - .end(); + .build(); assertEquals(0, curve.getValue(0f), 0.001); assertEquals(4, curve.getValue(0.4f), 0.001); @@ -27,7 +28,7 @@ public void builder_doubleStraightLine(){ .anchorPoint(0,0) .anchorPoint(0.4f,10) .anchorPoint(1f, 10) - .end(); + .build(); assertEquals(0, curve.getValue(0f), 0.001); assertEquals(5, curve.getValue(0.2f), 0.001); @@ -48,7 +49,7 @@ public void builder_curve(){ .controlPoint1(0.2f, 1) .controlPoint2(0.8f, 0) .anchorPoint(1,1) - .end(); + .build(); //expected values obtained using https://www.desmos.com/calculator/ebdtbxgbq0 @@ -71,4 +72,14 @@ public void builder_curve(){ assertEquals(0.5, curve.getValue(0.5f), 0.001); assertEquals(1, curve.getValue(1), 0.001); } -} \ No newline at end of file + + @Test(expected = IllegalStateException.class) + public void builder_reuseLeadsToException(){ + CurveBuilderAtAnchor builder = Curve.builder() + .anchorPoint(0,0); + + Curve legalUse = builder.build(); + Curve illegalReuse = builder.build(); + } + +} From 5a65fbaa0b99cdb1332fb10ca43badb767bb49e2 Mon Sep 17 00:00:00 2001 From: Richard Tingle <6330028+richardTingle@users.noreply.github.com> Date: Sat, 18 Dec 2021 17:00:04 +0000 Subject: [PATCH 6/8] #6 Clean up the curve builder javadocs --- .../valuetypes/curvebuilder/CurveBuilderAtAnchor.java | 2 +- .../curvebuilder/CurveBuilderAtControlPoint1.java | 6 +++--- .../curvebuilder/CurveBuilderAtControlPoint2.java | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java index 6cb3144..f53053e 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtAnchor.java @@ -56,7 +56,7 @@ public CurveBuilderAtAnchor anchorPoint(float x, float y){ */ public CurveBuilderAtAnchor anchorPoint(Vector2f nextAnchor ){ //no checkReuse() as the call to controlPoint1 will do that - //simulate a straight line using a Bézier curve + //simulate a straight line using a Bézier-like curve Vector2f midOne = currentAnchor.mult(2f/3).add(nextAnchor.mult(1f/3)); Vector2f midTwo = currentAnchor.mult(1f/3).add(nextAnchor.mult(2f/3)); return controlPoint1(midOne).controlPoint2(midTwo).anchorPoint(nextAnchor); diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java index 741f192..9afa29a 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint1.java @@ -13,9 +13,9 @@ public CurveBuilderAtControlPoint1(Curve curveBeingBuilt, Vector2f controlPointI } /** - * Adds a point that the curve will attempt to move towards but may not actually touch. + * Adds a point that the curve will attempt to move towards (but may not actually touch). * - * The 2 control points are used to define a cubic Bézier curve between 2 anchors + * The 2 control points are used to define a cubic Bézier-like curve between 2 anchors * @param x the control point's x * @param y the control point's y * @return a CurveBuilderAtControlPoint1 a part of the curve builder system @@ -27,7 +27,7 @@ public CurveBuilderAtControlPoint2 controlPoint2( float x, float y ){ /** * Adds a point that the curve will attempt to move towards (but may not actually touch). * - * The 2 control points are used to define a cubic Bézier curve between 2 anchors + * The 2 control points are used to define a cubic Bézier-like curve between 2 anchors * @param nextControlPoint the control point * @return a CurveBuilderAtControlPoint1 a part of the curve builder system */ diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java index bd1053f..5caace0 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderAtControlPoint2.java @@ -16,7 +16,7 @@ public CurveBuilderAtControlPoint2(Curve curveBeingBuilt, Vector2f inControlPoin /** * Adds a point that the curve go through. * - * Anchors are the starts and ends of cubic Bézier curves + * Anchors are the starts and ends of cubic Bézier-like curves * @param x the anchor point's x * @param y the anchor point's y * @return a CurveBuilderAtAnchor a part of the curve builder system @@ -26,9 +26,9 @@ public CurveBuilderAtAnchor anchorPoint(float x, float y){ } /** - * Adds a point that the curve go through. + * Adds a point that the curve will go through. * - * Anchors are the starts and ends of cubic Bézier curves + * Anchors are the starts and ends of cubic Bézier-like curves * @param nextAnchor the anchor point * @return a CurveBuilderAtAnchor a part of the curve builder system */ From e9b8408ee3910920535218f734433d0ff20d72eb Mon Sep 17 00:00:00 2001 From: Richard Tingle <6330028+richardTingle@users.noreply.github.com> Date: Sat, 18 Dec 2021 17:03:04 +0000 Subject: [PATCH 7/8] #6 Update classes to follow the coding standards of particle monkey --- .../curvebuilder/CurveBuilderPiece.java | 12 +- .../epaga/particles/valuetypes/CurveTest.java | 148 +++++++++--------- 2 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderPiece.java b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderPiece.java index 3323106..ff8638c 100644 --- a/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderPiece.java +++ b/src/main/java/com/epaga/particles/valuetypes/curvebuilder/CurveBuilderPiece.java @@ -2,12 +2,12 @@ public class CurveBuilderPiece{ - boolean used = false; + boolean used = false; - protected void checkReuse(){ - if (used){ - throw new IllegalStateException("Curve builders must not be reused (As they actually build a single curve as they go along)"); - } - used = true; + protected void checkReuse(){ + if (used){ + throw new IllegalStateException("Curve builders must not be reused (As they actually build a single curve as they go along)"); } + used = true; + } } diff --git a/src/test/java/com/epaga/particles/valuetypes/CurveTest.java b/src/test/java/com/epaga/particles/valuetypes/CurveTest.java index d8cf4fa..0645133 100644 --- a/src/test/java/com/epaga/particles/valuetypes/CurveTest.java +++ b/src/test/java/com/epaga/particles/valuetypes/CurveTest.java @@ -7,79 +7,79 @@ public class CurveTest{ - @Test - public void builder_straightLine(){ - Curve curve = Curve.builder() - .anchorPoint(0,0) - .anchorPoint(1,10) - .build(); - - assertEquals(0, curve.getValue(0f), 0.001); - assertEquals(4, curve.getValue(0.4f), 0.001); - assertEquals(10, curve.getValue(1f), 0.001); - } - - /** - * Tests that 2 straight lines joined together functions correctly - */ - @Test - public void builder_doubleStraightLine(){ - Curve curve = Curve.builder() - .anchorPoint(0,0) - .anchorPoint(0.4f,10) - .anchorPoint(1f, 10) - .build(); - - assertEquals(0, curve.getValue(0f), 0.001); - assertEquals(5, curve.getValue(0.2f), 0.001); - assertEquals(10, curve.getValue(0.8f), 0.001); - } - - /** - * Tests that a Bézier-like curve functions correctly - * - * (Its not actually a true Bézier curve becuse a Bézier curve can "go backwards" and follows a - * slightly different path - */ - @Test - public void builder_curve(){ - - Curve curve = Curve.builder() - .anchorPoint(0,0) - .controlPoint1(0.2f, 1) - .controlPoint2(0.8f, 0) - .anchorPoint(1,1) - .build(); - - //expected values obtained using https://www.desmos.com/calculator/ebdtbxgbq0 - - assertEquals(0, curve.getValue(0f), 0.001); - - //value obtained as 0.1 along using the following - // along line 1 = 0.9 * 0 + 0.1 * 1 = 0.1 - // along line 2 = 0.9 * 1 + 0.1 * 0 = 0.9 - // along line 3 = 0.9 * 0 + 0.1 * 1 = 0.1 - - //obtain 2 new lines between along line 1 -> along line 2 and along line 2 -> along line 3. Get 0.1 along each one - //along second order 1 = 0.9 * 0.1 + 0.1 * 0.9 = 0.18 - //along second order 2 = 0.9 * 0.9 + 0.1 * 0.1 = 0.82 - - //final result is 0.1 along the line between the second order points - // 0.9 * 0.18 + 0.1 * 0.82 - - assertEquals(0.244, curve.getValue(0.1f), 0.001); - - assertEquals(0.5, curve.getValue(0.5f), 0.001); - assertEquals(1, curve.getValue(1), 0.001); - } - - @Test(expected = IllegalStateException.class) - public void builder_reuseLeadsToException(){ - CurveBuilderAtAnchor builder = Curve.builder() - .anchorPoint(0,0); - - Curve legalUse = builder.build(); - Curve illegalReuse = builder.build(); - } + @Test + public void builder_straightLine(){ + Curve curve = Curve.builder() + .anchorPoint(0,0) + .anchorPoint(1,10) + .build(); + + assertEquals(0, curve.getValue(0f), 0.001); + assertEquals(4, curve.getValue(0.4f), 0.001); + assertEquals(10, curve.getValue(1f), 0.001); + } + + /** + * Tests that 2 straight lines joined together functions correctly + */ + @Test + public void builder_doubleStraightLine(){ + Curve curve = Curve.builder() + .anchorPoint(0,0) + .anchorPoint(0.4f,10) + .anchorPoint(1f, 10) + .build(); + + assertEquals(0, curve.getValue(0f), 0.001); + assertEquals(5, curve.getValue(0.2f), 0.001); + assertEquals(10, curve.getValue(0.8f), 0.001); + } + + /** + * Tests that a Bézier-like curve functions correctly + * + * (Its not actually a true Bézier curve becuse a Bézier curve can "go backwards" and follows a + * slightly different path + */ + @Test + public void builder_curve(){ + + Curve curve = Curve.builder() + .anchorPoint(0,0) + .controlPoint1(0.2f, 1) + .controlPoint2(0.8f, 0) + .anchorPoint(1,1) + .build(); + + //expected values obtained using https://www.desmos.com/calculator/ebdtbxgbq0 + + assertEquals(0, curve.getValue(0f), 0.001); + + //value obtained as 0.1 along using the following + // along line 1 = 0.9 * 0 + 0.1 * 1 = 0.1 + // along line 2 = 0.9 * 1 + 0.1 * 0 = 0.9 + // along line 3 = 0.9 * 0 + 0.1 * 1 = 0.1 + + //obtain 2 new lines between along line 1 -> along line 2 and along line 2 -> along line 3. Get 0.1 along each one + //along second order 1 = 0.9 * 0.1 + 0.1 * 0.9 = 0.18 + //along second order 2 = 0.9 * 0.9 + 0.1 * 0.1 = 0.82 + + //final result is 0.1 along the line between the second order points + // 0.9 * 0.18 + 0.1 * 0.82 + + assertEquals(0.244, curve.getValue(0.1f), 0.001); + + assertEquals(0.5, curve.getValue(0.5f), 0.001); + assertEquals(1, curve.getValue(1), 0.001); + } + + @Test(expected = IllegalStateException.class) + public void builder_reuseLeadsToException(){ + CurveBuilderAtAnchor builder = Curve.builder() + .anchorPoint(0,0); + + Curve legalUse = builder.build(); + Curve illegalReuse = builder.build(); + } } From aa1a45a6344d00c9175dd4a801b24fc6ee993cf1 Mon Sep 17 00:00:00 2001 From: Richard Tingle <6330028+richardTingle@users.noreply.github.com> Date: Tue, 21 Dec 2021 11:29:35 +0000 Subject: [PATCH 8/8] #6 Javadocs can't contain > characters --- src/main/java/com/epaga/particles/valuetypes/Curve.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/epaga/particles/valuetypes/Curve.java b/src/main/java/com/epaga/particles/valuetypes/Curve.java index 0a7787c..cec34bd 100644 --- a/src/main/java/com/epaga/particles/valuetypes/Curve.java +++ b/src/main/java/com/epaga/particles/valuetypes/Curve.java @@ -185,7 +185,7 @@ public boolean equals(Object o) { * .build(); * } * - * This example produces a straight line from (0,0) -> (0.5,0.5), then a cubic Besier curves between (0.5,0.5) -> (1,2) with control points (0.6,0.5) and (0.8,2) + * This example produces a straight line from (0,0) to (0.5,0.5), then a cubic Besier curves between (0.5,0.5) to (1,2) with control points (0.6,0.5) and (0.8,2) * * Note that a builder should not be reused. *