diff --git a/OsmAnd-java/src/main/java/net/osmand/router/RouteStatistics.java b/OsmAnd-java/src/main/java/net/osmand/router/RouteStatistics.java index 4156bbe4ef..e9ebba749f 100644 --- a/OsmAnd-java/src/main/java/net/osmand/router/RouteStatistics.java +++ b/OsmAnd-java/src/main/java/net/osmand/router/RouteStatistics.java @@ -1,593 +1,586 @@ package net.osmand.router; +import net.osmand.render.RenderingRuleSearchRequest; +import net.osmand.render.RenderingRulesStorage; + import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.TreeMap; -import java.util.TreeSet; public class RouteStatistics { - private final List route; + private static final String UNDEFINED_ATTR = "undefined"; - private RouteStatistics(List route) { - this.route = route; - } + private final List route; + private final RenderingRulesStorage currentRenderer; + private final RenderingRulesStorage defaultRenderer; - public static RouteStatistics newRouteStatistic(List route) { - return new RouteStatistics(route); - } + private final boolean nightMode; - public Statistics getRouteSurfaceStatistic() { - RouteStatisticComputer statisticComputer = new RouteSurfaceStatisticComputer(route); - return statisticComputer.computeStatistic(); - } + private RouteStatistics(List route, RenderingRulesStorage currentRenderer, RenderingRulesStorage defaultRenderer, boolean nightMode) { + this.route = route; + this.currentRenderer = currentRenderer; + this.defaultRenderer = defaultRenderer; + this.nightMode = nightMode; + } - public Statistics getRouteSmoothnessStatistic() { - RouteStatisticComputer statisticComputer = new RouteSmoothnessStatisticComputer(route); - return statisticComputer.computeStatistic(); - } + public static RouteStatistics newRouteStatistic(List route, RenderingRulesStorage currentRenderer, RenderingRulesStorage defaultRenderer, boolean nightMode) { + return new RouteStatistics(route, currentRenderer, defaultRenderer, nightMode); + } - public Statistics getRouteClassStatistic() { - RouteStatisticComputer statisticComputer = new RouteClassStatisticComputer(route); - return statisticComputer.computeStatistic(); - } + public Statistics getRouteSurfaceStatistic() { + RouteStatisticComputer statisticComputer = new RouteSurfaceStatisticComputer(route, currentRenderer, defaultRenderer, nightMode); + return statisticComputer.computeStatistic(); + } - public Statistics getRouteSteepnessStatistic(List inclines) { - RouteStatisticComputer statisticComputer = new RouteSteepnessStatisticComputer(inclines); - return statisticComputer.computeStatistic(); - } + public Statistics getRouteSmoothnessStatistic() { + RouteStatisticComputer statisticComputer = new RouteSmoothnessStatisticComputer(route, currentRenderer, defaultRenderer, nightMode); + return statisticComputer.computeStatistic(); + } + + public Statistics getRouteClassStatistic() { + RouteStatisticComputer statisticComputer = new RouteClassStatisticComputer(route, currentRenderer, defaultRenderer, nightMode); + return statisticComputer.computeStatistic(); + } + + public Statistics getRouteSteepnessStatistic(List inclines) { + RouteStatisticComputer statisticComputer = new RouteSteepnessStatisticComputer(inclines, currentRenderer, defaultRenderer, nightMode); + return statisticComputer.computeStatistic(); + } - private abstract static class RouteStatisticComputer> { + private abstract static class RouteStatisticComputer> { - private final List route; + private final List route; + private final StatisticType type; - private final StatisticType type; + protected final RenderingRulesStorage currentRenderer; + protected final RenderingRulesStorage defaultRenderer; + protected final boolean nightMode; - public RouteStatisticComputer(List route, StatisticType type) { - this.route = route; - this.type = type; - } + public RouteStatisticComputer(RenderingRulesStorage currentRenderer, RenderingRulesStorage defaultRenderer, List route, StatisticType type, boolean nightMode) { + this.route = route; + this.currentRenderer = currentRenderer; + this.defaultRenderer = defaultRenderer; + this.type = type; + this.nightMode = nightMode; + } - protected Map> makePartition(List> routeAttributes) { - Map> partition = new TreeMap<>(); - for (RouteSegmentAttribute attribute : routeAttributes) { - E key = attribute.getAttribute(); - RouteSegmentAttribute pattr = partition.get(key); - if (pattr == null) { - pattr = new RouteSegmentAttribute<>(attribute); - partition.put(key, pattr); - } - pattr.incrementDistanceBy(attribute.getDistance()); - } - return partition; - } + protected Map> makePartition(List> routeAttributes) { + Map> partition = new TreeMap<>(); + for (RouteSegmentAttribute attribute : routeAttributes) { + E key = attribute.getAttribute(); + RouteSegmentAttribute pattr = partition.get(key); + if (pattr == null) { + pattr = new RouteSegmentAttribute<>(attribute); + partition.put(key, pattr); + } + pattr.incrementDistanceBy(attribute.getDistance()); + } + return partition; + } - private float computeTotalDistance(List> attributes) { - float distance = 0f; - for (RouteSegmentAttribute attribute : attributes) { - distance += attribute.getDistance(); - } - return distance; - } + private float computeTotalDistance(List> attributes) { + float distance = 0f; + for (RouteSegmentAttribute attribute : attributes) { + distance += attribute.getDistance(); + } + return distance; + } - protected List getRoute() { - return route; - } + protected List getRoute() { + return route; + } - protected List> processRoute() { - int index = 0; - List> routes = new ArrayList<>(); - E prev = null; - for (RouteSegmentResult segment : getRoute()) { - E current = getAttribute(segment); - if (prev != null && !prev.equals(current)) { - index++; - } - if (index >= routes.size()) { - String colorAttrName = getColorAttrName(current); - String colorName = getColorName(current); - routes.add(new RouteSegmentAttribute<>(index, current, colorAttrName, colorName)); - } - RouteSegmentAttribute surface = routes.get(index); - surface.incrementDistanceBy(segment.getDistance()); - prev = current; - } - return routes; - } + protected List> processRoute() { + int index = 0; + List> routes = new ArrayList<>(); + E prev = null; + for (RouteSegmentResult segment : getRoute()) { + E current = getAttribute(segment); + if (prev != null && !prev.equals(current)) { + index++; + } + if (index >= routes.size()) { + int color = getColor(current); + String propertyName = getPropertyName(current); + routes.add(new RouteSegmentAttribute<>(index, current, propertyName, color)); + } + RouteSegmentAttribute surface = routes.get(index); + surface.incrementDistanceBy(segment.getDistance()); + prev = current; + } + return routes; + } - public Statistics computeStatistic() { - List> routeAttributes = processRoute(); - Map> partition = makePartition(routeAttributes); - float totalDistance = computeTotalDistance(routeAttributes); - return new Statistics<>(routeAttributes, partition, totalDistance, type); - } + public Statistics computeStatistic() { + List> routeAttributes = processRoute(); + Map> partition = makePartition(routeAttributes); + float totalDistance = computeTotalDistance(routeAttributes); + return new Statistics<>(routeAttributes, partition, totalDistance, type); + } - public abstract E getAttribute(RouteSegmentResult segment); + public int getColor(E attribute) { + int color = 0; + RenderingRuleSearchRequest currentRequest = new RenderingRuleSearchRequest(currentRenderer); + if (searchRenderingAttribute(currentRenderer, currentRequest, attribute)) { + color = currentRequest.getIntPropertyValue(currentRenderer.PROPS.R_ATTR_COLOR_VALUE); + } else { + RenderingRuleSearchRequest defaultRequest = new RenderingRuleSearchRequest(defaultRenderer); + if (searchRenderingAttribute(defaultRenderer, defaultRequest, attribute)) { + color = defaultRequest.getIntPropertyValue(defaultRenderer.PROPS.R_ATTR_COLOR_VALUE); + } + } + return color; + } - public abstract String getColorAttrName(E attribute); + public abstract E getAttribute(RouteSegmentResult segment); - public abstract String getColorName(E attribute); - } + public abstract String getPropertyName(E attribute); - private static class RouteSurfaceStatisticComputer extends RouteStatisticComputer { + protected abstract boolean searchRenderingAttribute(RenderingRulesStorage rrs, RenderingRuleSearchRequest req, E attribute); + } - public RouteSurfaceStatisticComputer(List route) { - super(route, StatisticType.SURFACE); - } + private static class RouteSurfaceStatisticComputer extends RouteStatisticComputer { - @Override - public RoadSurface getAttribute(RouteSegmentResult segment) { - String segmentSurface = segment.getSurface(); - if (segmentSurface == null) { - return RoadSurface.UNDEFINED; - } - for (RoadSurface roadSurface : RoadSurface.values()) { - if (roadSurface.contains(segmentSurface)) { - return roadSurface; - } - } - return RoadSurface.UNDEFINED; - } + private static final String SURFACE_ATTR = "surface"; + private static final String SURFACE_COLOR_ATTR = "surfaceColor"; - @Override - public String getColorAttrName(RoadSurface attribute) { - return attribute.getColorAttrName(); - } + public RouteSurfaceStatisticComputer(List route, RenderingRulesStorage currentRenderer, RenderingRulesStorage defaultRenderer, boolean nightMode) { + super(currentRenderer, defaultRenderer, route, StatisticType.SURFACE, nightMode); + } - @Override - public String getColorName(RoadSurface attribute) { - return attribute.getColorName(); - } - } + @Override + public String getAttribute(RouteSegmentResult segment) { + String segmentSurface = segment.getSurface(); + if (segmentSurface == null) { + return UNDEFINED_ATTR; + } + RenderingRuleSearchRequest currentRequest = new RenderingRuleSearchRequest(currentRenderer); + if (searchRenderingAttribute(currentRenderer, currentRequest, segmentSurface)) { + return segmentSurface; + } else { + RenderingRuleSearchRequest defaultRequest = new RenderingRuleSearchRequest(defaultRenderer); + if (searchRenderingAttribute(defaultRenderer, defaultRequest, segmentSurface)) { + return segmentSurface; + } + } + return UNDEFINED_ATTR; + } - private static class RouteSmoothnessStatisticComputer extends RouteStatisticComputer { + @Override + public String getPropertyName(String attribute) { + return attribute; + } - public RouteSmoothnessStatisticComputer(List route) { - super(route, StatisticType.SMOOTHNESS); - } + @Override + public boolean searchRenderingAttribute(RenderingRulesStorage rrs, RenderingRuleSearchRequest req, String attribute) { + String additional = SURFACE_ATTR + "=" + attribute; + req.setBooleanFilter(rrs.PROPS.R_NIGHT_MODE, nightMode); + req.setStringFilter(rrs.PROPS.R_ATTR_STRING_VALUE, SURFACE_ATTR + "_" + attribute); + req.setStringFilter(rrs.PROPS.R_ADDITIONAL, additional); + return req.searchRenderingAttribute(SURFACE_COLOR_ATTR); + } + } - @Override - public RoadSmoothness getAttribute(RouteSegmentResult segment) { - String segmentSmoothness = segment.getSmoothness(); - if (segmentSmoothness == null) { - return RoadSmoothness.UNDEFINED; - } - for (RoadSmoothness roadSmoothness : RoadSmoothness.values()) { - if (roadSmoothness.contains(segmentSmoothness)) { - return roadSmoothness; - } - } - return RoadSmoothness.UNDEFINED; - } + private static class RouteSmoothnessStatisticComputer extends RouteStatisticComputer { - @Override - public String getColorAttrName(RoadSmoothness attribute) { - return attribute.getColorAttrName(); - } + private static final String SMOOTHNESS_ATTR = "smoothness"; + private static final String SMOOTHNESS_COLOR_ATTR = "smoothnessColor"; - @Override - public String getColorName(RoadSmoothness attribute) { - return attribute.getColorName(); - } - } + public RouteSmoothnessStatisticComputer(List route, RenderingRulesStorage currentRenderer, RenderingRulesStorage defaultRenderer, boolean nightMode) { + super(currentRenderer, defaultRenderer, route, StatisticType.SMOOTHNESS, nightMode); + } - private static class RouteClassStatisticComputer extends RouteStatisticComputer { + @Override + public String getAttribute(RouteSegmentResult segment) { + String segmentSmoothness = segment.getSmoothness(); + if (segmentSmoothness == null) { + return UNDEFINED_ATTR; + } + RenderingRuleSearchRequest currentRequest = new RenderingRuleSearchRequest(currentRenderer); + if (searchRenderingAttribute(currentRenderer, currentRequest, segmentSmoothness)) { + return segmentSmoothness; + } else { + RenderingRuleSearchRequest defaultRequest = new RenderingRuleSearchRequest(defaultRenderer); + if (searchRenderingAttribute(defaultRenderer, defaultRequest, segmentSmoothness)) { + return segmentSmoothness; + } + } + return UNDEFINED_ATTR; + } - public RouteClassStatisticComputer(List route) { - super(route, StatisticType.CLASS); - } + @Override + public String getPropertyName(String attribute) { + return attribute; + } - @Override - public RoadClass getAttribute(RouteSegmentResult segment) { - String segmentClass = segment.getHighway(); - if (segmentClass == null) { - return RoadClass.UNDEFINED; - } - for (RoadClass roadClass : RoadClass.values()) { - if (roadClass.contains(segmentClass)) { - return roadClass; - } - } - return RoadClass.UNDEFINED; - } + @Override + public boolean searchRenderingAttribute(RenderingRulesStorage rrs, RenderingRuleSearchRequest req, String attribute) { + String additional = SMOOTHNESS_ATTR + "=" + attribute; + req.setBooleanFilter(rrs.PROPS.R_NIGHT_MODE, nightMode); + req.setStringFilter(rrs.PROPS.R_ATTR_STRING_VALUE, SMOOTHNESS_ATTR + "_" + attribute); + req.setStringFilter(rrs.PROPS.R_ADDITIONAL, additional); + return req.searchRenderingAttribute(SMOOTHNESS_COLOR_ATTR); + } + } - @Override - public String getColorAttrName(RoadClass attribute) { - return attribute.getColorAttrName(); - } + private static class RouteClassStatisticComputer extends RouteStatisticComputer { - @Override - public String getColorName(RoadClass attribute) { - return attribute.getColorName(); - } - } + private static final String HIGHWAY_ATTR = "highway"; + private static final String ROAD_CLASS_COLOR_ATTR = "roadClassColor"; - private static class RouteSteepnessStatisticComputer extends RouteStatisticComputer { + public RouteClassStatisticComputer(List route, RenderingRulesStorage currentRenderer, RenderingRulesStorage defaultRenderer, boolean nightMode) { + super(currentRenderer, defaultRenderer, route, StatisticType.CLASS, nightMode); + } - private static final String POSITIVE_INCLINE_COLOR_ATTR_NAME = "greenColor"; - private static final String NEGATIVE_INCLINE_COLOR_ATTR_NAME = "redColor"; + @Override + public String getAttribute(RouteSegmentResult segment) { + String segmentClass = segment.getHighway(); + if (segmentClass == null) { + return UNDEFINED_ATTR; + } + String type = getAttributeType(segmentClass); + return type != null ? type : UNDEFINED_ATTR; + } - private final List inclines; + @Override + public int getColor(String attribute) { + int color = 0; + RenderingRuleSearchRequest currentRequest = new RenderingRuleSearchRequest(currentRenderer); + if (currentRequest.searchRenderingAttribute(attribute)) { + color = currentRequest.getIntPropertyValue(currentRenderer.PROPS.R_ATTR_COLOR_VALUE); + } else { + RenderingRuleSearchRequest defaultRequest = new RenderingRuleSearchRequest(defaultRenderer); + if (defaultRequest.searchRenderingAttribute(attribute)) { + color = defaultRequest.getIntPropertyValue(defaultRenderer.PROPS.R_ATTR_COLOR_VALUE); + } + } + return color; + } - public RouteSteepnessStatisticComputer(List inclines) { - super(null, StatisticType.STEEPNESS); - this.inclines = inclines; - } + @Override + public String getPropertyName(String attribute) { + String type = getAttributeType(attribute); + return type != null ? type : attribute; + } - @Override - public List> processRoute() { - List> routeInclines = new ArrayList<>(); - int index = 0; - Boundaries prev = null; - Incline prevIncline = null; - for (Incline incline : inclines) { - Boundaries current = incline.getBoundaries(); - if (prev != null && !prev.equals(current)) { - index++; - } - if (index >= routeInclines.size()) { - String colorAttrName = getColorAttrName(current); - String colorName = getColorName(current); - RouteSegmentAttribute attribute = new RouteSegmentAttribute<>(index, current, colorAttrName, colorName); - if (prevIncline != null) { - attribute.setInitDistance(prevIncline.getDistance()); - } - routeInclines.add(attribute); - } - RouteSegmentAttribute routeIncline = routeInclines.get(index); - routeIncline.relativeSum(incline.getDistance()); - prev = current; - prevIncline = incline; - } - return routeInclines; - } + @Override + public boolean searchRenderingAttribute(RenderingRulesStorage rrs, RenderingRuleSearchRequest req, String attribute) { + req.setBooleanFilter(rrs.PROPS.R_NIGHT_MODE, nightMode); + req.setStringFilter(rrs.PROPS.R_TAG, HIGHWAY_ATTR); + req.setStringFilter(rrs.PROPS.R_VALUE, attribute); + return req.searchRenderingAttribute(ROAD_CLASS_COLOR_ATTR); + } - @Override - public Boundaries getAttribute(RouteSegmentResult segment) { + private String getAttributeType(String attribute) { + String type = null; + RenderingRuleSearchRequest currentRequest = new RenderingRuleSearchRequest(currentRenderer); + if (searchRenderingAttribute(currentRenderer, currentRequest, attribute)) { + type = currentRequest.getStringPropertyValue(currentRenderer.PROPS.R_ATTR_STRING_VALUE); + if (currentRequest.searchRenderingAttribute(type)) { + type = currentRequest.getStringPropertyValue(currentRenderer.PROPS.R_ATTR_STRING_VALUE); + } + } else { + RenderingRuleSearchRequest defaultRequest = new RenderingRuleSearchRequest(defaultRenderer); + if (searchRenderingAttribute(defaultRenderer, defaultRequest, attribute)) { + type = defaultRequest.getStringPropertyValue(currentRenderer.PROPS.R_ATTR_STRING_VALUE); + if (defaultRequest.searchRenderingAttribute(type)) { + type = defaultRequest.getStringPropertyValue(currentRenderer.PROPS.R_ATTR_STRING_VALUE); + } + } + } + return type; + } + } + + private static class RouteSteepnessStatisticComputer extends RouteStatisticComputer { + + private static final String STEEPNESS_ATTR = "steepness"; + private static final String STEEPNESS_COLOR_ATTR = "steepnessColor"; + + private final List inclines; + + public RouteSteepnessStatisticComputer(List inclines, RenderingRulesStorage currentRenderer, RenderingRulesStorage defaultRenderer, boolean nightMode) { + super(currentRenderer, defaultRenderer, null, StatisticType.STEEPNESS, nightMode); + this.inclines = inclines; + } + + @Override + public List> processRoute() { + List> routeInclines = new ArrayList<>(); + int index = 0; + Boundaries prev = null; + Incline prevIncline = null; + for (Incline incline : inclines) { + Boundaries current = incline.getBoundaries(); + if (prev != null && !prev.equals(current)) { + index++; + } + if (index >= routeInclines.size()) { + String propertyName = getPropertyName(current); + int color = getColor(current); + RouteSegmentAttribute attribute = new RouteSegmentAttribute<>(index, current, propertyName, color); + if (prevIncline != null) { + attribute.setInitDistance(prevIncline.getDistance()); + } + routeInclines.add(attribute); + } + RouteSegmentAttribute routeIncline = routeInclines.get(index); + routeIncline.relativeSum(incline.getDistance()); + prev = current; + prevIncline = incline; + } + return routeInclines; + } + + @Override + public Boundaries getAttribute(RouteSegmentResult segment) { /* no-op */ - return null; - } - - @Override - public String getColorAttrName(Boundaries attribute) { - return attribute.getLowerBoundary() >= 0 ? POSITIVE_INCLINE_COLOR_ATTR_NAME : NEGATIVE_INCLINE_COLOR_ATTR_NAME; - } - - @Override - public String getColorName(Boundaries attribute) { - return null; - } - } - - public static class RouteSegmentAttribute { - - private final int index; - private final E attribute; - private final String colorAttrName; - private final String colorName; - - private float distance; - private float initDistance; - - public RouteSegmentAttribute(int index, E attribute, String colorAttrName, String colorName) { - this.index = index; - this.attribute = attribute; - this.colorAttrName = colorAttrName; - this.colorName = colorName; - } - - public RouteSegmentAttribute(RouteSegmentAttribute segmentAttribute) { - this.index = segmentAttribute.getIndex(); - this.attribute = segmentAttribute.getAttribute(); - this.colorAttrName = segmentAttribute.getColorAttrName(); - this.colorName = segmentAttribute.getColorName(); - } - - public int getIndex() { - return index; - } - - public E getAttribute() { - return attribute; - } - - public float getDistance() { - return distance; - } - - public void setInitDistance(float initDistance) { - this.initDistance = initDistance; - } - - public void incrementDistanceBy(float distance) { - this.distance += distance; - } - - public void relativeSum(float distance) { - this.distance = this.distance + ((distance - this.initDistance) - this.distance); - } - - public String getColorAttrName() { - return colorAttrName; - } - - public String getColorName() { - return colorName; - } - - @Override - public String toString() { - return "RouteSegmentAttribute{" + - "index=" + index + - ", attribute='" + attribute + '\'' + - ", colorAttrName='" + colorAttrName + '\'' + - ", distance=" + distance + - '}'; - } - } - - public static class Incline { - - private float inclineValue; - private final float distance; - private final Boundaries boundaries; - - public Incline(float inclineValue, float distance) { - this.inclineValue = inclineValue; - this.distance = distance; - this.boundaries = Boundaries.newBoundariesFor(inclineValue); - } - - public float getValue() { - return inclineValue; - } - - public float getDistance() { - return distance; - } - - public Boundaries getBoundaries() { - return this.boundaries; - } - - @Override - public String toString() { - return "Incline{" + - ", incline=" + inclineValue + - ", distance=" + distance + - '}'; - } - } - - public static class Boundaries implements Comparable { - - private static final int MIN_INCLINE = -100; - private static final int MAX_INCLINE = 100; - private static final int STEP = 4; - private static final int NUM; - private static final int[] BOUNDARIES_ARRAY; - - static { - NUM = ((MAX_INCLINE - MIN_INCLINE) / STEP + 1); - BOUNDARIES_ARRAY = new int[NUM]; - for (int i = 0; i < NUM; i++) { - BOUNDARIES_ARRAY[i] = MIN_INCLINE + i * STEP; - } - } - - private final float upperBoundary; - private final float lowerBoundary; - - private Boundaries(float upperBoundary, float lowerBoundary) { - this.upperBoundary = upperBoundary; - this.lowerBoundary = lowerBoundary; - } - - public static Boundaries newBoundariesFor(float incline) { - if (incline > MAX_INCLINE) { - return new Boundaries(MAX_INCLINE, MAX_INCLINE - STEP); - } - if (incline < MIN_INCLINE) { - return new Boundaries(MIN_INCLINE + STEP, MIN_INCLINE); - } - for (int i = 1; i < NUM; i++) { - if (incline >= BOUNDARIES_ARRAY[i - 1] && incline < BOUNDARIES_ARRAY[i]) { - return new Boundaries(BOUNDARIES_ARRAY[i], BOUNDARIES_ARRAY[i - 1]); - } - } - return null; - } - - public float getUpperBoundary() { - return upperBoundary; - } - - public float getLowerBoundary() { - return lowerBoundary; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Boundaries that = (Boundaries) o; - - if (Float.compare(that.upperBoundary, upperBoundary) != 0) return false; - return Float.compare(that.lowerBoundary, lowerBoundary) == 0; - } - - @Override - public int hashCode() { - int result = (upperBoundary != +0.0f ? Float.floatToIntBits(upperBoundary) : 0); - result = 31 * result + (lowerBoundary != +0.0f ? Float.floatToIntBits(lowerBoundary) : 0); - return result; - } - - @Override - public int compareTo(Boundaries boundaries) { - return (int) (getLowerBoundary() - boundaries.getLowerBoundary()); - } - - @Override - public String toString() { - return String.format("%d%% - %d%%", Math.round(getLowerBoundary()), Math.round(getUpperBoundary())); - } - } - - public static class Statistics { - - private final List> elements; - private final Map> partition; - private final float totalDistance; - private final StatisticType type; - - private Statistics(List> elements, - Map> partition, - float totalDistance, StatisticType type) { - this.elements = elements; - this.partition = partition; - this.totalDistance = totalDistance; - this.type = type; - } - - public float getTotalDistance() { - return totalDistance; - } - - public List> getElements() { - return elements; - } - - public Map> getPartition() { - return partition; - } - - public StatisticType getStatisticType() { - return type; - } - } - - public enum RoadClass { - MOTORWAY(null, "#ffa200", "motorway", "motorway_link"), - STATE_ROAD(null, "#ffae1d", "trunk", "trunk_link", "primary", "primary_link"), - ROAD(null, "#ffb939", "secondary", "secondary_link", "tertiary", "tertiary_link", "unclassified"), - STREET(null, "#ffc554", "residential", "living_street"), - SERVICE(null, "#ffd070", "service"), - TRACK(null, "#ffdb8a", "track", "road"), - FOOTWAY(null, "#ffe7a7", "footway"), - CYCLE_WAY(null, "#fff4c6", "cycleway"), - PATH(null, "#fffadd", "path"), - UNDEFINED(null, "#DCDBDD", "undefined"); - - final Set roadClasses = new TreeSet<>(); - final String colorAttrName; - final String colorName; - - RoadClass(String colorAttrName, String colorName, String... classes) { - roadClasses.addAll(Arrays.asList(classes)); - this.colorAttrName = colorAttrName; - this.colorName = colorName; + return null; } - boolean contains(String roadClass) { - return roadClasses.contains(roadClass); + @Override + public String getPropertyName(Boundaries attribute) { + int lowerBoundary = Math.round(attribute.getLowerBoundary()); + int upperBoundary = Math.round(attribute.getUpperBoundary()); + if (lowerBoundary > Boundaries.MIN_INCLINE) { + lowerBoundary++; + } + return String.format("%d%% ... %d%%", lowerBoundary, upperBoundary); } - String getColorAttrName() { - return colorAttrName; - } - - public String getColorName() { - return this.colorName; + @Override + public boolean searchRenderingAttribute(RenderingRulesStorage rrs, RenderingRuleSearchRequest req, Boundaries attribute) { + int lowerBoundary = Math.round(attribute.getLowerBoundary()); + int upperBoundary = Math.round(attribute.getUpperBoundary()); + StringBuilder range = new StringBuilder(); + if (lowerBoundary > Boundaries.MIN_INCLINE) { + lowerBoundary++; + } + range.append(lowerBoundary); + range.append(upperBoundary < 0 ? "_" : "-"); + range.append(upperBoundary); + String additional = STEEPNESS_ATTR + "=" + range; + req.setBooleanFilter(rrs.PROPS.R_NIGHT_MODE, nightMode); + req.setStringFilter(rrs.PROPS.R_ADDITIONAL, additional); + return req.searchRenderingAttribute(STEEPNESS_COLOR_ATTR); } } - public enum RoadSurface { - ASPHALT(null, "#6f687e", "asphalt"), - CONCRETE(null, "#a7cdf8", "concrete"), - UNPAVED(null, "#cc9900", "unpaved"), - PAVED(null, "#a7cdf8", "paved"), - COMPACTED(null, "#cbcbe8", "compacted"), - FINE_GRAVEL(null, "#cbcbe8", "fine_gravel"), - PAVING_STONES(null, "#a7cdf8", "paving_stones"), - SETT(null, "#a7cdf8", "sett"), - COBBLESTONE(null, "#a7cdf8", "cobblestone"), - PEBBLESTONE("#a7cdf8", "pebblestone"), - STONE(null, "#a7cdf8", "stone"), - METAL(null, "#a7cdf8", "metal"), - GRASS_PAVER(null, "#a7bef8", "grass_paver"), - WOOD(null, "#a7cdf8", "wood"), - GRAVEL(null, "#cbcbe8", "gravel"), - GROUND(null, "#cc9900", "ground", "mud"), - CLAY(null, "#cc9900", "clay"), - GRASS(null, "#1fbe1f", "grass"), - SAND(null, "#ffd700", "sand"), - SALT(null, "#7eded8", "salt"), - SNOW(null, "#9feeef", "snow"), - ICE(null, "#9feeef", "ice"), - UNDEFINED(null, "#e8e8e8", "undefined"); + public static class RouteSegmentAttribute { - final Set surfaces = new TreeSet<>(); - final String colorAttrName; - final String colorName; + private final int index; + private final E attribute; + private final int color; + private final String propertyName; - RoadSurface(String colorAttrName, String colorName, String... surfaces) { - this.surfaces.addAll(Arrays.asList(surfaces)); - this.colorAttrName = colorAttrName; - this.colorName = colorName; + private float distance; + private float initDistance; + + public RouteSegmentAttribute(int index, E attribute, String propertyName, int color) { + this.index = index; + this.attribute = attribute; + this.propertyName = propertyName; + this.color = color; } - boolean contains(String surface) { - return surfaces.contains(surface); + public RouteSegmentAttribute(RouteSegmentAttribute segmentAttribute) { + this.index = segmentAttribute.getIndex(); + this.attribute = segmentAttribute.getAttribute(); + this.propertyName = segmentAttribute.getPropertyName(); + this.color = segmentAttribute.getColor(); } - public String getColorAttrName() { - return this.colorAttrName; + public int getIndex() { + return index; } - public String getColorName() { - return this.colorName; + public E getAttribute() { + return attribute; + } + + public float getDistance() { + return distance; + } + + public void setInitDistance(float initDistance) { + this.initDistance = initDistance; + } + + public void incrementDistanceBy(float distance) { + this.distance += distance; + } + + public void relativeSum(float distance) { + this.distance = this.distance + ((distance - this.initDistance) - this.distance); + } + + public String getPropertyName() { + return propertyName; + } + + public int getColor() { + return color; + } + + @Override + public String toString() { + return "RouteSegmentAttribute{" + + "index=" + index + + ", attribute='" + attribute + '\'' + + ", color='" + color + '\'' + + ", distance=" + distance + + '}'; } } - public enum RoadSmoothness { - EXCELLENT("orangeColor", null, "excellent"), - GOOD("brownColor", null, "good"), - INTERMEDIATE("darkyellowColor", null, "intermediate"), - BAD("yellowColor", null, "bad"), - VERY_BAD("lightgreenColor", null, "very_bad"), - HORRIBLE("greenColor", null, "horrible"), - VERY_HORRIBLE("lightblueColor", null, "very_horrible"), - IMPASSABLE("blueColor", null, "impassable"), - UNDEFINED("redColor", null, "undefined"); + public static class Incline { - final Set surfaces = new TreeSet<>(); - final String colorAttrName; - final String colorName; + private float inclineValue; + private final float distance; + private final Boundaries boundaries; - RoadSmoothness(String colorAttrName, String colorName, String... surfaces) { - this.surfaces.addAll(Arrays.asList(surfaces)); - this.colorAttrName = colorAttrName; - this.colorName = colorName; + public Incline(float inclineValue, float distance) { + this.inclineValue = inclineValue; + this.distance = distance; + this.boundaries = Boundaries.newBoundariesFor(inclineValue); } - boolean contains(String surface) { - return surfaces.contains(surface); + public float getValue() { + return inclineValue; } - public String getColorAttrName() { - return this.colorAttrName; + public float getDistance() { + return distance; } - public String getColorName() { - return this.colorName; + public Boundaries getBoundaries() { + return this.boundaries; + } + + @Override + public String toString() { + return "Incline{" + + ", incline=" + inclineValue + + ", distance=" + distance + + '}'; + } + } + + public static class Boundaries implements Comparable { + + private static final int MIN_INCLINE = -100; + private static final int MIN_DIVIDED_INCLINE = -20; + private static final int MAX_INCLINE = 100; + private static final int MAX_DIVIDED_INCLINE = 20; + private static final int STEP = 4; + private static final int NUM; + private static final int[] BOUNDARIES_ARRAY; + + static { + NUM = ((MAX_DIVIDED_INCLINE - MIN_DIVIDED_INCLINE) / STEP) + 3; + BOUNDARIES_ARRAY = new int[NUM]; + BOUNDARIES_ARRAY[0] = MIN_INCLINE; + for (int i = 1; i < NUM - 1; i++) { + BOUNDARIES_ARRAY[i] = MIN_DIVIDED_INCLINE + (i - 1) * STEP; + } + BOUNDARIES_ARRAY[NUM - 1] = MAX_INCLINE; + } + + private final float upperBoundary; + private final float lowerBoundary; + + private Boundaries(float upperBoundary, float lowerBoundary) { + this.upperBoundary = upperBoundary; + this.lowerBoundary = lowerBoundary; + } + + public static Boundaries newBoundariesFor(float incline) { + if (incline > MAX_INCLINE) { + return new Boundaries(MAX_INCLINE, MAX_INCLINE - STEP); + } + if (incline < MIN_INCLINE) { + return new Boundaries(MIN_INCLINE + STEP, MIN_INCLINE); + } + for (int i = 1; i < NUM; i++) { + if (incline >= BOUNDARIES_ARRAY[i - 1] && incline < BOUNDARIES_ARRAY[i]) { + return new Boundaries(BOUNDARIES_ARRAY[i], BOUNDARIES_ARRAY[i - 1]); + } + } + return null; + } + + public float getUpperBoundary() { + return upperBoundary; + } + + public float getLowerBoundary() { + return lowerBoundary; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Boundaries that = (Boundaries) o; + + if (Float.compare(that.upperBoundary, upperBoundary) != 0) return false; + return Float.compare(that.lowerBoundary, lowerBoundary) == 0; + } + + @Override + public int hashCode() { + int result = (upperBoundary != +0.0f ? Float.floatToIntBits(upperBoundary) : 0); + result = 31 * result + (lowerBoundary != +0.0f ? Float.floatToIntBits(lowerBoundary) : 0); + return result; + } + + @Override + public int compareTo(Boundaries boundaries) { + return (int) (getLowerBoundary() - boundaries.getLowerBoundary()); + } + + @Override + public String toString() { + return String.format("%d%% ... %d%%", Math.round(getLowerBoundary()), Math.round(getUpperBoundary())); + } + } + + public static class Statistics { + + private final List> elements; + private final Map> partition; + private final float totalDistance; + private final StatisticType type; + + private Statistics(List> elements, + Map> partition, + float totalDistance, StatisticType type) { + this.elements = elements; + this.partition = partition; + this.totalDistance = totalDistance; + this.type = type; + } + + public float getTotalDistance() { + return totalDistance; + } + + public List> getElements() { + return elements; + } + + public Map> getPartition() { + return partition; + } + + public StatisticType getStatisticType() { + return type; } } @@ -597,4 +590,4 @@ public class RouteStatistics { SMOOTHNESS, STEEPNESS } -} +} \ No newline at end of file diff --git a/OsmAnd/res/values-de/strings.xml b/OsmAnd/res/values-de/strings.xml index 51dc3df8ac..b09288aba2 100644 --- a/OsmAnd/res/values-de/strings.xml +++ b/OsmAnd/res/values-de/strings.xml @@ -2922,7 +2922,7 @@ Abgedeckte Fläche: %1$s x %2$s Vorherige Route Tauschen Mehr anzeigen - Tracks auf der Karte + Angezeigte Tracks Tageszeit Von %1$s Schritt für Schritt diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 2d80bbd774..8affa58f36 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,49 @@ Thx - Hardy --> + Unpaved + Sand + Grass + Grass paver + Ground + Dirt + Mud + Ice + Salt + Snow + Asphalt + Paved + Concrete + Sett + Cobblestone + Paving stones + Pebblestone + Stone + Metal + Wood + Gravel + Fine gravel + Compacted + Excellent + Good + Intermediate + Bad + Very bad + Horrible + Very horrible + Impassable + Motorway + State road + Road + Street + Service + Footway + Track + Bridleway + Steps + Path + Cycleway + Undefined • New \'Directions\' screen: Displays Home and Work destination buttons, \'previous route\' shortcut, list of active GPX tracks and markers, search history\n\n • Additional info under \'Route details\': road types, surface, steepness, smoothness\n\n @@ -31,7 +74,7 @@ Board at stop Swap Show more - Tracks on the map + Displayed tracks Show/Hide GPX Tracks Tapping this action button shows or hides selected GPX tracks on the map Hide GPX Tracks diff --git a/OsmAnd/src/net/osmand/plus/activities/ShowRouteInfoDialogFragment.java b/OsmAnd/src/net/osmand/plus/activities/ShowRouteInfoDialogFragment.java index 885996859e..9b3e26351f 100644 --- a/OsmAnd/src/net/osmand/plus/activities/ShowRouteInfoDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/activities/ShowRouteInfoDialogFragment.java @@ -102,6 +102,7 @@ import net.osmand.plus.views.TurnPathHelper; import net.osmand.plus.views.controls.HorizontalSwipeConfirm; import net.osmand.plus.widgets.TextViewEx; import net.osmand.plus.widgets.style.CustomTypefaceSpan; +import net.osmand.render.RenderingRulesStorage; import net.osmand.router.RouteSegmentResult; import net.osmand.router.RouteStatistics; import net.osmand.router.RouteStatistics.Incline; @@ -508,7 +509,9 @@ public class ShowRouteInfoDialogFragment extends BaseOsmAndFragment { elevationDataSet = statisticCard.getElevationDataSet(); List route = routingHelper.getRoute().getOriginalRoute(); if (route != null) { - RouteStatistics routeStatistics = RouteStatistics.newRouteStatistic(route); + RenderingRulesStorage currentRenderer = app.getRendererRegistry().getCurrentSelectedRenderer(); + RenderingRulesStorage defaultRender = app.getRendererRegistry().defaultRender(); + RouteStatistics routeStatistics = RouteStatistics.newRouteStatistic(route, currentRenderer,defaultRender, nightMode); GPXUtilities.GPXTrackAnalysis analysis = gpx.getAnalysis(0); RouteInfoCard routeClassCard = new RouteInfoCard(mapActivity, routeStatistics.getRouteClassStatistic(), analysis); diff --git a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java index b20c19c131..4fb0e276d1 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/GpxUiHelper.java @@ -9,7 +9,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; -import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -92,7 +91,6 @@ import net.osmand.plus.dialogs.ConfigureMapMenu.GpxAppearanceAdapter; import net.osmand.plus.monitoring.OsmandMonitoringPlugin; import net.osmand.plus.routing.RouteCalculationResult; import net.osmand.render.RenderingRuleProperty; -import net.osmand.render.RenderingRuleSearchRequest; import net.osmand.render.RenderingRulesStorage; import net.osmand.router.RouteStatistics; import net.osmand.util.Algorithms; @@ -1268,8 +1266,7 @@ public class GpxUiHelper { @NonNull HorizontalBarChart mChart, @NonNull RouteStatistics.Statistics routeStatistics, @NonNull GPXTrackAnalysis analysis, - boolean useRightAxis, - boolean nightMode) { + boolean useRightAxis) { XAxis xAxis = mChart.getXAxis(); xAxis.setEnabled(false); @@ -1290,7 +1287,7 @@ public class GpxUiHelper { for (int i = 0; i < stacks.length; i++) { RouteStatistics.RouteSegmentAttribute segment = segments.get(i); stacks[i] = segment.getDistance() / divX; - colors[i] = getColorFromRouteSegmentAttribute(app, segment, nightMode); + colors[i] = segment.getColor(); } entries.add(new BarEntry(0, stacks)); BarDataSet barDataSet = new BarDataSet(entries, ""); @@ -1304,31 +1301,6 @@ public class GpxUiHelper { return dataSet; } - public static int getColorFromRouteSegmentAttribute(OsmandApplication app, RouteStatistics.RouteSegmentAttribute segment, boolean nightMode) { - String colorAttrName = segment.getColorAttrName(); - String colorName = segment.getColorName(); - int color = 0; - if (colorName != null) { - try { - color = Color.parseColor(colorName); - } catch (Exception e) { - } - } else if (colorAttrName != null) { - color = GpxUiHelper.getColorFromStyle(app, colorAttrName, nightMode); - } - return color; - } - - public static int getColorFromStyle(OsmandApplication app, String colorAttrName, boolean nightMode) { - RenderingRulesStorage rrs = app.getRendererRegistry().getCurrentSelectedRenderer(); - RenderingRuleSearchRequest req = new RenderingRuleSearchRequest(rrs); - req.setBooleanFilter(rrs.PROPS.R_NIGHT_MODE, nightMode); - if (req.searchRenderingAttribute(colorAttrName)) { - return req.getIntPropertyValue(rrs.PROPS.R_ATTR_COLOR_VALUE); - } - return 0; - } - public static OrderedLineDataSet createGPXElevationDataSet(@NonNull OsmandApplication ctx, @NonNull LineChart mChart, @NonNull GPXTrackAnalysis analysis, diff --git a/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java b/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java index ede5bb6cca..247199b886 100644 --- a/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java +++ b/OsmAnd/src/net/osmand/plus/helpers/WaypointDialogHelper.java @@ -484,7 +484,7 @@ public class WaypointDialogHelper { final BaseBottomSheetItem[] addWaypointItem = new BaseBottomSheetItem[1]; addWaypointItem[0] = new SimpleBottomSheetItem.Builder() .setIcon(getContentIcon(R.drawable.ic_action_plus)) - .setTitle(getString(R.string.add_waypoint)) + .setTitle(getString(R.string.add_intermediate_point)) .setLayoutId(R.layout.bottom_sheet_item_simple) .setOnClickListener(new View.OnClickListener() { @Override diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java index da7ebc2ec7..ce5eb6f8e4 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/MapRouteInfoMenu.java @@ -800,6 +800,12 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener }); View cancelButton = mainView.findViewById(R.id.cancel_button); + TextView cancelButtonText = (TextView) mainView.findViewById(R.id.cancel_button_descr); + if (routingHelper.isRouteCalculated() || routingHelper.isRouteBeingCalculated() || isTransportRouteCalculated()) { + cancelButtonText.setText(R.string.shared_string_dismiss); + } else { + cancelButtonText.setText(R.string.shared_string_cancel); + } AndroidUtils.setBackground(app, cancelButton, nightMode, R.color.card_and_list_background_light, R.color.card_and_list_background_dark); cancelButton.setOnClickListener(new OnClickListener() { @Override @@ -1236,8 +1242,8 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener viaLayout.setVisibility(View.VISIBLE); viaLayoutDivider.setVisibility(View.VISIBLE); ((TextView) mainView.findViewById(R.id.ViaView)).setText(via); - ((TextView) mainView.findViewById(R.id.ViaSubView)).setText(mapActivity.getString(R.string.intermediate_destinations) + ": " + - mapActivity.getMyApplication().getTargetPointsHelper().getIntermediatePoints().size()); + ((TextView) mainView.findViewById(R.id.ViaSubView)).setText(mapActivity.getString(R.string.intermediate_destinations) + " (" + + mapActivity.getMyApplication().getTargetPointsHelper().getIntermediatePoints().size() + ")"); } FrameLayout viaButton = (FrameLayout) mainView.findViewById(R.id.via_button); diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/WaypointsFragment.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/WaypointsFragment.java index 0ee98c94c5..75aafea57c 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/WaypointsFragment.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/WaypointsFragment.java @@ -600,7 +600,7 @@ public class WaypointsFragment extends BaseOsmAndFragment implements ObservableS if (isAdded()) { final TextViewEx title = (TextViewEx) view.findViewById(R.id.title); int pointsSize = app.getTargetPointsHelper().getAllPoints().size(); - String text = getString(R.string.shared_string_target_points) + ": " + (pointsSize != 0 ? pointsSize : 1); + String text = getString(R.string.shared_string_target_points) + " (" + (pointsSize != 0 ? pointsSize : 1) + ")"; title.setText(text); } } diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java index 66ac6dd943..2f69b8cfa8 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/RouteInfoCard.java @@ -18,15 +18,12 @@ import net.osmand.GPXUtilities; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; +import net.osmand.plus.activities.SettingsNavigationActivity; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.router.RouteStatistics; import net.osmand.util.Algorithms; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.Map; -import java.util.Set; public class RouteInfoCard extends BaseCard { @@ -49,7 +46,7 @@ public class RouteInfoCard extends BaseCard { updateHeader(); final HorizontalBarChart chart = (HorizontalBarChart) view.findViewById(R.id.chart); GpxUiHelper.setupHorizontalGPXChart(app, chart, 5, 10, 10, true, nightMode); - BarData barData = GpxUiHelper.buildStatisticChart(app, chart, routeStatistics, analysis, true, nightMode); + BarData barData = GpxUiHelper.buildStatisticChart(app, chart, routeStatistics, analysis, true); chart.setData(barData); LinearLayout container = view.findViewById(R.id.route_items); attachLegend(container, routeStatistics); @@ -82,9 +79,11 @@ public class RouteInfoCard extends BaseCard { Map> partition = routeStatistics.getPartition(); for (E key : partition.keySet()) { RouteStatistics.RouteSegmentAttribute segment = partition.get(key); - int color = GpxUiHelper.getColorFromRouteSegmentAttribute(app, segment, nightMode); + int color = segment.getColor(); Drawable circle = app.getUIUtilities().getPaintedIcon(R.drawable.ic_action_circle, color); - Spannable text = getSpanLegend(key.toString().toLowerCase(), segment); + String propertyName = segment.getPropertyName(); + String name = SettingsNavigationActivity.getStringPropertyName(app, propertyName, propertyName.replaceAll("_", " ")); + Spannable text = getSpanLegend(name, segment); TextView legend = new TextView(app); AndroidUtils.setTextPrimaryColor(app, legend, nightMode); diff --git a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/TracksCard.java b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/TracksCard.java index f842ef007d..0ecb1ef65f 100644 --- a/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/TracksCard.java +++ b/OsmAnd/src/net/osmand/plus/routepreparationmenu/cards/TracksCard.java @@ -135,6 +135,6 @@ public class TracksCard extends BaseCard { } ((TextView) view.findViewById(R.id.gpx_card_title)).setText( - String.format("%s — %d", app.getString(R.string.tracks_on_map), list.size())); + String.format("%s (%d)", app.getString(R.string.tracks_on_map), list.size())); } }