diff options
author | Peter Wu <lekensteyn@gmail.com> | 2014-01-16 21:58:31 +0100 |
---|---|---|
committer | Peter Wu <lekensteyn@gmail.com> | 2014-01-16 21:58:31 +0100 |
commit | 39f1b2e104d1180e0444f0873982d5e71ab0cb8a (patch) | |
tree | c31654df04cd0d199162c5e2ac647ef9587cd26e /src/RaceTrack.java | |
parent | 0c2643015add73a4f34f7856e588baa8cef2bd10 (diff) | |
download | 2iv60-robots-39f1b2e104d1180e0444f0873982d5e71ab0cb8a.tar.gz |
Bézier spline track! (WIP)
Initial implementation of a O race track. WIP, the robots still need to
walk on the track and the dummy track and control points should be
changed.
Diffstat (limited to 'src/RaceTrack.java')
-rw-r--r-- | src/RaceTrack.java | 145 |
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)); + } } |