/** * Created by Nicholas Hallahan on 1/22/15. * nhallahan@spatialdev.com */ package com.spatialdev.osm.renderer; import android.graphics.Canvas; import android.graphics.PointF; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.geometry.BoundingBox; import com.mapbox.mapboxsdk.overlay.Icon; import com.mapbox.mapboxsdk.overlay.Overlay; import com.mapbox.mapboxsdk.views.MapView; import com.spatialdev.osm.marker.OSMMarker; import com.spatialdev.osm.model.JTSModel; import com.spatialdev.osm.model.OSMNode; import com.spatialdev.osm.model.OSMElement; import com.spatialdev.osm.model.OSMWay; import com.vividsolutions.jts.geom.Envelope; import java.util.ArrayList; import java.util.List; public class OSMOverlay extends Overlay { private static final int DEFAULT_OVERLAY_INDEX = 4; private JTSModel model; private Envelope envelope; private float minVectorRenderZoom = 0; private float zoom = 0; // current zoom of map private List<OSMNode> viewPortNodes = new ArrayList<>(); private boolean needToAddItemizedOverlay = true; /** * This should only be created by OSMMap. * * * * @param model */ public OSMOverlay(JTSModel model) { this.model = model; setOverlayIndex(DEFAULT_OVERLAY_INDEX); } /** * This should only be created by OSMMap. * * * * @param model * @param minVectorRenderZoom */ public OSMOverlay(JTSModel model, float minVectorRenderZoom) { this(model); this.minVectorRenderZoom = minVectorRenderZoom; } public void updateBoundingBox(BoundingBox bbox) { double x1 = bbox.getLonWest(); double x2 = bbox.getLonEast(); double y1 = bbox.getLatSouth(); double y2 = bbox.getLatNorth(); envelope = new Envelope(x1, x2, y1, y2); } /** * Have the map set the current zoom. * * * @param zoom */ public void updateZoom(float zoom) { this.zoom = zoom; } public List<OSMNode> getViewPortNodes() { return viewPortNodes; } @Override protected void draw(Canvas c, MapView mapView, boolean shadow) { // no shadow support & need a bounding box to query rtree & at or above min render zoom if (shadow || envelope == null || zoom < minVectorRenderZoom) { return; } List<OSMWay> polys = new ArrayList<>(); List<OSMWay> lines = new ArrayList<>(); // We want to always be referring to the same list so external sources // do not reference stale lists. viewPortNodes.clear(); List<OSMElement> viewPortElements = model.queryFromEnvelope(envelope); // Sort the elements into their geom types so we can draw // points on top of lines on top of polys. for (OSMElement el : viewPortElements) { if (el instanceof OSMWay) { OSMWay w = (OSMWay) el; if (w.isClosed()) { polys.add(w); } else { lines.add(w); } continue; } // If it isn't a Way, it's a Node. // We need to render the marker... renderMarker(mapView, (OSMNode) el); } // Draw polygons for (OSMWay w : polys) { w.getOSMPath(mapView).draw(c); } // Draw lines for (OSMWay w : lines) { w.getOSMPath(mapView).draw(c); } } private void renderMarker(MapView mapView, OSMNode node) { viewPortNodes.add(node); if (node.getMarker() == null) { OSMMarker marker = new OSMMarker(mapView, node); marker.setMarker(mapView.getContext().getResources().getDrawable(R.mipmap.maki_star_blue)); /** * Issue #81 * setMarker doesn't position bitmaps in the same way as setIcon. * By setting the anchor, we bring down the image slightly so that the marker * does indeed point to the point it refers to. */ PointF anchor = new PointF(0.5f, 0.8f); marker.setAnchor(anchor); mapView.addOSMMarker(this, marker); } else if (needToAddItemizedOverlay){ mapView.setDefaultOSMItemizedOverlay(this); needToAddItemizedOverlay = false; } } }