package net.osmand.plus.osmedit; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PointF; import android.os.AsyncTask; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.widget.Toast; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.data.RotatedTileBox; import net.osmand.osm.edit.Node; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.views.ContextMenuLayer; import net.osmand.plus.views.OsmandMapLayer; import net.osmand.plus.views.OsmandMapTileView; import java.util.ArrayList; import java.util.List; public class OsmEditsLayer extends OsmandMapLayer implements ContextMenuLayer.IContextMenuProvider, ContextMenuLayer.IMoveObjectProvider { private static final int startZoom = 10; private final OsmEditingPlugin plugin; private final MapActivity activity; private final OpenstreetmapLocalUtil mOsmChangeUtil; private final OsmBugsLocalUtil mOsmBugsUtil; private Bitmap poi; private Bitmap bug; private OsmandMapTileView view; private Paint paintIcon; private ContextMenuLayer contextMenuLayer; public OsmEditsLayer(MapActivity activity, OsmEditingPlugin plugin) { this.activity = activity; this.plugin = plugin; mOsmChangeUtil = plugin.getPoiModificationLocalUtil(); mOsmBugsUtil = plugin.getOsmNotesLocalUtil(); } @Override public void initLayer(OsmandMapTileView view) { this.view = view; poi = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_pin_poi); bug = poi; paintIcon = new Paint(); contextMenuLayer = view.getLayerByClass(ContextMenuLayer.class); } @Override public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) { if (contextMenuLayer.getMoveableObject() instanceof OsmPoint) { OsmPoint objectInMotion = (OsmPoint) contextMenuLayer.getMoveableObject(); PointF pf = contextMenuLayer.getMovableCenterPoint(tileBox); drawPoint(canvas, objectInMotion, pf.x, pf.y); } } @Override public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) { if (tileBox.getZoom() >= startZoom) { List<LatLon> fullObjectsLatLon = new ArrayList<>(); drawPoints(canvas, tileBox, plugin.getDBBug().getOsmbugsPoints(), fullObjectsLatLon); drawPoints(canvas, tileBox, plugin.getDBPOI().getOpenstreetmapPoints(), fullObjectsLatLon); this.fullObjectsLatLon = fullObjectsLatLon; } } private void drawPoints(Canvas canvas, RotatedTileBox tileBox, List<? extends OsmPoint> objects, List<LatLon> fullObjectsLatLon) { for (OsmPoint o : objects) { if (contextMenuLayer.getMoveableObject() != o) { float x = tileBox.getPixXFromLatLon(o.getLatitude(), o.getLongitude()); float y = tileBox.getPixYFromLatLon(o.getLatitude(), o.getLongitude()); drawPoint(canvas, o, x, y); fullObjectsLatLon.add(new LatLon(o.getLatitude(), o.getLongitude())); } } } private void drawPoint(Canvas canvas, OsmPoint o, float x, float y) { Bitmap b; if (o.getGroup() == OsmPoint.Group.POI) { b = poi; } else if (o.getGroup() == OsmPoint.Group.BUG) { b = bug; } else { b = poi; } canvas.drawBitmap(b, x - b.getWidth() / 2, y - b.getHeight() / 2, paintIcon); } @Override public void destroyLayer() { } @Override public boolean drawInScreenPixels() { return true; } public void getOsmEditsFromPoint(PointF point, RotatedTileBox tileBox, List<? super OsmPoint> am) { int ex = (int) point.x; int ey = (int) point.y; int compare = getRadiusPoi(tileBox); int radius = compare * 3 / 2; compare = getFromPoint(tileBox, am, ex, ey, compare, radius, plugin.getDBBug().getOsmbugsPoints()); getFromPoint(tileBox, am, ex, ey, compare, radius, plugin.getDBPOI().getOpenstreetmapPoints()); } private int getFromPoint(RotatedTileBox tileBox, List<? super OsmPoint> am, int ex, int ey, int compare, int radius, List<? extends OsmPoint> pnts) { for (OsmPoint n : pnts) { int x = (int) tileBox.getPixXFromLatLon(n.getLatitude(), n.getLongitude()); int y = (int) tileBox.getPixYFromLatLon(n.getLatitude(), n.getLongitude()); if (calculateBelongs(ex, ey, x, y, compare)) { compare = radius; am.add(n); } } return compare; } private boolean calculateBelongs(int ex, int ey, int objx, int objy, int radius) { return Math.abs(objx - ex) <= radius && (ey - objy) <= radius / 2 && (objy - ey) <= 3 * radius; } public int getRadiusPoi(RotatedTileBox tb) { int r; if (tb.getZoom() < startZoom) { r = 0; } else { r = 15; } return (int) (r * tb.getDensity()); } @Override public boolean disableSingleTap() { return false; } @Override public boolean disableLongPressOnMap() { return false; } @Override public boolean isObjectClickable(Object o) { return o instanceof OsmPoint; } @Override public void collectObjectsFromPoint(PointF point, RotatedTileBox tileBox, List<Object> o) { if (tileBox.getZoom() >= startZoom) { getOsmEditsFromPoint(point, tileBox, o); } } @Override public LatLon getObjectLocation(Object o) { if (o instanceof OsmPoint) { return new LatLon(((OsmPoint) o).getLatitude(), ((OsmPoint) o).getLongitude()); } return null; } @Override public PointDescription getObjectName(Object o) { if (o instanceof OsmPoint) { OsmPoint point = (OsmPoint) o; String name = ""; String type = ""; if (point.getGroup() == OsmPoint.Group.POI) { name = ((OpenstreetmapPoint) point).getName(); type = PointDescription.POINT_TYPE_OSM_NOTE; } else if (point.getGroup() == OsmPoint.Group.BUG) { name = ((OsmNotesPoint) point).getText(); type = PointDescription.POINT_TYPE_OSM_BUG; } return new PointDescription(type, name); } return null; } @Override public boolean isObjectMovable(Object o) { return o instanceof OsmPoint; } @Override public void applyNewObjectPosition(@NonNull Object o, @NonNull LatLon position, @Nullable ContextMenuLayer.ApplyMovedObjectCallback callback) { if (o instanceof OsmPoint) { if (o instanceof OpenstreetmapPoint) { OpenstreetmapPoint objectInMotion = (OpenstreetmapPoint) o; Node node = objectInMotion.getEntity(); node.setLatitude(position.getLatitude()); node.setLongitude(position.getLongitude()); new SaveOsmChangeAsyncTask(mOsmChangeUtil, callback, objectInMotion).execute(); } else if (o instanceof OsmNotesPoint) { OsmNotesPoint objectInMotion = (OsmNotesPoint) o; objectInMotion.setLatitude(position.getLatitude()); objectInMotion.setLongitude(position.getLongitude()); new SaveOsmNoteAsyncTask(objectInMotion.getText(), activity, callback, plugin, mOsmBugsUtil) .execute(objectInMotion); } } } static class SaveOsmChangeAsyncTask extends AsyncTask<Void, Void, Node> { private final OpenstreetmapLocalUtil mOpenstreetmapUtil; @Nullable private final ContextMenuLayer.ApplyMovedObjectCallback mCallback; private final OpenstreetmapPoint objectInMotion; SaveOsmChangeAsyncTask(OpenstreetmapLocalUtil openstreetmapUtil, @Nullable ContextMenuLayer.ApplyMovedObjectCallback callback, OpenstreetmapPoint objectInMotion) { this.mOpenstreetmapUtil = openstreetmapUtil; this.mCallback = callback; this.objectInMotion = objectInMotion; } @Override protected Node doInBackground(Void... params) { Node node = objectInMotion.getEntity(); return mOpenstreetmapUtil.commitNodeImpl(objectInMotion.getAction(), node, mOpenstreetmapUtil.getEntityInfo(node.getId()), "", false); } @Override protected void onPostExecute(Node newNode) { if (mCallback != null) { mCallback.onApplyMovedObject(newNode != null, objectInMotion); } } } private static class SaveOsmNoteAsyncTask extends AsyncTask<OsmNotesPoint, Void, OsmNotesPoint> { private final String mText; private final MapActivity mActivity; @Nullable private final ContextMenuLayer.ApplyMovedObjectCallback mCallback; private final OsmEditingPlugin plugin; private OsmBugsUtil mOsmbugsUtil; public SaveOsmNoteAsyncTask(String text, MapActivity activity, @Nullable ContextMenuLayer.ApplyMovedObjectCallback callback, OsmEditingPlugin plugin, OsmBugsUtil osmbugsUtil) { mText = text; mActivity = activity; mCallback = callback; this.plugin = plugin; mOsmbugsUtil = osmbugsUtil; } @Override protected OsmNotesPoint doInBackground(OsmNotesPoint... params) { OsmNotesPoint mOsmNotesPoint = params[0]; OsmPoint.Action action = mOsmNotesPoint.getAction(); plugin.getDBBug().deleteAllBugModifications(mOsmNotesPoint); OsmBugsUtil.OsmBugResult result = mOsmbugsUtil.commit(mOsmNotesPoint, mText, action); return result == null ? null : result.local; } @Override protected void onPostExecute(OsmNotesPoint point) { if (point != null) { Toast.makeText(mActivity, R.string.osm_changes_added_to_local_edits, Toast.LENGTH_LONG).show(); } if (mCallback != null) { mCallback.onApplyMovedObject(point != null, point); } } } }