Terrain.java
package lab.sample.terrain;
import lab.sample.model.Leg;
import lab.sample.model.Mode;
/**
* Slowdown caused by the terrain, averaged over a leg's sub-segments.
*
* <p>Two reasons to exist:
* <ul>
* <li>it is the program's <b>computational core</b> — without it, the application spends
* its time in the JDK's iterators and a profiler shows nothing of the business;</li>
* <li>it is called only for the modes sensitive to terrain: the train follows a track
* whose gradient is negligible, so it skips this whole sub-tree.</li>
* </ul>
*/
public final class Terrain {
/** Number of sub-segments analysed per leg. */
private static final int STEPS = 24;
private Terrain() {}
public static boolean applies(Mode mode) {
return mode != Mode.TRAIN;
}
public static double slowdownFactor(Leg leg, Mode mode) {
double sum = 0;
for (int step = 0; step < STEPS; step++) {
double grade = Elevation.gradePercentAt(leg, step);
sum += penaltyFor(grade, mode);
}
return sum / STEPS;
}
/** A climb costs more than a descent gives back, all the more so under one's own
* muscle power. */
private static double penaltyFor(double gradePercent, Mode mode) {
double sensitivity = switch (mode) {
case BIKE -> 0.09;
case WALK -> 0.05;
case CAR -> 0.01;
case TRAIN -> 0.00;
case PLANE -> 0.00;
};
if (gradePercent > 0) {
return 1.0 + gradePercent * sensitivity;
}
return 1.0 + gradePercent * sensitivity * 0.3; // going down only partly makes up for it
}
}