move enums to top level, fix errors in incline stats calculation

This commit is contained in:
evgenij27 2018-11-02 18:33:33 +02:00
parent e8beeb512e
commit 8a473250b6
5 changed files with 267 additions and 167 deletions

View file

@ -0,0 +1,27 @@
package net.osmand.router;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
public enum RoadClass {
MOTORWAY("motorway", "motorway_link"),
STATE_ROAD("trunk", "trunk_link", "primary", "primary_link"),
ROAD("secondary", "secondary_link", "tertiary", "tertiary_link", "unclassified"),
STREET("residential", "living_street"),
SERVICE("service"),
TRACK("track", "road"),
FOOTWAY("footway"),
PATH("path"),
CYCLE_WAY("cycleway");
final Set<String> roadClasses = new TreeSet<>();
RoadClass(String... classes) {
roadClasses.addAll(Arrays.asList(classes));
}
boolean contains(String roadClass) {
return roadClasses.contains(roadClass);
}
}

View file

@ -0,0 +1,40 @@
package net.osmand.router;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
public enum RoadSurface {
PAVED("paved"),
UNPAVED("unpaved"),
ASPHALT("asphalt"),
CONCRETE("concrete"),
COMPACTED("compacted"),
GRAVEL("gravel"),
FINE_GRAVEL("fine_gravel"),
PAVING_STONES("paving_stones"),
SETT("sett"),
COBBLESTONE("cobblestone"),
PEBBLESTONE("pebblestone"),
STONE("stone"),
METAL("metal"),
GROUND("ground", "mud"),
WOOD("wood"),
GRASS_PAVER("grass_paver"),
GRASS("grass"),
SAND("sand"),
SALT("salt"),
SNOW("snow"),
ICE("ice"),
CLAY("clay");
final Set<String> surfaces = new TreeSet<>();
RoadSurface(String... surfaces) {
this.surfaces.addAll(Arrays.asList(surfaces));
}
boolean contains(String surface) {
return surfaces.contains(surface);
}
}

View file

@ -2,6 +2,7 @@ package net.osmand.router;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -43,19 +44,28 @@ public class RouteSegmentResult {
int st = Math.min(startPointIndex, endPointIndex); int st = Math.min(startPointIndex, endPointIndex);
int end = Math.max(startPointIndex, endPointIndex); int end = Math.max(startPointIndex, endPointIndex);
float[] res = new float[(end - st + 1) * 2]; float[] res = new float[(end - st + 1) * 2];
for (int k = 0; k < res.length / 2; k++) { if (reverse) {
int ind = reverse ? (2 * (end - k)) : (2 * (k + st)); for (int k = 1; k <= res.length / 2; k++) {
if (k == 0) { int ind = (2 * (end--));
res[2 * k] = 0; if (ind < pf.length && k < res.length / 2) {
} else {
if(ind < pf.length) {
res[2 * k] = pf[ind]; res[2 * k] = pf[ind];
} }
if (ind < pf.length) {
res[2 * (k - 1) + 1] = pf[ind + 1];
} }
if(ind < pf.length) { }
} else {
for (int k = 0; k < res.length / 2; k++) {
int ind = (2 * (st + k));
if (k > 0 && ind < pf.length) {
res[2 * k] = pf[ind];
}
if (ind < pf.length) {
res[2 * k + 1] = pf[ind + 1]; res[2 * k + 1] = pf[ind + 1];
} }
} }
}
return res; return res;
} }

View file

@ -0,0 +1,13 @@
package net.osmand.router;
import java.util.List;
import java.util.Map;
public interface RouteStatistic {
float getTotalDistance();
List<RouteStatistics.RouteSegmentAttribute> getElements();
Map<String, RouteStatistics.RouteSegmentAttribute> getPartition();
}

View file

@ -6,47 +6,34 @@ public class RouteStatistics {
private static final String UNDEFINED = "undefined"; private static final String UNDEFINED = "undefined";
private final RouteStatisticComputer routeSurfaceStatisticComputer; private final List<RouteSegmentResult> route;
private final RouteStatisticComputer routeSmoothnessStatisticComputer;
private final RouteStatisticComputer routeClassStatisticComputer;
private final RouteStatisticComputer routeSteepnessStatisticComputer;
private RouteStatistics(List<RouteSegmentResult> route) {
private RouteStatistics(RouteStatisticComputer routeSurfaceStatisticComputer, this.route = route;
RouteStatisticComputer routeSmoothnessStatisticComputer,
RouteStatisticComputer routeClassStatisticComputer,
RouteStatisticComputer routeSteepnessStatisticComputer) {
this.routeSurfaceStatisticComputer = routeSurfaceStatisticComputer;
this.routeSmoothnessStatisticComputer = routeSmoothnessStatisticComputer;
this.routeClassStatisticComputer = routeClassStatisticComputer;
this.routeSteepnessStatisticComputer = routeSteepnessStatisticComputer;
} }
public static RouteStatistics newRouteStatistic(List<RouteSegmentResult> route) { public static RouteStatistics newRouteStatistic(List<RouteSegmentResult> route) {
RouteStatisticComputer routeSurfaceStatisticComputer = new RouteSegmentSurfaceStatisticComputer(route); return new RouteStatistics(route);
RouteStatisticComputer routeSmoothnessStatisticComputer = new RouteSegmentSmoothnessStatisticComputer(route);
RouteStatisticComputer routeClassStatisticComputer = new RouteSegmentClassStatisticComputer(route);
RouteStatisticComputer routeSteepnessStatisticComputer = new RouteSegmentSteepnessStatisticComputer(route);
return new RouteStatistics(routeSurfaceStatisticComputer,
routeSmoothnessStatisticComputer,
routeClassStatisticComputer,
routeSteepnessStatisticComputer);
} }
public List<RouteSegmentAttribute> getRouteSurfaceStatistic() { public RouteStatistic getRouteSurfaceStatistic() {
return routeSurfaceStatisticComputer.computeStatistic(); RouteStatisticComputer statisticComputer = new RouteSurfaceStatisticComputer(route);
return statisticComputer.computeStatistic();
} }
public List<RouteSegmentAttribute> getRouteSmoothnessStatistic() { public RouteStatistic getRouteSmoothnessStatistic() {
return routeSmoothnessStatisticComputer.computeStatistic(); RouteStatisticComputer statisticComputer = new RouteSmoothnessStatisticComputer(route);
return statisticComputer.computeStatistic();
} }
public List<RouteSegmentAttribute> getRouteClassStatistic() { public RouteStatistic getRouteClassStatistic() {
return routeClassStatisticComputer.computeStatistic(); RouteStatisticComputer statisticComputer = new RouteClassStatisticComputer(route);
return statisticComputer.computeStatistic();
} }
public List<RouteSegmentAttribute> getRouteSteepnessStatistic() { public RouteStatistic getRouteSteepnessStatistic() {
return routeSteepnessStatisticComputer.computeStatistic(); RouteStatisticComputer statisticComputer = new RouteSteepnessStatisticComputer(route);
return statisticComputer.computeStatistic();
} }
@ -58,13 +45,35 @@ public class RouteStatistics {
this.route = new ArrayList<>(route); this.route = new ArrayList<>(route);
} }
public List<RouteSegmentResult> getRoute() { private Map<String, RouteSegmentAttribute> makePartition(List<RouteSegmentAttribute> routeAttributes) {
Map<String, RouteSegmentAttribute> partition = new HashMap<>();
for (RouteSegmentAttribute attribute : routeAttributes) {
String key = attribute.getAttribute();
RouteSegmentAttribute pattr = partition.get(key);
if (pattr == null) {
pattr = new RouteSegmentAttribute(attribute.getIndex(), attribute.getAttribute());
partition.put(key, pattr);
}
pattr.incrementDistanceBy(attribute.getDistance());
}
return partition;
}
private float computeTotalDistance(List<RouteSegmentAttribute> attributes) {
float distance = 0f;
for (RouteSegmentAttribute attribute : attributes) {
distance += attribute.getDistance();
}
return distance;
}
protected List<RouteSegmentResult> getRoute() {
return route; return route;
} }
protected List<RouteSegmentAttribute> computeStatistic() { protected List<RouteSegmentAttribute> processRoute() {
int index = 0; int index = 0;
List<RouteSegmentAttribute> routeSurfaces = new ArrayList<>(); List<RouteSegmentAttribute> routes = new ArrayList<>();
String prev = null; String prev = null;
for (RouteSegmentResult segment : getRoute()) { for (RouteSegmentResult segment : getRoute()) {
String current = getAttribute(segment); String current = getAttribute(segment);
@ -74,23 +83,61 @@ public class RouteStatistics {
if (prev != null && !prev.equals(current)) { if (prev != null && !prev.equals(current)) {
index++; index++;
} }
if (index >= routeSurfaces.size()) { if (index >= routes.size()) {
routeSurfaces.add(new RouteSegmentAttribute(index, current)); routes.add(new RouteSegmentAttribute(index, current));
} }
RouteSegmentAttribute surface = routeSurfaces.get(index); RouteSegmentAttribute surface = routes.get(index);
surface.incrementDistanceBy(segment.getDistance()); surface.incrementDistanceBy(segment.getDistance());
prev = current; prev = current;
} }
return routeSurfaces; return routes;
}
public RouteStatistic computeStatistic() {
List<RouteSegmentAttribute> routeAttributes = processRoute();
Map<String, RouteSegmentAttribute> partition = makePartition(routeAttributes);
float totalDistance = computeTotalDistance(routeAttributes);
return new RouteStatisticImpl(routeAttributes, partition, totalDistance);
} }
public abstract String getAttribute(RouteSegmentResult segment); public abstract String getAttribute(RouteSegmentResult segment);
private static class RouteStatisticImpl implements RouteStatistic {
private final List<RouteStatistics.RouteSegmentAttribute> elements;
private final Map<String, RouteStatistics.RouteSegmentAttribute> partition;
private final float totalDistance;
public RouteStatisticImpl(List<RouteSegmentAttribute> elements,
Map<String, RouteSegmentAttribute> partition,
float totalDistance) {
this.elements = elements;
this.partition = partition;
this.totalDistance = totalDistance;
} }
private static class RouteSegmentSurfaceStatisticComputer extends RouteStatisticComputer { @Override
public float getTotalDistance() {
return totalDistance;
}
public RouteSegmentSurfaceStatisticComputer(List<RouteSegmentResult> route) { @Override
public List<RouteSegmentAttribute> getElements() {
return new ArrayList<>(elements);
}
@Override
public Map<String, RouteSegmentAttribute> getPartition() {
return new HashMap<>(partition);
}
}
}
private static class RouteSurfaceStatisticComputer extends RouteStatisticComputer {
public RouteSurfaceStatisticComputer(List<RouteSegmentResult> route) {
super(route); super(route);
} }
@ -109,9 +156,9 @@ public class RouteStatistics {
} }
} }
private static class RouteSegmentSmoothnessStatisticComputer extends RouteStatisticComputer { private static class RouteSmoothnessStatisticComputer extends RouteStatisticComputer {
public RouteSegmentSmoothnessStatisticComputer(List<RouteSegmentResult> route) { public RouteSmoothnessStatisticComputer(List<RouteSegmentResult> route) {
super(route); super(route);
} }
@ -121,9 +168,10 @@ public class RouteStatistics {
} }
} }
private static class RouteSegmentClassStatisticComputer extends RouteStatisticComputer {
public RouteSegmentClassStatisticComputer(List<RouteSegmentResult> route) { private static class RouteClassStatisticComputer extends RouteStatisticComputer {
public RouteClassStatisticComputer(List<RouteSegmentResult> route) {
super(route); super(route);
} }
@ -142,28 +190,31 @@ public class RouteStatistics {
} }
} }
private static class RouteSegmentSteepnessStatisticComputer extends RouteStatisticComputer {
public RouteSegmentSteepnessStatisticComputer(List<RouteSegmentResult> route) { private static class RouteSteepnessStatisticComputer extends RouteStatisticComputer {
public RouteSteepnessStatisticComputer(List<RouteSegmentResult> route) {
super(route); super(route);
} }
@Override private float computeIncline(float prevHeight, float currHeight, float distance) {
public String getAttribute(RouteSegmentResult segment) { float incline = (currHeight - prevHeight) / distance;
return null; if (incline > 30f || incline < -30f) {
throw new IllegalArgumentException("Invalid incline " + incline);
}
if (Float.isInfinite(incline) || Float.isNaN(incline)) {
incline = 0f;
}
return incline * 100;
} }
@Override private List<Incline> computeSegmentInclines() {
public List<RouteSegmentAttribute> computeStatistic() { List<Incline> inclines = new ArrayList<>();
List<RouteSegmentAttribute> routeInclines = new ArrayList<>();
int inclineIndex = 0;
for (RouteSegmentResult segment : getRoute()) { for (RouteSegmentResult segment : getRoute()) {
float[] heights = segment.getHeightValues(); float[] heights = segment.getHeightValues();
if (heights.length == 0) { if (heights.length == 0) {
RouteSegmentIncline routeIncline = new RouteSegmentIncline(inclineIndex++); Incline incline = new Incline(0, segment.getDistance());
routeIncline.mayJoin(0); inclines.add(incline);
routeIncline.incrementDistanceBy(segment.getDistance());
routeInclines.add(routeIncline);
continue; continue;
} }
for (int index = 1; index < heights.length / 2; index++) { for (int index = 1; index < heights.length / 2; index++) {
@ -173,35 +224,42 @@ public class RouteStatistics {
float prevHeight = heights[prevHeightIndex]; float prevHeight = heights[prevHeightIndex];
float currHeight = heights[currHeightIndex]; float currHeight = heights[currHeightIndex];
float distanceBetweenHeights = heights[distanceBetweenHeightsIndex]; float distanceBetweenHeights = heights[distanceBetweenHeightsIndex];
float incline = computeIncline(prevHeight, currHeight, distanceBetweenHeights); float computedIncline = computeIncline(prevHeight, currHeight, distanceBetweenHeights);
Incline incline = new Incline(computedIncline, distanceBetweenHeights);
if (inclineIndex >= routeInclines.size()) { inclines.add(incline);
routeInclines.add(new RouteSegmentIncline(inclineIndex));
}
RouteSegmentIncline routeIncline = (RouteSegmentIncline) routeInclines.get(inclineIndex);
if (routeIncline.mayJoin(incline)) {
routeIncline.addIncline(incline);
routeIncline.incrementDistanceBy(distanceBetweenHeights);
} else {
inclineIndex++;
} }
} }
return inclines;
}
@Override
public List<RouteSegmentAttribute> processRoute() {
List<RouteSegmentAttribute> routeInclines = new ArrayList<>();
int index = 0;
String prev = null;
for (Incline incline : computeSegmentInclines()) {
String current = incline.getBoundariesAsString();
if (prev != null && !prev.equals(current)) {
index++;
}
if (index >= routeInclines.size()) {
routeInclines.add(new RouteSegmentAttribute(index, current));
}
RouteSegmentAttribute routeIncline = routeInclines.get(index);
routeIncline.incrementDistanceBy(incline.getDistance());
prev = current;
} }
return routeInclines; return routeInclines;
} }
private float computeIncline(float prevHeight, float currHeight, float distance) { @Override
float incline = (currHeight - prevHeight) / distance; public String getAttribute(RouteSegmentResult segment) {
if (Float.isInfinite(incline) || Float.isNaN(incline)) { return null;
incline = 0f;
}
return incline * 100;
} }
} }
public static class RouteSegmentAttribute { public static class RouteSegmentAttribute {
private final int index; private final int index;
@ -241,7 +299,9 @@ public class RouteStatistics {
} }
} }
public static class RouteSegmentIncline extends RouteSegmentAttribute {
private static class Incline {
private static final float MAX_INCLINE = 30; private static final float MAX_INCLINE = 30;
private static final float MIN_INCLINE = -30; private static final float MIN_INCLINE = -30;
@ -257,15 +317,6 @@ public class RouteStatistics {
} }
} }
private final List<Float> inclines = new ArrayList<>();
private float upperBoundary;
private float lowerBoundary;
private float middlePoint;
public RouteSegmentIncline(int index) {
super(index,"incline");
}
private void determineBoundaries(float incline) { private void determineBoundaries(float incline) {
for (int pos = 1; pos < INTERVALS.length; pos++) { for (int pos = 1; pos < INTERVALS.length; pos++) {
float lower = INTERVALS[pos - 1]; float lower = INTERVALS[pos - 1];
@ -279,6 +330,22 @@ public class RouteStatistics {
} }
} }
private float upperBoundary;
private float lowerBoundary;
private float middlePoint;
private final float inclineValue;
private final float distance;
public Incline(float inclineValue, float distance) {
this.inclineValue = inclineValue;
this.distance = distance;
determineBoundaries(inclineValue);
if (upperBoundary == lowerBoundary) {
throw new IllegalArgumentException("Invalid boundaries");
}
}
public float getUpperBoundary() { public float getUpperBoundary() {
return upperBoundary; return upperBoundary;
} }
@ -287,88 +354,31 @@ public class RouteStatistics {
return lowerBoundary; return lowerBoundary;
} }
public boolean mayJoin(float incline) {
if (lowerBoundary == upperBoundary) {
determineBoundaries(incline);
}
return incline >= lowerBoundary && incline < upperBoundary;
}
public void addIncline(float incline) {
inclines.add(incline);
}
public float getMiddlePoint() { public float getMiddlePoint() {
return this.middlePoint; return middlePoint;
}
public float getValue() {
return inclineValue;
}
public float getDistance() {
return distance;
}
public String getBoundariesAsString() {
return String.format("%.2f|%.2f", getLowerBoundary(), getUpperBoundary());
} }
@Override @Override
public String toString() { public String toString() {
return "RouteSegmentIncline{" + return "Incline{" +
"index=" + getIndex() + "upperBoundary=" + upperBoundary +
", distance=" + getDistance() +
", inclines=" + inclines +
", upperBoundary=" + upperBoundary +
", lowerBoundary=" + lowerBoundary + ", lowerBoundary=" + lowerBoundary +
", middlePoint=" + middlePoint + ", middlePoint=" + middlePoint +
", incline=" + inclineValue +
", distance=" + distance +
'}'; '}';
} }
} }
public enum RoadSurface {
PAVED("paved"),
UNPAVED("unpaved"),
ASPHALT("asphalt"),
CONCRETE("concrete"),
COMPACTED("compacted"),
GRAVEL("gravel"),
FINE_GRAVEL("fine_gravel"),
PAVING_STONES("paving_stones"),
SETT("sett"),
COBBLESTONE("cobblestone"),
PEBBLESTONE("pebblestone"),
STONE("stone"),
METAL("metal"),
GROUND("ground", "mud"),
WOOD("wood"),
GRASS_PAVER("grass_paver"),
GRASS("grass"),
SAND("sand"),
SALT("salt"),
SNOW("snow"),
ICE("ice"),
CLAY("clay");
final Set<String> surfaces = new TreeSet<>();
RoadSurface(String... surfaces) {
this.surfaces.addAll(Arrays.asList(surfaces));
}
boolean contains(String surface) {
return surfaces.contains(surface);
}
}
public enum RoadClass {
MOTORWAY("motorway", "motorway_link"),
STATE_ROAD("trunk", "trunk_link", "primary", "primary_link"),
ROAD("secondary", "secondary_link", "tertiary", "tertiary_link", "unclassified"),
STREET("residential", "living_street"),
SERVICE("service"),
TRACK("track", "road"),
FOOTWAY("footway"),
PATH("path"),
CYCLE_WAY("cycleway");
final Set<String> roadClasses = new TreeSet<>();
RoadClass(String... classes) {
roadClasses.addAll(Arrays.asList(classes));
}
boolean contains(String roadClass) {
return roadClasses.contains(roadClass);
}
}
} }