From 762e574bf0f5e5f7a8b90d3a3d5ee4cd0aa5cb8c Mon Sep 17 00:00:00 2001 From: cepprice Date: Wed, 31 Mar 2021 22:51:30 +0500 Subject: [PATCH 1/9] Use profile color for plan route lines --- .../MeasurementEditingContext.java | 6 +- .../measurementtool/MeasurementToolLayer.java | 55 +++- .../views/layers/geometry/GeometryWay.java | 15 +- .../layers/geometry/GeometryWayContext.java | 3 +- .../geometry/MultiProfileGeometryWay.java | 252 ++++++++++++++++++ .../MultiProfileGeometryWayContext.java | 85 ++++++ .../MultiProfileGeometryWayDrawer.java | 32 +++ 7 files changed, 432 insertions(+), 16 deletions(-) create mode 100644 OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java create mode 100644 OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java create mode 100644 OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java index 3512de68bc..bda7c5404b 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java @@ -1111,8 +1111,12 @@ public class MeasurementEditingContext implements IRouteSettingsListener { return res; } + public boolean isInMultiProfileMode() { + return lastCalculationMode == CalculationMode.NEXT_SEGMENT; + } + @Override public void onRouteSettingsChanged(@Nullable ApplicationMode mode) { recalculateRouteSegments(mode); } -} +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java index 3c6bcf6c89..7ab66f44b2 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java @@ -23,6 +23,8 @@ import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.Renderable; import net.osmand.plus.views.layers.ContextMenuLayer; import net.osmand.plus.views.layers.geometry.GeometryWay; +import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay; +import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWayContext; import net.osmand.util.MapUtils; import java.util.ArrayList; @@ -33,20 +35,28 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL private OsmandMapTileView view; private boolean inMeasurementMode; + private Bitmap centerIconDay; private Bitmap centerIconNight; private Bitmap pointIcon; private Bitmap applyingPointIcon; private Paint bitmapPaint; private final RenderingLineAttributes lineAttrs = new RenderingLineAttributes("measureDistanceLine"); + private final RenderingLineAttributes multiProfileLineAttrs = new RenderingLineAttributes("multiProfileMeasureDistanceLine"); + + private MultiProfileGeometryWay multiProfileGeometry; + private MultiProfileGeometryWayContext multiProfileGeometryWayContext; + private int marginPointIconX; private int marginPointIconY; private int marginApplyingPointIconX; private int marginApplyingPointIconY; private final Path path = new Path(); + private final List tx = new ArrayList<>(); private final List ty = new ArrayList<>(); private OnMeasureDistanceToCenter measureDistanceToCenterListener; + private OnSingleTapListener singleTapListener; private OnEnterMovePointModeListener enterMovePointModeListener; private LatLon pressedPointLatLon; @@ -63,6 +73,18 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL pointIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_measure_point_day); applyingPointIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_measure_point_move_day); + float density = view.getDensity(); + multiProfileLineAttrs.isPaint_1 = false; + multiProfileLineAttrs.paint_1.setColor(0xFFFFFFFF); + multiProfileLineAttrs.paint_1.setStyle(Paint.Style.FILL); + multiProfileLineAttrs.paint.setStrokeWidth(density * 14); + multiProfileLineAttrs.paint2.setStrokeWidth(density * 10); + multiProfileLineAttrs.isPaint3 = false; + multiProfileLineAttrs.paint3.setStrokeWidth(density * 2); + + multiProfileGeometryWayContext = new MultiProfileGeometryWayContext(view.getContext(), density); + multiProfileGeometry = new MultiProfileGeometryWay(multiProfileGeometryWayContext); + bitmapPaint = new Paint(); bitmapPaint.setAntiAlias(true); bitmapPaint.setDither(true); @@ -194,15 +216,28 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL } } - List before = editingCtx.getBeforeTrkSegmentLine(); - for (TrkSegment segment : before) { - new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2). - drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb); - } - List after = editingCtx.getAfterTrkSegmentLine(); - for (TrkSegment segment : after) { - new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2). - drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb); + if (editingCtx.isInMultiProfileMode()) { + multiProfileGeometryWayContext.updatePaints(settings.isNightMode(), multiProfileLineAttrs); + for (int i = 0; i < editingCtx.getBeforeSegments().size(); i++) { + multiProfileGeometry.updateRoute(tb, editingCtx.getRoadSegmentData(), true, editingCtx.getBeforeSegments(), i); + multiProfileGeometry.drawSegments(canvas, tb); + } + for (int i = 0; i < editingCtx.getAfterSegments().size(); i++) { + multiProfileGeometry.updateRoute(tb, editingCtx.getRoadSegmentData(), false, editingCtx.getAfterSegments(), i); + multiProfileGeometry.drawSegments(canvas, tb); + } + } else { + List before = editingCtx.getBeforeTrkSegmentLine(); + for (TrkSegment segment : before) { + new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2). + drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb); + } + + List after = editingCtx.getAfterTrkSegmentLine(); + for (TrkSegment segment : after) { + new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2). + drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb); + } } drawPoints(canvas, tb); @@ -509,4 +544,4 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL interface OnMeasureDistanceToCenter { void onMeasure(float distance, float bearing); } -} +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java index 9c7fd1c782..cc1633839e 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java @@ -174,8 +174,8 @@ public abstract class GeometryWay style, List tx, List ty, List angles, List distances, double dist, List> styles) { @@ -333,7 +340,7 @@ public abstract class GeometryWay tx, List ty, + protected void drawRouteSegment(RotatedTileBox tb, Canvas canvas, List tx, List ty, List angles, List distances, double distToFinish, List> styles) { if (tx.size() < 2) { return; @@ -449,4 +456,4 @@ public abstract class GeometryWay { + + private static final String DEFAULT_PROFILE_KEY = ApplicationMode.DEFAULT.getStringKey(); + + private Map, RoadSegmentData> segmentData; + private List beforeSegments; + private List afterSegments; + + public MultiProfileGeometryWay(MultiProfileGeometryWayContext context) { + super(context, new MultiProfileGeometryWayDrawer(context)); + } + + public void drawSegments(Canvas canvas, RotatedTileBox tileBox) { + QuadRect bounds = tileBox.getLatLonBounds(); + drawSegments(tileBox, canvas, bounds.top, bounds.left, bounds.bottom, bounds.right, null, 0); + } + + @Override + protected void drawRouteSegment(RotatedTileBox tb, Canvas canvas, List tx, List ty, List angles, List distances, double distToFinish, List> styles) { + if (tx.size() < 2) { + return; + } + try { + List>> pathStyles = new ArrayList<>(); + canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); + calculatePath(tb, tx, ty, styles, pathStyles); + + for (int i = 0; i < pathStyles.size(); i++) { + Pair> currPathStyle = pathStyles.get(i); + getDrawer().drawPathBorder(canvas, currPathStyle.first, currPathStyle.second); + getDrawer().drawPath(canvas, currPathStyle.first, currPathStyle.second); + } +// drawer.drawArrowsOverPath(canvas, tb, tx, ty, angles, distances, distToFinish, styles); + } finally { + canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); + } + } + + public void updateRoute(RotatedTileBox tileBox, Map, RoadSegmentData> segmentData, + boolean before, List segments, int segmentIdx) { + boolean shouldUpdateRoute = tileBox.getMapDensity() != getMapDensity() || segmentDataChanged(segmentData) + || getSegments(before) != segments || true; + if (shouldUpdateRoute && segments.get(segmentIdx).points.size() >= 2) { + this.segmentData = segmentData; + setSegments(before, segments); + List userPoints = segments.get(segmentIdx).points; + List locations; + Map> styleMap; + + List ways = new ArrayList<>(); + List> styles = new ArrayList<>(); + setStyles(userPoints, ways, styles); + locations = new ArrayList<>(); + + styleMap = new TreeMap<>(); + int i = 0; + int k = 0; + if (ways.size() > 0) { + for (Way w : ways) { + styleMap.put(k, styles.get(i++)); + for (Node n : w.getNodes()) { + Location ln = new Location(""); + ln.setLatitude(n.getLatitude()); + ln.setLongitude(n.getLongitude()); + locations.add(ln); + k++; + } + } + } + + updateWay(locations, styleMap, tileBox); + } + } + + private void setStyles(List userPoints, List ways, List> styles) { + String prevProfileKey = ""; + Way way = new Way(-2); + + for (int i = 0; i < userPoints.size() - 1; i++) { + WptPt leftPt = userPoints.get(i); + Pair userLine = new Pair<>(leftPt, userPoints.get(i + 1)); + RoadSegmentData routeBetweenPoints = segmentData.get(userLine); + + if (!prevProfileKey.equals(getProfileKey(leftPt)) && !leftPt.isGap()) { + way = new Way(-2); + String currProfileKey = getProfileKey(leftPt); + Pair profileData = getProfileData(currProfileKey); + styles.add(new GeometryMultiProfileWayStyle(getContext(), profileData.first, profileData.second)); + ways.add(way); + prevProfileKey = currProfileKey; + } + + boolean isSecondToLast = i + 2 == userPoints.size(); + if (routeBetweenPoints == null || Algorithms.isEmpty(routeBetweenPoints.getPoints())) { + way.addNode(new Node(userLine.first.lat, userLine.first.lon, -1)); + if (isSecondToLast) { + way.addNode(new Node(userLine.second.lat, userLine.second.lon, -1)); + } + } else { + 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)); + } + } + } + } + } + + @Override + protected boolean shouldAddLocation(double leftLon, double rightLon, double bottomLat, double topLat, GeometryWayProvider provider, int currLocationIdx) { + return super.shouldAddLocation(leftLon, rightLon, bottomLat, topLat, provider, currLocationIdx) + || currLocationIdx + 1 < provider.getSize() + && super.shouldAddLocation(leftLon, rightLon, bottomLat, topLat, provider, currLocationIdx + 1); + } + + private boolean segmentDataChanged(Map, RoadSegmentData> other) { + if (other.size() != segmentData.size()) { + return true; + } + for (Pair data : other.keySet()) { + if (other.get(data) != segmentData.get(data)) { + return true; + } + } + return false; + } + + private void setSegments(boolean before, List segments) { + if (before) { + this.beforeSegments = segments; + } else { + this.afterSegments = segments; + } + } + + private List getSegments(boolean before) { + return before ? this.beforeSegments : this.afterSegments; + } + + @NonNull + private String getProfileKey(WptPt pt) { + String key = pt.getProfileType(); + return key == null ? DEFAULT_PROFILE_KEY : key; + } + + private Pair getProfileData(String profileKey) { + boolean night = getContext().isNightMode(); + ApplicationMode mode = ApplicationMode.valueOfStringKey(profileKey, ApplicationMode.DEFAULT); + return ApplicationMode.DEFAULT.getStringKey().equals(mode.getStringKey()) ? + new Pair<>(ContextCompat.getColor(getContext().getCtx(), ProfileIconColors.DARK_YELLOW.getColor(night)), R.drawable.ic_action_split_interval) : + new Pair<>(mode.getProfileColor(night), mode.getIconRes()); + } + + @NonNull + @Override + public GeometryWayStyle getDefaultWayStyle() { + return null; + } + + public static class GeometryMultiProfileWayStyle extends GeometryWayStyle { + + @ColorInt + private final int lineColor; + @ColorInt + private final int borderColor; + @DrawableRes + private final int profileIconRes; + + public GeometryMultiProfileWayStyle(MultiProfileGeometryWayContext context, + @ColorInt int profileColor, @DrawableRes int profileIconRes) { + super(context); + this.lineColor = profileColor; + this.borderColor = ColorUtils.blendARGB(profileColor, Color.BLACK, 0.2f); + this.profileIconRes = profileIconRes; + } + + @ColorInt + public int getBorderColor() { + return borderColor; + } + + @ColorInt + public int getLineColor() { + return lineColor; + } + + @DrawableRes + public int getProfileIconRes() { + return profileIconRes; + } + + @Override + public Bitmap getPointBitmap() { +// return getContext().getProfileIconBitmap(); + return null; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + if (!super.equals(other)) { + return false; + } + GeometryMultiProfileWayStyle that = (GeometryMultiProfileWayStyle) other; + return lineColor == that.lineColor && + borderColor == that.borderColor && + profileIconRes == that.profileIconRes; + } + + @Override + public boolean hasPathLine() { + return true; + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java new file mode 100644 index 0000000000..6d4a92a70b --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java @@ -0,0 +1,85 @@ +package net.osmand.plus.views.layers.geometry; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; + +import net.osmand.plus.views.OsmandMapLayer.RenderingLineAttributes; +import net.osmand.util.Algorithms; + +import java.util.HashMap; +import java.util.Map; + +import androidx.annotation.NonNull; + +public class MultiProfileGeometryWayContext extends GeometryWayContext { + + private RenderingLineAttributes multiProfileAttrs; + + private Bitmap pointIcon; + + private final Map profileIconsBitmapCache; + + public MultiProfileGeometryWayContext(Context ctx, float density) { + super(ctx, density); + profileIconsBitmapCache = new HashMap<>(); + } + + public void updatePaints(boolean nightMode, @NonNull RenderingLineAttributes multiProfileAttrs) { + this.multiProfileAttrs = multiProfileAttrs; + super.updatePaints(nightMode, multiProfileAttrs); + } + + @Override + protected void recreateBitmaps() { + float density = getDensity(); + float size = density * 12.5f; + float outerRadius = density * 6.25f; + float centerRadius = density * 6; + float innerRadius = density * 4; + float centerXY = size / 2; + + pointIcon = Bitmap.createBitmap((int) size, (int) size, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(pointIcon); + Paint paint = new Paint(); + paint.setStyle(Paint.Style.FILL); + + paint.setColor(Color.BLACK); + canvas.drawCircle(centerXY, centerXY, outerRadius, paint); + + paint.setColor(Color.WHITE); + canvas.drawCircle(centerXY, centerXY, centerRadius, paint); + + paint.setColor(Algorithms.parseColor("#637EFB")); + canvas.drawCircle(centerXY, centerXY, innerRadius, paint); + } + + @Override + protected int getArrowBitmapResId() { + return 0; + } + + @NonNull + public Bitmap getProfileIconBitmap(@NonNull String profileKey, int profileColor) { + String key = profileKey + "_" + profileColor; + Bitmap bitmap = profileIconsBitmapCache.get(key); + if (bitmap == null) { + float density = getDensity(); + float diameter = density * 18; + bitmap = Bitmap.createBitmap((int) diameter, (int) diameter, Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(bitmap); + canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, multiProfileAttrs.paint_1); + multiProfileAttrs.paint3.setColor(profileColor); + canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, multiProfileAttrs.paint3); + } + return bitmap; + } + + @NonNull + public Bitmap getPointIcon() { + return pointIcon; + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java new file mode 100644 index 0000000000..5d8120f1c2 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java @@ -0,0 +1,32 @@ +package net.osmand.plus.views.layers.geometry; + +import android.graphics.Canvas; +import android.graphics.Path; + +import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay.GeometryMultiProfileWayStyle; + +import net.osmand.plus.views.OsmandMapLayer.RenderingLineAttributes; + +public class MultiProfileGeometryWayDrawer extends GeometryWayDrawer { + + public MultiProfileGeometryWayDrawer(MultiProfileGeometryWayContext context) { + super(context); + } + + @Override + public void drawPath(Canvas canvas, Path path, GeometryWayStyle style) { + if (style instanceof GeometryMultiProfileWayStyle) { + RenderingLineAttributes attrs = getContext().getAttrs(); + attrs.paint2.setColor(((GeometryMultiProfileWayStyle) style).getLineColor()); + canvas.drawPath(path, attrs.paint2); + } + } + + public void drawPathBorder(Canvas canvas, Path path, GeometryWayStyle style) { + if (style instanceof GeometryMultiProfileWayStyle) { + RenderingLineAttributes attrs = getContext().getAttrs(); + attrs.paint.setColor(((GeometryMultiProfileWayStyle) style).getBorderColor()); + canvas.drawPath(path, attrs.paint); + } + } +} \ No newline at end of file From bf55e86a7e7e4f75b0a29ef3a77201a6e369d0a5 Mon Sep 17 00:00:00 2001 From: cepprice Date: Thu, 1 Apr 2021 22:39:33 +0500 Subject: [PATCH 2/9] Draw profile icon on line center --- OsmAnd/src/net/osmand/AndroidUtils.java | 4 + .../measurementtool/MeasurementToolLayer.java | 4 +- .../views/layers/geometry/GeometryWay.java | 22 ++-- .../geometry/MultiProfileGeometryWay.java | 117 ++++++++++++------ .../MultiProfileGeometryWayContext.java | 39 ++++-- .../MultiProfileGeometryWayDrawer.java | 21 +++- 6 files changed, 144 insertions(+), 63 deletions(-) diff --git a/OsmAnd/src/net/osmand/AndroidUtils.java b/OsmAnd/src/net/osmand/AndroidUtils.java index 42b4a60919..4f0729d355 100644 --- a/OsmAnd/src/net/osmand/AndroidUtils.java +++ b/OsmAnd/src/net/osmand/AndroidUtils.java @@ -151,6 +151,10 @@ public class AndroidUtils { return resizedBitmap; } + public static Bitmap createScaledBitmap(Drawable drawable, int width, int height) { + return scaleBitmap(drawableToBitmap(drawable), width, height, false); + } + public static ColorStateList createBottomNavColorStateList(Context ctx, boolean nightMode) { return AndroidUtils.createCheckedColorStateList(ctx, nightMode, R.color.icon_color_default_light, R.color.wikivoyage_active_light, diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java index 7ab66f44b2..4ed8aa719a 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java @@ -82,7 +82,8 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL multiProfileLineAttrs.isPaint3 = false; multiProfileLineAttrs.paint3.setStrokeWidth(density * 2); - multiProfileGeometryWayContext = new MultiProfileGeometryWayContext(view.getContext(), density); + multiProfileGeometryWayContext = new MultiProfileGeometryWayContext( + view.getContext(), view.getApplication().getUIUtilities(), density); multiProfileGeometry = new MultiProfileGeometryWay(multiProfileGeometryWayContext); bitmapPaint = new Paint(); @@ -227,6 +228,7 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL multiProfileGeometry.drawSegments(canvas, tb); } } else { + multiProfileGeometry.clearWay(); List before = editingCtx.getBeforeTrkSegmentLine(); for (TrkSegment segment : before) { new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2). diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java index cc1633839e..9489cd9620 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java @@ -174,7 +174,7 @@ public abstract class GeometryWay= lx && x <= rx && y >= ty && y <= by; } + public static boolean isIn(float x, float y, int lx, int ty, int rx, int by, float outMargin) { + return x >= lx - outMargin && x <= rx + outMargin && y >= ty - outMargin && y <= by + outMargin; + } + public static int calculatePath(RotatedTileBox tb, List xs, List ys, Path path) { List>> paths = new ArrayList<>(); - int res = calculatePath(tb, xs, ys, null, paths); + int res = calculatePath(tb, xs, ys, 0, null, paths); if (paths.size() > 0) { path.addPath(paths.get(0).first); } return res; } - public static int calculatePath(RotatedTileBox tb, List xs, List ys, List> styles, List>> paths) { + public static int calculatePath(RotatedTileBox tb, List xs, List ys, float outMargin, List> styles, List>> paths) { boolean segmentStarted = false; float prevX = xs.get(0); float prevY = ys.get(0); @@ -280,11 +284,11 @@ public abstract class GeometryWay style = hasStyles ? styles.get(0) : null; Path path = new Path(); - boolean prevIn = isIn(prevX, prevY, 0, 0, width, height); + boolean prevIn = isIn(prevX, prevY, 0, 0, width, height, outMargin); for (int i = 1; i < xs.size(); i++) { float currX = xs.get(i); float currY = ys.get(i); - boolean currIn = isIn(currX, currY, 0, 0, width, height); + boolean currIn = isIn(currX, currY, 0, 0, width, height, outMargin); boolean draw = false; if (prevIn && currIn) { draw = true; @@ -356,7 +360,7 @@ public abstract class GeometryWay>> paths = new ArrayList<>(); canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); - calculatePath(tb, tx, ty, styles, paths); + calculatePath(tb, tx, ty, 0, styles, paths); for (Pair> pc : paths) { GeometryWayStyle style = pc.second; if (style.hasPathLine()) { diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java index e378c4edbd..865e56e60b 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java @@ -4,6 +4,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Path; +import android.graphics.PathMeasure; import android.util.Pair; import net.osmand.GPXUtilities.TrkSegment; @@ -55,14 +56,14 @@ public class MultiProfileGeometryWay extends GeometryWay>> pathStyles = new ArrayList<>(); canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); - calculatePath(tb, tx, ty, styles, pathStyles); + calculatePath(tb, tx, ty, getContext().circleSize, styles, pathStyles); for (int i = 0; i < pathStyles.size(); i++) { Pair> currPathStyle = pathStyles.get(i); getDrawer().drawPathBorder(canvas, currPathStyle.first, currPathStyle.second); getDrawer().drawPath(canvas, currPathStyle.first, currPathStyle.second); } -// drawer.drawArrowsOverPath(canvas, tb, tx, ty, angles, distances, distToFinish, styles); + getDrawer().drawArrowsOverPath(canvas, tb, tx, ty, angles, distances, distToFinish, styles); } finally { canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); } @@ -71,8 +72,8 @@ public class MultiProfileGeometryWay extends GeometryWay, RoadSegmentData> segmentData, boolean before, List segments, int segmentIdx) { boolean shouldUpdateRoute = tileBox.getMapDensity() != getMapDensity() || segmentDataChanged(segmentData) - || getSegments(before) != segments || true; - if (shouldUpdateRoute && segments.get(segmentIdx).points.size() >= 2) { + || getSegments(before) != segments || getLocationProvider() == null; + if (shouldUpdateRoute) { this.segmentData = segmentData; setSegments(before, segments); List userPoints = segments.get(segmentIdx).points; @@ -81,7 +82,7 @@ public class MultiProfileGeometryWay extends GeometryWay ways = new ArrayList<>(); List> styles = new ArrayList<>(); - setStyles(userPoints, ways, styles); + setStyles(tileBox, userPoints, ways, styles); locations = new ArrayList<>(); styleMap = new TreeMap<>(); @@ -104,45 +105,68 @@ public class MultiProfileGeometryWay extends GeometryWay userPoints, List ways, List> styles) { - String prevProfileKey = ""; - Way way = new Way(-2); + private void setStyles(RotatedTileBox tileBox, List userPoints, List ways, List> styles) { + MultiProfileGeometryWayContext context = getContext(); + Path path = new Path(); + PathMeasure pathMeasure = new PathMeasure(); for (int i = 0; i < userPoints.size() - 1; i++) { WptPt leftPt = userPoints.get(i); Pair userLine = new Pair<>(leftPt, userPoints.get(i + 1)); RoadSegmentData routeBetweenPoints = segmentData.get(userLine); - if (!prevProfileKey.equals(getProfileKey(leftPt)) && !leftPt.isGap()) { - way = new Way(-2); - String currProfileKey = getProfileKey(leftPt); - Pair profileData = getProfileData(currProfileKey); - styles.add(new GeometryMultiProfileWayStyle(getContext(), profileData.first, profileData.second)); - ways.add(way); - prevProfileKey = currProfileKey; - } + Way way = new Way(-1); + String currProfileKey = getProfileKey(leftPt); + Pair profileData = getProfileData(currProfileKey); + GeometryMultiProfileWayStyle style = new GeometryMultiProfileWayStyle( + getContext(), currProfileKey, profileData.first, profileData.second); + styles.add(style); + ways.add(way); + path.reset(); boolean isSecondToLast = i + 2 == userPoints.size(); if (routeBetweenPoints == null || Algorithms.isEmpty(routeBetweenPoints.getPoints())) { way.addNode(new Node(userLine.first.lat, userLine.first.lon, -1)); if (isSecondToLast) { 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]; + pathMeasure.setPath(path, false); + float routeLength = pathMeasure.getLength(); + if ((routeLength - context.circleSize) / 2 >= context.minIconMargin) { + pathMeasure.getPosTan(pathMeasure.getLength() * 0.5f, xy, null); + style.setIconLat(tileBox.getLatFromPixel(xy[0], xy[1])); + style.setIconLon(tileBox.getLonFromPixel(xy[0], xy[1])); + } } } @Override - protected boolean shouldAddLocation(double leftLon, double rightLon, double bottomLat, double topLat, GeometryWayProvider provider, int currLocationIdx) { - return super.shouldAddLocation(leftLon, rightLon, bottomLat, topLat, provider, currLocationIdx) - || currLocationIdx + 1 < provider.getSize() - && super.shouldAddLocation(leftLon, rightLon, bottomLat, topLat, provider, currLocationIdx + 1); + protected boolean shouldAddLocation(RotatedTileBox tileBox, double leftLon, double rightLon, + double bottomLat, double topLat, GeometryWayProvider provider, + int currLocationIdx) { + float currX = tileBox.getPixXFromLatLon(provider.getLatitude(currLocationIdx), provider.getLongitude(currLocationIdx)); + float currY = tileBox.getPixYFromLatLon(provider.getLatitude(currLocationIdx), provider.getLongitude(currLocationIdx)); + if (tileBox.containsPoint(currX, currY, getContext().circleSize)) { + return true; + } else if (currLocationIdx + 1 >= provider.getSize()) { + return false; + } + float nextX = tileBox.getPixXFromLatLon(provider.getLatitude(currLocationIdx + 1), provider.getLongitude(currLocationIdx + 1)); + float nextY = tileBox.getPixXFromLatLon(provider.getLatitude(currLocationIdx + 1), provider.getLongitude(currLocationIdx + 1)); + return tileBox.containsPoint(nextX, nextY, getContext().circleSize); } private boolean segmentDataChanged(Map, RoadSegmentData> other) { @@ -169,6 +193,14 @@ public class MultiProfileGeometryWay extends GeometryWay { + private final String profileKey; @ColorInt private final int lineColor; @ColorInt @@ -198,9 +231,13 @@ public class MultiProfileGeometryWay extends GeometryWay profileIconsBitmapCache; - public MultiProfileGeometryWayContext(Context ctx, float density) { + public MultiProfileGeometryWayContext(Context ctx, UiUtilities iconsCache, float density) { super(ctx, density); + this.iconsCache = iconsCache; profileIconsBitmapCache = new HashMap<>(); + minIconMargin = density * 30; + circleSize = density * 70; } public void updatePaints(boolean nightMode, @NonNull RenderingLineAttributes multiProfileAttrs) { @@ -62,18 +73,24 @@ public class MultiProfileGeometryWayContext extends GeometryWayContext { } @NonNull - public Bitmap getProfileIconBitmap(@NonNull String profileKey, int profileColor) { - String key = profileKey + "_" + profileColor; + public Bitmap getProfileIconBitmap(String profileKey, @DrawableRes int iconRes, @ColorInt int color) { + String key = profileKey + "_" + iconRes + "_" + color; Bitmap bitmap = profileIconsBitmapCache.get(key); if (bitmap == null) { - float density = getDensity(); - float diameter = density * 18; - bitmap = Bitmap.createBitmap((int) diameter, (int) diameter, Bitmap.Config.ARGB_8888); - + bitmap = Bitmap.createBitmap((int) circleSize, (int) circleSize, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); - canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, multiProfileAttrs.paint_1); - multiProfileAttrs.paint3.setColor(profileColor); - canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, multiProfileAttrs.paint3); + float center = bitmap.getWidth() / 2f; + + canvas.drawCircle(center, center, center / 2, multiProfileAttrs.paint_1); + multiProfileAttrs.paint3.setColor(color); + canvas.drawCircle(center, center, center / 2, multiProfileAttrs.paint3); + + float iconSize = center - getDensity() * 10; + Bitmap profileIconBitmap = AndroidUtils.createScaledBitmap( + iconsCache.getPaintedIcon(iconRes, color), (int) iconSize, (int) iconSize); + canvas.drawBitmap(profileIconBitmap, center - iconSize / 2, center - iconSize / 2, multiProfileAttrs.paint3); + + profileIconsBitmapCache.put(key, bitmap); } return bitmap; } diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java index 5d8120f1c2..6e947a26a3 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java @@ -3,9 +3,11 @@ package net.osmand.plus.views.layers.geometry; import android.graphics.Canvas; import android.graphics.Path; +import net.osmand.data.RotatedTileBox; +import net.osmand.plus.views.OsmandMapLayer.RenderingLineAttributes; import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay.GeometryMultiProfileWayStyle; -import net.osmand.plus.views.OsmandMapLayer.RenderingLineAttributes; +import java.util.List; public class MultiProfileGeometryWayDrawer extends GeometryWayDrawer { @@ -22,6 +24,23 @@ public class MultiProfileGeometryWayDrawer extends GeometryWayDrawer tx, List ty, List angles, List distances, double distPixToFinish, List> styles) { + MultiProfileGeometryWayContext context = getContext(); + GeometryMultiProfileWayStyle style = null; + + for (int i = 0; i < styles.size(); i++) { + if (styles.get(i) != null && !styles.get(i).equals(style)) { + style = (GeometryMultiProfileWayStyle) styles.get(i); + double lat = style.getIconLat(); + double lon = style.getIconLon(); + float x = tb.getPixXFromLatLon(lat, lon) - context.circleSize / 2; + float y = tb.getPixYFromLatLon(lat, lon) - context.circleSize / 2; + canvas.drawBitmap(style.getPointBitmap(), x, y, null); + } + } + } + public void drawPathBorder(Canvas canvas, Path path, GeometryWayStyle style) { if (style instanceof GeometryMultiProfileWayStyle) { RenderingLineAttributes attrs = getContext().getAttrs(); From 14209dbd015e67d4efabccfe751f84ca9d18c393 Mon Sep 17 00:00:00 2001 From: cepprice Date: Fri, 2 Apr 2021 01:26:38 +0500 Subject: [PATCH 3/9] Support multiple segments --- .../measurementtool/MeasurementToolLayer.java | 13 +- .../geometry/MultiProfileGeometryWay.java | 150 ++++++++++-------- .../MultiProfileGeometryWayContext.java | 4 +- .../MultiProfileGeometryWayDrawer.java | 8 +- 4 files changed, 95 insertions(+), 80 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java index 4ed8aa719a..b630233137 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java @@ -219,14 +219,11 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL if (editingCtx.isInMultiProfileMode()) { multiProfileGeometryWayContext.updatePaints(settings.isNightMode(), multiProfileLineAttrs); - for (int i = 0; i < editingCtx.getBeforeSegments().size(); i++) { - multiProfileGeometry.updateRoute(tb, editingCtx.getRoadSegmentData(), true, editingCtx.getBeforeSegments(), i); - multiProfileGeometry.drawSegments(canvas, tb); - } - for (int i = 0; i < editingCtx.getAfterSegments().size(); i++) { - multiProfileGeometry.updateRoute(tb, editingCtx.getRoadSegmentData(), false, editingCtx.getAfterSegments(), i); - multiProfileGeometry.drawSegments(canvas, tb); - } + List allSegments = new ArrayList<>(); + allSegments.addAll(editingCtx.getBeforeSegments()); + allSegments.addAll(editingCtx.getAfterSegments()); + multiProfileGeometry.updateRoute(tb, editingCtx.getRoadSegmentData(), allSegments); + multiProfileGeometry.drawSegments(canvas, tb); } else { multiProfileGeometry.clearWay(); List before = editingCtx.getBeforeTrkSegmentLine(); diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java index 865e56e60b..5096cfa59f 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java @@ -36,8 +36,7 @@ public class MultiProfileGeometryWay extends GeometryWay, RoadSegmentData> segmentData; - private List beforeSegments; - private List afterSegments; + private List segments; public MultiProfileGeometryWay(MultiProfileGeometryWayContext context) { super(context, new MultiProfileGeometryWayDrawer(context)); @@ -60,8 +59,10 @@ public class MultiProfileGeometryWay extends GeometryWay> currPathStyle = pathStyles.get(i); - getDrawer().drawPathBorder(canvas, currPathStyle.first, currPathStyle.second); - getDrawer().drawPath(canvas, currPathStyle.first, currPathStyle.second); + if (!((GeometryMultiProfileWayStyle) currPathStyle.second).isGap) { + getDrawer().drawPathBorder(canvas, currPathStyle.first, currPathStyle.second); + getDrawer().drawPath(canvas, currPathStyle.first, currPathStyle.second); + } } getDrawer().drawArrowsOverPath(canvas, tb, tx, ty, angles, distances, distToFinish, styles); } finally { @@ -69,20 +70,18 @@ public class MultiProfileGeometryWay extends GeometryWay, RoadSegmentData> segmentData, - boolean before, List segments, int segmentIdx) { + public void updateRoute(RotatedTileBox tileBox, Map, RoadSegmentData> segmentData, List segments) { boolean shouldUpdateRoute = tileBox.getMapDensity() != getMapDensity() || segmentDataChanged(segmentData) - || getSegments(before) != segments || getLocationProvider() == null; + || this.segments != segments || getLocationProvider() == null; if (shouldUpdateRoute) { this.segmentData = segmentData; - setSegments(before, segments); - List userPoints = segments.get(segmentIdx).points; + this.segments = segments; List locations; Map> styleMap; List ways = new ArrayList<>(); List> styles = new ArrayList<>(); - setStyles(tileBox, userPoints, ways, styles); + setStyles(tileBox, segments, ways, styles); locations = new ArrayList<>(); styleMap = new TreeMap<>(); @@ -105,51 +104,72 @@ public class MultiProfileGeometryWay extends GeometryWay userPoints, List ways, List> styles) { - MultiProfileGeometryWayContext context = getContext(); + @Override + public void clearWay() { + super.clearWay(); + if (segmentData != null) { + segmentData.clear(); + } + } + + private void setStyles(RotatedTileBox tileBox, List segments, List ways, List> styles) { Path path = new Path(); PathMeasure pathMeasure = new PathMeasure(); - for (int i = 0; i < userPoints.size() - 1; i++) { - WptPt leftPt = userPoints.get(i); - Pair userLine = new Pair<>(leftPt, userPoints.get(i + 1)); - RoadSegmentData routeBetweenPoints = segmentData.get(userLine); - + for (TrkSegment segment : segments) { + List points = segment.points; + for (int i = 0; i < points.size() - 1; i++) { + setStylesInternal(tileBox, points, i, ways, styles, path, pathMeasure); + } + styles.add(new GeometryMultiProfileWayStyle(getContext(), 0, 0, true)); Way way = new Way(-1); - String currProfileKey = getProfileKey(leftPt); - Pair profileData = getProfileData(currProfileKey); - GeometryMultiProfileWayStyle style = new GeometryMultiProfileWayStyle( - getContext(), currProfileKey, profileData.first, profileData.second); - styles.add(style); + WptPt last = points.get(points.size() - 1); + way.addNode(new Node(last.lat, last.lon, -1)); ways.add(way); + } + } - path.reset(); - boolean isSecondToLast = i + 2 == userPoints.size(); - if (routeBetweenPoints == null || Algorithms.isEmpty(routeBetweenPoints.getPoints())) { - way.addNode(new Node(userLine.first.lat, userLine.first.lon, -1)); - if (isSecondToLast) { - 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); - } - } + private void setStylesInternal(RotatedTileBox tileBox, List points, int idx, List ways, + List> styles, Path path, PathMeasure pathMeasure) { + MultiProfileGeometryWayContext context = getContext(); + WptPt leftPt = points.get(idx); + Pair userLine = new Pair<>(leftPt, points.get(idx + 1)); + RoadSegmentData routeBetweenPoints = segmentData.get(userLine); + boolean isSecondToLast = idx + 2 == points.size(); - float[] xy = new float[2]; - pathMeasure.setPath(path, false); - float routeLength = pathMeasure.getLength(); - if ((routeLength - context.circleSize) / 2 >= context.minIconMargin) { - pathMeasure.getPosTan(pathMeasure.getLength() * 0.5f, xy, null); - style.setIconLat(tileBox.getLatFromPixel(xy[0], xy[1])); - style.setIconLon(tileBox.getLonFromPixel(xy[0], xy[1])); + Way way = new Way(-1); + String currProfileKey = getProfileKey(leftPt); + Pair profileData = getProfileData(currProfileKey); + GeometryMultiProfileWayStyle style = new GeometryMultiProfileWayStyle( + getContext(), profileData.first, profileData.second); + styles.add(style); + ways.add(way); + + path.reset(); + if (routeBetweenPoints == null || Algorithms.isEmpty(routeBetweenPoints.getPoints())) { + way.addNode(new Node(userLine.first.lat, userLine.first.lon, -1)); + if (isSecondToLast) { + 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]; + pathMeasure.setPath(path, false); + float routeLength = pathMeasure.getLength(); + if ((routeLength - context.circleSize) / 2 >= context.minIconMargin) { + pathMeasure.getPosTan(pathMeasure.getLength() * 0.5f, xy, null); + style.setIconLat(tileBox.getLatFromPixel(xy[0], xy[1])); + style.setIconLon(tileBox.getLonFromPixel(xy[0], xy[1])); } } @@ -181,18 +201,6 @@ public class MultiProfileGeometryWay extends GeometryWay segments) { - if (before) { - this.beforeSegments = segments; - } else { - this.afterSegments = segments; - } - } - - private List getSegments(boolean before) { - return before ? this.beforeSegments : this.afterSegments; - } - private void movePathToWpt(Path path, RotatedTileBox tileBox, WptPt pt) { path.moveTo(tileBox.getPixXFromLatLon(pt.lat, pt.lon), tileBox.getPixYFromLatLon(pt.lat, pt.lon)); } @@ -221,9 +229,8 @@ public class MultiProfileGeometryWay extends GeometryWay { + public static class GeometryMultiProfileWayStyle extends GeometryWayStyle { - private final String profileKey; @ColorInt private final int lineColor; @ColorInt @@ -231,16 +238,25 @@ public class MultiProfileGeometryWay extends GeometryWay Date: Fri, 2 Apr 2021 01:51:28 +0500 Subject: [PATCH 4/9] Change user point icons for multi profile mode --- .../measurementtool/MeasurementToolLayer.java | 41 +++++++++---------- .../MultiProfileGeometryWayContext.java | 13 +++--- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java index b630233137..90ebcfda36 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java @@ -271,10 +271,10 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL List beforePoints = editingCtx.getBeforePoints(); List afterPoints = editingCtx.getAfterPoints(); if (beforePoints.size() > 0) { - drawPointIcon(canvas, tb, beforePoints.get(beforePoints.size() - 1)); + drawPointIcon(canvas, tb, beforePoints.get(beforePoints.size() - 1), true); } if (afterPoints.size() > 0) { - drawPointIcon(canvas, tb, afterPoints.get(0)); + drawPointIcon(canvas, tb, afterPoints.get(0), true); } if (editingCtx.getSelectedPointPosition() != -1) { @@ -321,25 +321,13 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL } if (overlapped) { WptPt pt = points.get(0); - if (pt != lastBeforePoint && pt != firstAfterPoint && isInTileBox(tb, pt)) { - float locX = tb.getPixXFromLatLon(pt.lat, pt.lon); - float locY = tb.getPixYFromLatLon(pt.lat, pt.lon); - canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint); - } + drawPointIcon(canvas, tb, pt, false); pt = points.get(points.size() - 1); - if (pt != lastBeforePoint && pt != firstAfterPoint && isInTileBox(tb, pt)) { - float locX = tb.getPixXFromLatLon(pt.lat, pt.lon); - float locY = tb.getPixYFromLatLon(pt.lat, pt.lon); - canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint); - } + drawPointIcon(canvas, tb, pt, false); } else { for (int i = 0; i < points.size(); i++) { WptPt pt = points.get(i); - if (pt != lastBeforePoint && pt != firstAfterPoint && isInTileBox(tb, pt)) { - float locX = tb.getPixXFromLatLon(pt.lat, pt.lon); - float locY = tb.getPixYFromLatLon(pt.lat, pt.lon); - canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint); - } + drawPointIcon(canvas, tb, pt, false); } } @@ -404,14 +392,23 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); } - private void drawPointIcon(Canvas canvas, RotatedTileBox tb, WptPt pt) { - canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); + private void drawPointIcon(Canvas canvas, RotatedTileBox tb, WptPt pt, boolean rotate) { + if (rotate) { + canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); + } float locX = tb.getPixXFromLatLon(pt.lat, pt.lon); float locY = tb.getPixYFromLatLon(pt.lat, pt.lon); - if (tb.containsPoint(locX, locY, 0)) { - canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint); + if (editingCtx.isInMultiProfileMode()) { + canvas.drawBitmap(multiProfileGeometryWayContext.getPointIcon(), locX - multiProfileGeometryWayContext.pointIconSize / 2, + locY - multiProfileGeometryWayContext.pointIconSize / 2, bitmapPaint); + } else { + if (tb.containsPoint(locX, locY, 0)) { + canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint); + } + } + if (rotate) { + canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); } - canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); } public WptPt addCenterPoint(boolean addPointBefore) { diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java index 3866611c92..555194ba87 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java @@ -24,6 +24,7 @@ public class MultiProfileGeometryWayContext extends GeometryWayContext { public final float minIconMargin; public final float circleSize; + public final float pointIconSize; private RenderingLineAttributes multiProfileAttrs; @@ -36,6 +37,7 @@ public class MultiProfileGeometryWayContext extends GeometryWayContext { profileIconsBitmapCache = new HashMap<>(); minIconMargin = density * 30; circleSize = density * 70; + pointIconSize = density * 22f; } public void updatePaints(boolean nightMode, @NonNull RenderingLineAttributes multiProfileAttrs) { @@ -46,13 +48,12 @@ public class MultiProfileGeometryWayContext extends GeometryWayContext { @Override protected void recreateBitmaps() { float density = getDensity(); - float size = density * 12.5f; - float outerRadius = density * 6.25f; - float centerRadius = density * 6; - float innerRadius = density * 4; - float centerXY = size / 2; + float outerRadius = density * 11f; + float centerRadius = density * 10.5f; + float innerRadius = density * 6.5f; + float centerXY = pointIconSize / 2; - pointIcon = Bitmap.createBitmap((int) size, (int) size, Bitmap.Config.ARGB_8888); + pointIcon = Bitmap.createBitmap((int) pointIconSize, (int) pointIconSize, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(pointIcon); Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); From 4d9d1fd18fe5d1bcabaa8cc9ba339ff142d50eac Mon Sep 17 00:00:00 2001 From: cepprice Date: Sun, 4 Apr 2021 18:25:53 +0500 Subject: [PATCH 5/9] Fix route saving --- .../measurementtool/MeasurementToolLayer.java | 5 +---- .../geometry/MultiProfileGeometryWay.java | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java index 90ebcfda36..9d3f8812c4 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementToolLayer.java @@ -219,10 +219,7 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL if (editingCtx.isInMultiProfileMode()) { multiProfileGeometryWayContext.updatePaints(settings.isNightMode(), multiProfileLineAttrs); - List allSegments = new ArrayList<>(); - allSegments.addAll(editingCtx.getBeforeSegments()); - allSegments.addAll(editingCtx.getAfterSegments()); - multiProfileGeometry.updateRoute(tb, editingCtx.getRoadSegmentData(), allSegments); + multiProfileGeometry.updateRoute(tb, editingCtx.getRoadSegmentData(), editingCtx.getBeforeSegments(), editingCtx.getAfterSegments()); multiProfileGeometry.drawSegments(canvas, tb); } else { multiProfileGeometry.clearWay(); diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java index 5096cfa59f..c2d98d7a54 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java @@ -5,6 +5,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Path; import android.graphics.PathMeasure; +import android.util.Log; import android.util.Pair; import net.osmand.GPXUtilities.TrkSegment; @@ -36,7 +37,8 @@ public class MultiProfileGeometryWay extends GeometryWay, RoadSegmentData> segmentData; - private List segments; + private List beforeSegments; + private List afterSegments; public MultiProfileGeometryWay(MultiProfileGeometryWayContext context) { super(context, new MultiProfileGeometryWayDrawer(context)); @@ -70,20 +72,26 @@ public class MultiProfileGeometryWay extends GeometryWay, RoadSegmentData> segmentData, List segments) { + public void updateRoute(RotatedTileBox tileBox, Map, RoadSegmentData> segmentData, + List beforeSegments, List afterSegments) { boolean shouldUpdateRoute = tileBox.getMapDensity() != getMapDensity() || segmentDataChanged(segmentData) - || this.segments != segments || getLocationProvider() == null; + || this.beforeSegments != beforeSegments || this.afterSegments != afterSegments || getLocationProvider() == null; if (shouldUpdateRoute) { this.segmentData = segmentData; - this.segments = segments; + this.beforeSegments = beforeSegments; + this.afterSegments = afterSegments; + List locations; Map> styleMap; - List ways = new ArrayList<>(); List> styles = new ArrayList<>(); - setStyles(tileBox, segments, ways, styles); locations = new ArrayList<>(); + List allSegments = new ArrayList<>(); + allSegments.addAll(beforeSegments); + allSegments.addAll(afterSegments); + setStyles(tileBox, allSegments, ways, styles); + styleMap = new TreeMap<>(); int i = 0; int k = 0; From eb4a1108f8a346448d1bdf636a54981fff40a9ab Mon Sep 17 00:00:00 2001 From: cepprice Date: Mon, 5 Apr 2021 11:44:55 +0500 Subject: [PATCH 6/9] Review fixes --- .../MeasurementEditingContext.java | 29 ++++++++++++++++--- .../views/layers/geometry/GeometryWay.java | 12 ++++++-- .../layers/geometry/GeometryWayContext.java | 3 +- .../geometry/MultiProfileGeometryWay.java | 28 ++++-------------- .../MultiProfileGeometryWayContext.java | 15 ++++++---- .../MultiProfileGeometryWayDrawer.java | 12 +++----- 6 files changed, 54 insertions(+), 45 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java index bda7c5404b..ba28e9402a 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java @@ -2,9 +2,6 @@ package net.osmand.plus.measurementtool; import android.util.Pair; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - import net.osmand.GPXUtilities.GPXFile; import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; @@ -38,12 +35,18 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import static net.osmand.plus.measurementtool.MeasurementEditingContext.CalculationMode.NEXT_SEGMENT; import static net.osmand.plus.measurementtool.MeasurementEditingContext.CalculationMode.WHOLE_TRACK; import static net.osmand.plus.measurementtool.command.MeasurementModeCommand.MeasurementCommandType.APPROXIMATE_POINTS; @@ -1112,7 +1115,25 @@ public class MeasurementEditingContext implements IRouteSettingsListener { } public boolean isInMultiProfileMode() { - return lastCalculationMode == CalculationMode.NEXT_SEGMENT; + if (lastCalculationMode == CalculationMode.NEXT_SEGMENT) { + return true; + } + Set profiles = new HashSet<>(); + List segments = new ArrayList<>(); + segments.addAll(beforeSegments); + segments.addAll(afterSegments); + for (TrkSegment segment : segments) { + if (Algorithms.isEmpty(segment.points)) { + continue; + } + for (WptPt pt : segment.points) { + if (!pt.isGap()) { + profiles.add(pt.getProfileType()); + } + } + } + lastCalculationMode = profiles.size() >= 2 ? NEXT_SEGMENT : WHOLE_TRACK; + return profiles.size() >= 2; } @Override diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java index 9489cd9620..d5f206ec90 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java @@ -11,6 +11,8 @@ import net.osmand.Location; import net.osmand.data.RotatedTileBox; import net.osmand.util.MapAlgorithms; import net.osmand.util.MapUtils; +import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay.GeometryMultiProfileWayStyle; + import java.util.ArrayList; import java.util.Collections; @@ -188,7 +190,9 @@ public abstract class GeometryWay prevStyle = style instanceof GeometryMultiProfileWayStyle ? + getStyle(i - 1, style) : style; + addLocation(tb, prevLat, prevLon, prevStyle, tx, ty, angles, distances, dist, styles); // first point } } addLocation(tb, lat, lon, style, tx, ty, angles, distances, dist, styles); @@ -360,7 +364,7 @@ public abstract class GeometryWay>> paths = new ArrayList<>(); canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); - calculatePath(tb, tx, ty, 0, styles, paths); + calculatePath(tb, tx, ty, getOutMargin(), styles, paths); for (Pair> pc : paths) { GeometryWayStyle style = pc.second; if (style.hasPathLine()) { @@ -377,6 +381,10 @@ public abstract class GeometryWay tx, List ty, List angles, List distances, double distToFinish, List> styles) { - if (tx.size() < 2) { - return; - } - try { - List>> pathStyles = new ArrayList<>(); - canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); - calculatePath(tb, tx, ty, getContext().circleSize, styles, pathStyles); - - for (int i = 0; i < pathStyles.size(); i++) { - Pair> currPathStyle = pathStyles.get(i); - if (!((GeometryMultiProfileWayStyle) currPathStyle.second).isGap) { - getDrawer().drawPathBorder(canvas, currPathStyle.first, currPathStyle.second); - getDrawer().drawPath(canvas, currPathStyle.first, currPathStyle.second); - } - } - getDrawer().drawArrowsOverPath(canvas, tb, tx, ty, angles, distances, distToFinish, styles); - } finally { - canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); - } - } - public void updateRoute(RotatedTileBox tileBox, Map, RoadSegmentData> segmentData, List beforeSegments, List afterSegments) { boolean shouldUpdateRoute = tileBox.getMapDensity() != getMapDensity() || segmentDataChanged(segmentData) @@ -231,6 +208,11 @@ public class MultiProfileGeometryWay extends GeometryWay(mode.getProfileColor(night), mode.getIconRes()); } + @Override + protected float getOutMargin() { + return getContext().getAttrs().paint.getStrokeWidth() * 2; + } + @NonNull @Override public GeometryWayStyle getDefaultWayStyle() { diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java index 555194ba87..d6ef3cfa72 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayContext.java @@ -7,6 +7,7 @@ import android.graphics.Color; import android.graphics.Paint; import net.osmand.AndroidUtils; +import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.views.OsmandMapLayer.RenderingLineAttributes; import net.osmand.util.Algorithms; @@ -26,6 +27,8 @@ public class MultiProfileGeometryWayContext extends GeometryWayContext { public final float circleSize; public final float pointIconSize; + private static final String pointColorHex = "#637EFB"; + private RenderingLineAttributes multiProfileAttrs; private Bitmap pointIcon; @@ -64,15 +67,10 @@ public class MultiProfileGeometryWayContext extends GeometryWayContext { paint.setColor(Color.WHITE); canvas.drawCircle(centerXY, centerXY, centerRadius, paint); - paint.setColor(Algorithms.parseColor("#637EFB")); + paint.setColor(Algorithms.parseColor(pointColorHex)); canvas.drawCircle(centerXY, centerXY, innerRadius, paint); } - @Override - protected int getArrowBitmapResId() { - return 0; - } - @NonNull public Bitmap getProfileIconBitmap(@DrawableRes int iconRes, @ColorInt int color) { String key = iconRes + "_" + color; @@ -100,4 +98,9 @@ public class MultiProfileGeometryWayContext extends GeometryWayContext { public Bitmap getPointIcon() { return pointIcon; } + + @Override + protected int getArrowBitmapResId() { + return R.drawable.ic_action_split_interval; + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java index 7bc5620d18..52fed039ac 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java @@ -19,6 +19,10 @@ public class MultiProfileGeometryWayDrawer extends GeometryWayDrawer style) { if (style instanceof GeometryMultiProfileWayStyle) { RenderingLineAttributes attrs = getContext().getAttrs(); + + attrs.paint.setColor(((GeometryMultiProfileWayStyle) style).getBorderColor()); + canvas.drawPath(path, attrs.paint); + attrs.paint2.setColor(((GeometryMultiProfileWayStyle) style).getLineColor()); canvas.drawPath(path, attrs.paint2); } @@ -42,12 +46,4 @@ public class MultiProfileGeometryWayDrawer extends GeometryWayDrawer style) { - if (style instanceof GeometryMultiProfileWayStyle) { - RenderingLineAttributes attrs = getContext().getAttrs(); - attrs.paint.setColor(((GeometryMultiProfileWayStyle) style).getBorderColor()); - canvas.drawPath(path, attrs.paint); - } - } } \ No newline at end of file From 34f3474f1293b54a2511a77750d09e355ebc7798 Mon Sep 17 00:00:00 2001 From: cepprice Date: Mon, 5 Apr 2021 13:59:22 +0500 Subject: [PATCH 7/9] Fix profile icons placing --- .../geometry/MultiProfileGeometryWay.java | 103 +++++++----------- .../MultiProfileGeometryWayDrawer.java | 47 +++++++- 2 files changed, 79 insertions(+), 71 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java index eda20443e8..fa5f648217 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWay.java @@ -3,14 +3,12 @@ package net.osmand.plus.views.layers.geometry; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.Path; -import android.graphics.PathMeasure; -import android.util.Log; import android.util.Pair; import net.osmand.GPXUtilities.TrkSegment; import net.osmand.GPXUtilities.WptPt; import net.osmand.Location; +import net.osmand.data.LatLon; import net.osmand.data.QuadRect; import net.osmand.data.RotatedTileBox; import net.osmand.osm.edit.Node; @@ -67,7 +65,7 @@ public class MultiProfileGeometryWay extends GeometryWay allSegments = new ArrayList<>(); allSegments.addAll(beforeSegments); allSegments.addAll(afterSegments); - setStyles(tileBox, allSegments, ways, styles); + setStyles(allSegments, ways, styles); styleMap = new TreeMap<>(); int i = 0; @@ -97,16 +95,13 @@ public class MultiProfileGeometryWay extends GeometryWay segments, List ways, List> styles) { - Path path = new Path(); - PathMeasure pathMeasure = new PathMeasure(); - + private void setStyles(List segments, List ways, List> styles) { for (TrkSegment segment : segments) { List points = segment.points; 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(), 0, 0, true)); Way way = new Way(-1); WptPt last = points.get(points.size() - 1); way.addNode(new Node(last.lat, last.lon, -1)); @@ -114,48 +109,42 @@ public class MultiProfileGeometryWay extends GeometryWay points, int idx, List ways, - List> styles, Path path, PathMeasure pathMeasure) { - MultiProfileGeometryWayContext context = getContext(); - WptPt leftPt = points.get(idx); - Pair userLine = new Pair<>(leftPt, points.get(idx + 1)); - RoadSegmentData routeBetweenPoints = segmentData.get(userLine); + private void setStylesInternal(List points, int idx, List ways, List> styles) { + WptPt startPt = points.get(idx); + WptPt endPt = points.get(idx + 1); + List routePoints = getRoutePoints(startPt, endPt); boolean isSecondToLast = idx + 2 == points.size(); Way way = new Way(-1); - String currProfileKey = getProfileKey(leftPt); + String currProfileKey = getProfileKey(startPt); Pair profileData = getProfileData(currProfileKey); GeometryMultiProfileWayStyle style = new GeometryMultiProfileWayStyle( - getContext(), profileData.first, profileData.second); + getContext(), routePoints, profileData.first, profileData.second); styles.add(style); ways.add(way); - path.reset(); - if (routeBetweenPoints == null || Algorithms.isEmpty(routeBetweenPoints.getPoints())) { - way.addNode(new Node(userLine.first.lat, userLine.first.lon, -1)); - if (isSecondToLast) { - 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); + for (LatLon routePt : routePoints) { + if (isSecondToLast || routePt.getLatitude() != endPt.getLatitude() + && routePt.getLongitude() != endPt.getLongitude()) { + way.addNode(new Node(routePt.getLatitude(), routePt.getLongitude(), -1)); } } + } - float[] xy = new float[2]; - pathMeasure.setPath(path, false); - float routeLength = pathMeasure.getLength(); - if ((routeLength - context.circleSize) / 2 >= context.minIconMargin) { - pathMeasure.getPosTan(pathMeasure.getLength() * 0.5f, xy, null); - style.setIconLat(tileBox.getLatFromPixel(xy[0], xy[1])); - style.setIconLon(tileBox.getLonFromPixel(xy[0], xy[1])); + private List getRoutePoints(WptPt start, WptPt end) { + Pair userLine = new Pair<>(start, end); + RoadSegmentData roadSegmentData = segmentData.get(userLine); + List routePoints = new ArrayList<>(); + + if (roadSegmentData == null || Algorithms.isEmpty(roadSegmentData.getPoints())) { + 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 @@ -186,14 +175,6 @@ public class MultiProfileGeometryWay extends GeometryWay routePoints; - public GeometryMultiProfileWayStyle(MultiProfileGeometryWayContext context, + public GeometryMultiProfileWayStyle(MultiProfileGeometryWayContext context, List routePoints, @ColorInt int profileColor, @DrawableRes int profileIconRes, boolean isGap) { super(context); + this.routePoints = routePoints; this.lineColor = profileColor; this.borderColor = ColorUtils.blendARGB(profileColor, Color.BLACK, 0.2f); this.profileIconRes = profileIconRes; @@ -244,9 +225,9 @@ public class MultiProfileGeometryWay extends GeometryWay routePoints, @ColorInt int profileColor, @DrawableRes int profileIconRes) { - this(context, profileColor, profileIconRes, false); + this(context, routePoints, profileColor, profileIconRes, false); } @ColorInt @@ -264,20 +245,12 @@ public class MultiProfileGeometryWay extends GeometryWay getRoutePoints() { + return routePoints; } - public void setIconLon(double lon) { - iconLon = lon; - } - - public double getIconLat() { - return iconLat; - } - - public double getIconLon() { - return iconLon; + public boolean isGap() { + return isGap; } @Override diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java index 52fed039ac..b0c7e7c369 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java @@ -2,10 +2,14 @@ package net.osmand.plus.views.layers.geometry; import android.graphics.Canvas; 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.plus.views.OsmandMapLayer.RenderingLineAttributes; import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay.GeometryMultiProfileWayStyle; +import net.osmand.util.Algorithms; import java.util.List; @@ -30,20 +34,51 @@ public class MultiProfileGeometryWayDrawer extends GeometryWayDrawer tx, List ty, List angles, List distances, double distPixToFinish, List> styles) { + Path path = new Path(); + PathMeasure pathMeasure = new PathMeasure(); MultiProfileGeometryWayContext context = getContext(); GeometryMultiProfileWayStyle style = null; 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); - double lat = style.getIconLat(); - double lon = style.getIconLon(); - if (!Double.isNaN(lat) && !Double.isNaN(lon)) { - float x = tb.getPixXFromLatLon(lat, lon) - context.circleSize / 2; - float y = tb.getPixYFromLatLon(lat, lon) - context.circleSize / 2; + PointF center = getIconCenter(tb, style.getRoutePoints(), path, pathMeasure); + if (center != null && tb.containsPoint(center.x, center.y, context.circleSize)) { + float x = center.x - context.circleSize / 2; + float y = center.y - context.circleSize / 2; canvas.drawBitmap(style.getPointBitmap(), x, y, null); } } } } + + private PointF getIconCenter(RotatedTileBox tileBox, List 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())); + } } \ No newline at end of file From 0604374475cfa396da680cb60bc601eb55910c92 Mon Sep 17 00:00:00 2001 From: cepprice Date: Mon, 5 Apr 2021 14:21:00 +0500 Subject: [PATCH 8/9] Remove out margin --- .../views/layers/geometry/GeometryWay.java | 18 +++++------------- .../geometry/MultiProfileGeometryWay.java | 5 ----- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java index d5f206ec90..2538103ec0 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java @@ -265,20 +265,16 @@ public abstract class GeometryWay= lx && x <= rx && y >= ty && y <= by; } - public static boolean isIn(float x, float y, int lx, int ty, int rx, int by, float outMargin) { - return x >= lx - outMargin && x <= rx + outMargin && y >= ty - outMargin && y <= by + outMargin; - } - public static int calculatePath(RotatedTileBox tb, List xs, List ys, Path path) { List>> paths = new ArrayList<>(); - int res = calculatePath(tb, xs, ys, 0, null, paths); + int res = calculatePath(tb, xs, ys, null, paths); if (paths.size() > 0) { path.addPath(paths.get(0).first); } return res; } - public static int calculatePath(RotatedTileBox tb, List xs, List ys, float outMargin, List> styles, List>> paths) { + public static int calculatePath(RotatedTileBox tb, List xs, List ys, List> styles, List>> paths) { boolean segmentStarted = false; float prevX = xs.get(0); float prevY = ys.get(0); @@ -288,11 +284,11 @@ public abstract class GeometryWay style = hasStyles ? styles.get(0) : null; Path path = new Path(); - boolean prevIn = isIn(prevX, prevY, 0, 0, width, height, outMargin); + boolean prevIn = isIn(prevX, prevY, 0, 0, width, height); for (int i = 1; i < xs.size(); i++) { float currX = xs.get(i); float currY = ys.get(i); - boolean currIn = isIn(currX, currY, 0, 0, width, height, outMargin); + boolean currIn = isIn(currX, currY, 0, 0, width, height); boolean draw = false; if (prevIn && currIn) { draw = true; @@ -364,7 +360,7 @@ public abstract class GeometryWay>> paths = new ArrayList<>(); canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY()); - calculatePath(tb, tx, ty, getOutMargin(), styles, paths); + calculatePath(tb, tx, ty, styles, paths); for (Pair> pc : paths) { GeometryWayStyle style = pc.second; if (style.hasPathLine()) { @@ -381,10 +377,6 @@ public abstract class GeometryWay(mode.getProfileColor(night), mode.getIconRes()); } - @Override - protected float getOutMargin() { - return getContext().getAttrs().paint.getStrokeWidth() * 2; - } - @NonNull @Override public GeometryWayStyle getDefaultWayStyle() { From 7fd107c97aab309845e256faf0d36d62b4003400 Mon Sep 17 00:00:00 2001 From: cepprice Date: Mon, 5 Apr 2021 19:56:03 +0500 Subject: [PATCH 9/9] Review fixes --- .../MeasurementEditingContext.java | 20 ++++++++----------- .../views/layers/geometry/GeometryWay.java | 4 +--- .../MultiProfileGeometryWayDrawer.java | 2 +- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java index ba28e9402a..af4d599afa 100644 --- a/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java +++ b/OsmAnd/src/net/osmand/plus/measurementtool/MeasurementEditingContext.java @@ -1119,21 +1119,17 @@ public class MeasurementEditingContext implements IRouteSettingsListener { return true; } Set profiles = new HashSet<>(); - List segments = new ArrayList<>(); - segments.addAll(beforeSegments); - segments.addAll(afterSegments); - for (TrkSegment segment : segments) { - if (Algorithms.isEmpty(segment.points)) { - continue; - } - for (WptPt pt : segment.points) { - if (!pt.isGap()) { - profiles.add(pt.getProfileType()); + for (RoadSegmentData segmentData : roadSegmentData.values()) { + String profile = segmentData.getAppMode().getStringKey(); + if (!DEFAULT_APP_MODE.getStringKey().equals(profile)) { + profiles.add(profile); + if (profiles.size() >= 2) { + lastCalculationMode = NEXT_SEGMENT; + return true; } } } - lastCalculationMode = profiles.size() >= 2 ? NEXT_SEGMENT : WHOLE_TRACK; - return profiles.size() >= 2; + return false; } @Override diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java index 2538103ec0..ab98990d36 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/GeometryWay.java @@ -190,9 +190,7 @@ public abstract class GeometryWay prevStyle = style instanceof GeometryMultiProfileWayStyle ? - getStyle(i - 1, style) : style; - addLocation(tb, prevLat, prevLon, prevStyle, tx, ty, angles, distances, dist, styles); // first point + addLocation(tb, prevLat, prevLon, getStyle(i - 1, style), tx, ty, angles, distances, dist, styles); // first point } } addLocation(tb, lat, lon, style, tx, ty, angles, distances, dist, styles); diff --git a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java index b0c7e7c369..c9e5f8101f 100644 --- a/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java +++ b/OsmAnd/src/net/osmand/plus/views/layers/geometry/MultiProfileGeometryWayDrawer.java @@ -21,7 +21,7 @@ public class MultiProfileGeometryWayDrawer extends GeometryWayDrawer style) { - if (style instanceof GeometryMultiProfileWayStyle) { + if (style instanceof GeometryMultiProfileWayStyle && !((GeometryMultiProfileWayStyle) style).isGap()) { RenderingLineAttributes attrs = getContext().getAttrs(); attrs.paint.setColor(((GeometryMultiProfileWayStyle) style).getBorderColor());