Fix profile icons placing
This commit is contained in:
parent
eb4a1108f8
commit
34f3474f12
2 changed files with 79 additions and 71 deletions
|
@ -3,14 +3,12 @@ package net.osmand.plus.views.layers.geometry;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Path;
|
|
||||||
import android.graphics.PathMeasure;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import net.osmand.GPXUtilities.TrkSegment;
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.data.QuadRect;
|
import net.osmand.data.QuadRect;
|
||||||
import net.osmand.data.RotatedTileBox;
|
import net.osmand.data.RotatedTileBox;
|
||||||
import net.osmand.osm.edit.Node;
|
import net.osmand.osm.edit.Node;
|
||||||
|
@ -67,7 +65,7 @@ public class MultiProfileGeometryWay extends GeometryWay<MultiProfileGeometryWay
|
||||||
List<TrkSegment> allSegments = new ArrayList<>();
|
List<TrkSegment> allSegments = new ArrayList<>();
|
||||||
allSegments.addAll(beforeSegments);
|
allSegments.addAll(beforeSegments);
|
||||||
allSegments.addAll(afterSegments);
|
allSegments.addAll(afterSegments);
|
||||||
setStyles(tileBox, allSegments, ways, styles);
|
setStyles(allSegments, ways, styles);
|
||||||
|
|
||||||
styleMap = new TreeMap<>();
|
styleMap = new TreeMap<>();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -97,16 +95,13 @@ public class MultiProfileGeometryWay extends GeometryWay<MultiProfileGeometryWay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setStyles(RotatedTileBox tileBox, List<TrkSegment> segments, List<Way> ways, List<GeometryWayStyle<?>> styles) {
|
private void setStyles(List<TrkSegment> segments, List<Way> ways, List<GeometryWayStyle<?>> styles) {
|
||||||
Path path = new Path();
|
|
||||||
PathMeasure pathMeasure = new PathMeasure();
|
|
||||||
|
|
||||||
for (TrkSegment segment : segments) {
|
for (TrkSegment segment : segments) {
|
||||||
List<WptPt> points = segment.points;
|
List<WptPt> points = segment.points;
|
||||||
for (int i = 0; i < points.size() - 1; i++) {
|
for (int i = 0; i < points.size() - 1; i++) {
|
||||||
setStylesInternal(tileBox, points, i, ways, styles, path, pathMeasure);
|
setStylesInternal(points, i, ways, styles);
|
||||||
}
|
}
|
||||||
styles.add(new GeometryMultiProfileWayStyle(getContext(), 0, 0, true));
|
styles.add(new GeometryMultiProfileWayStyle(getContext(), new ArrayList<LatLon>(), 0, 0, true));
|
||||||
Way way = new Way(-1);
|
Way way = new Way(-1);
|
||||||
WptPt last = points.get(points.size() - 1);
|
WptPt last = points.get(points.size() - 1);
|
||||||
way.addNode(new Node(last.lat, last.lon, -1));
|
way.addNode(new Node(last.lat, last.lon, -1));
|
||||||
|
@ -114,48 +109,42 @@ public class MultiProfileGeometryWay extends GeometryWay<MultiProfileGeometryWay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setStylesInternal(RotatedTileBox tileBox, List<WptPt> points, int idx, List<Way> ways,
|
private void setStylesInternal(List<WptPt> points, int idx, List<Way> ways, List<GeometryWayStyle<?>> styles) {
|
||||||
List<GeometryWayStyle<?>> styles, Path path, PathMeasure pathMeasure) {
|
WptPt startPt = points.get(idx);
|
||||||
MultiProfileGeometryWayContext context = getContext();
|
WptPt endPt = points.get(idx + 1);
|
||||||
WptPt leftPt = points.get(idx);
|
List<LatLon> routePoints = getRoutePoints(startPt, endPt);
|
||||||
Pair<WptPt, WptPt> userLine = new Pair<>(leftPt, points.get(idx + 1));
|
|
||||||
RoadSegmentData routeBetweenPoints = segmentData.get(userLine);
|
|
||||||
boolean isSecondToLast = idx + 2 == points.size();
|
boolean isSecondToLast = idx + 2 == points.size();
|
||||||
|
|
||||||
Way way = new Way(-1);
|
Way way = new Way(-1);
|
||||||
String currProfileKey = getProfileKey(leftPt);
|
String currProfileKey = getProfileKey(startPt);
|
||||||
Pair<Integer, Integer> profileData = getProfileData(currProfileKey);
|
Pair<Integer, Integer> profileData = getProfileData(currProfileKey);
|
||||||
GeometryMultiProfileWayStyle style = new GeometryMultiProfileWayStyle(
|
GeometryMultiProfileWayStyle style = new GeometryMultiProfileWayStyle(
|
||||||
getContext(), profileData.first, profileData.second);
|
getContext(), routePoints, profileData.first, profileData.second);
|
||||||
styles.add(style);
|
styles.add(style);
|
||||||
ways.add(way);
|
ways.add(way);
|
||||||
|
|
||||||
path.reset();
|
for (LatLon routePt : routePoints) {
|
||||||
if (routeBetweenPoints == null || Algorithms.isEmpty(routeBetweenPoints.getPoints())) {
|
if (isSecondToLast || routePt.getLatitude() != endPt.getLatitude()
|
||||||
way.addNode(new Node(userLine.first.lat, userLine.first.lon, -1));
|
&& routePt.getLongitude() != endPt.getLongitude()) {
|
||||||
if (isSecondToLast) {
|
way.addNode(new Node(routePt.getLatitude(), routePt.getLongitude(), -1));
|
||||||
way.addNode(new Node(userLine.second.lat, userLine.second.lon, -1));
|
|
||||||
}
|
|
||||||
movePathToWpt(path, tileBox, userLine.first);
|
|
||||||
pathLineToWpt(path, tileBox, userLine.second);
|
|
||||||
} else {
|
|
||||||
movePathToWpt(path, tileBox, routeBetweenPoints.getPoints().get(0));
|
|
||||||
for (WptPt pt : routeBetweenPoints.getPoints()) {
|
|
||||||
if (pt.lat != userLine.second.lat && pt.lon != userLine.second.lon || isSecondToLast) {
|
|
||||||
way.addNode(new Node(pt.lat, pt.lon, -1));
|
|
||||||
}
|
|
||||||
pathLineToWpt(path, tileBox, pt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float[] xy = new float[2];
|
private List<LatLon> getRoutePoints(WptPt start, WptPt end) {
|
||||||
pathMeasure.setPath(path, false);
|
Pair<WptPt, WptPt> userLine = new Pair<>(start, end);
|
||||||
float routeLength = pathMeasure.getLength();
|
RoadSegmentData roadSegmentData = segmentData.get(userLine);
|
||||||
if ((routeLength - context.circleSize) / 2 >= context.minIconMargin) {
|
List<LatLon> routePoints = new ArrayList<>();
|
||||||
pathMeasure.getPosTan(pathMeasure.getLength() * 0.5f, xy, null);
|
|
||||||
style.setIconLat(tileBox.getLatFromPixel(xy[0], xy[1]));
|
if (roadSegmentData == null || Algorithms.isEmpty(roadSegmentData.getPoints())) {
|
||||||
style.setIconLon(tileBox.getLonFromPixel(xy[0], xy[1]));
|
routePoints.add(new LatLon(start.lat, start.lon));
|
||||||
|
routePoints.add(new LatLon(end.lat, end.lon));
|
||||||
|
} else {
|
||||||
|
for (WptPt routePt : roadSegmentData.getPoints()) {
|
||||||
|
routePoints.add(new LatLon(routePt.lat, routePt.lon));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return routePoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -186,14 +175,6 @@ public class MultiProfileGeometryWay extends GeometryWay<MultiProfileGeometryWay
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void movePathToWpt(Path path, RotatedTileBox tileBox, WptPt pt) {
|
|
||||||
path.moveTo(tileBox.getPixXFromLatLon(pt.lat, pt.lon), tileBox.getPixYFromLatLon(pt.lat, pt.lon));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void pathLineToWpt(Path path, RotatedTileBox tileBox, WptPt pt) {
|
|
||||||
path.lineTo(tileBox.getPixXFromLatLon(pt.lat, pt.lon), tileBox.getPixYFromLatLon(pt.lat, pt.lon));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private String getProfileKey(WptPt pt) {
|
private String getProfileKey(WptPt pt) {
|
||||||
String key = pt.getProfileType();
|
String key = pt.getProfileType();
|
||||||
|
@ -230,13 +211,13 @@ public class MultiProfileGeometryWay extends GeometryWay<MultiProfileGeometryWay
|
||||||
|
|
||||||
private final boolean isGap;
|
private final boolean isGap;
|
||||||
|
|
||||||
private double iconLat = Double.NaN;
|
private final List<LatLon> routePoints;
|
||||||
private double iconLon = Double.NaN;
|
|
||||||
|
|
||||||
public GeometryMultiProfileWayStyle(MultiProfileGeometryWayContext context,
|
public GeometryMultiProfileWayStyle(MultiProfileGeometryWayContext context, List<LatLon> routePoints,
|
||||||
@ColorInt int profileColor, @DrawableRes int profileIconRes,
|
@ColorInt int profileColor, @DrawableRes int profileIconRes,
|
||||||
boolean isGap) {
|
boolean isGap) {
|
||||||
super(context);
|
super(context);
|
||||||
|
this.routePoints = routePoints;
|
||||||
this.lineColor = profileColor;
|
this.lineColor = profileColor;
|
||||||
this.borderColor = ColorUtils.blendARGB(profileColor, Color.BLACK, 0.2f);
|
this.borderColor = ColorUtils.blendARGB(profileColor, Color.BLACK, 0.2f);
|
||||||
this.profileIconRes = profileIconRes;
|
this.profileIconRes = profileIconRes;
|
||||||
|
@ -244,9 +225,9 @@ public class MultiProfileGeometryWay extends GeometryWay<MultiProfileGeometryWay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public GeometryMultiProfileWayStyle(MultiProfileGeometryWayContext context,
|
public GeometryMultiProfileWayStyle(MultiProfileGeometryWayContext context, List<LatLon> routePoints,
|
||||||
@ColorInt int profileColor, @DrawableRes int profileIconRes) {
|
@ColorInt int profileColor, @DrawableRes int profileIconRes) {
|
||||||
this(context, profileColor, profileIconRes, false);
|
this(context, routePoints, profileColor, profileIconRes, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ColorInt
|
@ColorInt
|
||||||
|
@ -264,20 +245,12 @@ public class MultiProfileGeometryWay extends GeometryWay<MultiProfileGeometryWay
|
||||||
return getContext().getProfileIconBitmap(profileIconRes, borderColor);
|
return getContext().getProfileIconBitmap(profileIconRes, borderColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIconLat(double lat) {
|
public List<LatLon> getRoutePoints() {
|
||||||
iconLat = lat;
|
return routePoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIconLon(double lon) {
|
public boolean isGap() {
|
||||||
iconLon = lon;
|
return isGap;
|
||||||
}
|
|
||||||
|
|
||||||
public double getIconLat() {
|
|
||||||
return iconLat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getIconLon() {
|
|
||||||
return iconLon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,10 +2,14 @@ package net.osmand.plus.views.layers.geometry;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
import android.graphics.PathMeasure;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.data.RotatedTileBox;
|
import net.osmand.data.RotatedTileBox;
|
||||||
import net.osmand.plus.views.OsmandMapLayer.RenderingLineAttributes;
|
import net.osmand.plus.views.OsmandMapLayer.RenderingLineAttributes;
|
||||||
import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay.GeometryMultiProfileWayStyle;
|
import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay.GeometryMultiProfileWayStyle;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -30,20 +34,51 @@ public class MultiProfileGeometryWayDrawer extends GeometryWayDrawer<MultiProfil
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawArrowsOverPath(Canvas canvas, RotatedTileBox tb, List<Float> tx, List<Float> ty, List<Double> angles, List<Double> distances, double distPixToFinish, List<GeometryWayStyle<?>> styles) {
|
public void drawArrowsOverPath(Canvas canvas, RotatedTileBox tb, List<Float> tx, List<Float> ty, List<Double> angles, List<Double> distances, double distPixToFinish, List<GeometryWayStyle<?>> styles) {
|
||||||
|
Path path = new Path();
|
||||||
|
PathMeasure pathMeasure = new PathMeasure();
|
||||||
MultiProfileGeometryWayContext context = getContext();
|
MultiProfileGeometryWayContext context = getContext();
|
||||||
GeometryMultiProfileWayStyle style = null;
|
GeometryMultiProfileWayStyle style = null;
|
||||||
|
|
||||||
for (int i = 0; i < styles.size(); i++) {
|
for (int i = 0; i < styles.size(); i++) {
|
||||||
if (styles.get(i) != null && !styles.get(i).equals(style)) {
|
GeometryWayStyle<?> s = styles.get(i);
|
||||||
|
if (s != null && !s.equals(style) || !((GeometryMultiProfileWayStyle) s).isGap()) {
|
||||||
style = (GeometryMultiProfileWayStyle) styles.get(i);
|
style = (GeometryMultiProfileWayStyle) styles.get(i);
|
||||||
double lat = style.getIconLat();
|
PointF center = getIconCenter(tb, style.getRoutePoints(), path, pathMeasure);
|
||||||
double lon = style.getIconLon();
|
if (center != null && tb.containsPoint(center.x, center.y, context.circleSize)) {
|
||||||
if (!Double.isNaN(lat) && !Double.isNaN(lon)) {
|
float x = center.x - context.circleSize / 2;
|
||||||
float x = tb.getPixXFromLatLon(lat, lon) - context.circleSize / 2;
|
float y = center.y - context.circleSize / 2;
|
||||||
float y = tb.getPixYFromLatLon(lat, lon) - context.circleSize / 2;
|
|
||||||
canvas.drawBitmap(style.getPointBitmap(), x, y, null);
|
canvas.drawBitmap(style.getPointBitmap(), x, y, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PointF getIconCenter(RotatedTileBox tileBox, List<LatLon> routePoints, Path path, PathMeasure pathMeasure) {
|
||||||
|
if (Algorithms.isEmpty(routePoints)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.reset();
|
||||||
|
PointF first = getPoint(tileBox, routePoints.get(0));
|
||||||
|
path.moveTo(first.x, first.y);
|
||||||
|
for (int i = 1; i < routePoints.size(); i++) {
|
||||||
|
PointF pt = getPoint(tileBox, routePoints.get(i));
|
||||||
|
path.lineTo(pt.x, pt.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
pathMeasure.setPath(path, false);
|
||||||
|
float routeLength = pathMeasure.getLength();
|
||||||
|
if ((routeLength - getContext().circleSize) / 2 < getContext().minIconMargin) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] xy = new float[2];
|
||||||
|
pathMeasure.getPosTan(routeLength * 0.5f, xy, null);
|
||||||
|
return new PointF(xy[0], xy[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PointF getPoint(RotatedTileBox tileBox, LatLon latLon) {
|
||||||
|
return new PointF(tileBox.getPixXFromLatLon(latLon.getLatitude(), latLon.getLongitude()),
|
||||||
|
tileBox.getPixYFromLatLon(latLon.getLatitude(), latLon.getLongitude()));
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue