summaryrefslogtreecommitdiff
path: root/src/RaceTrack.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/RaceTrack.java')
-rw-r--r--src/RaceTrack.java145
1 files changed, 139 insertions, 6 deletions
diff --git a/src/RaceTrack.java b/src/RaceTrack.java
index 0dfb194..ea9694a 100644
--- a/src/RaceTrack.java
+++ b/src/RaceTrack.java
@@ -26,7 +26,7 @@ class RaceTrack extends BetterBase {
/**
* Array with control points for the O-track.
*/
- private Vector[] controlPointsOTrack;
+ private final Vector[] controlPointsOTrack;
/**
* Array with control points for the L-track.
@@ -43,30 +43,68 @@ class RaceTrack extends BetterBase {
*/
private Vector[] controlPointsCustomTrack;
private final RobotRace race;
+ /**
+ * Debug option: set to true to show control points.
+ */
+ private static final boolean drawControlPoints = true;
/**
* Constructs the race track, sets up display lists.
*/
public RaceTrack(RobotRace race) {
this.race = race;
+
+ // points are chosen such that the boundaries of a quarter lay
+ // on a straight line (to get second-order continuity).
+ // top #---|#---#
+ // left ^- - - - - - - begin here (top right)
+ // # #
+ // | | (v then continue clock-wise)
+ // | -
+ // # # <- - this point is the last of top-right,
+ // - | and the first of bottom-left
+ // | bottom |
+ // # left right #
+ // #----#|--#
+ controlPointsOTrack = new Vector[] {
+ // top-right
+ new Vector( 0, 15, 1),
+ new Vector( 8, 15, 1),
+
+ new Vector( 15, 8, 1),
+ // bottom-right
+ new Vector( 15, 0, 1),
+ new Vector( 15, -8, 1),
+
+ new Vector( 8, -15, 1),
+ // bottom-left
+ new Vector( 0, -15, 1),
+ new Vector( -8, -15, 1),
+
+ new Vector(-15, -8, 1),
+ // top-left
+ new Vector(-15, 0, 1),
+ new Vector(-15, 8, 1),
+
+ new Vector( -8, 15, 1),
+ };
}
/**
* Draws this track, based on the selected track number.
*/
public void draw(int trackNr) {
-
// The test track is selected
if (0 == trackNr) {
drawTestTrack();
} else if (1 == trackNr) { // The O-track is selected
- // code goes here ...
+ drawTrack(controlPointsOTrack);
} else if (2 == trackNr) { // The L-track is selected
- // code goes here ...
+ drawTrack(controlPointsLTrack);
} else if (3 == trackNr) { // The C-track is selected
- // code goes here ...
+ drawTrack(controlPointsCTrack);
} else if (4 == trackNr) { // The custom track is selected
- // code goes here ...
+ drawTrack(controlPointsOTrack);
}
}
@@ -212,4 +250,99 @@ class RaceTrack extends BetterBase {
point_G = point_H;
}
}
+
+ /**
+ * Draw a closed race track.
+ *
+ * @param pts Control points.
+ */
+ private void drawTrack(Vector[] pts) {
+ if (pts == null) {
+ System.err.println("not implemented points");
+ return;
+ }
+
+ assert pts.length % 3 == 0 : "Multiple of three control points required";
+
+ int number_of_segments = pts.length / 3;
+ // number of "u" units per segment
+ double segment_size = 1.0 / number_of_segments;
+
+ gl.glLineWidth(5);
+ gl.glBegin(GL_LINE_STRIP);
+ for (double i = 0; i <= SEGMENTS; ++i) {
+ double u = i / SEGMENTS;
+ int segment_number = (int) ((i / (SEGMENTS + 1)) / segment_size);
+ int start = 3 * segment_number;
+ double segment_u = u - segment_number * segment_size;
+ // scale the part to 0.0 to 0.1
+ segment_u *= number_of_segments;
+
+ assert segment_u >= 0.0 && segment_u <= 1.0 : "Segment out of bounds";
+ Vector bezierPt = getCubicBezierPnt(segment_u, pts, start);
+ gl.glColor4d(1.0, 0.0, segment_number, .8);
+ glVertex(bezierPt);
+ }
+ gl.glEnd();
+
+ if (drawControlPoints) {
+ // draw control points
+ gl.glPointSize(10);
+ gl.glBegin(GL_POINTS);
+ for (int i = 0; i < pts.length; i++) {
+ double color = ((double) i / 3.0);
+ gl.glColor3d(0.0, color, 1.0);
+ glVertex(pts[i]);
+ }
+ gl.glEnd();
+ }
+ }
+
+ /**
+ * Obtains a cubic Bézier segment from points P0, P1, P2 and P3 for
+ * parameter value t.
+ */
+ public static Vector getCubicBezierPnt(double t, Vector P0, Vector P1,
+ Vector P2, Vector P3) {
+ // the factorials for the Bézier blending functions (Bernstein
+ // polynomials) with n=3 are pre-calculated.
+ // P(u) = (1 - u)^3 . P0 +
+ // 3u (1 - u)^2 . P1 +
+ // 3u^2 (1 - u) . P2 +
+ // u^3 . P3
+ // Implementation note: Vector is instantiated 7 times!
+ return P0.scale( pow(1 - t, 3)) // k = 0
+ .add(P1.scale(3 * t * pow(1 - t, 2))) // k = 1
+ .add(P2.scale(3 * pow(t, 2) * (1 - t))) // k = 2
+ .add(P3.scale( pow(t, 3))); // k = 3
+ }
+
+ /**
+ * Obtains a point on the Bézier curve from points P, starting at index i.
+ */
+ public static Vector getCubicBezierPnt(double t, Vector[] P, int i) {
+ Vector P4 = P[(i + 3) % P.length];
+ return getCubicBezierPnt(t, P[i], P[i + 1], P[i + 2], P4);
+ }
+
+ /**
+ * Evaluate the tangent of a cubic Bézier segment from points P0, P2, P2 and
+ * P3 for parameter value t.
+ */
+ public static Vector getCubicBezierTng(double t, Vector P0, Vector P1,
+ Vector P2, Vector P3) {
+ // The tangent is the derivative of the Bézier curve P(t).
+ // dP(u) / du = 3 (1 - u)^2 . P0 +
+ // (3 (1 - u)^2 + 6u (1 - u)) . P1 +
+ // (6u (1 - u) - 3u^2) . P2 +
+ // 3u^2 . P3
+ // = 3 (1 - u)^2 . P0 +
+ // (3 - 3u^2) . P1 +
+ // (6u - 9u^2) . P2 +
+ // 3u^2 . P3
+ return P0.scale(3 * pow(1 - t, 2))
+ .add(P1.scale(3 - 3 * t * t))
+ .add(P2.scale(6 * t + 9 * t * t))
+ .add(P3.scale(3 * t * t));
+ }
}