Specify whether Curve uses scaled or unscaled coordinates.

Unscaled coordinates will be used in a future commit (hopefully).

Added a normalize() method to Vec2f.

Throw RuntimeExceptions for any Curve initialization errors; the game would crash anyway, and this way the objects can be substituted for DummyObjects for a graceful failure.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-09-02 01:47:15 -05:00
parent 6c956e927f
commit d360b73bf5
7 changed files with 74 additions and 43 deletions

View File

@ -18,13 +18,10 @@
package itdelatrisu.opsu.objects.curves; package itdelatrisu.opsu.objects.curves;
import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.beatmap.HitObject; import itdelatrisu.opsu.beatmap.HitObject;
import java.util.LinkedList; import java.util.LinkedList;
import org.newdawn.slick.SlickException;
/** /**
* Representation of Catmull Curve with equidistant points. * Representation of Catmull Curve with equidistant points.
* *
@ -36,7 +33,16 @@ public class CatmullCurve extends EqualDistanceMultiCurve {
* @param hitObject the associated HitObject * @param hitObject the associated HitObject
*/ */
public CatmullCurve(HitObject hitObject) { public CatmullCurve(HitObject hitObject) {
super(hitObject); this(hitObject, true);
}
/**
* Constructor.
* @param hitObject the associated HitObject
* @param scaled whether to use scaled coordinates
*/
public CatmullCurve(HitObject hitObject, boolean scaled) {
super(hitObject, scaled);
LinkedList<CurveType> catmulls = new LinkedList<CurveType>(); LinkedList<CurveType> catmulls = new LinkedList<CurveType>();
int ncontrolPoints = hitObject.getSliderX().length + 1; int ncontrolPoints = hitObject.getSliderX().length + 1;
LinkedList<Vec2f> points = new LinkedList<Vec2f>(); // temporary list of points to separate different curves LinkedList<Vec2f> points = new LinkedList<Vec2f>(); // temporary list of points to separate different curves
@ -51,24 +57,15 @@ public class CatmullCurve extends EqualDistanceMultiCurve {
for (int i = 0; i < ncontrolPoints; i++) { for (int i = 0; i < ncontrolPoints; i++) {
points.addLast(new Vec2f(getX(i), getY(i))); points.addLast(new Vec2f(getX(i), getY(i)));
if (points.size() >= 4) { if (points.size() >= 4) {
try { catmulls.add(new CentripetalCatmullRom(points.toArray(new Vec2f[0])));
catmulls.add(new CentripetalCatmullRom(points.toArray(new Vec2f[0])));
} catch (SlickException e) {
ErrorHandler.error(null, e, true);
}
points.removeFirst(); points.removeFirst();
} }
} }
if (getX(ncontrolPoints - 1) != getX(ncontrolPoints - 2) || if (getX(ncontrolPoints - 1) != getX(ncontrolPoints - 2) ||
getY(ncontrolPoints - 1) != getY(ncontrolPoints - 2)) getY(ncontrolPoints - 1) != getY(ncontrolPoints - 2))
points.addLast(new Vec2f(getX(ncontrolPoints - 1), getY(ncontrolPoints - 1))); points.addLast(new Vec2f(getX(ncontrolPoints - 1), getY(ncontrolPoints - 1)));
if (points.size() >= 4) { if (points.size() >= 4)
try { catmulls.add(new CentripetalCatmullRom(points.toArray(new Vec2f[0])));
catmulls.add(new CentripetalCatmullRom(points.toArray(new Vec2f[0])));
} catch (SlickException e) {
ErrorHandler.error(null, e, true);
}
}
init(catmulls); init(catmulls);
} }

View File

@ -18,8 +18,6 @@
package itdelatrisu.opsu.objects.curves; package itdelatrisu.opsu.objects.curves;
import org.newdawn.slick.SlickException;
/** /**
* Representation of a Centripetal CatmullRom spline. * Representation of a Centripetal CatmullRom spline.
* (Currently not technically Centripetal CatmullRom.) * (Currently not technically Centripetal CatmullRom.)
@ -37,11 +35,10 @@ public class CentripetalCatmullRom extends CurveType {
/** /**
* Constructor. * Constructor.
* @param points the control points of the curve * @param points the control points of the curve
* @throws SlickException
*/ */
protected CentripetalCatmullRom(Vec2f[] points) throws SlickException { protected CentripetalCatmullRom(Vec2f[] points) {
if (points.length != 4) if (points.length != 4)
throw new SlickException(String.format("Need exactly 4 points to initialize CentripetalCatmullRom, %d provided.", points.length)); throw new RuntimeException(String.format("Need exactly 4 points to initialize CentripetalCatmullRom, %d provided.", points.length));
this.points = points; this.points = points;
time = new float[4]; time = new float[4];

View File

@ -18,7 +18,6 @@
package itdelatrisu.opsu.objects.curves; package itdelatrisu.opsu.objects.curves;
import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.HitObject; import itdelatrisu.opsu.beatmap.HitObject;
@ -54,7 +53,16 @@ public class CircumscribedCircle extends Curve {
* @param hitObject the associated HitObject * @param hitObject the associated HitObject
*/ */
public CircumscribedCircle(HitObject hitObject) { public CircumscribedCircle(HitObject hitObject) {
super(hitObject); this(hitObject, true);
}
/**
* Constructor.
* @param hitObject the associated HitObject
* @param scaled whether to use scaled coordinates
*/
public CircumscribedCircle(HitObject hitObject, boolean scaled) {
super(hitObject, scaled);
// construct the three points // construct the three points
this.start = new Vec2f(getX(0), getY(0)); this.start = new Vec2f(getX(0), getY(0));
@ -68,8 +76,6 @@ public class CircumscribedCircle extends Curve {
Vec2f norb = mid.cpy().sub(end).nor(); Vec2f norb = mid.cpy().sub(end).nor();
this.circleCenter = intersect(mida, nora, midb, norb); this.circleCenter = intersect(mida, nora, midb, norb);
if (circleCenter == null)
return;
// find the angles relative to the circle center // find the angles relative to the circle center
Vec2f startAngPoint = start.cpy().sub(circleCenter); Vec2f startAngPoint = start.cpy().sub(circleCenter);
@ -90,13 +96,8 @@ public class CircumscribedCircle extends Curve {
startAng -= TWO_PI; startAng -= TWO_PI;
else if (Math.abs(startAng - (endAng - TWO_PI)) < TWO_PI && isIn(startAng, midAng, endAng - (TWO_PI))) else if (Math.abs(startAng - (endAng - TWO_PI)) < TWO_PI && isIn(startAng, midAng, endAng - (TWO_PI)))
endAng -= TWO_PI; endAng -= TWO_PI;
else { else
ErrorHandler.error( throw new RuntimeException(String.format("Cannot find angles between midAng (%.3f %.3f %.3f).", startAng, midAng, endAng));
String.format("Cannot find angles between midAng (%.3f %.3f %.3f).",
startAng, midAng, endAng), null, true
);
return;
}
} }
// find an angle with an arc length of pixelLength along this circle // find an angle with an arc length of pixelLength along this circle
@ -149,10 +150,8 @@ public class CircumscribedCircle extends Curve {
//u = ((b.y-a.y)ta.x +(a.x-b.x)ta.y) / (tb.x*ta.y - tb.y*ta.x); //u = ((b.y-a.y)ta.x +(a.x-b.x)ta.y) / (tb.x*ta.y - tb.y*ta.x);
float des = tb.x * ta.y - tb.y * ta.x; float des = tb.x * ta.y - tb.y * ta.x;
if (Math.abs(des) < 0.00001f) { if (Math.abs(des) < 0.00001f)
ErrorHandler.error("Vectors are parallel.", null, true); throw new RuntimeException("Vectors are parallel.");
return null;
}
float u = ((b.y - a.y) * ta.x + (a.x - b.x) * ta.y) / des; float u = ((b.y - a.y) * ta.x + (a.x - b.x) * ta.y) / des;
return b.cpy().add(tb.x * u, tb.y * u); return b.cpy().add(tb.x * u, tb.y * u);
} }

View File

@ -64,13 +64,21 @@ public abstract class Curve {
/** /**
* Constructor. * Constructor.
* @param hitObject the associated HitObject * @param hitObject the associated HitObject
* @param scaled whether to use scaled coordinates
*/ */
protected Curve(HitObject hitObject) { protected Curve(HitObject hitObject, boolean scaled) {
this.hitObject = hitObject; this.hitObject = hitObject;
this.x = hitObject.getScaledX(); if (scaled) {
this.y = hitObject.getScaledY(); this.x = hitObject.getScaledX();
this.sliderX = hitObject.getScaledSliderX(); this.y = hitObject.getScaledY();
this.sliderY = hitObject.getScaledSliderY(); this.sliderX = hitObject.getScaledSliderX();
this.sliderY = hitObject.getScaledSliderY();
} else {
this.x = hitObject.getX();
this.y = hitObject.getY();
this.sliderX = hitObject.getSliderX();
this.sliderY = hitObject.getSliderY();
}
this.renderState = null; this.renderState = null;
} }

View File

@ -42,7 +42,16 @@ public abstract class EqualDistanceMultiCurve extends Curve {
* @param hitObject the associated HitObject * @param hitObject the associated HitObject
*/ */
public EqualDistanceMultiCurve(HitObject hitObject) { public EqualDistanceMultiCurve(HitObject hitObject) {
super(hitObject); this(hitObject, true);
}
/**
* Constructor.
* @param hitObject the associated HitObject
* @param scaled whether to use scaled coordinates
*/
public EqualDistanceMultiCurve(HitObject hitObject, boolean scaled) {
super(hitObject, scaled);
} }
/** /**

View File

@ -35,7 +35,17 @@ public class LinearBezier extends EqualDistanceMultiCurve {
* @param line whether a new curve should be generated for each sequential pair * @param line whether a new curve should be generated for each sequential pair
*/ */
public LinearBezier(HitObject hitObject, boolean line) { public LinearBezier(HitObject hitObject, boolean line) {
super(hitObject); this(hitObject, line, true);
}
/**
* Constructor.
* @param hitObject the associated HitObject
* @param line whether a new curve should be generated for each sequential pair
* @param scaled whether to use scaled coordinates
*/
public LinearBezier(HitObject hitObject, boolean line, boolean scaled) {
super(hitObject, scaled);
LinkedList<CurveType> beziers = new LinkedList<CurveType>(); LinkedList<CurveType> beziers = new LinkedList<CurveType>();

View File

@ -93,6 +93,17 @@ public class Vec2f {
return this; return this;
} }
/**
* Turns this vector into a unit vector.
* @return itself (for chaining)
*/
public Vec2f normalize() {
float len = len();
x /= len;
y /= len;
return this;
}
/** /**
* Returns a copy of this vector. * Returns a copy of this vector.
*/ */