8

Ich muss Formen wie diejenigen, die Sie erstellen würden mit benutzerdefinierte Karten auf Google Maps, mit Android MapView zeichnen.Zeichnen von Formen in Android MapView unabhängig von der Zoomstufe

Mit anderen Worten, wenn ich eine Form auf der Karte zeichnen, wenn ich verkleinere, sollte es schrumpfen, den gleichen Bereich der Karte unabhängig von der Zoomstufe abdecken.

Beispiel nach der Android Referenz:

@Override 
    public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) 
    { 
     super.draw(canvas, mapView, shadow); 

     //---translate the GeoPoint to screen pixels--- 
     Point screenPts = new Point(); 
     mapView.getProjection().toPixels(p, screenPts); 

     Paint boxPaint = new Paint(); 
     boxPaint.setColor(android.graphics.Color.WHITE); 
     boxPaint.setStyle(Paint.Style.FILL); 
     boxPaint.setAlpha(140); 
     canvas.drawCircle(screenPts.x, screenPts.y, 20, boxPaint); 

     return true; 
    } 

Dies zeigt einen weißen Kreis auf der Karte, aber wenn Sie die Ansicht verkleinern, ist der Kreis die gleiche Größe. Vielleicht ist die Verwendung von Leinwand nicht richtig?

Ich brauche so etwas wie Google Maps Highlights Nachbarschaften oder Städte:

Google Map showing the search result for Lower East Side, New York

Irgendwelche Ideen? Danke im Voraus!

+0

beginnen mit Overlay-Hilfe Form zeichnen [Hier gehen Sie] (http://androidtrainningcenter.blogspot.in/2013/01/android-map-drawing-path- using-overlay.html) – Sameer

Antwort

2

Dies vielleicht, was Sie suchen: Can "overlay" size be zoomed together with the google map on android?

public class ImpactOverlay extends Overlay { 

private static int CIRCLERADIUS = 0; 
private GeoPoint geopoint; 

public ImpactOverlay(GeoPoint point, int myRadius) { 
    geopoint = point; 
    CIRCLERADIUS = myRadius; 
} 

@Override 
public void draw(Canvas canvas, MapView mapView, boolean shadow) { 
    // Transfrom geoposition to Point on canvas 
    Projection projection = mapView.getProjection(); 
    Point point = new Point(); 
    projection.toPixels(geopoint, point); 

    // the circle to mark the spot 
    Paint circle = new Paint(); 
    circle.setColor(Color.BLACK); 
    int myCircleRadius = metersToRadius(CIRCLERADIUS, mapView, (double)geopoint.getLatitudeE6()/1000000); 
    canvas.drawCircle(point.x, point.y, myCircleRadius, circle); 
} 

public static int metersToRadius(float meters, MapView map, double latitude) { 
    return (int) (map.getProjection().metersToEquatorPixels(meters) * (1/ Math.cos(Math.toRadians(latitude))));   
} 
} 
+0

Dies löst Kreis, was ist mit Polygon wie oben gezeigt http://i.stack.imgur.com/5goEw.png – ericlee

+0

Ich würde sagen, dass Google würde mehrere Rechtecke wiederholt im überdachten Bereich zeichnen. Sie zeichnen dann Strichlinien am äußeren Rand des Union-Bereichs. Das Zeichnen und Skalieren von Grafiken erfolgt über traditionelle Methoden. Dies ist jedoch nur meine Spekulation. Ich bin mir sicher, dass das Ganze viel komplizierter ist. Google hat alle Ortsangaben bezüglich dieser Adresse, wie Postleitzahl oder Stadt, usw. Es ist daher wahrscheinlich einfacher für sie, diese Informationen zu einem Objekt zu gruppieren und diese Informationen dann für die genaue Darstellung des Gebiets zu verwenden. Auch hier rate ich nur, wie das funktionieren soll. – RobGThai

+0

Ich finde, dass das Zeichnen dieser Kreise in der Kartenansicht das Scrollen der Karte wirklich verlangsamen kann, wenn Sie näher an die Form heranzoomen, und sobald der Kreis einen bestimmten Zoom erreicht, wird der Kreis verschwinden. Wie wird das normalerweise gehandhabt, wenn der Kreis nicht von der Karte verschwinden soll? – topwik

2

Was Sie brauchen eine Liste von lat/lon Punkte für jede Form, die Sie auf der Karte zeichnen möchten ist. In der OnDraw-Methode, müssen Sie über diese Liste iterieren (für jede Form, die Sie zeichnen mögen), und dies tun:

//---translate the GeoPoint to screen pixels--- 
    Point screenPts = new Point(); 
    mapView.getProjection().toPixels(p, screenPts); 

dann auf der Leinwand, um die Form zeichnen. IIRC, die unabhängig vom Zoom korrekt funktioniert, da die mapView die Zoomstufe kennt und Ihnen die geeignete Pixelposition für das lat/long-Paar bei dieser Zoomstufe zur Verfügung stellt.

+0

In der Tat, so weit ich weiß, führt die Projektion auf Pixel dazu, dass Zeichnungen unabhängig von Zoomstufen erscheinen. – tolgap

+0

Nun, Sie müssen nicht die Zoom-Ebene verwalten, die Projektion Mathematik weiß, wie mit der Zoomstufe umzugehen. – Travis

+0

@tolgap, Ihre Aussage über 'toPixels()' ist falsch. Es ist der Zweck, mit Zoomstufen umzugehen! @Travis beschreibt eine korrekte Antwort. Sie benötigen eine Beschreibung des Polygons, das Sie rendern möchten. Wenn diese Beschreibung eine Liste von Scheitelpunkten im Koordinatenraum lat/lon ist, müssen Sie diese nur in Pixel konvertieren und zeichnen. Die Projektion macht den Rest der Arbeit. – Gene

8

ich das gleiche Problem selbst hatte, hier ist eine vollständige Lösung mit Demo-Standorten:

import java.util.*; 

import android.graphics.*; 
import android.graphics.Paint.Style; 
import android.graphics.Region.Op; 
import android.os.Bundle; 

import com.google.android.maps.*; 

public class ShapeOverlayTest extends MapActivity { 
    private MapView m_map; 

    @Override 
    public void onCreate(final Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     m_map = (MapView) findViewById(R.id.mapview); 
     m_map.displayZoomControls(true); 
     m_map.setBuiltInZoomControls(true); 
    } 

    @Override 
    protected void onStart() { 
     super.onStart(); 

     Loc[][] areas = { 
      { 
      new Loc(51.51695436113811, -0.28686325139653757), 
      new Loc(51.5268179962453, -0.28118722558738923), 
      new Loc(51.526498459594215, -0.27779666308279755), 
      new Loc(51.52521530775356, -0.26943974607777654), 
      new Loc(51.52292555645698, -0.25813738590178786), 
      new Loc(51.52054465991048, -0.2498381618983569), 
      new Loc(51.51012230470141, -0.24509233633017083), 
      new Loc(51.50884762913046, -0.24465130560570497), 
      new Loc(51.50732063336974, -0.2441767643132881), 
      new Loc(51.50431624597833, -0.24473900326760137), 
      new Loc(51.49756328092904, -0.2714528238165076), 
      new Loc(51.50092541797557, -0.28360267232347336), 
      new Loc(51.50205958485736, -0.28490018935582045), 
      new Loc(51.50488447379555, -0.28681164237730944) 
      }, 
      { 
      new Loc(51.50368617913765, -0.25313579464343156), 
      new Loc(51.51978611305675, -0.24842567405905958), 
      new Loc(51.51039382684418, -0.24460628015366626), 
      new Loc(51.508792552597576, -0.24397604687682156), 
      new Loc(51.50713008309719, -0.24346350415674722), 
      new Loc(51.502411013302684, -0.2508501075008919), 
      new Loc(51.502377240039664, -0.25160073203846817), 
      new Loc(51.50274364303565, -0.25204783703705536) 
      }, 
      { 
      new Loc(51.49924084955314, -0.2858705706471945), 
      new Loc(51.50212820259818, -0.2791479893522646), 
      new Loc(51.49724510427319, -0.27427453152961206), 
      new Loc(51.49429724502515, -0.2799184038304611), 
      new Loc(51.494270969987404, -0.28180678948730314) 
      } 
     }; 
     String[] areaNames = { "W3 Ealing", "W3 Hammersmith & Fulham", "W3 Hounslow" }; 

     // for (Map.Entry<String, List<Loc>> area : m_areas.entrySet()) { 
     // // to have much less points and make sure they are in order 
     // // the demo data already has these properties 
     // // http://en.wikipedia.org/wiki/Gift_wrapping_algorithm#Pseudocode 
     // area.setValue(Algo.convexHull(area.getValue())); 
     // } 

     Map<String, List<GeoPoint>> areaMap = new HashMap<String, List<GeoPoint>>(); 
     for (int i = 0; i < areaNames.length; i++) { 
      List<GeoPoint> points = new ArrayList<GeoPoint>(); 
      for (int j = 0; j < areas[i].length; j++) { 
       points.add(areas[i][j].toGeoPoint()); 
      } 
      areaMap.put(areaNames[i], points); 
     } 
     m_map.getOverlays().add(new AreasOverlay(areaMap)); 

     // TODO determine location better, e.g. averaging area points 
     GeoPoint center = new GeoPoint(51509704, -270710); 
     m_map.getController().setCenter(center); 
     m_map.getController().setZoom(15); 
    } 

    @Override 
    protected boolean isRouteDisplayed() { 
     return false; 
    } 

    static class Loc { 
     private double m_lat; 
     private double m_lon; 

     public Loc(final double lat, final double lon) { 
      m_lat = lat; 
      m_lon = lon; 
     } 

     public GeoPoint toGeoPoint() { 
      return new GeoPoint((int) (m_lat * 1e6), (int) (m_lon * 1e6)); 
     } 
    }; 

    static class AreasOverlay extends Overlay { 
     private final Map<String, List<GeoPoint>> m_areas; 
     private final Paint m_paintFill; 
     private final Paint m_paintStroke; 
     private static final int ALPHA = 0x30ffffff; // 48 out of 255 transparent 
     private static final int[] COLORS = 
     { Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.RED, Color.GREEN, Color.BLUE }; 
     static { 
      for (int i = 0; i < AreasOverlay.COLORS.length; i++) { 
       AreasOverlay.COLORS[i] &= AreasOverlay.ALPHA; 
      } 
     } 

     public AreasOverlay(final Map<String, List<GeoPoint>> areaMap) { 
      m_areas = areaMap; 

      // prepare paints 
      m_paintFill = new Paint(); 
      m_paintFill.setStyle(Paint.Style.FILL); 
      m_paintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); 
      m_paintStroke.setStyle(Style.STROKE); 
      m_paintStroke.setAntiAlias(true); 
      m_paintStroke.setStrokeWidth(3); 
     } 

     @Override 
     public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) { 
      super.draw(canvas, mapView, shadow); 
      if (shadow) { 
       return; 
      } 
      Projection projection = mapView.getProjection(); 

      List<Path> areaPaths = getPaths(projection, m_areas); 
      drawPaths(canvas, areaPaths); 
     } 

     private List<Path> getPaths(final Projection projection, final Map<String, List<GeoPoint>> areas) { 
      List<Path> areaPaths = new ArrayList<Path>(areas.size()); 
      for (Map.Entry<String, List<GeoPoint>> entry : areas.entrySet()) { 
       List<GeoPoint> sourceList = entry.getValue(); 
       Path path = new Path(); 
       path.setFillType(Path.FillType.EVEN_ODD); 
       Iterator<GeoPoint> it = sourceList.iterator(); 
       Point point = nextDrawPoint(projection, it); 
       path.moveTo(point.x, point.y); 
       while (it.hasNext()) { 
        point = nextDrawPoint(projection, it); 
        path.lineTo(point.x, point.y); 
       } 
       path.close(); 
       areaPaths.add(path); 
      } 
      return areaPaths; 
     } 

     /** 
     * <ul> 
     * <li>Draw with different colors. 
     * <li>Draw strokes first for them to be always visible. 
     * <li>Draw fills next with each removing from the drawable area. 
     * </ul> 
     */ 
     private void drawPaths(final Canvas canvas, final List<Path> areaPaths) { 
      int currentColorIndex; 

      currentColorIndex = 0; 
      for (Path path : areaPaths) { 
       int currentColor = AreasOverlay.COLORS[currentColorIndex++]; 
       currentColorIndex %= AreasOverlay.COLORS.length; 
       m_paintStroke.setColor(currentColor & 0xff7f7f7f); // make it darker by clearing the high bit 
       canvas.drawPath(path, m_paintStroke); 
      } 
      currentColorIndex = 0; 
      for (Path path : areaPaths) { 
       int currentColor = AreasOverlay.COLORS[currentColorIndex++]; 
       currentColorIndex %= AreasOverlay.COLORS.length; 
       m_paintFill.setColor(currentColor); 
       canvas.drawPath(path, m_paintFill); 
       canvas.clipPath(path, Op.DIFFERENCE); // don't allow to draw over each other 
      } 
     } 

     private Point nextDrawPoint(final Projection projection, final Iterator<GeoPoint> it) { 
      GeoPoint geo = it.next(); 
      Point p = new Point(); 
      projection.toPixels(geo, p); 
      return p; 
     } 
    } 
} 
5

Der Radius für drawCircle in Pixel ist, so dass es sinnvoll, dass der Kreis ist immer die gleiche Größe. Sie müssen den Radius basierend auf der Zoomstufe skalieren. Im folgenden Beispiel wird eine Geometrie aus der JTS Topology Suite grafisch dargestellt, die skaliert wird.

public class MapOverlay extends Overlay { 
    private static final String TAG = MapOverlay.class.getName(); 

    // Allocate once and reuse 
    private final Paint mPaint = new Paint(); 
    private final Path mPath = new Path(); 

    // Region to highlight 
    private Geometry mGeometry; 

    /** 
    * @param geometry Region to highlight on map 
    */ 
    public MapOverlay(Geometry geometry) { 
      // Set region 
      mGeometry = geometry; 

      // Edit paint style 
      mPaint.setDither(true); 
      mPaint.setColor(Color.rgb(128, 136, 231)); 
      mPaint.setAlpha(100); 
      mPaint.setStyle(Paint.Style.FILL_AND_STROKE); 
      mPaint.setStrokeJoin(Paint.Join.ROUND); 
      mPaint.setStrokeCap(Paint.Cap.ROUND); 
      mPaint.setStrokeWidth(6); 
    } 


    /** 
    * Draw the overlay over the map. 
    * 
    * @see com.google.android.maps.Overlay#draw(Canvas, MapView, boolean) 
    */ 
    @Override 
    public void draw(Canvas canvas, MapView mapv, boolean shadow) { 
      super.draw(canvas, mapv, shadow); 

      if (mGeometry != null) { 
        // TODO There could be more than one geometries 
        Geometry g = mGeometry.getGeometryN(0); 
        final Point p = new Point(); 
        boolean first = true; 

        mPath.reset(); 
        for (Coordinate c : g.getCoordinates()) { 
          // Convert lat/lon to pixels on screen 
          // GeoPoint is immutable so allocation is unavoidable 
          Projection projection = mapv.getProjection(); 
          projection.toPixels(new GeoPoint((int) (c.y * 1E6), (int) (c.x * 1E6)), p); 

          // Set path starting point to first coordinate 
          // otherwise default start is (0,0) 
          if (first) { 
            mPath.moveTo(p.x, p.y); 
            first = false; 
          } 

          // Add new point to path 
          mPath.lineTo(p.x, p.y); 
        } 
      } 

      // Draw the path with give paint 
      canvas.drawPath(mPath, mPaint); 
    } 

von Angepasst hier: MapSelectionOverlay.java

+0

Woher hast du die Geometrie-Klassen? – topwik

+0

Von JTS http://sourceforge.net/projects/jts-topo-suite/ – Frohnzie