spacer1
spacer2 1_1 1_2
2_1
 Subscribe
 The MP2K Update!
 
 
 
 Magazine
Front Cover
What's New
Articles
News
Sample Data
Gallery
Advertise
About
 Features
MapPoint 2013
Press Releases
MapPoint Forums
Companies
Link to MP2Kmag
Wish List
MapPoint Trial
Authors
 Earlier Content
Past News Items
Past What's New Announcements
 Sponsors
 Order

MapPoint 2013

Programming MapPoint in .NET

MapPoint Book

  Spatial Community
SVG Tutorials
MapPoint

Map Visitors

  ARTICLES  


Using the New MapFeatures Collection and MapFeature Objects in MapPoint 2010

Richard Marsden explores the new MapFeatures Collection in MapPoint 2010 and how to programmatically control the "Map Settings" via the API. Includes a table with the complete list of the MapFeature indices.

One of the most notable and asked for additions to MapPoint 2010, is the ability to switch different map features on or off. A dozen or so different features can have their graphical representations (aka ‘symbols’) and/or labels switched on (default), off, or to display additional detail. The ability to switch labels on or off has been frequently requested,  but this new feature goes further and provides a much finer level of control than was expected.

This new functionality is also implemented in the API using the MapFeatures property and collection in the MapPoint Map object. This is covered in the documentation, although some of the documentation is incomplete. This article describes how to use this MapFeatures collection, and describes a couple of pitfalls. Examples are given using C#.

Calling MapPoint 2010 from C#

The example code (see below) is implemented in a series of functions. These are called with a test harness, implemented as a standard C# console application. When creating this console project, you must add a reference to the MapPoint COM object model.  MapPoint 2010’s object model is version 17.0. The reference dialog box will use the name “Microsoft MapPoint 17.0 Object Library (North America)”.

Additional “using” references should also be added to the System.IO and System.Collections .NET libraries. These are only required for my demonstration code and are not required by MapPoint.

The test harness is below.  This will be very familiar to anyone who has programmed previous versions of MapPoint with C#, and much of it should be familiar to programmers of other languages. It creates an Application object, displays MapPoint, gets a reference to the Map object; runs the test code; then shuts MapPoint down. 

static void Main(string[] args)

{

// A series of development tests for the MapFeature and MapFeatures objects in MapPoint 2010

// Project must reference Microsoft MapPoint COM Object Model 17.0 or later

 

MapPoint.Application myApp = new MapPoint.Application();

myApp.Visible = true;

 

MapPoint.Map myMap = myApp.ActiveMap;

 

// Get the MapFeatures collection

MapPoint.MapFeatures myFeatureList = myMap.MapFeatures;

 

// Some sample routines

Console.WriteLine("Available Map Features:");

DisplayMapFeatures(myFeatureList);

 

Console.WriteLine("\nSorted list of Map Features:");

DisplaySortedMapFeatures(myFeatureList);

 

Console.WriteLine("\nModify some features...");

ModifyMapFeatures(myFeatureList);

Console.WriteLine("...Features modified.");

 

      // Standard shutdown (but only when the user says it is okay)

Console.Write("Press ENTER to shutdown");

Console.ReadLine();

 

try

{   // (user might have closed things - therefore trap and ignore any errors

//  this is a simple demo, after all. A commercial App should handle things better)

myMap.Saved = true;

myMap = null;

(myApp as MapPoint._Application).Quit();

myApp = null;

}

catch

{

}

}

 

The only line of code which is new for MapPoint 2010, is the MapPoint.MapFeatures line. This obtains a reference to the MapFeatures collection using the Map object’s new MapFeatures property.  This reference is passed to each individual test routine.

Accessing the MapFeatures Collection

Most if not all of MapPoint’s collections can be accessed using C#’s foreach statement. Our first test routine demonstrates that the same applies to the MapFeatures collection:

 

// Display Map Features: Demonstrates using foreach to iterate through a MapFeature collection

static public void DisplayMapFeatures(MapPoint.MapFeatures myFeatureList)

{

// Loop through all MapFeature objects

foreach (MapPoint.MapFeature thisFeature in myFeatureList)

{

Console.WriteLine("Index:{0}, Feature:\"{1}\"", thisFeature.Index, thisFeature.Name);

 

// This approach could also be used to set all features to the same setting, eg:

// (Options are: geoNeverDisplay, geoDefault, geoMoreDetail)

// thisFeature.DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

}

}

All this routine does, is to iterate through the collection querying every MapFeature object. Each map feature’s index and name is displayed. The resulting list is reproduced at the end of this article, for reference.

The foreach construct can also be used to set all map features to the same setting – eg. All on, all off, or extra detail for everything. See the commented code for a sample of how to do this using the DetailedLevel property. This property uses a new enumeration called MapPoint.GeoMapDetail. Use GeoMapDetail.geoNeverDisplay to switch the feature off. Use GeoMapDetail.geoDefault to switch the feature on at the default level. Use GeoMapDetail.geoMoreDetail if you wish to display additional detail. The final example in this article uses this last option to show extra river detail.

The DetailedLevel property could also be used to query feature visibilities (e.g. to serialize all map feature visibilities).

Obtaining an Alphabetical List of Map Feature Names

The following example is very similar to the above example, except the map feature names are displayed in alphabetical order:

       // A useful alphabetical list

static public void DisplaySortedMapFeatures(MapPoint.MapFeatures myFeatureList)

   {

// It is actually quicker to collect the names and then sort, rather than to use

// a Dictionary to maintain a sorted list.

ArrayList alFeatureNames = new ArrayList();

// Iterate through the feature list, adding each name

foreach (MapPoint.MapFeature thisFeature in myFeatureList)

{

alFeatureNames.Add(thisFeature.Name);

}

alFeatureNames.Sort();

 

// Display the sorted list

foreach (string sFeature in alFeatureNames)

{

Console.WriteLine(sFeature);

}

        }

Rather than using a .NET Dictionary object which keeps its contents sorted on the fly, an ArrayList is used instead. This is only sorted once after all the names have been added. This approach can be considerably faster for a simple “load/read” sequence like this.


Accessing Individual MapFeature Objects

The MapFeatures collection has an Item method which can be used to access individual MapFeature objects. As with other MapPoint collections, this appears in C# as the get_Item() method and expects an object reference as the parameter. This allows the calling application to refer to an object in the collection by its index or by its name. The downside is that it complicates the interface in C#. This is because the index (an integer) or the name (a string) has to be boxed as an object, and a reference has to be passed. This typically requires at least one extra line of code, so I have implemented two new functions which automate the process. These take an integer or a string, and return a reference to the resulting MapFeature object:

// Note in C#, the item reference for all collections is with a method called "get_Item"

// Also, the parameter is an object (Variant) because it can be a string or an integer

// Here we simplify the code by creating an integer index implementation

static public MapPoint.MapFeature GetMapFeatureByIndex(MapPoint.MapFeatures myFeatures, int idx)

{

object oIdx;

oIdx = idx as object;

return myFeatures.get_Item( ref oIdx);

}

 

// Similar to above, but using a string name implementation

static public MapPoint.MapFeature GetMapFeatureByName(MapPoint.MapFeatures myFeatures, string sName)

{

object oName;

oName = sName as object;

return myFeatures.get_Item(ref oName);

}

 

 

GetMapFeatureByIndex works as expected. Unfortunately, GetMapFeatureByName does not work if you pass the name (eg. "Boundaries - Country - Symbols") of the required MapFeature object. An ‘index not found’ exception is thrown. This method can be made to work, but only if you pass the required index as a string, eg. “8” instead of "Boundaries - Country - Symbols"!  I observe that the string implementation is of little use for this collection, and developers should use the integer index instead.

The integer index might pose problems in the future. There is nothing in the documentation to say that these numbers will remain the same. A conscientious developer should write code that checks the MapFeature names are what the developer expects. The alternative is code that might break or behave in an unexpected manner when a new version of MapPoint is released with new MapFeatures or different index codes.

Here is some example code which uses GetMapFeatureByIndex (and to a lesser extent GetMapFeatureByName) to change a number of feature visibility settings:

 

 

// Modify some of the feature settings

static public void ModifyMapFeatures(MapPoint.MapFeatures myFeatureList)

{

// Switch roads and railroads off, using their indices:

     GetMapFeatureByIndex(myFeatureList, 11).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

GetMapFeatureByIndex(myFeatureList, 12).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

GetMapFeatureByIndex(myFeatureList, 13).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

GetMapFeatureByIndex(myFeatureList, 26).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

GetMapFeatureByIndex(myFeatureList, 27).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

GetMapFeatureByIndex(myFeatureList, 32).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

GetMapFeatureByIndex(myFeatureList, 33).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

 

// Also switch small cities and their names off

GetMapFeatureByIndex(myFeatureList, 4).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

GetMapFeatureByIndex(myFeatureList, 5).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

GetMapFeatureByIndex(myFeatureList, 19).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

GetMapFeatureByIndex(myFeatureList, 20).DetailLevel = MapPoint.GeoMapDetail.geoNeverDisplay;

 

 

// The following do NOT work

// Note: Many MapPoint collections can take names like this in their Item methods

//            GetMapFeatureByName(myFeatureList, "Miscellaneous - Water Features - Labels").DetailLevel = MapPoint.GeoMapDetail.geoMoreDetail;

//            GetMapFeatureByName(myFeatureList, "Miscellaneous - Water Features - Symbols").DetailLevel = MapPoint.GeoMapDetail.geoMoreDetail;

 

// Instead, if we pass a string, it must be of the index number, like this:

GetMapFeatureByName(myFeatureList, "1").DetailLevel = MapPoint.GeoMapDetail.geoMoreDetail;

GetMapFeatureByName(myFeatureList, "16").DetailLevel = MapPoint.GeoMapDetail.geoMoreDetail;

 

// Switch some parks on

GetMapFeatureByIndex(myFeatureList, 2).DetailLevel = MapPoint.GeoMapDetail.geoMoreDetail;

GetMapFeatureByIndex(myFeatureList, 17).DetailLevel = MapPoint.GeoMapDetail.geoMoreDetail;

 

}

 

This code switches all roads, railroads, and smaller cities off. Rivers and parks are switched on with “additional detail”. This produces the display below. As can be seen, “additional detail” adds a number of additional park icons, but it also adds a lot of additional smaller rivers and lakes.

Note that the above methods return references which could also be used to query the visibility of individual map features.

Conclusions

And that is it! The new map feature functionality implements a much-requested feature, and includes more capabilities than anyone was expecting. It should greatly enhance MapPoint’s utility in producing presentation maps.

The programming interface has a few quirks. The documentation could be more complete, and the get_Item() function could implement names. Or better still, it would be great if MapFeature objects could be queried using an enumeration. A correctly implemented enumeration should be immune to any future changes or additions to the available map features.

A complete list of the Map Feature Names and Indices is posted on Mapping-Tools.com here:
http://www.mapping-tools.com/info/pushpins/features_2010.shtml

Discuss this story in the forum.

Author: Richard Marsden
Email: enquiries(AT)winwaed.com
URL: http://www.winwaed.com
Richard Marsden is the proprietor of Winwaed Software Technology, LLC which provides software consulting and development services, specializing in both MapPoint and online mapping applications. He operates the Mapping-Tools.com Website for MapPoint Tools and Utilities, and recently launched the GeoWeb Guru a community website for developers of the geospatial web. In 2008, Richard was awarded Virtual Earth MVP status by Microsoft.

Prior to Winwaed, Richard worked as a software developer working on seismic processing algorithms for the oil exploration industry. He holds geology and geophysics degrees from the University of Cambridge (Churchill College), and the University of Durham; and an interdisciplinary MBA from the University of Dallas.



Google
 
MP2Kmag Internet


 Recent Discussion
 Resources
Browse GIS books and periodicals
Find a MapPoint Partner or Consultant
Real Estate Columbia For Sale By Owner


Want Your Site To Appear Here?

   © 1999-2012 MP2K. Questions and comments to: website@mp2kmag.com
  Microsoft and MapPoint 2002/2004/2006/2009/2010/2011/2013 are either trademarks or registered trademarks of Microsoft.