Drawing shapes in Android MapView independent of the zoom level

后端 未结 4 1563
南方客
南方客 2021-01-31 23:34

I need to draw shapes just like those you would create with custom maps on Google Maps, using Android\'s MapView.

In other words, if I draw a shape on t

4条回答
  •  挽巷
    挽巷 (楼主)
    2021-01-31 23:53

    I had the same problem myself, here's a full solution with demo locations:

    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> 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> areaMap = new HashMap>();
            for (int i = 0; i < areaNames.length; i++) {
                List points = new ArrayList();
                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> 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> 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 areaPaths = getPaths(projection, m_areas);
                drawPaths(canvas, areaPaths);
            }
    
            private List getPaths(final Projection projection, final Map> areas) {
                List areaPaths = new ArrayList(areas.size());
                for (Map.Entry> entry : areas.entrySet()) {
                    List sourceList = entry.getValue();
                    Path path = new Path();
                    path.setFillType(Path.FillType.EVEN_ODD);
                    Iterator 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;
            }
    
            /**
             * 
      *
    • Draw with different colors. *
    • Draw strokes first for them to be always visible. *
    • Draw fills next with each removing from the drawable area. *
    */ private void drawPaths(final Canvas canvas, final List 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 it) { GeoPoint geo = it.next(); Point p = new Point(); projection.toPixels(geo, p); return p; } } }

提交回复
热议问题