8

Muszę narysować kształty, takie jak te, które utworzysz za pomocą niestandardowych map w Mapach Google przy użyciu MapView systemu Android.Rysowanie kształtów w systemie Android MapView niezależnie od poziomu powiększenia

Innymi słowy, jeśli narysuję kształt na mapie, kiedy pomniejszy go, powinien się zmniejszyć, pokrywając ten sam obszar mapy, niezależnie od poziomu powiększenia.

Przykład następstwie Android Reference:

@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; 
    } 

To pokazuje biały okrąg na mapie, ale jeśli pomniejszyć, okrąg ma taki sam rozmiar. Być może użycie płótna nie jest właściwym podejściem?

muszę coś takiego jak Google Maps podkreśla osiedla lub miasta:

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

jakieś pomysły? Z góry dziękuję!

+0

start przy pomocy nakładki narysować kształt [Tu idziesz] (http://androidtrainningcenter.blogspot.in/2013/01/android-map-drawing-path- using-overlay.html) – Sameer

Odpowiedz

2

to może to, czego szukasz: 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

to rozwiązuje krąg, a co z wielobokiem, jak pokazano powyżej http://i.stack.imgur.com/5goEw.png – ericlee

+0

Powiedziałbym, że Google wielokrotnie rysowałoby wiele prostokątów w obszarze objętym zakresem. Następnie narysują linię przerywaną na zewnętrznej krawędzi obszaru połączenia. Rysowanie i skalowanie grafiki odbywa się tradycyjną metodą. Jednak to tylko moja spekulacja. Jestem pewien, że cała sprawa jest znacznie bardziej skomplikowana. Google ma wszystkie informacje o lokalizacji dotyczące tego adresu, takie jak kod pocztowy lub miasto itp. Prawdopodobnie łatwiej im pogrupować te informacje w jeden obiekt, a następnie użyć tych informacji do precyzyjnego wykreślenia obszaru. Ponownie, po prostu zgaduję, jak to powinno działać. – RobGThai

+0

Uważam, że rysowanie tych okręgów w widoku mapy może znacznie spowolnić przewijanie mapy w miarę zbliżania się do kształtu, a gdy osiągnie pewien zoom, kółko zniknie. jak to się zwykle robi, jeśli nie chcesz, aby krąg zniknął z mapy? – topwik

2

Co trzeba to lista łac punktów/LON do każdego kształtu chcesz narysować na mapie. W metodzie OnDraw, trzeba iteracyjne nad tej listy (dla każdego kształtu, który chcesz zwrócić) i to zrobić:

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

następnie narysować kształt na płótnie. IIRC, który działa poprawnie niezależnie od zoomu, ponieważ mapView jest świadomy poziomu zoomu i zapewnia odpowiednie położenie pikseli dla pary długiej/długiej na tym poziomie powiększenia.

+0

Rzeczywiście, o ile mi wiadomo, projekcja na piksele powoduje, że rysunki pojawiają się niezależnie od poziomów powiększenia. – tolgap

+0

Cóż, nie musisz zarządzać poziomem zoomu, matematyka rzutowania wie, jak obsługiwać poziom powiększenia. – Travis

+0

@tolgap, twoje stwierdzenie o 'toPixels()' jest niepoprawne. Jego celem jest radzenie sobie z poziomami powiększenia! @Travis opisuje poprawną odpowiedź. Będziesz potrzebował opisu wieloboku, który chcesz renderować. Jeśli ten opis jest listą wierzchołków w przestrzeni współrzędnych lat/lon, to musisz tylko przekonwertować te piksele i narysować. Projekcja wykona resztę pracy. – Gene

8

miałem ten sam problem sam, oto pełne rozwiązanie z miejsc Demo:

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

Promień dla drawCircle jest w pikselach więc to ma sens, że koło jest zawsze taki sam rozmiar. Musisz skalować promień na podstawie poziomu powiększenia. W poniższym przykładzie wykreślemy geometrię z pakietu JTS Topology Suite, który będzie skalowany.

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); 
    } 

Adaptacja tutaj: MapSelectionOverlay.java

+0

Skąd masz zajęcia z geometrii? – topwik

+0

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

Powiązane problemy