Section 6.4. Working with Find Methods


6.4. Working with Find Methods

MapPoint Web Service Find Service is programmatically exposed as part of the FindServiceSoap class, which has many find methods including Find, FindAddress, FindNearby, and FindById. Choose an appropriate find method based on your application's requirements. In this section, let's look in detail at each find method offered by the MapPoint Web Service Find Service.

6.4.1. Finding Places

To find geographic entities and places by their names, use the FindServiceSoap.Find method. This method takes the FindSpecification as an input argument and returns the FindResults object as a return value. The FindSpecification wraps several values, including the input place name as a string, the data source to be used for searching the place, and an array of entity type names to find. Table 6-2 shows the fields of the FindSpecification class.

Table 6-2. Fields of the FindSpecification class

Field

Description

DataSourceName

A string representing the name of the data source in which to search for a place. For example, MapPoint.NA is the data source used for finding places in North America.

EntityTypeNames

An array of strings representing the names of the entity types to find.

InputPlace

The place name to find.

Options

The search options (FindOptions object), which includes the range of results, the threshold score of results returned, the search context, and a flag to identify which objects are desired in the returned results.


The data source used for the Find method must have the CanFindPlaces capability. The FindResults return value indicates the number of matches for the input place query using the FindResults.NumberFound field; when no results match your query, the NumberFound field is set to zero. All matches are exposed via the FindResults.Results field as a collection of FindResult objects; each FindResult object returned as a match contains a Location object that wraps the location information and a score indicating the level of confidence in the match. A valid Location object provides one or all of the following: address information, entity information, latitude/longitude information, and best map view information.

Next, let's look at the Find method details: the following code shows how the Find API can be used to find all places named Redmond:

     //Create find service soap     FindServiceSoap findsoap = new FindServiceSoap( );     //Assign credentials     . . .     //Create FindSpecification     FindSpecification findspec = new FindSpecification( );     //Assign data source     findspec.DataSourceName = "MapPoint.NA";     //Assign input place to search     findspec.InputPlace = "Redmond";     //Now call find     FindResults findresults = findsoap.Find(findspec);     //Assign found count     foreach(FindResult findresult in findresults.Results) {        //Display results        . . .     }

With options set at their defaults, this query returns the following seven places named Redmond:

     Redmond, Washington, United States     Redmond, Oregon, United States     Redmond, Western Australia, Australia     Redmond, Larimer, Colorado, United States     Redmond, Butler, Pennsylvania, United States     Redmond, Sevier, Utah, United States     Redmond, Mason, West Virginia, United States

6.4.1.1. Finding more default matches

These results include places from both the United States and Australia. By default, the find threshold score is set to 0.85, which means that any find match with a confidence score of less than 0.85 is not returned. So, to get more results for this query, you can simply decrease the threshold score using the FindOptions.ThresholdScore field:

     //Create find options     findspec.Options = new FindOptions( );     //Set threshold score to zero     findspec.Options.ThresholdScore = 0;

With the threshold score set to zero, the same query for Redmond yields 32 results of which only the following first 25 are returned:

     Redmond, Washington, United States     Redmond, Oregon, United States     Redmond, Western Australia, Australia     Redmond, Larimer, Colorado, United States     Redmond, Butler, Pennsylvania, United States     Redmond, Sevier, Utah, United States     Redmond, Mason, West Virginia, United States     Redmond Fall City Road Park (park), Washington, United States     Redmond Park (park), Cedar Rapids, Iowa, United States     Redmond Park (city park), Yonkers, New York, United States     Redmond Branch Library (library), Redmond, Oregon, United States     Redmond Chamber of Commerce (tourist information office), Redmond, Oregon,  United States     Redmond Chamber of Commerce (tourist information office), Redmond, Washington,  United States     Redmond City Hall (city hall), Redmond, Oregon, United States     Redmond City Hall (city hall), Redmond, Washington, United States     Redmond Community Cemetery (cemetery), Redmond, Washington, United States     Redmond Corner, Oneida, New York, United States     Redmond Cut (pass), California, United States     Redmond District Court (courthouse), Redmond, Washington, United States     Redmond Elementary School (school), Redmond, Washington, United States     Redmond High School (school), Redmond, Washington, United States     Redmond Junior High School (school), Redmond, Washington, United States     Redmond Memorial Cemetery (cemetery), Redmond, Oregon, United States     Redmond Municipal Court (courthouse), Redmond, Oregon, United States     Redmond Municipal Court (courthouse), Redmond, Washington, United States

6.4.1.2. Returning more find results

By default, MapPoint Web Service always returns only 25 results at once, but you can get a maximum of 500 results using the FindOptions.Range field:

     //Create find options     findspec.Options = new FindOptions( );     //Set result count     findspec.Options.Range = new FindRange( );     //Set to the maximum count     findspec.Options.Range.Count = 500;

After adding this code to the Find code, you get all 32 results returned by the Find method.

6.4.1.3. Selectively finding entity types

Notice that this list includes all kinds of entities, such as city halls, parks, libraries, and schools in the result list. Imagine for now that you need only a list of cities named after Redmondyou need to tell MapPoint Web Service that you are only looking for city entity matches to your query. You can do this using the FindSpecification.EntityTypeNames field. The EntityTypeNames field is an array of strings that represents the entity type names that the Find method needs to look for. Since you are only interested in cities named Redmond, pass the entity type name PopulatedPlace:

     //Assign entities to search     fndspec.EntityTypeNames = new string[] {"PopulatedPlace"};

A call to the Find method with this addition returns the following nine cities named Redmond:

     Redmond, Washington, United States     Redmond, Oregon, United States     Redmond, Western Australia, Australia     Redmond, Larimer, Colorado, United States     Redmond, Butler, Pennsylvania, United States     Redmond, Sevier, Utah, United States     Redmond, Mason, West Virginia, United States     Redmond Corner, Oneida, New York, United States     Redmondville, Iron, Missouri, United States

Even though your threshold score is 0 and there are 500 returned results requested, by assigning specific entity type, the find is narrowed down to 9 results from the original 32 results.

6.4.1.4. Limiting search to a geographic area

Notice that the above list contains cities from both the United States and Australia. If you are looking only for cities in the United States and need to instruct MapPoint Web Service to limit the search within a geographic boundary, using the FindOptions.SearchContext field you can limit the search to a particular geographic area. The SearchContext field is an integer value that represents the entity ID of a specific geographic area. Since you are specifically looking for cities named Redmond in the United States, the context ID should be set to the United States country entity ID 244. The following code shows the addition of search context to the find request:

     //Assign country context for United States     findspec.Options.SearchContext = 244;

With this addition, the search now only returns the following 8 results:

     Redmond, Washington, United States     Redmond, Oregon, United States     Redmond, Larimer, Colorado, United States     Redmond, Butler, Pennsylvania, United States     Redmond, Sevier, Utah, United States     Redmond, Mason, West Virginia, United States     Redmond Corner, Oneida, New York, United States     Redmondville, Iron, Missouri, United States

The list now includes only cities in the United States.

6.4.1.5. Finding geographic entities with no input place name

The Find method is very powerful because it allows you to find geographic entities without actually specifying a place name. Example queries include: "Find all states in the United States" and "Find all airports in Australia." You can perform these queries based on entity type names, geographic contexts, or by assigning the input place name a null value. The following code shows how to get all state names in the United States:

     //Create find service soap     FindServiceSoap findsoap = new FindServiceSoap( );     //Assign credentials     . . .     //Create FindSpecification     FindSpecification findspec = new FindSpecification( );     //Assign data source     findspec.DataSourceName = "MapPoint.NA";     //Assign null to input place     findspec.InputPlace = null;     //Create find options     findspec.Options = new FindOptions( );     //Set result count     findspec.Options.Range = new FindRange( );     //Set to the maximum count     findspec.Options.Range.Count = 500;     //Set threshold score to zero     findspec.Options.ThresholdScore = 0;     //Assign state entity type to search     fndspec.EntityTypeNames = new string[] {"AdminDivision1"};     //Now call find     FindResults findresults = findsoap.Find(findspec);     //Assign found count     foreach(FindResult findresult in findresults.Results)     {        //Display results        . . .     }

This search results in 51 entities (50 states and Washington D.C.).

To explore more on data sources, entity types, and entity based finds, I have included an application, MapPoint Web Service Data Source Browser, on the companion material as part of the Chapter06 sample solution. Figure 6-2 shows a screenshot of the application with results for the query "Find all airports in Australia."

Finally, it is important remember that, due to performance reasons, for any find query, the maximum number of results returned (FindResult objects) is 500; you cannot issue a find query such as "Find all cities in the world," but if you do have such a requirement, I recommend breaking down the query to get a manageable result set that is less than or equal to 500 each time. An example of such implementation would be to provide a browse functionality where your customers can select a country first, a state second, a county third, and then find all cities within that county without hitting any maximum result count issues, since you are confining your query to a smaller, limited geographic area.

6.4.2. Finding Addresses

While the FindServiceSoap.Find method works well for finding places and geographic entities in general, it doesn't offer any help to find addresses; use the FindServiceSoap.FindAddress method for that purpose.

Like any FindServiceSoap.Find method, the FindServiceSoap.FindAddress method takes a specification object of type FindAddressSpecification and inputs a data source name field of type String and an Options field of type FindOptions as input fields to expose an InputAddress field of type Address. Table 6-3 shows the fields exposed on the FindAddressSpecification object.

Figure 6-2. MapPoint Web Service data source browser


Table 6-3. Fields exposed in the FindAddressSpecification class

Field

Description

DataSourceName

A string representing the name of the data source in which to search for the address. Example: MapPoint.NA.

InputAddress

The input address to be found. This field is of type Address class.

Options

The search options (FindOptions object), which include the range of results, the threshold score of results returned, and a flag to identify which objects are desired in the returned results.


To use a data source to find addresses, it must have the CanFindAddress capability. An address in MapPoint Web Service is always represented as a valid instance of the Address object; the Address class provides fields such as AddressLine, PrimaryCity, SecondaryCity, Subdivision, PostalCode, CountryRegion to represent a valid address for all countries/regions. When used as input, the address line information of an address is optional. When an address is returned as an output, the address object also provides a formatted address string via the FormattedAddress field.

Say you want to find the following address:

     1 Microsoft Way     Redmond, WA 98052     US

First, you need to create an Address object:

     //Create an address object     //And assign address values     Address address =  new Address( );     address.AddressLine = "1 Microsoft Way";     address.PrimaryCity = "Redmond";     address.Subdivision = "WA";     address.PostalCode = "98052";     address.CountryRegion = "US";

Once the Address object is ready, you can find the address information (such as latitude/longitude, best map view information, etc.) using the FindServiceSoap.FindAddress method:

     //Create a find address specification object     FindAddressSpecification findAddressSpec = new FindAddressSpecification();     //Assign input address     findAddressSpec.InputAddress = address;     findAddressSpec.DataSourceName = "MapPoint.NA";     //Call the find address method     FindResults foundAddressResults =                   findService.FindAddress(findAddressSpec);     //Process found results     if (foundAddressResults.NumberFound > 0)     {        if(foundAddressResults.Results[0].FoundLocation.LatLong != null)          {            //Process latitude/longitude information            . . .          }     }

The previous code snippet assumes that you have the FindService object available with proper credentials assigned.

The FindAddressSpecification also exposes the Options field so that you can control the behavior of the locations returned by this method using the FindOptions class; the FindOptions behavior that we have looked at in the Find method still holds true for this method except that you can only get a maximum of 100 results instead of 500.

6.4.3. Finding Points of Interest Around a Location

To find points of interest around a given location, use the FindServiceSoap.FindNearby method. The FindNearby method works only with data sources that have the CanFindNearby capability. As a general rule of thumb, only the point of interest data sources supplied by data vendors such as NavTeq and Acxiom have this capability; data sources such as MapPoint.NA and MapPoint.EU do not support the FindNearby method.

Like any other find service method, the FindNearby method also takes a specification of type FindNearbySpecification class. The FindNearbySpecification object takes information such as the data source name, input location around which you want to find points of interest (as a latitude/longitude), distance to be covered around the original location to find points of interest, and entity types you want to find. Table 6-4 gives an idea of the fields presented in the FindNearbySpecification object.

Table 6-4. Fields in a FindNearbySpecification object

Field

Description

DataSourceName

Data source name as a string.

Distance

The distance from the LatLong property.

Filter

The filter (FindFilter object) to apply to the results. In other words, it is the specific entity type, properties, and values that the returned results must match.

LatLong

The latitude and longitude coordinate (LatLong object) of the point around which the search is made.

Options

The search options (FindOptions object), which include the range of results and a flag to identify which objects are desired in the returned results.


To find all ATMs around the address 1 Microsoft Way, Redmond, WA, get the latitude and longitude information using the FindServiceSoap.FindAddress method, and call FindServiceSoap.FindNearby with one of the point of interest data sources (in this case, I chose to use NavTech.NA) and the entity type name for ATM, SIC3578:

     //Create find service soap instance     FindServiceSoap findService = new FindServiceSoap();     //Assign credentials     . . .     //Define findnearby specification     FindNearbySpecification findNearbySpec  = new FindNearbySpecification();     //Assign a data source     findNearbySpec.DataSourceName = "NavTech.NA";     //Since you are looking for ATMs, assign ATMs entity type     findNearbySpec.Filter = new FindFilter();     //Assign entity type for ATMs     findNearbySpec.Filter.EntityTypeName = "SIC3578";     //Set the distance in miles     findNearbySpec.Distance = 1;     //Assign the location around which you want to find ATMs     findNearbySpec.LatLong = new LatLong();     findNearbySpec.LatLong.Latitude = 47.6;     findNearbySpec.LatLong.Longitude = -122.33;     //Call findnearby method     FindResults foundResults;     foundResults = findService.FindNearby(findNearbySpec);     //Process the results     foreach(FindResult fr in foundResults.Results)     {        . . .     }

The previous code finds ATMs around the specified address within one mile using the NavTech.NA data source; of course you could have also used other points of interest data sources from Acxiom.

Next, say that you are working for a banking company and building an ATM locator application; obviously you would display your company's ATMs around any specified address. It is possible to display your ATMs with the FindNearby method, but since none of the MapPoint data sources or vendor data sources (NavTech, Acxiom, and so on) know about your bank's ATMs specifically, you need to provide a data source for MapPoint Web Service to use with the FindNearby method. That's when the customer data sources come into the picture.

If you do not want to upload your data to MapPoint servers due to security reasons, you can implement your own FindNearby functionality using SQL Serversee Appendix C for more details.


6.4.3.1. Customer data sourcesdisplaying your data

When you sign up for MapPoint Web Service, you are assigned space on MapPoint servers to upload your business data (such as points of interest and icons) to use with the FindNearby method. Using this space, you can create a maximum of 25 data sources on the MapPoint Web Service servers. For example, if your company has banks and ATMs, you would create two data sources with one assigned to each entity type. So, with multiple data sources, you can use different data source files for different types of data. Having said that, there are certain requirements for creating your own data sources:

  • The combined size of all your data sources cannot exceed 2 gigabytes.

  • Each data file that you upload (that contains a number of location records) cannot exceed 100 megabytes.

  • Each data source and the entities it contains must have an entity type, which is a user-defined alphanumeric string, and an entity id, which is an integer.

  • The total number of searchable non-Boolean cells (or entity properties) per data source cannot exceed 8.75 million.

Every entity (or location record) has three required properties (EntityID, latitude, and longitude) and six additional properties created by the MapPoint Geocoder sevice, including MatchCode, MatchedAddress, MatchedMethod, EditedLocationUTC, EditedPropertyUTC, and InputModified. All of these properties are treated as searchable non-Boolean cells, so the number of entities contained in a single data source cannot exceed 972,222 (8.75 million cells divided by 9 non-Boolean, searchable properties per row). The number of Boolean cells per entity in a data source cannot exceed 200.

There are additional requirements applicable for entity property types in MapPoint Web Service, such as number of characters per field and type of characters per field.

For more information on the customer data formatting requirements, see the "Requirements for Custom Location Data" section from the MapPoint Web Service Customer Services site help documentation.


There are two options for uploading and downloading your entities to and from the customer services site: you can either use the Customer Services site web UI, or programmatically upload and download using the Customer Data Service Web Service , which is discussed in detail in Appendix A. Once you upload your custom data, you can use the FindServiceSoap.FindNearby method to use it against your own data.

6.4.4. Finding Points of Interest Along a Route

To find points of interest along a given route, use the FindServiceSoap.FindNearRoute method. The FindNearRoute method works only with data sources that have the CanFindNearby capability. As with the FindNearby method, only the point of interest data sources supplied by data vendors such as NavTeq and Acxiom have this capability; data sources such as MapPoint.NA and MapPoint.EU do not support the FindNearRoute method.

You can read more about calculating routes using RouteServiceSoap in Chapter 7.


Like any other find service method, the FindNearRoute method also takes a specification of type FindNearRouteSpecification class. The FindNearRouteSpecification object takes information, such as the data source name, input route (as a Route object) around which you want to find points of interest, and distance to be covered along the route, and uses it to find points of interest and entity types you want to find. Table 6-5 gives an idea of the fields presented in the FindNearRouteSpecification object.

Table 6-5. Fields in a FindNearRouteSpecification object

Field

Description

DataSourceName

The data source name as a string

Distance

The distance from the Route property

Filter

The filter (FindFilter object) to apply to the results; that is, the specific entity type, properties, and values that the returned results must match

Route

The route from which the points of interest are searched

Options

The search options (FindOptions object), which include the range of results and a flag to identify which objects are desired in the returned results


Say you want to find all the coffee shops along the route that you are planning for a road trip. First, calculate your route using the RouteServiceSoap class; next, call the FindServiceSoap.FindNearRoute with one of the point of interest data sources (I chose to use MapPoint.FourthCoffeeSample) and the entity type name for coffee shops, FourthCoffeeShops, as follows:

     FindServiceSoap findService =                       new FindServiceSoap();     findService.Credentials =                   new System.Net.NetworkCredential(myMapPointUserId,                                                    mySecurePassword);     RouteServiceSoap routeService = new RouteServiceSoap();     routeService.Credentials =                  new System.Net.NetworkCredential(myMapPointUserId,                                                  mySecurePassword);     //Route between two locations     LatLong[] latLongs = new LatLong[2];     latLongs[0] = new LatLong();     latLongs[1] = new LatLong();     latLongs[0].Latitude = 52.5;     latLongs[0].Longitude = 13.1;     latLongs[1].Latitude = 52.51;     latLongs[1].Longitude = 13.11;     //Calculate route     Route myRoute =     routeService.CalculateSimpleRoute(latLongs,                                  "MapPoint.EU",                                 SegmentPreference.Quickest);     //Create near route specificiation     FindNearRouteSpecification findnearroutespec =                               new FindNearRouteSpecification();     findnearroutespec.DataSourceName = "MapPoint.FourthCoffeeSample";     findnearroutespec.Filter = new FindFilter();     findnearroutespec.Filter.EntityTypeName = "FourthCoffeeShops";     findnearroutespec.Distance = 20;     findnearroutespec.Route = myRoute;     FindResults foundResults;     foundResults = findService.FindNearRoute(findnearroutespec);     //Process the results to display on a map     ...

This code finds the coffee shops around the specified route within 20 miles from the beginning of the route using the MapPoint.FourthCoffeeSample data source; you could use different point of interest data sources from Acxiom or NavTech or even your own data source.

Finally, note that the distance must always be greater than 0.1 miles (0.160934 kilometers) and less than 25 miles (40.2336 kilometers).

6.4.5. Finding Custom Entity Types

MapPoint Web Service has a certain set of methods that find entities using their identities and properties, but these methods can only be used with the custom data uploaded to the MapPoint servers. These methods are particularly useful for queries that depend on nonspatial attributes. For example, if you upload all your ATMs to MapPoint servers and you want to display all ATMs in the city of Chicago, or only the ATM that has the unique identity of 13324, these methods can be either simple non-spatial queries or spatial queries. In this section, let's look at these find methods that can be used with your custom data.

6.4.5.1. Find entity by identity

You can use the FindServiceSoap.FindByID method to find entities using their entity IDs. Like any other find method, this method takes a specification object of type FindByIDSpecification and returns a FindResults object. The FindByIDSpecification object takes up to 500 IDs as input parameters. Table 6-6 shows the fields exposed on the FindByIDSpecification object.

Table 6-6. Fields exposed in the FindByIDSpecification object

Field

Description

DataSourceName

Data source name as a string

EntityIDs

Array of unique entity IDs; only points of interest with matching entity IDs are returned, while the rest are ignored

Filter

The filter (FindFilter object) to apply to the results, which includes the specific entity type, properties, and values that the returned results must match

Options

The search options (FindOptions object), which may include the range of results and a flag to identify which objects are desired in the returned results


The following code shows how to use the FindByID method:

     //Create a Find Service proxy     FindServiceSoap findService = new FindServiceSoap();     //Assign credentials     . . .     //Define find by id specification     FindByIDSpecification findbyidspec = new FindByIDSpecification();     //Assign a data source name     findbyidspec.DataSourceName = "MapPoint.FourthCoffeeSample";     //Apply a filter for entity name     findbyidspec.Filter = new FindFilter();     findbyidspec.Filter.EntityTypeName = "FourthCoffeeShops";     //Now assign the entity IDs to find     int[] arrayID = {-21835, -21836};     findbyidspec.EntityIDs = arrayID;     //Call FindById method     FindResults foundResults;     foundResults = findService.FindByID(findbyidspec);

The found entities are returned in the same order that the entity IDs are passed in, but you can override this sorting behavior using the FindFilter.SortProperties. Assuming that you want to sort the ATMs in the previous FindByID method by their associated bank name (assuming that there is a property called ParentBankName), the method call looks as follows:

     //Create a Find Service proxy     FindServiceSoap findService = new FindServiceSoap();     //Assign credentials     . . .     //Define find by id specification     FindByIDSpecification findbyidspec = new FindByIDSpecification();     //Assign a data source name     findbyidspec.DataSourceName = "MapPoint.FourthCoffeeSample";     //Apply a filter for entity name     findbyidspec.Filter = new FindFilter();     findbyidspec.Filter.EntityTypeName = "FourthCoffeeShops";     //Specify what properties to be used to sort the found results     SortProperty[] sortproperties = new SortProperty[1];     sortproperties[0] = new SortProperty();     //Assign the property name to be sorted on     sortproperties[0].PropertyName = "ParentBankName";     //Specify the sort direction: Ascending or Descending     sortproperties[0].Direction = SortDirection.Descending;     //Assign sort specification to the find filter     findbyidspec.Filter.SortProperties = sortproperties;     //Now assign the entity ids to find     int[] arrayID = {-21835, -21836};     findbyidspec.EntityIDs = arrayID;     //Call FindById method     FindResults foundResults;     foundResults = findService.FindByID(findbyidspec);

As you can see, the SortProperties method is an array, so you can sort the resulting entities by more than one attribute if needed.

It is important to remember that the points of interest entity identities are not persisted from one version of the MapPoint Web Service to another, so if you hardcode the point of interest entity IDs into your application, when you upgrade to a newer MapPoint Web Service, your application may break. To make it easy to distinguish between positive and negative IDs, all negative entity IDs (such as entity ID -21835 for a coffee shop) are not persisted across versions, while the positive IDs are (such as entity ID 244 for the United States).

6.4.5.2. Finding entity by properties

Many times, you want to query for entities based on their propertiesfor example, finding all ATMs in the city of Chicago, or all coffee shops that accept credit cards. In this case, the query is based solely on the entity properties, and you should use the FindServiceSoap.FindByProperty method for this purpose. The FindByProperty method takes a specification object of type FindByPropertySpecification, which takes the queries to find entities using their properties. Table 6-7 shows the fields exposed on the FindByPropertySpecification object.

Table 6-7. Fields in the FindByPropertySpecification object

Field

Description

DataSourceName

Name of the data source as a string

Filter

The filter (FindFilter object) to apply to the results; that is, the specific entity type, properties, and values that the returned results must match

Options

The search options (FindOptions object), which may include the range of results and a flag to identify which objects are desired in the returned results


The following code shows how to use these expressions to find entities using the FindByProperty method:

     //Create a find service soap proxy class     FindServiceSoap findService = new FindServiceSoap();     //Assign credentials     . . .     //Create find by property specification     FindByPropertySpecification findbypropspec = new FindByPropertySpecification();     //Define find by property specification     findbypropspec.DataSourceName = "MapPoint.FourthCoffeeSample";     //Assign a filter     findbypropspec.Filter = new FindFilter();     //Specify the entity type that you are looking for     findbypropspec.Filter.EntityTypeName = "FourthCoffeeShops";     //Now define and assign the expression     findbypropspec.Filter.Expression = new FilterExpression();     findbypropspec.Filter.Expression.Text = "PrimaryCity = {0} AND IsWiFiHotSpot";     findbypropspec.Filter.Expression.Parameters = new object[] {"Chicago"};     FindResults foundResults;     foundResults = findService.FindByProperty(findbypropspec);

The resulting expression from this code is "PrimaryCity = 'Chicago' AND IsWiFiHotSpot", which means to return only coffee shops in the city of Chicago that have WiFi Hotspots available. Even though the filter expressions look and behave like SQL expressions, there are limitations that you need to be aware of:

  • The expression text should never contain the values that are being compared, but the text must provide the placeholders for all non-Boolean value types. Placeholders are represented by "{nn}" where n is an integer between 0 and 9.

  • The comparison operators LIKE and NOT LIKE support only the "Starts with" condition.

  • Maximum length of the expression text is limited to 2,000 characters.

  • No more than one level of nesting (parenthesis) is allowed.

  • A maximum of 10 non-Boolean comparisons and a maximum of 10 sub-clauses are allowed.

  • A maximum of 50 total comparisons per expression is allowed.

Next, let's look at an example expression: you want to find all coffee shops in the city of Chicago that have a seating capacity greater than 20 or that are open 24 hours a day whose names start with the letter C. The expression to pass for the FindByProperty method would be: (City={0} AND SeatingCapacity>{1}) OR (StoreType={2} AND Name LIKE {3}) with the arguments Chicago, 20, Open 24 Hours and C.

Now that you know how to use the find service APIs, let's look at some of the common service methods that are relevant to the finding places, addresses, and entities.

6.4.6. Finding Polygons

With the find methods, you have seen how to find places, addresses, and points around a place or address, but all you have been finding so far are points (latitude and longitude coordinates). You may have a requirement to find polygons in situations with queries such as: "find all polygons that contain a point (latitude/longitude)" or "find all polygons that have spatial relationship with a rectangle." In order to accomplish such tasks, use the FindServiceSoap.FindPolygon method.

To learn more about polygons, refer to Appendix B.


Like any find method in Find Service, the FindPolygon method takes the FindPolygonSpecification object as an argument and returns a valid FindResults object. The FindPolygonSpecification object provides a way for you to specify arguments such as data source name and spatial filter. Table 6-8 shows the fields exposed by the FindPolygonSpecification class.

Table 6-8. Fields of the FindPolygonSpecification class

Field

Description

DataSourceName

Name of the data source as a string

Filter

The filter (FindFilter object) to apply to the results, including the specific entity type, properties, and values that the returned results must match

Options

The search options (FindOptions object), which may include the range of results and a flag to identify which objects are desired in the returned results

SpatialFilter

The spatial filter (SpatialFilter object) to apply to the results


One interesting field from Table 6-8 is the SpatialFilter field; this field is of type SpatialFilter class, and it defines the spatial relationship between polygons, points, and rectangles. The SpatialFilter class is an abstract class, and there are two classes that derive this abstract class to define two specific spatial relationships:


LatLongSpatialFilter

Defines a spatial filter that returns only polygons that include the point specified by the LatLong object. This is used in specifying a spatial filter to find polygons that contain a certain point. This class has only one field that takes the target point as a LatLong object. The following code shows how to specify a LatLongSpatialFilter to find polygons that contain a given set of latitude and longitude coordinates:

     //Create a new instance of LatLongSpatialFilter     LatLongSpatialFilter filter = new LatLongSpatialFilter();     //Assign the given latitude and longitude values     Filter.LatLong = new LatLong();     Filter.LatLong.Latitude = 47.44;     Filter.LatLong.Longitude = -122.55;


LatLongRectangleSpatialFilter

Defines a spatial filter that returns polygons related to the LatLongRectangle specified via the BoundingRectangle field. The relation between the polygons and the rectangle is determined by the PolygonRectangleRelation field. This field is of type SpatialRelation enumeration and has two values that are shown in Table 6-10. The LatLongRectangleSpatialFilter class is used in defining a spatial filter to find polygons that fall within or touch a rectangle. The following code shows how to define this spatial filter to find all polygons that fall within a rectangle:

     //Define a new instance of LatLongRectanglSpatialFilter     LatLongRectangleSpatialFilter rectangleFilter =                         new LatLongRectangleSpatialFilter();     //Define a bounding rectangle with north east and south west     //corners     LatLongRectangle boundingRectangle = new LatLongRectangle();     boundingRectangle.Northeast = new LatLong();     boundingRectangle.Northeast.Latitude = 47.44;     boundingRectangle.Northeast.Latitude = -122.56;     boundingRectangle.Southwest = new LatLong();     boundingRectangle.Southwest.Latitude = 41.44;     boundingRectangle.Southwest.Latitude = -119.56;     //Now assign bounding rectangle to the filter     rectangleFilter.BoundingRectangle = boundingRectangle;     //Define the spatial relationship to be     //"find polygons inside the rectangle"     rectangleFilter.PolygonRectangleRelation =                                 SpatialRelation.WithinArea;

Now that you know how to define spatial filters , let's look at the FindPolygon method in action, using the relations shown in Table 6-9.

Table 6-9. SpatialRelation enumeration

Item

Description

WithinArea

Returns all polygons contained entirely within the specified rectangle

TouchesArea

Returns all polygons that come into contact with the specified rectangle


Use the FindPolygon method to find Polygons that either contain a specified point or are spatially related to a rectangle. The y method takes the FindPolygonSpecification object as an argument, as shown in the following code:

     //Create an instance of FindServiceSoap and assign     //Credentials     FindServiceSoap findService                          = new FindserviceSoap();     //Assign your credentials     . . .     //Create an instance of FindPlygonSpecification     FindPolygonSpecification findPolySpec                          = new FindPolygonSpecification();     //Create a new instance of LatLongSpatialFilter     LatLongSpatialFilter filter = new LatLongSpatialFilter();     //Assign the given latitude and longitude values     Filter.LatLong = new LatLong();     Filter.LatLong.Latitude = 47.44;     Filter.LatLong.Longitude = -122.55;     //Assign the spatial   filter to the find polygon specification     findPolySpec.SpatialFilter=filter;     //Assign your polygon data source     findPolySpec.DataSourceName="your polygon data source";     //Define what kind of entities you are looking for     FindFilter findfilter = new FindFilter();     findfilter.EntityTypeName = "your entity name";     findPolySpec.Filter = findfilter;     //Call Find Polygon     FindResults findResults = findService.FindPolygon(findPolySpec);     //Now get the polygon entities     foreach(FindResult findResult in findResults.Results)     {         //Get polygons that matched the query         Console.WriteLine(String.Format(                            "Polygon Entity Matched with ID: {0}",                             findResult.FoundLocation.Entity.ID)                          );     }

Now that you have the entity IDs of polygons that match your spatial filter criteria, you can use that information either to render the polygons (covered more in Chapter 8) or to perform any other processing to suit your business needs.

6.4.7. Getting Entities from Latitude/Longitude

We have looked at find service methods that take place names and addresses and return the corresponding latitude/longitude and other entity information. To find entity (or address) information for any given latitude/longitude, use the FindServiceSoap.GetLocationInfo; it gives you entity information for any given latitude and longitude. The GetLocationInfo method takes the GetInfoOptions object as an argument, along with a latitude/longitude and a data source name as a string. The GetLocationInfo object gives you control to decide which entity types you want using the GetInfoOptions.EntityTypesToReturn field; you also have the option to obtain addresses for a given latitude/longitude (if available) using the GetInfoOptions.IncludeAddresses flag. The following code shows how to use the GetLocationInfo method:

     //Create a find service soap proxy     FindServiceSoap findService = new FindServiceSoap();     //Take an example lat long information that you want to     //find using GetLocationInfo     LatLong latlong = new LatLong();     latlong.Latitude = 47.682;     latlong.Longitude = -122.132;         //Define get info options object     GetInfoOptions options = new GetInfoOptions();     //I'm looking only for cities     options.IncludeAllEntityTypes = false;     options.EntityTypesToReturn = new string[] {"PopulatedPlace"};     //Define a field to hold returned locations     Location[] returnedLocations;     //Call GetLocationInfo with "MapPoint.NA" data source     returnedLocations = findService.GetLocationInfo(latlong, "MapPoint.NA", options);     //Get entity information     for(int i = 0; i < returnedLocations.Length; i++)     {     Console.WriteLine(returnedLocations[i].Entity.DisplayName);     }

When I'm querying for corresponding entities for the latitude/longitude, I limit my query to a city (the entity name PopulatedPlace) using the EntityTypesToReturn field; it is important to remember that you must set the IncludeAllEntityTypes to false when you request specific entities.

This method is not a direct inverse to the FindServiceSoap.FindAddress method, so if you call the FindServiceSoap.FindAddress method to obtain latitude/longitude for an address and pass that latitude/longitude to the FindServiceSoap.GetLocationInfo method, the resulting address won't match your original address because of the internal representation of the address data; in MapPoint data sources, addresses are stored in address range blocks along the streets, and the interpolation algorithms are used to calculate the address for a given latitude/longitude and vice versa. So, the addresses returned by the FindServiceSoap.GetLocationInfo are approximations of the original address; in fact, this method returns an array of four possible addresses for any given latitude/longitude in increasing order of the distance from the given latitude/longitude.

6.4.8. Parsing Addresses

We have seen various capabilities of Find Service to find places, addresses, nearby entities, and points of interest, but what happens if you have an address in an unstructured or unformatted form? What if you want to create an application where your users can type their address in a textbox without worrying about the formatting? How do you parse the address field to understand various parts of the address? You can use the FindServiceSoap.ParseAddress method for these purposes. The ParseAddress method takes two arguments, input address as a string and an optional country/region name, and returns an Address object for valid addresses. For example, if you have the address 1 Microsoft Way, Redmond, WA in string format, you can use the ParseAddress method to parse it into an Address object:

     //Create a web service proxy     FindServiceSoap findService  = new FindServiceSoap();     //Assign credentials     . . .     //Parse a string into a valid address object     Address address =          findService.ParseAddress("1 Microsoft Way, Redmond", "United States");

One of the greatest advantages of this method is that you can implement one user interface that can perform both find place and find address depending on what users input without having to design two different UIs for two different purposes.




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