fix sort order for incline boundaries

This commit is contained in:
evgenij27 2018-11-14 13:22:20 +02:00
parent 27f42f9020
commit ba77ddf6f6
3 changed files with 245 additions and 67 deletions

View file

@ -35,7 +35,7 @@ public class RouteStatistics {
} }
private abstract static class RouteStatisticComputer { private abstract static class RouteStatisticComputer<E extends Comparable<E>> {
private final List<RouteSegmentResult> route; private final List<RouteSegmentResult> route;
@ -43,13 +43,13 @@ public class RouteStatistics {
this.route = route; this.route = route;
} }
protected Map<String, RouteSegmentAttribute> makePartition(List<RouteSegmentAttribute> routeAttributes) { protected Map<E, RouteSegmentAttribute<E>> makePartition(List<RouteSegmentAttribute<E>> routeAttributes) {
Map<String, RouteSegmentAttribute> partition = new TreeMap<>(); Map<E, RouteSegmentAttribute<E>> partition = new TreeMap<>();
for (RouteSegmentAttribute attribute : routeAttributes) { for (RouteSegmentAttribute<E> attribute : routeAttributes) {
String key = attribute.getAttribute(); E key = attribute.getAttribute();
RouteSegmentAttribute pattr = partition.get(key); RouteSegmentAttribute<E> pattr = partition.get(key);
if (pattr == null) { if (pattr == null) {
pattr = new RouteSegmentAttribute(attribute.getIndex(), attribute.getAttribute(), attribute.getColorAttrName()); pattr = new RouteSegmentAttribute<>(attribute.getIndex(), attribute.getAttribute(), attribute.getColorAttrName());
partition.put(key, pattr); partition.put(key, pattr);
} }
pattr.incrementDistanceBy(attribute.getDistance()); pattr.incrementDistanceBy(attribute.getDistance());
@ -57,7 +57,7 @@ public class RouteStatistics {
return partition; return partition;
} }
private float computeTotalDistance(List<RouteSegmentAttribute> attributes) { private float computeTotalDistance(List<RouteSegmentAttribute<E>> attributes) {
float distance = 0f; float distance = 0f;
for (RouteSegmentAttribute attribute : attributes) { for (RouteSegmentAttribute attribute : attributes) {
distance += attribute.getDistance(); distance += attribute.getDistance();
@ -69,18 +69,18 @@ public class RouteStatistics {
return route; return route;
} }
protected List<RouteSegmentAttribute> processRoute() { protected List<RouteSegmentAttribute<E>> processRoute() {
int index = 0; int index = 0;
List<RouteSegmentAttribute> routes = new ArrayList<>(); List<RouteSegmentAttribute<E>> routes = new ArrayList<>();
String prev = null; E prev = null;
for (RouteSegmentResult segment : getRoute()) { for (RouteSegmentResult segment : getRoute()) {
String current = getAttribute(segment); E current = getAttribute(segment);
if (prev != null && !prev.equals(current)) { if (prev != null && !prev.equals(current)) {
index++; index++;
} }
if (index >= routes.size()) { if (index >= routes.size()) {
String colorAttrName = determineColor(current); String colorAttrName = determineColor(current);
routes.add(new RouteSegmentAttribute(index, current, colorAttrName)); routes.add(new RouteSegmentAttribute<>(index, current, colorAttrName));
} }
RouteSegmentAttribute surface = routes.get(index); RouteSegmentAttribute surface = routes.get(index);
surface.incrementDistanceBy(segment.getDistance()); surface.incrementDistanceBy(segment.getDistance());
@ -89,20 +89,20 @@ public class RouteStatistics {
return routes; return routes;
} }
public Statistics computeStatistic() { public Statistics<E> computeStatistic() {
List<RouteSegmentAttribute> routeAttributes = processRoute(); List<RouteSegmentAttribute<E>> routeAttributes = processRoute();
Map<String, RouteSegmentAttribute> partition = makePartition(routeAttributes); Map<E, RouteSegmentAttribute<E>> partition = makePartition(routeAttributes);
float totalDistance = computeTotalDistance(routeAttributes); float totalDistance = computeTotalDistance(routeAttributes);
return new Statistics(routeAttributes, partition, totalDistance); return new Statistics<>(routeAttributes, partition, totalDistance);
} }
public abstract String getAttribute(RouteSegmentResult segment); public abstract E getAttribute(RouteSegmentResult segment);
public abstract String determineColor(String attribute); public abstract String determineColor(E attribute);
} }
private static class RouteSurfaceStatisticComputer extends RouteStatisticComputer { private static class RouteSurfaceStatisticComputer extends RouteStatisticComputer<String> {
public RouteSurfaceStatisticComputer(List<RouteSegmentResult> route) { public RouteSurfaceStatisticComputer(List<RouteSegmentResult> route) {
super(route); super(route);
@ -129,7 +129,7 @@ public class RouteStatistics {
} }
} }
private static class RouteSmoothnessStatisticComputer extends RouteStatisticComputer { private static class RouteSmoothnessStatisticComputer extends RouteStatisticComputer<String> {
public RouteSmoothnessStatisticComputer(List<RouteSegmentResult> route) { public RouteSmoothnessStatisticComputer(List<RouteSegmentResult> route) {
super(route); super(route);
@ -157,7 +157,7 @@ public class RouteStatistics {
} }
private static class RouteClassStatisticComputer extends RouteStatisticComputer { private static class RouteClassStatisticComputer extends RouteStatisticComputer<String> {
public RouteClassStatisticComputer(List<RouteSegmentResult> route) { public RouteClassStatisticComputer(List<RouteSegmentResult> route) {
super(route); super(route);
@ -185,7 +185,7 @@ public class RouteStatistics {
} }
private static class RouteSteepnessStatisticComputer extends RouteStatisticComputer { private static class RouteSteepnessStatisticComputer extends RouteStatisticComputer<Boundaries> {
private static final String POSITIVE_INCLINE_COLOR_ATTR_NAME = "greenColor"; private static final String POSITIVE_INCLINE_COLOR_ATTR_NAME = "greenColor";
private static final String NEGATIVE_INCLINE_COLOR_ATTR_NAME = "redColor"; private static final String NEGATIVE_INCLINE_COLOR_ATTR_NAME = "redColor";
@ -198,22 +198,20 @@ public class RouteStatistics {
} }
@Override @Override
public List<RouteSegmentAttribute> processRoute() { public List<RouteSegmentAttribute<Boundaries>> processRoute() {
List<RouteSegmentAttribute> routeInclines = new ArrayList<>(); List<RouteSegmentAttribute<Boundaries>> routeInclines = new ArrayList<>();
int index = 0; int index = 0;
String prev = null; Boundaries prev = null;
Incline prevIncline = null; Incline prevIncline = null;
for (Incline incline : inclines) { for (Incline incline : inclines) {
String current = incline.getBoundariesAsString(); Boundaries current = incline.getBoundaries();
if (prev != null && !prev.equals(current)) { if (prev != null && !prev.equals(current)) {
index++; index++;
} }
if (index >= routeInclines.size()) { if (index >= routeInclines.size()) {
String colorAttrName = determineColor(incline); String colorAttrName = determineColor(current);
RouteSegmentAttribute attribute = new RouteSegmentAttribute(index, current, colorAttrName); RouteSegmentAttribute<Boundaries> attribute = new RouteSegmentAttribute<>(index, current, colorAttrName);
if ( if (prevIncline != null) {
//index > 0 &&
prevIncline != null) {
attribute.setInitDistance(prevIncline.getDistance()); attribute.setInitDistance(prevIncline.getDistance());
} }
routeInclines.add(attribute); routeInclines.add(attribute);
@ -227,32 +225,30 @@ public class RouteStatistics {
} }
@Override @Override
public String getAttribute(RouteSegmentResult segment) { public Boundaries getAttribute(RouteSegmentResult segment) {
/*
no-op
*/
return null; return null;
} }
@Override @Override
public String determineColor(String attribute) { public String determineColor(Boundaries attribute) {
return null; return attribute.getLowerBoundary() >= 0 ? POSITIVE_INCLINE_COLOR_ATTR_NAME : NEGATIVE_INCLINE_COLOR_ATTR_NAME;
}
public String determineColor(Incline incline) {
float value = incline.getValue();
return value >= 0 ? POSITIVE_INCLINE_COLOR_ATTR_NAME : NEGATIVE_INCLINE_COLOR_ATTR_NAME;
} }
} }
public static class RouteSegmentAttribute { public static class RouteSegmentAttribute<E> {
private final int index; private final int index;
private final String attribute; private final E attribute;
private final String colorAttrName; private final String colorAttrName;
private float distance; private float distance;
private float initDistance; private float initDistance;
public RouteSegmentAttribute(int index, String attribute, String colorAttrName) { public RouteSegmentAttribute(int index, E attribute, String colorAttrName) {
this.index = index; this.index = index;
this.attribute = attribute; this.attribute = attribute;
this.colorAttrName = colorAttrName; this.colorAttrName = colorAttrName;
@ -262,7 +258,7 @@ public class RouteStatistics {
return index; return index;
} }
public String getAttribute() { public E getAttribute() {
return attribute; return attribute;
} }
@ -317,10 +313,6 @@ public class RouteStatistics {
return distance; return distance;
} }
public String getBoundariesAsString() {
return String.format("%d-%d", Math.round(boundaries.getLowerBoundary()), Math.round(boundaries.getUpperBoundary()));
}
public Boundaries getBoundaries() { public Boundaries getBoundaries() {
return this.boundaries; return this.boundaries;
} }
@ -340,13 +332,13 @@ public class RouteStatistics {
private static final int MAX_INCLINE = 100; private static final int MAX_INCLINE = 100;
private static final int STEP = 4; private static final int STEP = 4;
private static final int NUM; private static final int NUM;
private static final int[] BOUNDARIES; private static final int[] BOUNDARIES_ARRAY;
static { static {
NUM = (int) ((MAX_INCLINE - MIN_INCLINE) / STEP + 1); NUM = ((MAX_INCLINE - MIN_INCLINE) / STEP + 1);
BOUNDARIES = new int[NUM]; BOUNDARIES_ARRAY = new int[NUM];
for (int i = 0; i < NUM; i++) { for (int i = 0; i < NUM; i++) {
BOUNDARIES[i] = MIN_INCLINE + i * STEP; BOUNDARIES_ARRAY[i] = MIN_INCLINE + i * STEP;
} }
} }
@ -366,8 +358,8 @@ public class RouteStatistics {
return new Boundaries(MIN_INCLINE + STEP, MIN_INCLINE); return new Boundaries(MIN_INCLINE + STEP, MIN_INCLINE);
} }
for (int i = 1; i < NUM; i++) { for (int i = 1; i < NUM; i++) {
if (incline >= BOUNDARIES[i - 1] && incline < BOUNDARIES[i]) { if (incline >= BOUNDARIES_ARRAY[i - 1] && incline < BOUNDARIES_ARRAY[i]) {
return new Boundaries(BOUNDARIES[i], BOUNDARIES[i - 1]); return new Boundaries(BOUNDARIES_ARRAY[i], BOUNDARIES_ARRAY[i - 1]);
} }
} }
return null; return null;
@ -403,16 +395,21 @@ public class RouteStatistics {
public int compareTo(Boundaries boundaries) { public int compareTo(Boundaries boundaries) {
return (int) (getLowerBoundary() - boundaries.getLowerBoundary()); return (int) (getLowerBoundary() - boundaries.getLowerBoundary());
} }
@Override
public String toString() {
return String.format("%d-%d", Math.round(getLowerBoundary()), Math.round(getUpperBoundary()));
}
} }
public static class Statistics { public static class Statistics<E> {
private final List<RouteSegmentAttribute> elements; private final List<RouteSegmentAttribute<E>> elements;
private final Map<String, RouteSegmentAttribute> partition; private final Map<E, RouteSegmentAttribute<E>> partition;
private final float totalDistance; private final float totalDistance;
private Statistics(List<RouteSegmentAttribute> elements, private Statistics(List<RouteSegmentAttribute<E>> elements,
Map<String, RouteSegmentAttribute> partition, Map<E, RouteSegmentAttribute<E>> partition,
float totalDistance) { float totalDistance) {
this.elements = elements; this.elements = elements;
this.partition = partition; this.partition = partition;
@ -423,11 +420,11 @@ public class RouteStatistics {
return totalDistance; return totalDistance;
} }
public List<RouteSegmentAttribute> getElements() { public List<RouteSegmentAttribute<E>> getElements() {
return elements; return elements;
} }
public Map<String, RouteSegmentAttribute> getPartition() { public Map<E, RouteSegmentAttribute<E>> getPartition() {
return partition; return partition;
} }
} }

View file

@ -252,6 +252,187 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="?attr/bg_color"
android:paddingTop="4dp"
android:paddingBottom="8dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/route_class_stat_container"
android:gravity="center"
android:layout_gravity="center_horizontal"
/>
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<com.github.mikephil.charting.charts.HorizontalBarChart
android:id="@+id/route_class_stat_chart"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_gravity="center_vertical"/>
<LinearLayout
android:id="@+id/route_class_stat_items"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="?attr/bg_color"
android:paddingTop="4dp"
android:paddingBottom="8dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/route_surface_stat_container"
android:gravity="center"
android:layout_gravity="center_horizontal"/>
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<com.github.mikephil.charting.charts.HorizontalBarChart
android:id="@+id/route_surface_stat_chart"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_gravity="center_vertical"/>
<LinearLayout
android:id="@+id/route_surface_stat_items"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="?attr/bg_color"
android:paddingTop="4dp"
android:paddingBottom="8dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/route_smoothness_stat_container"
android:gravity="center"
android:layout_gravity="center_horizontal"/>
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<com.github.mikephil.charting.charts.HorizontalBarChart
android:id="@+id/route_smoothness_stat_chart"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_gravity="center_vertical"/>
<LinearLayout
android:id="@+id/route_smoothness_stat_items"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="?attr/bg_color"
android:paddingTop="4dp"
android:paddingBottom="8dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/route_steepness_stat_container"
android:gravity="center"
android:layout_gravity="center_horizontal"/>
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<com.github.mikephil.charting.charts.HorizontalBarChart
android:id="@+id/route_steepness_stat_chart"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_gravity="center_vertical"/>
<LinearLayout
android:id="@+id/route_steepness_stat_items"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="?attr/bg_color"
android:paddingTop="4dp"
android:paddingBottom="8dp">
</LinearLayout>
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1dp" android:layout_height="1dp"

View file

@ -256,8 +256,8 @@ public class ShowRouteInfoDialogFragment extends DialogFragment {
return 0; return 0;
} }
private void buildStatisticChart(View view, int chartId, Statistics routeStatistics) { private <E> void buildStatisticChart(View view, int chartId, Statistics<E> routeStatistics) {
List<RouteSegmentAttribute> segments = routeStatistics.getElements(); List<RouteSegmentAttribute<E>> segments = routeStatistics.getElements();
HorizontalBarChart hbc = view.findViewById(chartId); HorizontalBarChart hbc = view.findViewById(chartId);
List<BarEntry> entries = new ArrayList<>(); List<BarEntry> entries = new ArrayList<>();
float[] stacks = new float[segments.size()]; float[] stacks = new float[segments.size()];
@ -299,10 +299,10 @@ public class ShowRouteInfoDialogFragment extends DialogFragment {
hbc.invalidate(); hbc.invalidate();
} }
private void attachLegend(OsmandApplication app, LayoutInflater inflater, ViewGroup container, Statistics routeStatistics) { private <E> void attachLegend(OsmandApplication app, LayoutInflater inflater, ViewGroup container, Statistics<E> routeStatistics) {
Map<String, RouteSegmentAttribute> partition = routeStatistics.getPartition(); Map<E, RouteSegmentAttribute<E>> partition = routeStatistics.getPartition();
for (String key : partition.keySet()) { for (E key : partition.keySet()) {
RouteSegmentAttribute segment = partition.get(key); RouteSegmentAttribute<E> segment = partition.get(key);
View view = inflater.inflate(R.layout.route_info_stat_item, container, false); View view = inflater.inflate(R.layout.route_info_stat_item, container, false);
TextView textView = view.findViewById(R.id.route_stat_item_text); TextView textView = view.findViewById(R.id.route_stat_item_text);
String formattedDistance = OsmAndFormatter.getFormattedDistance(segment.getDistance(), getMyApplication()); String formattedDistance = OsmAndFormatter.getFormattedDistance(segment.getDistance(), getMyApplication());