Section 8.2. Rendering Maps


8.2. Rendering Maps

Now that you know about views, map styles, and how to get a map image for both Windows and web applications, in this section of the chapter, let's look at how to render places, addresses, pushpins, and routes.

8.2.1. Rendering Places and Addresses

Rendering a place or address on a map starts with some type of Find calleither a Find call for a place or a FindAddress call. Once you successfully find a place or an address, use the found location's best map view to get the map using the RenderServiceSoap.GetMap method. For example, to render New York City on a map, start with the Find call and pass the found location's best map view to the GetMap method:

     //Find New York, NY     FindServiceSoap findService  = new FindServiceSoap( );     //Assign credentials     . . .     //Define find specification     FindSpecification findSpec = new FindSpecification( );     //Assign data source     findSpec.DataSourceName = "MapPoint.NA";     //Assign input place     findSpec.InputPlace = "New York, NY";     //Find place     FindResults foundResults = findService.Find(findSpec);     //Get the best map view     ViewByHeightWidth view =                foundResults.Results[0].FoundLocation.BestMapView.ByHeightWidth;     //Get Render Service Soap     RenderServiceSoap renderService  = new RenderServiceSoap( );     //Assign credentials     . . .     //Define map specification     MapSpecification mapSpec  = new MapSpecification( );     //Assign data source     mapSpec.DataSourceName = "MapPoint.NA";     //Assign the view     mapSpec.Views = new MapView[] {view}     //Get the map image     MapImage[] mapImages = renderService.GetMap(mapSpec);     //Get the bitmap image and assign it to a picture box     System.IO.Stream streamImage =                new System.IO.MemoryStream(mapImages[0].MimeData.Bits);     Bitmap bitmapImage = new Bitmap(streamImage);     //Assign it to the picture box     pictureBox1.Image = bitmapImage; 

When this code is executed, MapPoint Web Service renders the map shown in Figure 8-5.

Figure 8-5. Place map with default map options


This map was rendered using all default map options, such as style, zoom level, and map image size; with the default settings, the map image size was 240 pixels high and 296 pixels wide. What if you need a map 400 pixels high and 600 pixels wide? In order to render a map image with different dimensions, use the MapOptions.Format property of the MapOptions object. The Format property is of type ImageFormat object, and it holds the definition for the map image settings , such as the height, width, and Mime type of the image. To get a 400 x 600 map image, set the MapOptions as follows:

     //Create MapSpecification object     MapSpecification mapSpec = new MapSpecification( );     //Assign views and data source     . . .        //Create MapOptions     mapSpec.Options = new MapOptions( );     //Set Map Image Format Settings     mapSpec.Options.Format = new ImageFormat( );     //Set height     mapSpec.Options.Format.Height = 400;     //Set width     mapSpec.Options.Format.Width = 600;     //Get map     MapImage[] mapImages =              renderService.GetMap(mapSpec);

Once you add the map image specifications for width and height, the map is rendered using the desired settings, as shown in Figure 8-6.

Figure 8-6. A 400 x 600 map rendered for New York, NY


The map is now the desired size, but there is still a problemeven though we know the map center is New York, there is no clear indication of which place you were looking for. To work around this issue, you can place a pushpin on New York City as a visual indication using the MapSpecifications.Pushpins property.

8.2.2. Rendering Pushpins

To render pushpins on a map, you need to define them and assign them to the corresponding MapSpecification.Pushpins property. This property takes an array of Pushpin objects that define the exact locations (as latitude/longitude coordinates) to be marked with pushpins. To add a pushpin to the map in Figure 8-6 to show that exactly where New York City is, add a Pushpin to the MapSpecification object:

     //Create a pushpin     Pushpin pin = new Pushpin( );     //Assign data source     pin.IconDataSource = "MapPoint.Icons";     //Assign icon name     pin.IconName = "1";     //Assign label     pin.Label = this.inputPlace.Text;     //Assign location     pin.LatLong = foundLocation.LatLong;     //Add pushpin to map specificiation     mapSpec.Pushpins = new Pushpin[] {pin};

Adding this code renders a map with a pushpin as shown in Figure 8-7.

Figure 8-7. Map rendered with a pushpin


The MapSpecifications.Pushpins property is an array of pushpins, so of course you can draw more than one pushpin. However, the maximum limit to the number of pushpins that can be rendered on one map is 100. If you have more than 100 pushpins to be displayed on one map, the best solution is to implement pagination without cluttering the map with too many pushpins. If you look at how each pushpin is defined, it has a data source (standard data source is MapPoint.Icons, which has number of pushpins that you can use), a label, and a latitude/longitude.

For a full list of icons supported by MapPoint.Icons data source, go to http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mappointsdk/HTML/mpn35devTablesIcons.asp.


Of course, you can also upload your own icons to the MapPoint Web Service servers using the Customer Services site to use them with your render calls. Since you know how to render one pushpin, let's learn how to add more pushpins.

8.2.2.1. Rendering points of interest

One of the most frequently used scenarios for rendering maps and pushpins is to find a place and render points of interest around it. For example, first find New York City, and then render all coffee shops within five miles:

     //Define a find nearby specification     FindNearbySpecification fnbSpec = new FindNearbySpecification( );     //Assign data source     fnbSpec.DataSourceName = "MapPoint.FourthCoffeeSample";     //Assign original location     fnbSpec.LatLong = foundLocation.LatLong;     //Assign distance     fnbSpec.Distance = 5.0;     //Assign entity type     fnbSpec.Filter = new FindFilter( );     fnbSpec.Filter.EntityTypeName = "FourthCoffeeShops";     //Find nearby coffeeshops     FindResults findResults = findService.FindNearby(fnbSpec);        //Add all locations to an array list     System.Collections.ArrayList pinList =                 new ArrayList( );     foreach(FindResult findResult in findResults.Results)     {         //Create a pushpin         Pushpin pin = new Pushpin( );         pin.IconDataSource = "MapPoint.Icons";         pin.IconName = "CoffeeShopIcon";         pin.LatLong = findResult.FoundLocation.LatLong;         pin.Label = findResult.FoundLocation.Entity.DisplayName;         pinList.Add(pin);     }     //Add the original location pin     Pushpin originalLoc = new Pushpin( );     originalLoc.IconDataSource = "MapPoint.Icons";     originalLoc.IconName = "33";     originalLoc.LatLong = foundLocation.LatLong;     originalLoc.Label = "New York, NY";     pinList.Add(originalLoc);     //Assign pins to the map specification     mapSpec.Pushpins = pinList.ToArray(typeof(Pushpin)) as Pushpin[];     //Get map

After finding coffee shops around the input place, I added them to an ArrayList so that I can assign all the coffee shop locations, along with the original location, to the MapSpecification.Pushpins property to render on a map. When this code is executed, a map is rendered as shown in Figure 8-8.

Figure 8-8. Rendering multiple pushpins on a map


The map is not usable because the original map view is optimized to display the input location (New York, NY) but not the points of interest around it. You need to recalculate the map view to be optimized for all of these locations before rendering it. There are two methods you can use to perform the recalculation of the map view with all the pushpins around:

  • The ViewByBoundingLocations view to set MapSpecification views

  • The RenderServiceSoap.GetBestMapView method to calculate the map view and then assign it to the MapSpecification.Views property

Either way, you will get a better-looking map. In the following code, I have added each coffee shop to another array list that holds all location objects to be used for ViewByBoundingLocations view, which will be defined later using those locations:

        //Add all locations to an array list     System.Collections.ArrayList locationList =                     new ArrayList( );     //Add all pushpins to an array list     System.Collections.ArrayList pinList =                     new ArrayList( );     foreach(FindResult findResult in findResults.Results)     {         //Create a pushpin         Pushpin pin = new Pushpin( );         pin.IconDataSource = "MapPoint.Icons";         pin.IconName = "CoffeeShopIcon";         pin.LatLong = findResult.FoundLocation.LatLong;         //pin.Label = findResult.FoundLocation.Entity.DisplayName;         pinList.Add(pin);            //Add location         locationList.Add(findResult.FoundLocation);     }     //Add the original location pin     Pushpin originalLoc = new Pushpin( );     originalLoc.IconDataSource = "MapPoint.Icons";     originalLoc.IconName = "33";     originalLoc.LatLong = foundLocation.LatLong;     originalLoc.Label = "New York, NY";     pinList.Add(originalLoc);        //Define view     ViewByBoundingLocations vbl = new ViewByBoundingLocations( );     //View by Locations     vbl.Locations = locationList.ToArray(typeof(Location)) as Location[];     //Assign pins to the map specification     mapSpec.Pushpins = pinList.ToArray(typeof(Pushpin)) as Pushpin[];        //Assign view     mapSpec.Views = new MapView[] {vbl};     //Get map

When this code is executed, MapPoint Web Service recalculates the map view to fit all locations within an optimized view for all the encompassing locations. The map rendered for the new view is shown in Figure 8-9.

The map clearly shows all the coffee shops without much clutter, but some coffee shops overlap each other. How can you avoid this issue?

Figure 8-9. Map rendered with recalculated view


8.2.2.2. Avoiding icon collision

MapPoint Web Service allows you to render pushpins without icon collisions using the MapOptions.PreventIconCollisions property:

     //Prevent Icon Collisions     mapSpec.Options.PreventIconCollisions = true;

When this flag is set to true, the map is rendered as shown in Figure 8-10 in "icons on stick" mode to prevent icon collisions.

As you can see, the map is now free of colliding icons and is much more readable.

8.2.2.3. Suppressing standard entity types

To improve the readability, you can also suppress standard entities from the map. For example, in the map shown in Figure 8-10, there are two subway stations rendered on the map along with the coffee shops. For improved readability, you can suppress that extraneous information using the MapSpecification.HideEntityTypes property. This property takes an array of standard entity type names that needs to be eliminated from rendering; the map in Figure 8-11 is rendered when you chose to eliminate the MetroStation entity type from rendering:

     //Hide entity types     mapSpec.HideEntityTypes = new string[] {"MetroStation"};

The map no longer renders the subway stations.

Figure 8-10. Rendering icons without collisions


You can get a full list of standard entity types supported by each data source at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mappointsdk/HTML/index.asp.


8.2.2.4. Converting pushpins to pixel coordinates

Sometimes, you may need to know the pixel coordinates of the pushpins rendered on the map or the latitude and longitude coordinates of the pushpin pixel coordinates. Render Service offers two methods, ConvertToPoint and ConvertToLatLong, to calculate pixel position from a LatLong object and to obtain LatLong objects from pixel coordinates on a rendered map. The key to converting location to pixel and pixel to location on a map is the map view, which MapPoint Web Service uses to perform these calculations. If you have a requirement to build an application to obtain latitude and longitude when a user clicks on a map, it can be accomplished as follows:

     //Define a pixel coordinate array     PixelCoord[] pixels = new PixelCoord[1];     pixels[0] = new PixelCoord( );     //Trap OnMouseDown event and X, Y coordinates     pixels[0].X = e.X;     pixels[0].Y = e.Y;

Figure 8-11. Route rendered on a map


     //Get the latitude longitude from the point     LatLong[] latlongs =          renderService.ConvertToLatLong(pixels, mapSpec.Views[0],                                         400, 600);

The method ConvertToLatLong takes the pixel position, current map view, and the height and width of the map image (not the map distance covered on the ground) and returns the latitude and longitude coordinates for the corresponding pixel positions.

8.2.3. Rendering Routes

Although we have talked enough about rendering points, we have not yet discussed rendering routes on a map. As it turns out, the same MapSpecification object and the GetMap method can be used to render routes. The only difference is that while rendering routes, in addition to the map view, you also need to assign the route to be rendered on the map. The assigned Route object must have either the Route.Specification or the Route.CalculatedRepresentation present. Here is an example of rendering a route:

     //Route between two locations     LatLong[] latLongs = new LatLong[2];     latLongs[0] = new LatLong( );     latLongs[1] = new LatLong( );     //Define start location     latLongs[0].Latitude = 40;     latLongs[0].Longitude = -120;     //Define stop location     latLongs[1].Latitude = 41;     latLongs[1].Longitude = -121;     //Create a route service     RouteServiceSoap routeService = new RouteServiceSoap( );     //Add credentials     . . .     //Calculate route     Route route = routeService.CalculateSimpleRoute(latLongs, "MapPoint.NA",                                     SegmentPreference.Quickest);     //Get a map view of the route     ViewByHeightWidth[] views = new ViewByHeightWidth[1];     views[0] = route.Itinerary.View.ByHeightWidth;     //Create Start Pushpin     Pushpin start = new Pushpin( );     start.IconName = "1";     start.IconDataSource = "MapPoint.Icons";     start.Label = "Start";     start.LatLong = latLongs[0];     //Create Stop Pushpin     Pushpin stop = new Pushpin( );     stop.IconName = "1";     stop.IconDataSource = "MapPoint.Icons";     stop.Label = "Stop";     stop.LatLong = latLongs[1];     //Define map specification     MapSpecification mapSpec  = new MapSpecification( );     mapSpec.DataSourceName = "MapPoint.NA";     //Assign view     mapSpec.Views = views;        //Assign route     mapSpec.Route = route;     //Assign start and stop locations     mapSpec.Pushpins = new Pushpin[] {start, stop};     //Assign map options     mapSpec.Options = new MapOptions( );     mapSpec.Options.Format = new ImageFormat( );     mapSpec.Options.Format.Height = 400;     mapSpec.Options.Format.Width = 600;     //Get map     . . .

When this code is executed, the map in Figure 8-12 is rendered.

Figure 8-12. Standard route map


If you pass only the route and not the view, the entire route is rendered on the map. So, if you have a long route and want to render only a section of it, you can use the views; in case of a missing view specification, GetMap renders the entire route on the map. Also, keep in mind that any itinerary present in the Route object is ignored during the GetMap method.

You render routes using the standard GetMap method, but if you want to render LineDrive route maps, use the GetLineDriveMap method.

8.2.4. Rendering LineDrive Maps

Before we get into rendering LineDrive maps , let's look at what exactly they are. LineDrive maps are route maps that show the map of a route in an intuitive format, much as you might draw directions for a friend on a piece of paper. LineDrive provides the essential information about a route in an easy-to-use format that includes start and end points, names of streets and cross-streets, and mileage information. The core difference between a regular route map and a LineDrive map is that a LineDrive map gives more emphasis to starting/ending points and turns. For example, if you are driving from Redmond, WA to Portland, OR, a regular route map may look like Figure 8-13.

Figure 8-13. Regular route map


Rendering the same route on a LineDrive map gives you the map shown in Figure 8-14.

More emphasis is given to the turns and the starting and end points in the LineDrive map. It is important to note that a LineDrive route is not always identical to the route created using the standard map style. LineDrive maps also have some limitations in that they:

  • Do not support Pan or Zoom

  • Are not available for Australia (MapPoint.AP data source ) or Brazil (MapPoint.BR data source )

  • Are not drawn to scale

To render a LineDrive map, you still need a valid Route object (after all, a LineDrive map is just a variation in rendering a route). Call the GetLineDriveMap method using a valid LineDriveMapSpecification object. The LineDriveSpecification object specifies the size of the map, the route to be rendered, and the palette to be used for rendering the LineDrive map. You can pick a palette style using the PaletteType enumeration. The available options for the PaletteType enumeration are shown in Table 8-4.

Figure 8-14. LineDrive Map for the same route as in Figure 8-13


Table 8-4. LineDrive palette options

Item

Description

Color

Returns a full color representation of the LineDrive map. This is the default value.

GrayScale

Returns a grayscale representation of the LineDrive map.

Monochrome

Returns a black and white representation of the LineDrive map.


The following code shows how to use the LineDriveSpecification object to render a LineDrive map displaying a route:

     //Create an instance of RenderServiceSoap and     //Assign Credentials     RenderServiceSoap renderSoap =                           new RenderServiceSoap( );     //Create a LineDriveMapSpecification object     LineDriveMapSpecification lineDriveSpec =                           new LineDriveMapSpecification( );     //Assign the route to be rendered     //Assumes that the route is pre-calculated.     lineDriveSpec.Route = myroute;     //Set the LineDriveMapOptions such as Palette     LineDriveMapOptions lineDriveOptions =                           new LineDriveMapOptions( );     //Return Map Url     lineDriveOptions.ReturnType = MapReturnType.ReturnUrl;     //Set palette type as Color map     lineDriveOptions.PaletteType = PaletteType.Color;     //Assign options to the specification     lineDriveSpec.Options = lineDriveOptions;     //Get LineDrive maps     LineDriveMapImage[] lineDriveMaps                      = renderSoap.GetLineDriveMap(lineDriveSpec);     //Display the LineDrive Maps     . . .

The GetLineDriveMap returns the LineDriveMapImage array. Depending on the driving directions, the LineDrive map may be split into many map images, so you have to check for the image array length and display them accordingly. Also, to display the driving directions along with each LineDrive map image, match each LineDriveMapImage instance with the corresponding driving directions using the FirstDirectionID and LastDirectionID properties. The following code shows how to display LineDriveMapImage array along with the matching driving directions:

     //Get LineDrive Maps     LineDriveMapImage[] lineDriveMapImages =                    renderSoap.GetLineDriveMap(lineDriveSpec);     //Now process them to display the map and the driving directions     foreach(LineDriveMapImage lineDriveImage in lineDriveMapImages)     {         //Display the map image         //Something like: Assign the url to your img tag         . . .         //Display the matching driving directions            FormatDirectionsForLineDriveImage(lineDriveImage,                                           lineDriveSpec.Route);     }

The helper function FormatDirectionsForLineDriveImage is shown in the following code:

     //Returns the matching driving directions for a LineDriveImage     private string FormatDirectionsForLineDriveImage(                             LineDriveMapImage lineDriveMapImage,                             Route route)     {         if(lineDriveMapImage == null || route == null)             return string.Empty;         System.Text.StringBuilder stringBuffer = new System.Text.StringBuilder( );         //For each route segment         foreach(Segment segment in route.Itinerary.Segments)         {             //For each direction entry             foreach(Direction direction in segment.Directions)             {                 //See if the id of the direction falls in the range for the current                 //LineDrive image                    if(direction.ID >= lineDriveMapImage.FirstDirectionID ||                     direction.ID <= lineDriveMapImage.LastDirectionID)                 {                     //If so display it                     stringBuffer.Append(direction.Instruction);                     //Append a line break for display formatting purposes                     stringBuffer.Append("<BR>");                 }             }         }         //Return the matching directions         return stringBuffer.ToString( );     }

Use the LineDriveMapImage.FirstDirectionID and LineDriveMapImage.LastDirectionID properties to match the driving directions. Now that you have seen rendering of both points and routes, let's look at rendering polygons .

8.2.5. Rendering Polygons

In Chapter 6, we looked at finding polygons depending on various spatial filters; in this section, we'll learn how to render the polygons using render service.

Rendering polygons in MapPoint Web Service is fairly straightforward; just like rendering roads and pushpins, you use the RenderServiceSoap.GetMap method to render polygons by specifying which polygons to render using the MapSpecification object. Before getting into the rendering details, let's look at how polygons are represented programmatically in MapPoint Web Service.

In MapPoint Web Service, polygons are programmatically represented by Polygon class instances. Each Polygon class exposes a set of fields listed in Table 8-5 that define the identity and style of the polygon.

Table 8-5. Polygon class fields

Field

Description

DataSourceName

Name of the data source that the current polygon belongs to

EntityID

An integer that uniquely identifies the polygon entity in a given data source

BorderColor

An ElementColor object defining the color and level of transparency that is used when drawing the outside border of the polygon

FillColor

An ElementColor object defining the color and level of transparency that is used when shading the polygon

Label

The text to display when rendering the polygon


The BorderColor and FillColor use the ElementColor object to set the colors and transparency of the polygon. The ElementColor class defines the Red, Blue, and Green components of the color, along with the Alpha value, which defines transparency. Valid values range from 0 to 255. The fields exposed by the ElementColor class are shown in Table 8-6.

Table 8-6. ElementColor class fields

Field

Component value

A

Alpha

R

Red

G

Green

B

Blue


Let's look at the following code, which defines a polygon using the Polygon class:

     //Define a polygon instance     Polygon polygon = new Polygon( );     //Assign data source name and id     polygon.DataSourceName = "your poly data source";     polygon.EntityID = 23354;     //Define border color     ElementColor borderColor = new ElementColor( );     borderColor.A=221;     borderColor.B=255;     borderColor.G=255;     borderColor.R=128;     //Define fill color     ElementColor fillColor = new ElementColor( );     fillColor.A=90;     fillColor.B=255;     fillColor.G=255;     fillColor.R=128;     //Assign border and fill colors     polygon.BorderColor=borderColor;     polygon.FillColor=fillColor;

Once you have a valid polygon, it is easy to render it using the GetMap method:

     //Define a RenderServiceSoap instance     RenderServiceSoap renderSoap = new RenderServiceSoap( );     //Assign credentials     . . .     //Define a MapSpecification object     MapSpecification mapSpec = new MapSpecification( );     //Assign rendering data source     spec.DataSourceName = "MapPoint.NA";     //Assign views and map options     . . .     //Create a polygon     //Define a polygon instance     Polygon polygon = new Polygon( );     //Assign data source name and id     polygon.DataSourceName = "your poly data source";     polygon.EntityID = 23354;     //Define border color     ElementColor borderColor = new ElementColor( );     borderColor.A=221;     borderColor.B=255;     borderColor.G=255;     borderColor.R=128;     //Define fill color     ElementColor fillColor = new ElementColor( );     fillColor.A=90;     fillColor.B=255;     fillColor.G=255;     fillColor.R=128;     //Assign border and fill colors     polygon.BorderColor=borderColor;     polygon.FillColor=fillColor;     //Assign to Polygons array     mapSpec.Polygons = new Polygon[1] {polygon};     //Render them on a map     MapImage[] mapImages = renderSoap.GetMap(mapSpec);

Creating Polygon instances and assigning them to the MapSpecification.Polygons field is all it takes to render polygons using the GetMap method. Now that you know how to render points, routes, and polygons, let's look at map interaction, such as panning and zooming, in the context of rendering.




Programming MapPoint in  .NET
Programming MapPoint in .NET
ISBN: 0596009062
EAN: 2147483647
Year: 2005
Pages: 136
Authors: Chandu Thota

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net