diff --git a/src/itdelatrisu/opsu/objects/curves/Bezier2.java b/src/itdelatrisu/opsu/objects/curves/Bezier2.java index 979ae8a1..fa02b542 100644 --- a/src/itdelatrisu/opsu/objects/curves/Bezier2.java +++ b/src/itdelatrisu/opsu/objects/curves/Bezier2.java @@ -41,14 +41,9 @@ public class Bezier2 extends CurveType{ approxlength += points[i].cpy().sub(points[i + 1]).len(); init(approxlength); -// System.out.println("New Bezier2 "+points.length+" "+approxlength+" "+totalDistance()); } - /** - * Returns the point on the Bezier curve at a value t. - * @param t the t value [0, 1] - * @return the point [x, y] - */ + @Override public Vec2f pointAt(float t) { Vec2f c = new Vec2f(); int n = points.length - 1; diff --git a/src/itdelatrisu/opsu/objects/curves/CatmullCurve.java b/src/itdelatrisu/opsu/objects/curves/CatmullCurve.java index c0b51687..262906f5 100644 --- a/src/itdelatrisu/opsu/objects/curves/CatmullCurve.java +++ b/src/itdelatrisu/opsu/objects/curves/CatmullCurve.java @@ -24,28 +24,39 @@ import itdelatrisu.opsu.OsuHitObject; import org.newdawn.slick.Color; +/** + * Representation of Catmull Curve with equidistant points. + * + * @author fluddokt (https://github.com/fluddokt) + */ public class CatmullCurve extends EqualDistanceMultiCurve{ + /** + * Constructor. + * @param hitObject the associated OsuHitObject + * @param color the color of this curve + */ public CatmullCurve(OsuHitObject hitObject, Color color) { super(hitObject, color); LinkedList catmulls = new LinkedList(); int ncontrolPoints = hitObject.getSliderX().length + 1; - LinkedList points = new LinkedList(); // temporary list of points to separate different curves + // temporary list of points to separate different curves + LinkedList points = new LinkedList(); - //aaa .... needs at least two points - //aabb - //aabc abcc - //aabc abcd bcdd - points.addLast(new Vec2f(getX(0),getY(0))); - for(int i=0;i=4){ + // repeat the first and last points as controls points + // aabb + // aabc abcc + // aabc abcd bcdd + points.addLast(new Vec2f(getX(0), getY(0))); + for (int i = 0; i < ncontrolPoints; i++) { + points.addLast(new Vec2f(getX(i), getY(i))); + if (points.size() >= 4) { catmulls.add(new CentripetalCatmullRom(points.toArray(new Vec2f[0]))); points.removeFirst(); } } - points.addLast(new Vec2f(getX(ncontrolPoints-1),getY(ncontrolPoints-1))); - if(points.size()>=4){ + points.addLast(new Vec2f(getX(ncontrolPoints - 1),getY(ncontrolPoints - 1))); + if (points.size() >= 4) { catmulls.add(new CentripetalCatmullRom(points.toArray(new Vec2f[0]))); } init(catmulls); diff --git a/src/itdelatrisu/opsu/objects/curves/CentripetalCatmullRom.java b/src/itdelatrisu/opsu/objects/curves/CentripetalCatmullRom.java index 743cfcdf..283dab2b 100644 --- a/src/itdelatrisu/opsu/objects/curves/CentripetalCatmullRom.java +++ b/src/itdelatrisu/opsu/objects/curves/CentripetalCatmullRom.java @@ -28,74 +28,59 @@ package itdelatrisu.opsu.objects.curves; */ public class CentripetalCatmullRom extends CurveType{ + /** The time values of the Catmull curve. */ float [] time; + + /** The control points of the Catmull curve. */ Vec2f[] points; + + /** + * Constructor. + * @param hitObject the associated OsuHitObject + * @param color the color of this curve + */ protected CentripetalCatmullRom(Vec2f[] points) { if (points.length != 4) throw new Error("need exactly 4 points"); - + this.points = points; - System.out.println("C"); - for(int i=0;i<4;i++){ - System.out.println(points[i]); - } time = new float[4]; time[0] = 0; float approxLength = 0; - for(int i=1;i<4;i++){ + for (int i = 1; i < 4; i++) { float len = 0; - if(i>0) - len = points[i].cpy().sub(points[i-1]).len(); - if(len<=0) - len+=0.0001f; + if (i > 0) + len = points[i].cpy().sub(points[i - 1]).len(); + if (len <= 0) + len += 0.0001f; approxLength += len; - //time[i] = (float) Math.sqrt(len) + time[i-1];// ^(0.5) + // time[i] = (float) Math.sqrt(len) + time[i-1];// ^(0.5) time[i] = i; - System.out.println("knot:"+i+" "+time[i]); } - init(approxLength/2); + init(approxLength / 2); } - public Vec2f pointAt(float t, int start, int end){ - int ind1 = start; - int ind2 = end; - if(end-start==3){ - ind1 = 1; - ind2 = 2; - } - //System.out.println("ST:"+start+" "+end+" "+ind1+" "+ind2); - float div = (time[ind2] - time[ind1]); - float v1 = (time[ind2] - t)/div; - float v2 = (t - time[ind1])/div; - System.out.println("div"+div+" "+v1+" "+v2); - if(end-start==1) - return points[start].cpy().scale(v1).add(points[end].cpy().scale(v2)); - else - return pointAt(t,start,end-1).scale(v1).add(pointAt(t,start+1,end).scale(v2)); - } - - public Vec2f pointAt(float t){ - t = t * (time[2]-time[1]) + time[1]; - Vec2f A1 = points[0].cpy().scale((time[1]-t)/(time[1]-time[0])).add(points[1].cpy().scale((t-time[0])/(time[1]-time[0]))); - Vec2f A2 = points[1].cpy().scale((time[2]-t)/(time[2]-time[1])).add(points[2].cpy().scale((t-time[1])/(time[2]-time[1]))); - Vec2f A3 = points[2].cpy().scale((time[3]-t)/(time[3]-time[2])).add(points[3].cpy().scale((t-time[2])/(time[3]-time[2]))); - - Vec2f B1 = A1.cpy().scale((time[2]-t)/(time[2]-time[0])).add(A2.cpy().scale((t-time[0])/(time[2]-time[0]))); - Vec2f B2 = A2.cpy().scale((time[3]-t)/(time[3]-time[1])).add(A3.cpy().scale((t-time[1])/(time[3]-time[1]))); - - Vec2f C = B1.cpy().scale((time[2]-t)/(time[2]-time[1])).add(B2.cpy().scale((t-time[1])/(time[2]-time[1]))); + + @Override + public Vec2f pointAt(float t){ + t = t * (time[2] - time[1]) + time[1]; + + Vec2f A1 = points[0].cpy().scale((time[1] - t) / (time[1] - time[0])) + .add(points[1].cpy().scale((t - time[0]) / (time[1] - time[0]))); + Vec2f A2 = points[1].cpy().scale((time[2] - t) / (time[2] - time[1])) + .add(points[2].cpy().scale((t - time[1]) / (time[2] - time[1]))); + Vec2f A3 = points[2].cpy().scale((time[3] - t) / (time[3] - time[2])) + .add(points[3].cpy().scale((t - time[2]) / (time[3] - time[2]))); + + Vec2f B1 = A1.cpy().scale((time[2] - t) / (time[2] - time[0])) + .add(A2.cpy().scale((t - time[0]) / (time[2] - time[0]))); + Vec2f B2 = A2.cpy().scale((time[3] - t) / (time[3] - time[1])) + .add(A3.cpy().scale((t - time[1]) / (time[3] - time[1]))); + + Vec2f C = B1.cpy().scale((time[2] - t) / (time[2] - time[1])) + .add(B2.cpy().scale((t - time[1]) / (time[2] - time[1]))); return C; } - public String toString(){ - String t = "CATMULLROM"; - for(Vec2f p: points){ - t+=p; - } - - t+=pointAt(0); - t+=pointAt(1); - - return t; - } + } diff --git a/src/itdelatrisu/opsu/objects/curves/CircumscribedCircle.java b/src/itdelatrisu/opsu/objects/curves/CircumscribedCircle.java index 5b09cccb..0e334634 100644 --- a/src/itdelatrisu/opsu/objects/curves/CircumscribedCircle.java +++ b/src/itdelatrisu/opsu/objects/curves/CircumscribedCircle.java @@ -19,12 +19,9 @@ package itdelatrisu.opsu.objects.curves; import itdelatrisu.opsu.ErrorHandler; -import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.OsuHitObject; -import itdelatrisu.opsu.Utils; import org.newdawn.slick.Color; -import org.newdawn.slick.Image; /** * Representation of a curve along a Circumscribed Circle of three points. @@ -53,9 +50,6 @@ public class CircumscribedCircle extends Curve { /** The start and end angles for drawing. */ private float drawStartAngle, drawEndAngle; - /** The number of steps in the curve to draw. */ - private float step; - /** * Constructor. * @param hitObject the associated OsuHitObject @@ -64,7 +58,6 @@ public class CircumscribedCircle extends Curve { public CircumscribedCircle(OsuHitObject hitObject, Color color) { super(hitObject, color); - // construct the three points this.start = new Vec2f(getX(0), getY(0)); this.mid = new Vec2f(getX(1), getY(1)); @@ -121,7 +114,7 @@ public class CircumscribedCircle extends Curve { this.drawStartAngle = (float) ((startAng + (startAng > endAng ? -HALF_PI : HALF_PI)) * 180 / Math.PI); // calculate points - this.step = hitObject.getPixelLength() / CURVE_POINTS_SEPERATION; + float step = hitObject.getPixelLength() / CURVE_POINTS_SEPERATION; curve = new Vec2f[(int) step + 1]; for (int i = 0; i < curve.length; i++) { float[] xy = pointAt(i / step); diff --git a/src/itdelatrisu/opsu/objects/curves/Curve.java b/src/itdelatrisu/opsu/objects/curves/Curve.java index 59374a14..354c0135 100644 --- a/src/itdelatrisu/opsu/objects/curves/Curve.java +++ b/src/itdelatrisu/opsu/objects/curves/Curve.java @@ -32,7 +32,9 @@ import org.newdawn.slick.Image; */ public abstract class Curve { - protected static float CURVE_POINTS_SEPERATION = 50; + /** Points generated along the curve should be spaced this much apart*/ + protected static float CURVE_POINTS_SEPERATION = 5; + /** The associated OsuHitObject. */ protected OsuHitObject hitObject; @@ -56,7 +58,6 @@ public abstract class Curve { this.y = hitObject.getScaledY(); this.sliderX = hitObject.getScaledSliderX(); this.sliderY = hitObject.getScaledSliderY(); - CURVE_POINTS_SEPERATION = 5; } /** @@ -71,8 +72,7 @@ public abstract class Curve { * @param color the color filter */ public void draw(Color color) { - if ( curve == null){ - System.out.println("draw curve"+this); + if (curve == null){ return; } Image hitCircle = GameImage.HITCIRCLE.getImage(); diff --git a/src/itdelatrisu/opsu/objects/curves/CurveType.java b/src/itdelatrisu/opsu/objects/curves/CurveType.java index e41037b6..b1986ac1 100644 --- a/src/itdelatrisu/opsu/objects/curves/CurveType.java +++ b/src/itdelatrisu/opsu/objects/curves/CurveType.java @@ -37,13 +37,23 @@ public abstract class CurveType { /** The total distances of this Bezier. */ private float totalDistance; + /** + * Returns the point on the curve at a value t. + * @param t the t value [0, 1] + * @return the point [x, y] + */ public abstract Vec2f pointAt(float t); - public void init(float approxlength){ + /** + * Initialize the curve points and distance + * Must be called by inherited classes + * + * @param approxlength an approximate length of the curve + */ + public void init(float approxlength) { // subdivide the curve this.ncurve = (int) (approxlength / 4) + 1; this.curve = new Vec2f[ncurve]; - System.out.println(approxlength+" "+ncurve); for (int i = 0; i < ncurve; i++) curve[i] = pointAt(i / (float) (ncurve - 1)); @@ -53,13 +63,12 @@ public abstract class CurveType { for (int i = 0; i < ncurve; i++) { curveDis[i] = (i == 0) ? 0 : curve[i].cpy().sub(curve[i - 1]).len(); totalDistance += curveDis[i]; - System.out.println("curvedis:"+curveDis[i]); } } /** * Returns the points along the curve of the Bezier curve. */ - public Vec2f[] getCurve() { return curve; } + public Vec2f[] getCurvePoint() { return curve; } /** * Returns the distances between a point of the curve and the last point. diff --git a/src/itdelatrisu/opsu/objects/curves/EqualDistanceMultiCurve.java b/src/itdelatrisu/opsu/objects/curves/EqualDistanceMultiCurve.java index f3dc8bc4..f1959ffb 100644 --- a/src/itdelatrisu/opsu/objects/curves/EqualDistanceMultiCurve.java +++ b/src/itdelatrisu/opsu/objects/curves/EqualDistanceMultiCurve.java @@ -26,7 +26,7 @@ import java.util.LinkedList; import org.newdawn.slick.Color; /** - * Representation of a Bezier curve with equidistant points. + * Representation of multiple curve with equidistant points. * http://pomax.github.io/bezierinfo/#tracing * * @author fluddokt (https://github.com/fluddokt) @@ -48,22 +48,25 @@ public abstract class EqualDistanceMultiCurve extends Curve { } - public void init(LinkedList beziers){ - for(CurveType ct : beziers){ - System.out.println("CT:"+ct); - } + /** + * Initialize the curve points with equal distance + * Must be called by inherited classes + * + * @param curvesList a list of curves to join + */ + public void init(LinkedList curvesList){ // now try to creates points the are equidistant to each other this.ncurve = (int) (hitObject.getPixelLength() / CURVE_POINTS_SEPERATION); this.curve = new Vec2f[ncurve + 1]; float distanceAt = 0; - Iterator iter = beziers.iterator(); + Iterator iter = curvesList.iterator(); int curPoint = 0; - CurveType curBezier = iter.next(); - Vec2f lastCurve = curBezier.getCurve()[0]; + CurveType curCurve = iter.next(); + Vec2f lastCurve = curCurve.getCurvePoint()[0]; float lastDistanceAt = 0; - // length of Bezier should equal pixel length (in 640x480) + // length of Curve should equal pixel length (in 640x480) float pixelLength = hitObject.getPixelLength() * OsuHitObject.getXMultiplier(); // for each distance, try to get in between the two points that are between it @@ -71,15 +74,15 @@ public abstract class EqualDistanceMultiCurve extends Curve { int prefDistance = (int) (i * pixelLength / ncurve); while (distanceAt < prefDistance) { lastDistanceAt = distanceAt; - lastCurve = curBezier.getCurve()[curPoint]; - distanceAt += curBezier.getCurveDistances()[curPoint++]; + lastCurve = curCurve.getCurvePoint()[curPoint]; + distanceAt += curCurve.getCurveDistances()[curPoint++]; - if (curPoint >= curBezier.getCurvesCount()) { + if (curPoint >= curCurve.getCurvesCount()) { if (iter.hasNext()) { - curBezier = iter.next(); + curCurve = iter.next(); curPoint = 0; } else { - curPoint = curBezier.getCurvesCount() - 1; + curPoint = curCurve.getCurvesCount() - 1; if (lastDistanceAt == distanceAt) { // out of points even though the preferred distance hasn't been reached break; @@ -87,8 +90,7 @@ public abstract class EqualDistanceMultiCurve extends Curve { } } } - System.out.println("prefDis:"+prefDistance+" "+distanceAt+" "+lastDistanceAt); - Vec2f thisCurve = curBezier.getCurve()[curPoint]; + Vec2f thisCurve = curCurve.getCurvePoint()[curPoint]; // interpolate the point between the two closest distances if (distanceAt - lastDistanceAt > 1) { diff --git a/src/itdelatrisu/opsu/objects/curves/LinearBezier.java b/src/itdelatrisu/opsu/objects/curves/LinearBezier.java index cb919699..5d2e7a5c 100644 --- a/src/itdelatrisu/opsu/objects/curves/LinearBezier.java +++ b/src/itdelatrisu/opsu/objects/curves/LinearBezier.java @@ -24,7 +24,7 @@ import java.util.LinkedList; import org.newdawn.slick.Color; /** - * Representation of a Bezier curve with equidistant points. + * Representation of Bezier curve with equidistant points. * http://pomax.github.io/bezierinfo/#tracing * * @author fluddokt (https://github.com/fluddokt) @@ -40,9 +40,12 @@ public class LinearBezier extends EqualDistanceMultiCurve { super(hitObject, color); LinkedList beziers = new LinkedList(); + + // Beziers: splits points into different Beziers if has the same points (red points) // a b c - c d - d e f g + // Lines: generate a new curve for each sequential pair // ab bc cd de ef fg - // splits points into different Beziers if has the same points (red points) + int controlPoints = hitObject.getSliderX().length + 1; LinkedList points = new LinkedList(); // temporary list of points to separate different Bezier curves Vec2f lastPoi = null; diff --git a/src/itdelatrisu/opsu/objects/curves/Vec2f.java b/src/itdelatrisu/opsu/objects/curves/Vec2f.java index 7f1cd527..b857ad33 100644 --- a/src/itdelatrisu/opsu/objects/curves/Vec2f.java +++ b/src/itdelatrisu/opsu/objects/curves/Vec2f.java @@ -49,12 +49,22 @@ public class Vec2f { return new Vec2f((x + o.x) / 2, (y + o.y) / 2); } + /** + * Scales the vector. + * @param s scaler to scale by + * @return itself (for chaining) + */ public Vec2f scale(float s) { x *= s; y *= s; return this; } + /** + * Adds a vector to this vector. + * @param o the other vector + * @return itself (for chaining) + */ public Vec2f add(Vec2f o) { x += o.x; y += o.y; diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 728f72f7..cede90d4 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -1043,7 +1043,7 @@ public class Game extends BasicGameState { // reset game data resetGameData(); - // load the first timingPoint + // load the first timingPoint for stacking timingPointIndex = 0; beatLengthBase = beatLength = 1; if (!osu.timingPoints.isEmpty()) {