none
Making the rest of the map a polygon.

    Question

  • Hi,

    I have the polygons of the country and also her islands and I want only the country to be visible. 
    So I guess that everything else must be a polygon that I will paint. 

    Is there any easy way (in the MapControl), or else how can I do it?

    Monday, November 26, 2012 7:20 AM

Answers

All replies

  • Need a bit more details. What format is your polygon data in? XML, WKT, in a database?

    http://rbrundritt.wordpress.com

    Monday, November 26, 2012 5:02 PM
    Owner
  • A few thoughts:

    - Rather than "masking" everything other than the country you want (what country is it?!), would it be sufficient to instead just limit the bounds of the map view so that users couldn't scroll beyond the boundaries of the country? That can be done easily and efficiently.

    - If you really do want to mask the map image, I wouldn't do it using a vector polygon - it will be horribly inefficient. Instead, there should be a way to programatically generate a tile layer that is fully transparent over the polygon(s) in question but opaque everywhere else. If you tell us what data you have it might be possible to suggest a good way to do this.


    twitter: @alastaira blog: http://alastaira.wordpress.com/ | Pro Spatial with SQL Server 2012

    Monday, November 26, 2012 5:17 PM
    Moderator
  • Wednesday, November 28, 2012 6:50 AM
    Moderator
  • I've been away for a few days. 

    Very interesting post Tanoshimi, I'll check it out today I hope. Since you've asked which country is it, it's Greece, and I guess that makes it even harder since it has many islands (I ve mapped about 40-50 so far) so I'm afraid that this could seriously slow down the app . 

    So how can one restrain the map only to one location? I also tried to restrain the zoom lvl in the mousewheel event, but it doesnt work that good. 

    I'll post later after i follow your blog;s instructions

    @Richard_Brundrit: I actually hardcoded them to load into a LocationCollection. Doesn't really matter but I thought would be easier(and faster i guess) in my case. Does it make any difference on the specific subj?


    • Edited by Zerobabel Thursday, November 29, 2012 7:00 AM
    Thursday, November 29, 2012 6:59 AM
  • If you are using a LocationCollection I suspect you are using the Silverlight or WPF map control. In that case it might be a way to create something similar to what Alastair proposed above directly in code. Perhaps by creating a negative of the shape.

    http://rbrundritt.wordpress.com

    Thursday, November 29, 2012 11:00 AM
    Owner
  • If you are using a LocationCollection I suspect you are using the Silverlight or WPF map control. In that case it might be a way to create something similar to what Alastair proposed above directly in code. Perhaps by creating a negative of the shape.

    http://rbrundritt.wordpress.com

    Yes, I'm using the WPF, and I'm trying to figure out how can I use Alaister's example into it. Not that easy for me though for he uses tiles, while I just want to have a mappolygon or something, and graphics not really my field.

    Only if I could get a path out of a region things would be a lot easier but I see that this isnt an option

    Friday, November 30, 2012 9:43 AM
  •  - If you really do want to mask the map image, I wouldn't do it using a vector polygon - it will be horribly inefficient. Instead, there should be a way to programatically generate a tile layer that is fully transparent over the polygon(s) in question but opaque everywhere else. If you tell us what data you have it might be possible to suggest a good way to do this.

    What kind of data you need? :)

    I'm already on the way to make it tile based for i dont see any other way around it.

    Friday, November 30, 2012 11:59 AM
  • Ok. I played around with this using the geometry classes in WPF. I basically just used them to generate the negative polygon. Since the MapPolygon class doesn't support polygons with holes I have to split the polygon in half and carve out the polygon from the edges. I've made a pretty simple reusable class for generating these.

    Here is my random polygon I used for testing:

    MapPolygon polygon = new MapPolygon()
    {
        Locations = new LocationCollection()
        {
            new Location(40, -110),
            new Location(60, -100),
            new Location(30, -90),
            new Location(35, -120)
        },
        Fill = new SolidColorBrush(Colors.Blue)
    };

    Here is a screenshot of the Polygon on the map:

    Here is the class I created for generating the mask. It takes in a polygon and Brush which will be used to color the mask. This method will return a MapLayer that contains two polygons that make up the mask.

    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Media;
    using Microsoft.Maps.MapControl.WPF;
    
    namespace PolygonMask
    {
        public class MaskGenerator
        {
            public static MapLayer GenerateMask(MapPolygon polygon, Brush background)
            {
                MapLayer mask = new MapLayer();
    
                LocationCollection lc = polygon.Locations;
                PointCollection pc = new PointCollection();
    
                double sumLong = 0;
    
                foreach (Location l in lc)
                {
                    pc.Add(new Point(l.Longitude, l.Latitude));
                    sumLong += l.Longitude;
                }
    
                double midLong = sumLong / lc.Count;
    
                PathGeometry geom = CreatePathGeomFromPointCollection(pc);
    
                PathGeometry MapGeom1 = CreatePathGeomFromPointCollection(new PointCollection()
                {
                    new Point(midLong, -90),
                    new Point(-180, -90),
                    new Point(-180, 90),
                    new Point(midLong, 90)
                });
    
                PathGeometry MapGeom2 = CreatePathGeomFromPointCollection(new PointCollection()
                {
                    new Point(midLong, -90),
                    new Point(180, -90),
                    new Point(180, 90),
                    new Point(midLong, 90)
                });
    
                mask.Children.Add(CreatePolygonMask(MapGeom1, geom, background));
                mask.Children.Add(CreatePolygonMask(MapGeom2, geom, background));
    
                return mask;
            }
    
            private static MapPolygon CreatePolygonMask(PathGeometry canvas, PathGeometry polygon, Brush background)
            {
                CombinedGeometry cg = new CombinedGeometry(GeometryCombineMode.Exclude, canvas, polygon);
    
                PathGeometry pg = cg.GetFlattenedPathGeometry();
    
                List<PolyLineSegment> pathSegMask = new List<PolyLineSegment>();
    
                foreach (PathFigure pf in pg.Figures)
                {
                    foreach (PathSegment ps in pf.Segments)
                    {
                        if (ps is PolyLineSegment)
                        {
                            pathSegMask.Add(ps as PolyLineSegment);
                        }
                    }
                }
    
                //Create polyons for masking
                LocationCollection lc = new LocationCollection();
    
                foreach (Point p in pathSegMask[0].Points)
                {
                    lc.Add(new Location(p.Y, p.X));
                }
    
                return new MapPolygon() { Locations = lc, Fill = background };         
            }
    
            private static PathGeometry CreatePathGeomFromPointCollection(PointCollection pc)
            {
                PathGeometry geom = new PathGeometry();
    
                PolyLineSegment poly = new PolyLineSegment();
                poly.Points = pc;
    
                PathFigure fig = new PathFigure();
                fig.StartPoint = poly.Points[0];
                fig.Segments.Add(poly);
    
                geom.Figures.Add(fig);
    
                return geom;
            }
        }
    }
    

    You can easily implement this like so:

    MyMap.Children.Add(MaskGenerator.GenerateMask(polygon, new SolidColorBrush(Colors.Black)));

    Here is a screen shot of the mask:


    http://rbrundritt.wordpress.com

    Friday, November 30, 2012 4:50 PM
    Owner