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] #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); + } + +}