Value objects distance and speed.

#679
This commit is contained in:
Dennis Guse
2021-04-09 19:59:44 +02:00
parent f2b1d2a386
commit 6f9c788965
47 changed files with 773 additions and 502 deletions
@@ -0,0 +1,116 @@
package de.dennisguse.opentracks.content.data;
import androidx.annotation.NonNull;
import java.util.Objects;
import de.dennisguse.opentracks.util.UnitConversions;
public class Distance {
public static Distance of(double distance_m) {
return new Distance(distance_m);
}
public static Distance of(String distance_m) {
return of(Float.parseFloat(distance_m));
}
public static Distance ofMile(double distance_mile) {
return of(distance_mile * UnitConversions.MI_TO_M);
}
public static Distance invalid() {
return of(Double.NaN);
}
private final double distance_m;
private Distance(double distance_m) {
this.distance_m = distance_m;
}
public Distance plus(@NonNull Distance distance) {
return new Distance(distance_m + distance.distance_m);
}
public Distance multipliedBy(double factor) {
return new Distance(factor * distance_m);
}
public boolean isZero() {
return distance_m == 0;
}
public boolean isInvalid() {
return Double.isNaN(distance_m) || Double.isInfinite(distance_m);
}
public boolean lessThan(@NonNull Distance distance) {
return !greaterThan(distance);
}
public boolean greaterThan(@NonNull Distance distance) {
return distance_m > distance.distance_m;
}
public boolean greaterOrEqualThan(@NonNull Distance distance) {
return distance_m >= distance.distance_m;
}
public double toM() {
return distance_m;
}
public double toKM() {
return distance_m * UnitConversions.M_TO_KM;
}
public double toFT() {
return distance_m * UnitConversions.M_TO_FT;
}
public double toMI() {
return toKM() * UnitConversions.KM_TO_MI;
}
public double to(boolean metricUnit) {
return to(metricUnit ? Unit.KM : Unit.MILES);
}
public double to(Unit unit) {
switch (unit) {
case KM:
return toKM();
case MILES:
return toMI();
default:
throw new RuntimeException("Not implemented");
}
}
public enum Unit {
KM,
MILES
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Distance distance = (Distance) o;
return Double.compare(distance.distance_m, distance_m) == 0;
}
@Override
public int hashCode() {
return Objects.hash(distance_m);
}
@Override
public String toString() {
return "Distance{" +
"distance_m=" + distance_m +
'}';
}
}
@@ -28,12 +28,15 @@ import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import de.dennisguse.opentracks.stats.TrackStatistics;
/**
* NOTE: A marker is indirectly (via it's location) assigned to one {@link TrackPoint} with trackPoint.hasLocation() == true.
*
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
//TODO All data should be final; no default values.
public final class Marker {
private Id id;
@@ -51,7 +54,7 @@ public final class Marker {
private Float bearing;
//TODO It is the distance from the track starting point; rename to something more meaningful
private double length = 0.0;
private Distance length;
private Duration duration;
@Deprecated //TODO Make an URI instead of String
@@ -62,6 +65,7 @@ public final class Marker {
this.time = time;
}
@Deprecated //TODO Marker cannot be created without length AND duration!
public Marker(@Nullable Track.Id trackId, @NonNull TrackPoint trackPoint) {
this.trackId = trackId;
@@ -75,16 +79,19 @@ public final class Marker {
if (trackPoint.hasAccuracy()) this.accuracy = trackPoint.getAccuracy();
if (trackPoint.hasAltitude()) this.altitude_m = trackPoint.getAltitude();
if (trackPoint.hasBearing()) this.bearing = trackPoint.getBearing();
this.length = Distance.of(0); //TODO Not cool!
this.duration = Duration.ofMillis(0); //TODO Not cool!
}
public Marker(String name, String description, String category, String icon, @NonNull Track.Id trackId, double length, @NonNull Duration duration, @NonNull TrackPoint trackPoint, String photoUrl) {
public Marker(String name, String description, String category, String icon, @NonNull Track.Id trackId, @NonNull TrackStatistics statistics, @NonNull TrackPoint trackPoint, String photoUrl) {
this(trackId, trackPoint);
this.name = name;
this.description = description;
this.category = category;
this.icon = icon;
this.length = length;
this.duration = duration;
this.length = statistics.getTotalDistance();
this.duration = statistics.getTotalTime();
this.photoUrl = photoUrl;
}
@@ -218,11 +225,11 @@ public final class Marker {
this.bearing = bearing;
}
public double getLength() {
public Distance getLength() {
return length;
}
public void setLength(double length) {
public void setLength(Distance length) {
this.length = length;
}
@@ -0,0 +1,145 @@
package de.dennisguse.opentracks.content.data;
import java.time.Duration;
import java.util.Objects;
import de.dennisguse.opentracks.util.UnitConversions;
public class Speed {
public static Speed of(Distance distance, Duration duration) {
if (duration.isZero()) {
return zero();
}
return new Speed(distance.toM() / (duration.toMillis() * UnitConversions.MS_TO_S));
}
public static Speed of(double speed_mps) {
return new Speed(speed_mps);
}
public static Speed of(String speed_mps) {
return of(Float.parseFloat(speed_mps));
}
public static Speed invalid() {
return of(Double.NaN);
}
public static Speed zero() {
return of(0.0);
}
public static Speed max(Speed speed1, Speed speed2) {
if (speed1.greaterThan(speed2)) {
return speed1;
}
return speed2;
}
public static Speed absDiff(Speed speed1, Speed speed2) {
//TODO Why Math.abs? Seems to be a leftover.
return Speed.of(Math.abs(speed1.speed_mps - speed2.speed_mps));
}
// Anything faster than that (in meters per second) will be considered moving.
private static final double MAX_NO_MOVEMENT_SPEED = 0.224;
private final double speed_mps;
private Speed(double speed_mps) {
this.speed_mps = speed_mps;
}
public Speed mul(double factor) {
return new Speed(factor * speed_mps);
}
public boolean isZero() {
return speed_mps == 0;
}
public boolean isInvalid() {
return Double.isNaN(speed_mps) || Double.isInfinite(speed_mps);
}
public boolean isMoving() {
return !isInvalid() && speed_mps >= MAX_NO_MOVEMENT_SPEED;
}
public boolean lessThan(Speed speed) {
return !greaterThan(speed);
}
public boolean greaterThan(Speed speed) {
return speed_mps > speed.speed_mps;
}
public boolean greaterOrEqualThan(Speed speed) {
return speed_mps >= speed.speed_mps;
}
public double toMPS() {
return speed_mps;
}
public double toKMH() {
return speed_mps * UnitConversions.MPS_TO_KMH;
}
public double toMPH() {
return toKMH() * UnitConversions.KM_TO_MI;
}
public Duration toPace(boolean metricUnit) {
if (isZero()) {
return Duration.ofSeconds(0);
}
double distance = speed_mps * (metricUnit ? UnitConversions.M_TO_KM : UnitConversions.M_TO_MI);
return Duration.ofSeconds(Math.round(1 / distance));
}
public double to(boolean metricUnit) {
return to(metricUnit ? Unit.KMH : Unit.MPH);
}
public double to(Unit unit) {
switch (unit) {
case KMH:
return toKMH();
case MPH:
return toMPH();
default:
throw new RuntimeException("Not implemented");
}
}
public enum Unit {
KMH,
MPH,
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Speed speed = (Speed) o;
return Double.compare(speed.speed_mps, speed_mps) == 0;
}
@Override
public int hashCode() {
return Objects.hash(speed_mps);
}
@Override
public String toString() {
return "Speed{" +
"speed_mps=" + speed_mps +
'}';
}
}
@@ -45,9 +45,6 @@ public class TrackPoint {
private static final Duration MAX_LOCATION_AGE = Duration.ofMinutes(1);
// Anything faster than that (in meters per second) will be considered moving.
private static final double MAX_NO_MOVEMENT_SPEED = 0.224;
private TrackPoint.Id id;
private Instant time;
@@ -55,9 +52,9 @@ public class TrackPoint {
private Double longitude;
private Float accuracy;
private Double altitude_m;
private Float speed_mps;
private Speed speed;
private Float bearing;
private Float sensorDistance_m;
private Distance sensorDistance_m;
public enum Type {
SEGMENT_START_MANUAL(-2), //Start of a segment due to user interaction (start, resume)
@@ -106,7 +103,7 @@ public class TrackPoint {
this.latitude = location.getLatitude();
this.longitude = location.getLongitude();
this.altitude_m = location.getAltitude();
this.speed_mps = location.getSpeed();
this.speed = Speed.of(location.getSpeed());
this.accuracy = location.getAccuracy();
setTime(Instant.now());
@@ -272,19 +269,19 @@ public class TrackPoint {
}
public boolean hasSpeed() {
return speed_mps != null;
return speed != null;
}
public float getSpeed() {
return speed_mps;
public Speed getSpeed() {
return speed;
}
public void setSpeed(Float speed) {
this.speed_mps = speed;
public void setSpeed(Speed speed) {
this.speed = speed;
}
public boolean isMoving() {
return hasSpeed() && getSpeed() >= MAX_NO_MOVEMENT_SPEED;
return hasSpeed() && getSpeed().isMoving();
}
public boolean hasBearing() {
@@ -311,12 +308,12 @@ public class TrackPoint {
this.accuracy = horizontalAccuracy;
}
public float distanceToPrevious(@NonNull TrackPoint previous) {
public Distance distanceToPrevious(@NonNull TrackPoint previous) {
if (hasSensorDistance()) {
return getSensorDistance();
}
return getLocation().distanceTo(previous.getLocation());
return Distance.of(getLocation().distanceTo(previous.getLocation()));
}
public boolean fulfillsAccuracy(int poorAccuracy) {
@@ -336,11 +333,11 @@ public class TrackPoint {
return sensorDistance_m != null;
}
public Float getSensorDistance() {
public Distance getSensorDistance() {
return sensorDistance_m;
}
public void setSensorDistance(Float distance_m) {
public void setSensorDistance(Distance distance_m) {
this.sensorDistance_m = distance_m;
}