MapGuide Open Source Developer Guide
MapGuide Open Source Developer Guide
Developers Guide
January 2008
Trademarks
Autodesk, Autodesk Map, Autodesk MapGuide are registered trademarks of Autodesk, Inc., in the USA and/or other countries. DWF is a trademark of Autodesk, Inc., in the USA and/or other countries. All other brand names, product names or trademarks belong to their respective holders.
Contents
Chapter 1
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
What This Guide Covers . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Essential Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Preparing to Run the Examples . . . . . . . . . . . . . . . . . . . . . . . 2 Application Development . . . . . . . . . . . . . . . . . . . . . . . . . 3 Resources and Repositories . . . . . . . . . . . . . . . . . . . . . . . . . 3 Library and Session . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Hello, Map Displaying a Web Layout . . . . . . . . . . . . . . . . . . . 5 Hello, Map 2 Adding a Custom Command . . . . . . . . . . . . . . . 7 Web Layouts and MapGuide Server Pages . . . . . . . . . . . . . . 8 MapGuide Page Flow . . . . . . . . . . . . . . . . . . . . . . . . . 9 Example Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 How This Page Works . . . . . . . . . . . . . . . . . . . . . . . . 12 Understanding Services . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Chapter 2
iii
Calling the Viewer API from the Task Pane . . Extending Map Initialization Functionality . The Hello Viewer Sample . . . . . . . . . . . Embedding a Viewer in Your Own Page . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. 22 . 23 . 23 . 25
Chapter 3
Chapter 4
Chapter 5
iv | Contents
Creating Layers By Modifying XML . . . . . Another Way To Create Layers . . . . . . . Example - Creating A Layer That Uses Example - Using Line Rules . . . . . . Example - Using Point Rules . . . . . Adding Layers To A Map . . . . . . . . . . Making Changes Permanent . . . . . . . .
. . . . . . Area . . . . . . . . . . . .
. . . . . . . . Rules . . . . . . . . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. 58 . 60 . 64 . 65 . 66 . 68 . 71
Chapter 6
Analyzing Features . . . . . . . . . . . . . . . . . . . . . . . . 73
Introduction . . . . . . . . . . . . . . . . . . . . Representation of Geometry . . . . . . . . . . . Geometry Objects . . . . . . . . . . . . . . Comparing Geometry Objects . . . . . . . Coordinate Systems . . . . . . . . . . . . . . . . Measuring Distance . . . . . . . . . . . . . . . . Temporary Feature Sources . . . . . . . . . . . . Inserting, Deleting, and Updating Features . Creating a Buffer . . . . . . . . . . . . . . . . . Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 . 73 . 74 . 75 . 76 . 77 . 78 . 81 . 82 . 84
Chapter 7
Chapter 8
Custom Output . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 Rendering Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Mapping Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Contents | v
vi
Introduction
Essential Concepts
Refer to the MapGuide Getting Started guide for details about the MapGuide architecture and components. It is important to understand the relationship between a MapGuide Viewer, a MapGuide Web application, and the MapGuide site. It is also important to understand resources and repositories. Web applications reside on the Web Server. They are normally executed by requests from a MapGuide Viewer. They can in turn communicate with the MapGuide site and send data back to the Viewer. When you define a web layout, using Autodesk MapGuide or some other method, you also define toolbar and menu commands. These can be standard pre-defined Viewer commands like pan, zoom, and refresh, or they can be custom commands. Custom commands are a way of extending MapGuide to
interact with your mapping data. The custom commands are HTML pages, generated on the server using PHP, ASP.NET, or Java (JSP). These languages can use the Web API to retrieve, manipulate, and update mapping data. The current version of MapGuide Open Source Web Studio does not create or edit web layouts. It is possible, however, to create and edit web layouts using the Mapagent HTML pages at http://ServerAddress/mapguide/mapagent/index.html. Get an existing web layout, such as the web layout supplied with the sample applications, using the GetResourceContent and GetResourceHeader links. Edit the XML in a text editor, then save to the site repository using the SetResource link. Many custom commands run in the task area, a section of the Viewer that is designed for user input/output. For more details about the task area and how it integrates with the rest of the Viewer, see The MapGuide Viewer on page 15.
2 | Chapter 1 Introduction
The sample applications also include links to the MapGuide documentation, but the links only work if the documentation files are visible to the web server. By default, the installation program installs the documentation in the ...\WebServerExtensions\Help folder. If you copy or move the Help folder to ...\WebServerExtensions\www\Help the documentation will be available directly from the main page of the sample applications.
Application Development
Hints for debugging, etc. Making script frame visible to catch errors there Use Firefox because of DOM Inspector, Error console, Venckman, Reading Apache log for PHP errors. Is there an equivalent for IIS? Other sources of log information?
Feature data from SHP and SDF files Drawing data from DWF files Map symbols Layer definitions Map definitions Web layouts Connections to feature sources, including database credentials
Application Development | 3
A resource identifier for a session resource will always begin with Session:, followed by the session id. For example:
Session:70ea89fe-0000-1000-8000-005056c00008_en//layer.LayerDefinition
Maps
A map (MgMap object) is created from a map definition resource. The map definition contains basic information about the map, including things like
the coordinate system used in the map the initial map extents references to the layer definitions for layers in the map
When the MgMap object is created, it is initialized with data from the map definition. As a user interacts with the map, the MgMap may change, but the map definition does not. The map is saved in the session repository so it is available to all pages in the same session. You cannot save a map in the library repository. Map creation is handled by the Viewers. When a Viewer first loads, it creates a map in the session repository. The map name is taken from the map definition name. For example, if a web layout references a map definition named Sheboygan.MapDefinition, then the Viewer will create a map named Sheboygan.Map.
4 | Chapter 1 Introduction
If your application does not use a Viewer, you can create the map and store it in the repository yourself. To do this, your page must
Create an MgMap object. Initialize the MgMap object from a map definition. Assign a name to the MgMap object. Save the map in the session repository.
For example, the following section of code creates an MgMap object named Sheboygan.Map, based on Sheboygan.MapDefinition.
$mapDefId = new MgResourceIdentifier( "Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition"); $map = new MgMap(); $mapName = $mapDefId->GetName(); $map->Create($resourceService, $mapDefId, $mapName); $mapId = new MgResourceIdentifier( "Session:$sessionId//$mapName." . MgResourceType::Map); $map->Save($resourceService, $mapId);
Authentication
All MapGuide sites require authentication with user id and password. If authentication succeeds, MapGuide creates a session, identified by a unique session id. This keeps the state consistent between the viewer and the server across multiple HTTP requests. Subsequent access to the site requires the session id instead of the user id. By default, the Viewer handles authentication itself, and it prompts for user id and password when it first loads. There are situations, though, where it is better to authenticate before loading the Viewer page. One common example is a site offering read-only access to visitors. For this situation, the default MapGuide installation includes a user Anonymous with an empty password. To perform authentication before the Viewer loads, embed the Viewer in another page using a <frame> or <iframe> element. The outer page can do any necessary authentication, create a session, then pass the web layout and session id to the Viewer frame. The following example displays a web layout using the AJAX Viewer. It performs some basic initialization and creates a session, then displays a Viewer page using the session identifier and the web layout.
6 | Chapter 1 Introduction
<?php $installDir = 'C:Program FilesMapGuideOpenSourcece.buildprop.entity.ProdStu dio=Studio\'; $extensionsDir = $installDir . 'WebServerExtensions\www\\'; $viewerDir = $installDir . 'mapviewerphp\\'; include $viewerDir . 'constants.php'; MgInitializeWebTier($extensionsDir . 'webconfig.ini'); $site = new MgSite(); $site->Open(new MgUserInformation("Anonymous", "")); $sessionId = $site->CreateSession(); $webLayout = "Library://Samples/Layouts/SamplesPhp.WebLayout"; ?> <html> <head> <title>Simple Sample Application</title> </head> <body marginheight="0" marginwidth="0"> <iframe id="viewerFrame" width="100%" height="100%" frameborder=0 scrolling="no" src="/mapguide/mapviewerajax/?SESSION=<?= $sessionId ?>& WEBLAYOUT=<?= $webLayout ?>"></iframe> </body> </html>
This next sample MapGuide page displays some basic information about a map. It does not do any complicated processing. Its purpose is to illustrate the steps required to create a MapGuide page and have it connect to a Viewer on one side and the MapGuide site on the other.
When you open the web layout using a browser with either the AJAX Viewer or the DWF Viewer, the resource name is passed as part of the Viewer URL. Special characters in the resource name are URL-encoded, so the full URL would look something like this, (with line breaks removed):
http://localhost/mapguide/mapviewerajax/ ?WEBLAYOUT=Library%3a%2f%2fSamples%2fSheboygan%2fLayouts%2f SheboyganPhp.WebLayout
Part of the web layout defines commands and the toolbars and menus that contain the commands. These commands can be built-in commands, or they can be URLs to custom pages. The web layout also includes a URL to a home task that displays in the task pane. The home task can open other pages. To create a new page and make it available as a command from the task list, do the following:
8 | Chapter 1 Introduction
Add a command to the web layout. Set the command type to Invoke URL. Set the URL of the command to the URL of your page. Add the command to the Task Bar Menu.
NOTE Custom pages are loaded by the Viewer page, so a relative URL for a custom page must start at the Viewer directory, then go up one level to reach the mapguide directory. For example, a custom page located at www/mapguide/samplesphp/index.php would use the following relative URL in the web layout
../samplesphp/index.php
It is also possible to add custom commands to the toolbar and the context menu using the same technique. For most of the examples in this guide, however, the pages will be links from a home page loaded in the task pane frame. NOTE Installing the package that comes with the Developers Guide samples creates a web layout automatically. The home task page of this layout contains links to examples that correspond to chapters in the Developers Guide.
Example Code
The following sample illustrates basic page structure. It is designed to be called as a task from a Viewer. It connects to a MapGuide server and displays the map name and spatial reference system for the map currently being displayed in the Viewer. TIP This sample is very similar to the Hello Map sample in the Developers Guide samples.
10 | Chapter 1 Introduction
<html> <head><title>Hello, map</title></head> <body> <p> <?php // Define some common locations $installDir = 'C:Program FilesMapGuideOpenSourcece.buildprop.entity.Prod Studio=Studio\'; $extensionsDir = $installDir . 'WebServerExtensions\www\\'; $viewerDir = $extensionsDir . 'mapviewerphp\\'; // constants.php is required to set some enumerations // for PHP. The same step is not required for .NET // or Java applications. include $viewerDir . 'constants.php'; try { // Get the session information passed from the viewer. $args = ($_SERVER['REQUEST_METHOD'] == "POST") ? $_POST : $_GET; $mgSessionId = $args['SESSION'] $mgMapName = $args['MAPNAME'] // Basic initialization needs to be done every time. MgInitializeWebTier("$extensionsDir\webconfig.ini"); // Get the user information using the session id, // and set up a connection to the site server. $userInfo = new MgUserInformation($mgSessionId); $siteConnection = new MgSiteConnection(); $siteConnection->Open($userInfo); // Get an instance of the required service(s). $resourceService = $siteConnection-> CreateService(MgServiceType::ResourceService); // Display the spatial reference system used for the map. $map = new MgMap(); $map->Open($resourceService, $mgMapName);
Example Code | 11
$srs = $map->GetMapSRS(); echo 'Map <strong>' . $map->GetName() . '</strong> uses this reference system: <br />' . $srs; } catch (MgException $e) { echo "ERROR: " . $e->GetMessage() . "<br />"; echo $e->GetStackTrace() . "<br />"; } ?> </p> </body> </html>
12 | Chapter 1 Introduction
Any MapGuide pages require a connection to a site server, which manages the repository and site services. 5 Create a connection to a resource service. Access to resources is handled by a resource service. In this case, the page needs a resource service in order to retrieve information about the map resource. You may need to create connections to other services, depending on the needs of your application. 6 Retrieve map details. The map name is also passed by the viewer to the MapGuide page. Use this name to open a particular map resource with the resource service. Once the map is open you can get other information. This example displays the spatial reference system used by the map, but you can also get more complex information about the layers that make up the map.
Understanding Services
The MapGuide site performs many different functions. These can be all done by a single server, or you may balance the load across multiple servers. Some essential functions must execute on the site server, while other functions may execute on support servers. A service performs a particular set of related functions. For example, a resource service manages data in the repository, a feature service provides access to feature data sources, and a mapping service provides visualization and plotting functions. Before a page can use a service, it must open a site connection and create an instance of the necessary service type. The following example creates a resource service and a feature service:
$userInfo = new MgUserInformation($mgSessionId); $siteConnection = new MgSiteConnection(); $siteConnection->Open($userInfo); $resourceService = $siteConnection-> CreateService(MgServiceType::ResourceService); $featureService = $siteConnection-> CreateService(MgServiceType::FeatureService);
Understanding Services | 13
14
Introduction
TIP The Hello Viewer sample, in the Developers Guide samples, demonstrates concepts from this chapter. The MapGuide Viewer is a browser-based method for displaying map data in a MapGuide application. It is a complete application, with support for standard mapping functionality like zooming, theming, and selecting features. There are two different versions of the Viewer:
DWF Viewer, which runs only within Internet Explorer, and requires a browser plug-in AJAX Viewer, which runs within Internet Explorer, Mozilla Firefox, and Safari, without requiring a browser plug-in
As much as possible, the two versions of the Viewer operate in the same way, so deciding which to use depends on the needs of the application. If all the end users of the application use Internet Explorer, the DWF Viewer my be an appropriate choice, but if some of them use a different browser the AJAX Viewer is a better choice. Most MapGuide applications use a Viewer, though it is possible to create applications that perform data analysis or manipulation but do not display using the Viewer. For example, a MapGuide application can be used as a back-end to another mapping application.
15
The standard Viewer displays a map along with the following optional components surrounding the map:
Tool bar Layers pane Properties pane Status bar Task bar Task list (normally hidden, but available as a drop-down from the task bar) Task pane Context (right-click) menu Zoom slider (AJAX Viewer only)
MapGuide Viewer
The tool bar, task list, task pane, and context menu can contain a combination of pre-defined and custom MapGuide commands. A web layout defines how the Viewer looks and operates for a map. One function of a web layout is to define which optional components display with the map. All of the optional components can be disabled, leaving just the map itself.
The web layout also defines any custom functionality added to the web page through custom commands.
Custom Commands
Custom commands can be of two types:
JavaScript commands Web Server Extensions pages, written in PHP, ASP.NET, or JSP
JavaScript commands are defined in the web layout as commands of type Invoke Script. They are used primarily to interact with the Viewer, and can use the Viewer API. Web Server Extensions pages can be added to the web layout in two different ways. In one method, the web layout includes a home page. This home page is loaded in the task pane when the map first displays, and can be re-loaded by clicking the Home icon in the task bar. The home page can load other pages as needed. In addition, other task pages can be defined in the web layout as commands of type Invoke URL. These commands can be added to the tool bar, task list, or context menu. When a user selects one of these commands the corresponding URL is often loaded into the task pane, though it can also be loaded into a hidden frame so it is not visible. Because Web Server Extensions pages are created at the web tier before being passed to the Viewer, they can use both the Web Server Extensions API and the Viewer API.
Custom Commands | 17
Name
maparea
Description
Frame set containing the tool bar, map frame, form frame, and script frame. Frame containing the tool bar. Add new commands to the tool bar by modifying the web layout. Frame containing the map data. This includes the map display and the layers and properties palettes. Hidden frame that can be used to generate HTTP POST requests for sending data to the server. Hidden frame that can be used to load and execute pages without them being visible to the user. This is often used for executing client-side JavaScript. Frame set containing the task bar and the task frame. Frame containing the task bar. Frame used to hold the task list frame and the task pane frame. Frame used for displaying the task list. This is normally hidden, and is shown when a user clicks the task list button in the task bar. Add new commands to the task list by modifying the web layout. Frame used for displaying and executing MapGuide pages. A web layout has a default home page that displays in the task pane when the layout loads. Custom commands of type Invoke URL also load in the task pane. Frame containing the status bar.
tbFrame
mapFrame
formFrame
scriptFrame
taskArea
taskBar
taskFrame
taskListFrame
taskPaneFrame
sbFrame
/mapguide/mapviewerajax/? SESSION=sessionid&WEBLAYOUT=weblayout (2-row frameset) (2-column frameset) mapArea tbFrame (tool bar) taskArea taskBar (task bar)
mapFrame
taskFrame taskListFrame
taskPaneFrame
Viewer Frames
To execute any of the Viewer API functions, call them from JavaScript embedded in a page. There are three common techniques for this:
Define an Invoke Script command in the web layout. Use this technique when you want to call the Viewer API directly from the tool bar, task list, or context menu. Load a page into the hidden script frame and execute the script when the page loads. Use this technique when you want the Viewer to change as a result of an action in the MapGuide page, without reloading the page. Execute the JavaScript call from a page loaded in the task pane frame. The JavaScript can execute when the page first loads or as a result of user interaction.
It is important to know the relationships between the frames. JavaScript executes in the context of a single frame, but it can call functions from other frames by locating them in the frame hierarchy. The following frames are children of the main Viewer frame:
tbFrame mapFrame formFrame scriptFrame taskFrame
The taskPaneFrame is a child of the taskFrame. Custom JavaScript code can execute in the context of the main frame, the script frame, or the task pane frame. JavaScript defined as an Invoke Script command executes in the context of the main frame. To execute functions in one of the other frames, identify the function with the frame name and function name. For example, the following calls the ZoomToView() function of the mapFrame from the main frame:
mapFrame.ZoomToView(xLoc, yLoc, newScale, true);
JavaScript loaded into the scriptFrame must go up 1 level in the hierarchy using parent. For example:
parent.mapFrame.ZoomToView(xLoc, yLoc, newScale, true);
JavaScript loaded into the taskPaneFrame must go up 2 levels in the hierarchy using parent.parent. For example:
parent.parent.mapFrame.ZoomToView(xLoc, yLoc, newScale, true);
Many Viewer API calls will generate requests to the site server, either to refresh data in the Viewer or to notify the site server of a change in Viewer state. These requests are generated automatically.
Add the button to the tool bar. When a user clicks the button, the map view repositions to the location. Commands of type Invoke Script always execute in the context of the main frame. This means that all main frame functions are available. To execute a function in another frame, use the frame name as part of the function name. For example, formFrame.Submit().
The Hello Viewer sample application contains a file named gotopoint.php that is designed to run in the script frame. The <body> element is empty, so the page does not produce any output. Instead, it emits a JavaScript function to execute when the page loads. This function calls the ZoomToView() function in the Viewer API. The essential parts of gotopoint.php are:
<script language="javascript"> function OnPageLoad() { parent.ZoomToView(<?= $_GET['X'] ?>, <?= $_GET['Y'] ?>, <?= $_GET['Scale'] ?>, true); } </script> <body onLoad="OnPageLoad()"> </body>
To execute gotopoint.php from the task frame, insert code similar to the following:
$xLocation = -87.7116768; // Or calculate values $yLocation = 43.7766789973; $mapScale = 2000; echo "<p><a href=\"gotopoint.php?" . "X=$xLocation&Y=$yLocation&Scale=$mapScale\"" . "target=\"scriptFrame\">Click to position map</a></p>";
NOTE This technique is also appropriate for calling the Web API without reloading the task pane. See the Modifying Maps and Layers sample for an example.
the task pane, create a function that will be executed when the onLoad event occurs. The following is a simple example. If you add this to the task list and select the task, the displayed map will reposition to the given location.
<html> <head> <title>Viewer Sample Application - Zoom</title> </head> <script language="javascript"> function OnPageLoad() { parent.parent.ZoomToView(-87.7116768, 43.7766789973, 5000, true); } </script> <body onLoad="OnPageLoad()"> <h1>Zooming...</h1> </body> </html>
Use a similar technique to call custom JavaScript based on an action in the task pane, like clicking a link.
The tool bar for the sample contains a custom Invoke Script command that calls the ZoomToView() function of the mapFrame. This is executed in the context of the main frame, so the function is available using
mapFrame.ZoomToView()
The task pane loads a page that shows two other ways of calling ZoomToView(). One way loads a custom page into the hidden scriptFrame. The page reads GET parameters and passes them to the JavaScript function call. This is executed in the context of the scriptFrame, so ZoomToView() is available using
parent.mapFrame.ZoomToView()
Another way calls ZoomToView() directly when a link is clicked, using the JavaScript onclick event. This is executed in the context of the taskPaneFrame, so ZoomToView() is available using
parent.parent.mapFrame.ZoomToView()
The Developers Guide samples also demonstrate a more advanced method for using JavaScript in a Viewer. The file index.php includes an external JavaScript file that solves 2 problems:
When a map is first loading, the task pane displays before the map has been fully initialized. This can cause problems if users click any links in the task pane that depend on the map being available. The first time the Viewer loads a page into the task pane, it passes SESSION and WEBLAYOUT as GET parameters. The map name is not known until after the web layout has loaded. When a user clicks the Home button, the Viewer reloads the home page in the task pane, but passes SESSION and MAPNAME as GET parameters instead. In some cases, it may be useful for the home page to have the map name when it first loads.
To deal with these problems, the Hello Viewer sample loads pageLoadFunctions.js, which attaches a function to the window.onload event of the page in the task pane. This function does the following:
Replaces the OnMapLoaded() function of the main frame. This function is called after the map has been fully initialized. The new version performs some initialization (see below), then calls the original OnMapLoaded(). Saves the contents of the task pane page and replaces it with the text Loading.... After the map is fully initialized, it calls the new version of OnMapLoaded(). At this point, the map name is known, and is available from the
mapFrame.GetMapName() function. The new version of OnMapLoaded() restores the contents of the task pane page, then it searches all <a> elements, replacing MAPNAME=unknown with the correct map name in the href
attributes. See the Hello Viewer sample for links to view index.php and pageLoadFuctions.js.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"> <?php require_once('common/common.php'); try { // Initialize the web extensions, MgInitializeWebTier ($webconfigFilePath); // Connect to the site server and create a session $userInfo = new MgUserInformation("Author", "author"); $site = new MgSite(); $site->Open($userInfo); } catch (MgException $e) { echo "Could not connect to the MapGuide site server."; die(); } try { $sessionId = $site->CreateSession(); // Define some constants $webLayout = "Library://Samples/Layouts/SamplesPHP.WebLayout"; $title = "Samples"; } catch (MgException $e) { echo "ERROR: " . $e->GetMessage("eng") . "\n"; echo $e->GetStackTrace("eng") . "\n"; } ?> <html> <head> <title><?= $title ?></title> </head> <frameset rows="110,*"> <frame src="common/Title.php?TitleText=<?= $title ?>"
name="TitleFrame" scrolling="NO" noresize /> <frame src="/mapguide/mapviewerajax/? SESSION=<?= $sessionId ?>& WEBLAYOUT=<?= $webLayout ?>" name="ViewerFrame" /> </frameset> </html>
28
Overview of Layers
TIP The Interacting With Layers sample, in the Developers Guide samples, demonstrates concepts from this chapter. Layers represent vector data, raster data, and drawing data in a map. Each type of layer has unique characteristics. NOTE The word layer has different meanings in different contexts. A layer can refer to the layer definition in the resource repository, and it can also refer to the map layer. For the purposes of the Web Tier, a layer refers to a map layer, and a layer definition refers to the layer definition in the resource repository.
Layer name: A unique identifier Legend label: The label for the layer as it appears in the map legend. Visibility: whether the layer should be displayed in the map. Note that actual visibility is dependent on more than just the visibility setting for a layer. See Layer Visibility on page 31 for further details.
29
Selectable: Whether features in the layer are selectable. This only applies to layers containing feature data.
The MgMap::GetLayers() method returns an MgLayerCollection object that contains all the layers in the map. The MgLayerCollection::GetItem() method returns an individual MgLayer object, by either index number in the collection or layer name. Layers in the collection are sorted by drawing order, with the top layers at the beginning of the collection. For example, using PHP syntax, if $layers is a collection containing the layers in a map, then $layers->GetItem(0) returns the top-most layer.
Layer Groups
Layers can be optionally grouped into layer groups. Layers in the same group are displayed together in the legend. The visibility for all layers in a group can be set at the group level. If the group visibility is turned off then none of the layers in the group will be visible, regardless of their individual visibility settings. If the group visibility is turned on, then individual layers within the group can be made visible or not visible separately. Layer groups can be nested so a group can contain other groups. This provides a finer level of control for handling layer visibility or legend groups. The MgMap::GetLayerGroups() method returns an MgLayerGroupCollection object that contains all the layer groups in the map. Each layer group in a map must have a unique name, even if it is nested within another group.
Each base layer group has a series of pre-defined scales that are used for rendering. When a request is made to view a portion of the map at a given scale, the AJAX viewer renders the tiles at the pre-defined scale that is closest to the requested map view scale. Layers within a base layer group are rendered together. Visibility settings for individual layers are ignored and the visibility setting for the group is used instead. Layers above the base layers will generally be vector layers with transparent backgrounds. This makes the images small and relatively quick to load in the viewer. You may have more than one base layer group. Lower layers will be hidden by higher layers unless the higher layers have transparent areas or have their visibility turned off. NOTE A layer can only belong to one group at a time. It cannot be part of both a base layer group and a regular group.
Layer Style
The data source information and style information for a layer control how the layer looks when it displayed on a map. This is stored in the layer definition in the repository. To change any of the data source or style information, modify the layer definition. Layer definitions can be modified using . They can also be created and modified dynamically using the Web Extensions API. See Modifying Maps and Layers on page 57 for details.
Layer Visibility
Whether a layer is visible in a given map depends on three criteria:
The visibility setting for the layer The visibility settings for any groups that contain the layer The map view scale and the layer definition for that view scale
Layer Style | 31
In order for a layer to be visible, its layer visibility must be on, the visibility for any group containing the layer must be on, and the layer must have a style setting defined for the current map view scale.
Example:Actual Visibility
For example, assume that there is a layer named Roads that is part of the layer group Transportation. The layer has view style defined for the scale ranges 010000 and 1000024000. The following table shows some possible settings of the various visibility and view scale settings, and their effect on the actual layer visibility. Layer Visibility Group Visibility View Scale
On On On Off On On Off On 10000 25000 10000 10000
Actual Visibility
On Off Off Off
Example
The following example lists the layers in a map, along with an indicator of the layer visibility setting.
$layers = $map->GetLayers(); // Get layer collection echo "<p>Layers:<br />"; $count = $layers->GetCount(); for ($i = 0; $i < $count; $i++) { $layer = $layers->GetItem($i); echo $layer->GetName() . ' (' . ($layer->GetVisible() ? 'on' : 'off') . ')<br />'; } echo '</p>';
Manipulating Layers
Modifying basic layer properties and changing layer visibility settings can be done directly using API calls. More complex manipulation requires modifying layer resources in the repository. For details, see Modifying Maps and Layers on page 57.
Example
The following example toggles the label of the Roads layer between Roads and Streets.
Example | 33
MgInitializeWebTier ($webconfigFilePath); $userInfo = new MgUserInformation($mgSessionId); $siteConnection = new MgSiteConnection(); $siteConnection->Open($userInfo); $resourceService = $siteConnection->CreateService(MgServiceType::ResourceService); $map = new MgMap(); $map->Open($resourceService, $mgMapName); $layers = $map->GetLayers(); $roadLayer = $layers->GetItem('Roads'); $roadLabel = $roadLayer->GetLegendLabel(); if ($roadLabel == 'Roads') $newLabel = 'Streets'; else $newLabel = 'Roads'; $roadLayer->SetLegendLabel($newLabel); // You must save the updated map or the // changes will not be applied // Also be sure to refresh the map on page load. $map->Save($resourceService);
Changing Visibility
To query the actual layer visibility, use the MgLayer::IsVisible() method. There is no method to set actual visibility because it depends on other visibility settings. To query the visibility setting for a layer, use the MgLayer::GetVisible() method. To change the visibility setting for a layer, use the MgLayer::SetVisible() method. To query the visibility setting for a layer group, use the MgGroup::GetVisible() method. To change the visibility setting for a layer group, use the MgGroup::SetVisible() method.
To change the layer visibility for a given view scale, modify the layer resource and save it back to the repository. See Modifying Maps and Layers on page 57 for details. The following example turns on the visibility for the Roads layer.
$layers = $map->GetLayers(); $roadsLayer = $layers->GetItem('Roads'); $roadsLayer->SetVisible(True);
NOTE Changing the visibility will have no effect until the map is saved and refreshed.
Changing Visibility | 35
36
Overview of Features
TIP The Working With Feature Data sample, in the Developers Guide samples, demonstrates concepts from this chapter. Understanding features is fundamental to being able to use the MapGuide Web API. Nearly every application will need to interact with feature data in one form or another. Features are map objects representing items like roads (polylines), lakes (polygons), or locations (points). A feature source is a resource that contains a set of related features, stored in a file or database. Some common feature source types are SDF files, SHP files, or data in a spatial database. For example, you may have a feature source that contains data for roads. Feature sources can be stored in the library repository or in a session repository. A feature source identifier describes a complete path in the repository. For example,
Library://Samples/Sheboygan/Data/RoadCenterLines.FeatureSource
Within a single feature source there may be one or more feature classes. A feature class describes a subset of the features in the feature source. In many cases, there is one feature class for each feature source. For example, there may be a Roads feature class in the RoadCenterLines feature source. A feature class contains one or more features. Each feature has a geometry that defines the spatial representation of the feature. Features will also generally
37
have one or more properties that provide additional information. For example, a feature class containing road data may have properties for the road name and the number of lanes. Feature properties can be of different types, like strings, integers, and floating point numbers. Possible types are defined in the class MgPropertyType. In some cases, a feature property will be another feature. For example, a Roads feature might have a Sidewalk feature as one of its properties. A map layer may contain the features from a feature class. The features are rendered using the feature geometry. The Web API Feature Service provides functions for querying and updating feature data.
Feature Readers
A feature reader, represented by an MgFeatureReader object, is used to iterate through a list of features. Typically, the feature reader is created by selecting features from a feature source. To create a feature reader, use the MgFeatureService::SelectFeatures() method. See Selecting with the Web API on page 39 for details about selection. To process the features in a feature reader, use the MgFeatureReader::ReadNext() method. You must call this method before being able to read the first feature. Continue calling the method to process the rest of the features. The MgFeatureReader::GetPropertyCount() method returns the number of properties available for the current feature. When you know the name and type of the feature property, call one of the MgFeatureReader::GetPropertyType() methods (where PropertyType represents one of the available types) to retrieve the value. Otherwise, call MgFeatureReader::GetPropertyName() and MgFeatureReader::GetPropertyType() before retrieving the value.
Basic Filters
Basic filters perform logical tests of feature properties. You can construct complex queries by combining expressions. Expressions use the comparison operators below: Operator
= <> < <= > >=
Meaning
Equality Not equal Less than Less than or equal to Greater than Greater than or equal to Used for string comparisons. The % wildcard represents any sequence of 0 or more characters. The _ wildcard represents any single character. For example, LIKE
LIKE
Operator
Meaning
SCHMITT% will search for any names beginning with SCHMITT.
The comparison operators can be used with numeric or string properties, except for the LIKE operator, which can only be used with string properties. Combine or modify expressions with the standard boolean operators AND, OR, and NOT.
Examples
These examples assume that the feature class you are querying has an integer property named year and a string property named owner. To select all features newer than 2001, create a filter like this:
$queryOptions = new MgFeatureQueryOptions(); $queryOptions->SetFilter('year > 2001');
To select all features built between 2001 and 2004, create a filter like this:
$queryOptions = new MgFeatureQueryOptions(); $queryOptions->SetFilter('year >= 2001 and year <= 2004');
To select all features owned by Davis or Davies, create a filter like this:
$queryOptions = new MgFeatureQueryOptions(); $queryOptions->SetFilter("owner LIKE 'Davi%s'");
Spatial Filters
With spatial filters, you can do comparisons using geometric properties. For example, you can select all features that are inside an area on the map, or that intersect an area. NOTE For more information about geometry, see Representation of Geometry on page 73. There are two ways of using spatial filters:
Create a separate spatial filter to apply to the feature source, using the
MgFeatureQueryOptions::SetSpatialFilter() method.
The MgFeatureQueryOptions::SetSpatialFilter() method requires an MgGeometry object to define the geometry and a spatial operation to compare the feature property and the geometry. The spatial operations are defined in class MgFeatureSpatialOperations. To include spatial properties in a basic filter, define the geometry using WKT format. Use the GEOMFROMTEXT() function in the basic filter, along with one of the following spatial operations:
CONTAINS COVEREDBY CROSSES DISJOINT EQUALS INTERSECTS OVERLAPS TOUCHES WITHIN INSIDE
NOTE Not all spatial operations can be used on all features. It depends on the capabilities of the FDO provider that supplies the data. This restriction applies to separate spatial filters and spatial properties that are used in a basic filter.
Obtain the feature from the query using the MgFeatureReader::ReadNext() method. Get the geometry data from the feature using the
MgFeatureReader::GetGeometry() method. This data is in AGF binary
format.
Convert the AGF data to an MgGeometry object using the MgAgfReaderWriter::Read() method.
For example, the following sequence creates an MgGeometry object representing the boundaries of District 1 in the Sheboygan sample data.
$districtQuery = new MgFeatureQueryOptions(); $districtQuery->SetFilter("Autogenerated_SDF_ID = 1"); $layer = $map->GetLayers()->GetItem('Districts'); $featureReader = $layer->SelectFeatures($districtQuery); $featureReader->ReadNext(); $districtGeometryData = $featureReader->GetGeometry('Data'); $agfReaderWriter = new MgAgfReaderWriter(); $districtGeometry = $agfReaderWriter->Read($districtGeometryData);
To convert an MgGeometry object into its WKT representation, use the MgWktReaderWriter::Write() method, as in the following example:
$wktReaderWriter = new MgWktReaderWriter(); $districtWkt = $wktReaderWriter->Write($districtGeometry);
Examples
The following examples assume that $testArea is an MgGeometry object defining a polygon, and $testAreaWkt is a WKT description of the polygon. To create a filter to find all properties owned by SCHMITT in the area, use either of the following sequences:
$queryOptions = new MgFeatureQueryOptions(); $queryOptions->SetFilter("RNAME LIKE 'SCHMITT%'"); $queryOptions->SetSpatialFilter('SHPGEOM', $testArea, MgFeatureSpatialOperations::Inside);
$queryOptions = new MgFeatureQueryOptions(); $queryOptions->SetFilter("RNAME LIKE 'SCHMITT%' AND SHPGEOM inside GEOMFROMTEXT('$testAreaWkt')";
Example: Selection
The following example creates a selection, then lists properties from the selected features. See the Working With Feature Data sample, in the Developers Guide samples, for the complete version. It selects parcels within the boundaries of District 1 that are owned by SCHMITT. This requires a spatial filter and a basic filter.
Example: Selection | 43
$map = new MgMap($siteConnection); $map->Open($mapName); // Get the geometry for the boundaries of District 1 $districtQuery = new MgFeatureQueryOptions(); $districtQuery->SetFilter("Autogenerated_SDF_ID = 1"); $layer = $map->GetLayers()->GetItem('Districts'); $featureReader = $layer->SelectFeatures($districtQuery); $featureReader->ReadNext(); $districtGeometryData = $featureReader-> GetGeometry('Data'); // Convert the AGF binary data to MgGeometry. $agfReaderWriter = new MgAgfReaderWriter(); $districtGeometry = $agfReaderWriter-> Read($districtGeometryData); // Create a filter to select the desired features. // Combine a basic filter and a spatial filter. $queryOptions = new MgFeatureQueryOptions(); $queryOptions->SetFilter("RNAME LIKE 'SCHMITT%'"); $queryOptions->SetSpatialFilter('SHPGEOM', $districtGeometry, MgFeatureSpatialOperations::Inside); // Select the features. $layer = $map->GetLayers()->GetItem('Parcels'); $featureReader = $layer->SelectFeatures($queryOptions); // For each selected feature, display the address. echo '<p>Properties owned by Schmitt '; echo 'in District 1</p><p>'; while ($featureReader->ReadNext()) { $val = $featureReader->GetString('RPROPAD');
Active Selections
A map may have an active selection, which is a list of features on the map that have been selected and highlighted in the Viewer. The active selection is part of the run-time map state, and is not stored with the map resource in the repository. The most direct method for creating an active selection is to use the interactive selection tools in the Viewer. Applications can also create selections using the Web API and apply them to a users view of the map. NOTE There is a fundamental difference in how the two Viewers manage selections. In the DWF Viewer, selection is handled entirely by the Viewer. This means that the Web server must request the selection information before it can use it. In the AJAX Viewer, any changes to the active selection require re-generation of the map image. Because of this, the Web server keeps information about the selection.
The layer containing the feature must be visible at the current map view scale. The selectable property for the layer must be true. Change this property in the web layout or with the MgLayer::SetSelectable() method.
There are different selection tools available in the Viewer. They can be enabled or disabled as part of the web layout. Each tool allows a user to select one or more features on the map.
Active Selections | 45
as an additional parameter to an Invoke URL command in a web layout through an Invoke Script command that executes the Submit method of the hidden formFrame through an onClick or other event that executes the Submit method of the hidden formFrame
The best method to use depends on the requirements of the application. If you are invoking the request from a command defined in a web layout, you can pass the information either as an additional parameter to an Invoke URL command or through an Invoke Script command. Invoke URL is simpler, but it offers a restricted set of parameters. Invoke Script has complete access to all the JavaScript calls in the Viewer API. If you are invoking the request from a page in the task pane, you can execute JavaScript as part of an onClick event or a form action.
must be a valid HTTP POST key. For the value, enter $CurrentSelection. Add the command to the toolbar, context menu, or task bar menu. When the command is executed, the current selection is passed to the page, along with the standard variables like SESSION and MAPNAME. For example, if you define the key SEL to have the value $CurrentSelection, then when the URL is invoked
$selection = $_POST['SEL'];
gets the current selection, in XML format. See Working With the Active Selection on page 48 for details about using the XML data.
For example, the following function passes the map view scale and the center point as parameters to a page that opens in a new window.
function submitRequest(pageUrl) { xmlSel = parent.parent.mapFrame.GetSelectionXML(); mapScale = parent.parent.mapFrame.GetScale(); mapCenter = parent.parent.mapFrame.GetCenter(); params = new Array( "SESSION", parent.parent.mapFrame.GetSessionId(), "MAPNAME", parent.parent.mapFrame.GetMapName(), "SELECTION", xmlSel, "SCALE", mapScale, "CENTERX", mapCenter.X, "CENTERY", mapCenter.Y ); parent.parent.formFrame.Submit(pageUrl, params, "_blank"); }
To call the function, execute it as part of an onClick event or as the action in a form. For example, clicking the following link would execute the function:
<a href="#" onClick="submitRequest( '/mapguide/devguide/custom_output/property_report.php'); return false;"> Click for report</a>
2 Retrieve selected layers from the MgSelection object. 3 For each layer, retrieve selected feature classes. There will normally be one feature class for the layer, so you can use the MgSelection::GetClass() method instead of the MgSelection::GetClasses() method. 4 Call MgSelection::GenerateFilter() to create a selection filter that contains the selected features in the class. 5 Call MgFeatureService::SelectFeatures() to create an MgFeatureReader object for the selected features. 6 Process the MgFeatureReader object, retrieving each selected feature. The procedure for the DWF Viewer is similar, but the Viewer must send the selection information as part of the HTTP request. Note that this will also work for the AJAX Viewer. To retrieve and manipulate the active selection for a map (AJAX or DWF Viewer): 1 Get the current selection using the Viewer API call GetSelectionXML(). 2 Pass this to the Web server as part of an HTTP request. The simplest method for this is to use the Submit() method of the formFrame. This loads a page and passes the parameters using an HTTP POST. 3 In the page, create an MgSelection object for the map. 4 Initialize the MgSelection object with the list of features passed to the page. 5 Retrieve selected layers from the MgSelection object. 6 For each layer, retrieve selected feature classes. There will normally be one feature class for the layer, so you can use the MgSelection::GetClass() method instead of the MgSelection::GetClasses() method. 7 Call MgSelection::GenerateFilter() to create a selection filter that contains the selected features in the class. 8 Call MgFeatureService::SelectFeatures() to create an MgFeatureReader object for the selected features. 9 Process the MgFeatureReader object, retrieving each selected feature.
$map = new MgMap(); $map->Open($resourceService, $mapName); // ---------------------------------------------------------// Use the following code for AJAX or DWF Viewers // This requires passing selection data via HTTP POST if (isset($_POST['SELECTION']) && $_POST['SELECTION'] != '') { $selection = new MgSelection($map, $_POST['SELECTION']); $layers = $selection->GetLayers(); } else $layers = 0; // --------------------------------------------------------if ($layers) { $queryOptions = new MgFeatureQueryOptions(); for ($i = 0; $i < $layers->GetCount(); $i++) { // Only check selected features in the Parcels layer. $layer = $layers->GetItem($i); if ($layer && $layer->GetName() == 'Parcels') { // Create a filter containing the IDs of the selected // features on this layer $layerClassName = $layer->GetFeatureClassName(); $selectionString = $selection->GenerateFilter($layer, $layerClassName); // Get the feature resource for the selected layer $layerFeatureId = $layer->GetFeatureSourceId(); $layerFeatureResource = new MgResourceIdentifier($layerFeatureId); // Apply the filter to the feature resource for the // selected layer. This returns
// an MgFeatureReader of all the selected features. $queryOptions->SetFilter($selectionString); $featureReader = $featureService->SelectFeatures($layerFeatureResource, $layerClassName, $queryOptions); // Process each item in the MgFeatureReader, // displaying the owner name while ($featureReader->ReadNext()) { $val = $featureReader->GetString('NAME') . '<br /> ' . $featureReader->GetString('RPROPAD'); echo $val . '<br />'; } } } } else echo 'No selected layers'; echo '</p>';
with the following, which retrieves the selection from the run-time map state:
// --------------------------------------------------------// Use the following code for AJAX Viewers only. // This does not require passing selection data via HTTP POST. // $selection = new MgSelection($map); $selection->Open($resourceService, $mapName); $layers = $selection->GetLayers();
There is no need to create a JavaScript function to call this page using the Submit() method of the formFrame. It can be run directly as a link from the calling page, passing just the SESSION and MAPNAME.
Create a selection as described in Selecting with the Web API on page 39. This creates a feature reader containing the selected features. Create an MgSelection object to hold the features in the feature reader. Send the selection to the Viewer, along with a call to the Viewer API function SetSelectionXML().
<body class="AppFrame" onLoad="OnPageLoad()"> <h1 class="AppHeading">Select features</h1> <?php include '../common/common.php'; $args = ($_SERVER['REQUEST_METHOD'] == "POST")? $_POST : $_GET; $sessionId = $args['SESSION']; $mapName = $args['MAPNAME']; try { // Initialize the Web Extensions and connect to the Server // using the Web Extensions session identifier MgInitializeWebTier ($webconfigFilePath); $userInfo = new MgUserInformation($sessionId); $siteConnection = new MgSiteConnection(); $siteConnection->Open($userInfo); $map = new MgMap($siteConnection); $map->Open($mapName); // Get the geometry for the boundaries of District 1 $districtQuery = new MgFeatureQueryOptions(); $districtQuery->SetFilter("Autogenerated_SDF_ID = 1"); $layer = $map->GetLayers()->GetItem('Districts'); $featureReader = $layer->SelectFeatures($districtQuery); $featureReader->ReadNext(); $districtGeometryData = $featureReader-> GetGeometry('Data'); // Convert the AGF binary data to MgGeometry. $agfReaderWriter = new MgAgfReaderWriter(); $districtGeometry = $agfReaderWriter->Read($districtGeometryData);
// Create a filter to select the desired features. Combine // a basic filter and a spatial filter. $queryOptions = new MgFeatureQueryOptions(); $queryOptions->SetFilter("RNAME LIKE 'SCHMITT%'"); $queryOptions->SetSpatialFilter('SHPGEOM', $districtGeometry, MgFeatureSpatialOperations::Inside); // Get the features from the feature source, // turn it into a selection, then save the selection as XML. $layer = $map->GetLayers()->GetItem('Parcels'); $featureReader = $layer->SelectFeatures($queryOptions); $layer = $map->GetLayers()->GetItem('Parcels'); $selection = new MgSelection($map); $selection->AddFeatures($layer, $featureReader, 0); $selectionXml = $selection->ToXml(); echo 'Selecting parcels owned by Schmitt in District 1'; } catch (MgException $e) { echo $e->GetMessage(); echo $e->GetDetails(); } ?> </body> <script language="javascript"> // // // // // Emit this function and assocate it with the onLoad event for the page so that it gets executed when this page loads in the browser. The function calls the SetSelectionXML method on the Viewer Frame, which updates the current selection on the viewer and the server.
} </script>
Introduction
TIP The Modifying Maps and Layers sample, in the Developers Guide samples, demonstrates concepts from this chapter. This chapter describes how to modify maps and layers.
By default, newly added layers are added to the bottom of the drawing order, so they may be obscured by other layers. If you want to specify where the layer appears in the drawing order, use the $layerCollection->Insert() method. For an example, see Adding Layers To A Map on page 68. NOTE In the MapGuide API, getting a collection returns a reference to the collection. So adding the layer to the layer collection immediately updates the map.
57
loads a layer that has been created through uses the DOM to change the filter and its associated legend label
You can use the DOM to modify any layers, including ones that already exist in the map, not just new layers that you are adding to the map. You can also use the DOM to modify other resources; the XML schemas are described in the MapGuide Web API Reference.
// (initialization etc. not shown here) // Open the map $map = new MgMap(); $map->Open($resourceService, $mapName); // --------------------------------------------------// // Load a layer from XML, and use the DOM to change it // Load the prototype layer definition into // a PHP DOM object. $domDocument = DOMDocument::load('RecentlyBuilt.LayerDefinition'); if ($domDocument == NULL) { echo "The layer definition 'RecentlyBuilt.LayerDefinition' could not be found.<BR>\n"; return; } // Change the filter $xpath = new DOMXPath($domDocument); $query = '//AreaRule/Filter'; // Get a list of all the <AreaRule><Filter> elements in // the XML. $nodes = $xpath->query($query); // Find the correct node and change it foreach ($nodes as $node ) { if ($node->nodeValue == 'YRBUILT > 1950') { $node->nodeValue = 'YRBUILT > 1980'; } } // Change the legend label $query = '//LegendLabel'; // Get a list of all the <LegendLabel> elements in the // XML. $nodes = $xpath->query($query); // Find the correct node and change it foreach ($nodes as $node ) { if ($node->nodeValue == 'Built after 1950') { $node->nodeValue = 'Built after 1980'; }
} // ...
The page then goes on to save the XML to a resource and loads that resource into the map, as described in Adding Layers To A Map on page 68. If you wish to modify an existing layer that is visible in other users maps, without affecting those maps: 1 Copy the layer to the users session repository. 2 Modify the layer and save it back to the session repository. 3 Change the users map to refer to the modified layer. See Adding Layers To A Map on page 68.
This file contains several functions, which can be used to build up a layer definition. The parameters of these functions enable you to set the most commonly used settings. (If you need to change other settings, you will have to either use the UI, or modify the XML of the layer definition.) The layerdefinitionfactory is only available for PHP. For development using ASP.NET, a good alternative is to use the Visual Studio tool xsd.exe to generate .NET classes for the LayerDefinition schema.
AreaTypeStyle $areaRules
LineTypeStyle $lineRules
PointTypeStyle $pointRule
Function
CreateLayerDefinition()
Parameter
$resourceId
Description
The repository path of the feature source for the layer. For example: Library://Samples/Sheboygan/Data/Parcels.FeatureSource. Equivalent to the Data resource used in this layer field in s layer editor.
Function
Parameter
$featureClass
Description
The feature class to use. For example, SHP_Schema:Parcels. Equivalent to the Feature class field in s layer editor. The geometry to use from the feature class. For example, SHPGEOM. Equivalent to the Geometry field in s layer editor. A scale range created by filling in a scale range template (ScaleRange.templ). The minimum scale range to which this rule applies. Equivalent to the From field in s layer editor. The maximum scale range to which this rule applies. Equivalent to the To field in s layer editor. A type style created by using CreateAreaTypeStyle(), CreateLineTypeStyle() or CreatePointTypeStyle(). One or more area rules, created by CreateAreaRule. The text for the label shown beside this rule in the legend. Equivalent to the Legend Label field in s layer editor. The filter expression that determines which features match this rule. For example, SQFT >= 1 AND SQFT < 800. Equivalent to the Condition field in s layer editor.
$geometry
$featureClassRange
CreateScaleRange()
$minScale
$maxScale
$typeStyle
CreateAreaTypeStyle()
$areaRules
CreateAreaRule()
$legendLabel
$filterText
Function
Parameter
$foreGroundColor
Description
The color to be applied to areas that match this rule. Equivalent to the Foreground color field in s layer editor. The string for the text. The height for the font. The foreground color. One or more point rules, created by CreatePointRule(). The label shown beside this rule in the legend. Equivalent to the Legend label field in s layer editor. The filter expression that determines which features match this rule. Equivalent to the Condition field in s layer editor. The text symbol, created by CreateTextSymbol(). A mark symbol created by CreateMarkSymbol(). The resource ID of the symbol used to mark each point. For example, library://Samples/Sheboygan/Symbols/BasicSymbols.SymbolLibrary. Equivalent to the Location field in the Select a symbol from a Symbol Library dialog in s layer editor. The name of the desired symbol in the symbol library.
CreateTextSymbol()
$text
$fontHeight
$foregroundColor
CreatePointTypeStyle()
$pointRule
CreatePointRule()
$legendLabel
$filter
$label
$pointSym
CreateMarkSymbol()
$resourceId
$symbolName
Function
Parameter
$width
Description
The width of the symbol (in points). Equivalent to the Width field in the Style Point dialog in s layer editor. The height of the symbol (in points). Equivalent to the Height field in the Style Point dialog in s layer editor. The color for the symbol. Equivalent to the Foreground color field in the Style Point dialog in s layer editor. One or more line rules, created by CreateLineRule(). The color to be applied to lines that match this rule. Equivalent to the Color field in s layer editor. The label shown beside this rule in the legend. Equivalent to the Legend Label field in s layer editor. The filter expression that determines which features match this rule. Equivalent to the Condition field in s layer editor.
$height
$color
CreateLineTypeStyle()
$lineRules
CreateLineRule()
$color
$legendLabel
$filter
For more information on these settings, see the MapGuide Studio Help.
// ... /---------------------------------------------------// $factory = new LayerDefinitionFactory(); /// Create three area rules for three different // scale ranges. $areaRule1 = $factory->CreateAreaRule( '1 to 800', 'SQFT >= 1 AND SQFT < 800', 'FFFFFF00'); $areaRule2 = $factory->CreateAreaRule( '800 to 1600', 'SQFT >= 800 AND SQFT < 1600', 'FFFFBF20'); $areaRule3 = $factory->CreateAreaRule('1600 to 2400', 'SQFT >= 1600 AND SQFT < 2400', 'FFFF8040'); // Create an area type style. $areaTypeStyle = $factory->CreateAreaTypeStyle( $areaRule1 . $areaRule2 . $areaRule3); // Create a scale range. $minScale = '0'; $maxScale = '1000000000000'; $areaScaleRange = $factory->CreateScaleRange( $minScale, $maxScale, $areaTypeStyle); // Create the layer definiton. $featureClass = 'Library://Samples/Sheboygan/Data/' . 'Parcels.FeatureSource'; $featureName = 'SHP_Schema:Parcels'; $geometry = 'SHPGEOM'; $layerDefinition = $factory->CreateLayerDefinition( $featureClass, $featureName, $geometry, $areaScaleRange); //---------------------------------------------------// // ...
The script then saves the XML to a resource and loads that resource into the map. See Adding Layers To A Map on page 68.
// ... //---------------------------------------------------// $factory = new LayerDefinitionFactory(); // Create a line rule. $legendLabel = ''; $filter = ''; $color = 'FF0000FF'; $lineRule = $factory->CreateLineRule( $legendLabel, $filter, $color); // Create a line type style. $lineTypeStyle = $factory-> CreateLineTypeStyle($lineRule); // Create a scale range. $minScale = '0'; $maxScale = '1000000000000'; $lineScaleRange = $factory-> CreateScaleRange($minScale, $maxScale, $lineTypeStyle); // Create the layer definiton. $featureClass = 'Library://Samples/Sheboygan/Data/' . 'HydrographicLines.FeatureSource'; $featureName = 'SHP_Schema:HydrographicLines'; $geometry = 'SHPGEOM'; $layerDefinition = $factory-> CreateLayerDefinition($featureClass, $featureName, $geometry, $lineScaleRange); //---------------------------------------------------// // ...
// ... //---------------------------------------------------// $factory = new LayerDefinitionFactory(); // Create a mark symbol $resourceId = 'Library://Samples/Sheboygan/Symbols/BasicSymbols.SymbolLibrary'; $symbolName = 'PushPin'; $width = '24'; // points $height = '24'; // points $color = 'FFFF0000'; $markSymbol = $factory->CreateMarkSymbol($resourceId, $symbolName, $width, $height, $color); // Create a text symbol $text = "ID"; $fontHeight="12"; $foregroundColor = 'FF000000'; $textSymbol = $factory->CreateTextSymbol($text, $fontHeight, $foregroundColor); // Create a point rule. $legendLabel = 'trees'; $filter = ''; $pointRule = $factory->CreatePointRule($legendLabel, $filter, $textSymbol, $markSymbol); // Create a point type style. $pointTypeStyle = $factory-> CreatepointTypeStyle($pointRule); // Create a scale range. $minScale = '0'; $maxScale = '1000000000000'; $pointScaleRange = $factory->CreateScaleRange($minScale, $maxScale, $pointTypeStyle); // Create the layer definiton. $featureClass = 'Library://Tests/Trees.FeatureSource'; $featureName = 'Default:Trees'; $geometry = 'Geometry'; $layerDefinition = $factory-> CreateLayerDefinition($featureClass, $featureName, $geometry, $pointScaleRange); //---------------------------------------------------//
// ...
<?php require_once('../common/common.php'); /////////////////////////////////////////////////////////// function add_layer_definition_to_map($layerDefinition, $layerName, $layerLegendLabel, $mgSessionId, $resourceService, &$map) // Adds the layer definition (XML) to the map. // Returns the layer. { // Validate the XML. $domDocument = new DOMDocument; $domDocument->loadXML($layerDefinition); if (! $domDocument->schemaValidate( "$schemaDirectory\LayerDefinition-1.1.0.xsd") ) { echo "ERROR: The new XML document is invalid. <BR>\n."; return NULL; } // Save the new layer definition to the session // repository $byteSource = new MgByteSource($layerDefinition, strlen($layerDefinition)); $byteSource->SetMimeType(MgMimeType::Xml); $resourceID = new MgResourceIdentifier( "Session:$mgSessionId//$layerName.LayerDefinition"); $resourceService->SetResource($resourceID, $byteSource->GetReader(), null); $newLayer = add_layer_resource_to_map($resourceID, $resourceService, $layerName, $layerLegendLabel, $map); return $newLayer; }
function add_layer_resource_to_map($layerResourceID, $resourceService, $layerName, $layerLegendLabel, &$map) // Adds a layer defition (which can be stored either in the // Library or a session repository) to the map. // Returns the layer. { $newLayer = new MgLayer($layerResourceID, $resourceService); // Add the new layer to the map's layer collection $newLayer->SetName($layerName); $newLayer->SetVisible(true); $newLayer->SetLegendLabel($layerLegendLabel); $newLayer->SetDisplayInLegend(true); $layerCollection = $map->GetLayers(); if (! $layerCollection->Contains($layerName) ) { // Insert the new layer at position 0 so it is at // the top of the drawing order $layerCollection->Insert(0, $newLayer); } return $newLayer; }
function add_layer_to_group($layer, $layerGroupName, $layerGroupLegendLabel, &$map) // Adds a layer to a layer group. If necessary, it creates // the layer group. { // Get the layer group $layerGroupCollection = $map->GetLayerGroups(); if ($layerGroupCollection->Contains($layerGroupName)) { $layerGroup = $layerGroupCollection->GetItem($layerGroupName); } else { // It does not exist, so create it $layerGroup = new MgLayerGroup($layerGroupName); $layerGroup->SetVisible(true); $layerGroup->SetDisplayInLegend(true); $layerGroup->SetLegendLabel($layerGroupLegendLabel); $layerGroupCollection->Add($layerGroup); } // Add the layer to the group $layer->SetGroup($layerGroup); }
72
Analyzing Features
Introduction
TIP The Analyzing Features sample, in the Developers Guide samples, demonstrates concepts from this chapter. MapGuide includes methods for analyzing map features, including comparing the spatial relationships between features, measuring distances, and creating buffer areas around features. Analyzing features requires knowing how the features are represented and what spatial reference systems are being used. If different spatial reference systems are being used, it is important to be able to convert between them.
Representation of Geometry
MapGuide can represent geometric data in three different forms:
AGF text format, which is an extension of the Open Geospatial Consortium (OGC) Well Known Text (WKT) format. This is used to represent geometry as a character string. Binary AGF format. This is used by the FDO technology supporting the Feature Service. MapGuide internal representation, using MgGeometry and classes derived from it.
73
NOTE This guide and the Web API Reference will often use the term WKT to mean AGF text format. Be aware that AGF Text values do not always conform to the OGC WKT standard. See the Geometry module in the Web API Reference for details. To convert between AGF text and the MapGuide internal representation, use an MgWktReaderWriter object. Call MgWktReaderWriter.Read() to convert AGF text to MgGeometry. Call MgWktReaderWriter.Write() to convert MgGeometry to AGF text. To convert between binary AGF and the MapGuide internal representation, use an MgAgfReaderWriter object. Call MgAgfReaderWriter.Read() to convert binary AGF to MgGeometry. Call MgAgfReaderWriter.Write() to convert MgGeometry to binary AGF. For example, if you have a WKT representation of the geometry, you could create a geometry object as follows:
MgWktReaderWriter wktReaderWriter = new MgWktReaderWriter(); MgGeometry geometry = wktReaderWriter.Read(wktGeometry);
Geometry Objects
MgGeometry is the base class for all the geometry types. The simple geometry
types are:
MgPoint a single point MgLineString a series of connected line segments MgCurveString a series of connected curve segments MgPolygon a polygon with sides formed from line segments MgCurvePolygon a polygon with sides formed from curve segments
The curve segments are circular arcs, defined by a start point, an end point, and a control point. Complex types are formed by aggregating simple types. The complex types are:
MgMultiPoint a group of points MgMultiLineString a group of line strings
MgMultiCurveString a group of curve strings MgMultiPolygon a group of polygons MgMultiCurvePolygon a group of curve polygons MgMultiGeometry a group of simple geometry objects of any type
For example, if you have an MgLineString object $line and an MgPolygon object $polygon, you can test if the line crosses the polygon with a call to
$line->Crosses($polygon)
Methods to create new geometry objects from the point set of two other geometries include:
Difference() Intersection() SymmetricDifference() Union()
Complete details are in the Geometry module of the Web API reference, under Spatial Relationships.
Coordinate Systems
A single map will often combine data from different sources, and the different sources may use different coordinate systems. The map has its own coordinate system, and any feature sources used in the map may have different coordinate systems. It is important for display and analysis that all locations are transformed to the same coordinate system. NOTE A coordinate system can also be called a spatial reference system (SRS) or a coordinate reference system (CRS). This guide uses the abbreviation SRS. MapGuide supports three different types of coordinate system:
An MgCoordinateSystem object represents a coordinate system. NOTE You cannot transform between arbitrary X-Y coordinates and either geographic or projected coordinates. To create an MgCoordinateSystem object from an MgMap object,
Get the feature source for the layer. Get the active spatial context for the feature source. Convert the spatial context to a WKT. Create an MgCoordinateSystem object from the WKT.
To transform geometry from one coordinate system to another, create an MgCoordinateSystemTransform object using the two coordinate systems. Apply this transform to the MgGeometry object. For example, if you have geometry representing a feature on a layer that uses one coordinate system, and you want to compare it to a feature on another layer that uses a different coordinate system, perform the following steps:
$featureSource1 = $layer1->GetFeatureSourceId(); $contexts1 = $featureService->GetSpatialContexts( $featureSource1, true); $contexts1->ReadNext(); $srs1 = $contexts1->GetCoordinateSystemWkt(); $featureSource2 = $layer2->GetFeatureSourceId(); $contexts2 = $featureService->GetSpatialContexts( $featureSource2, true); $contexts2->ReadNext(); $srs2 = $contexts2->GetCoordinateSystemWkt(); $xform = new MgCoordinateSystemTransform($srs1, $srs2); $geometry1xform->$geometry1->Transform($xform);
Measuring Distance
Measuring distance in geographic or projected coordinate systems requires great circle calculations. Both MgGeometry::Buffer() and MgGeometry::Distance() accept a measurement parameter that defines the great circle to be used. If the measurement parameter is null, the calculation is done using a linear algorithm. Create the measurement parameter, an MgCoordinateSystemMeasure object, from the MgCoordinateSystem object. Distance is calculated in the units of the SRS. MgCoordinateSystem includes two methods, ConvertCoordinateSystemUnitsToMeters() and ConvertMetersToCoordinateSystemUnits() to convert to and from linear distances. For example, to calculate the distance between two MgGeometry objects $a and $b, using the coordinate system $srs, perform the following steps:
Measuring Distance | 77
Create a feature class definition. Determine what properties you need to store for the features. Add the property definitions to the feature class definition. Create a feature schema containing the feature class definition. Determine the SRS for the feature source. This can be the same as the SRS used for the map. Create a feature source using the schema and the SRS. The feature source can be stored in the session repository.
It is possible for a single feature source to contain more than one feature class. A feature source that is to be used for temporary data, however, normally contains one feature class. A feature schema (MgFeatureSchema object) contains class definitions (MgClassDefinition objects) for each feature class in the schema. Each class definition contains property definitions for each property in the feature class. The property definitions can be the following types:
MgDataPropertyDefinition MgGeometryPropertyDefinition MgObjectPropertyDefinition
MgRasterPropertyDefinition
MgDataPropertyDefinition is used to define simple properties like numbers or strings. MgGeometryPropertyDefinition is used to define geometric
properties. Most feature classes will have a geometric property to describe the features location. For example, the following creates a temporary feature source to hold buffer features. The feature source contains a single feature class named BufferClass. Features in BufferClass have two properties. ID is an autogenerated unique ID number, and BufferGeometry contains the geometry for the buffer polygon. The FDO technology supporting the Feature Service allows for multiple spatial reference systems within a single feature source. However, this capability is dependent on the data provider, and does not apply to the SDF provider that is used for creating feature sources within MapGuide. For temporary feature sources, you must define a single default SRS for the feature source, and you must set any geometry properties to use the same SRS. The name of the SRS is user-defined.
$bufferClass = new MgClassDefinition(); $bufferClass->SetName('BufferClass'); $properties = $bufferClass->GetProperties(); $idProperty = new MgDataPropertyDefinition('ID'); $idProperty->SetDataType(MgPropertyType::Int32); $idProperty->SetReadOnly(true); $idProperty->SetNullable(false); $idProperty->SetAutoGeneration(true); $properties->Add($idProperty); $polygonProperty = new MgGeometricPropertyDefinition('BufferGeometry'); $polygonProperty-> SetGeometryTypes(MgFeatureGeometricType::Surface); $polygonProperty->SetHasElevation(false); $polygonProperty->SetHasMeasure(false); $polygonProperty->SetReadOnly(false); $polygonProperty->SetSpatialContextAssociation('defaultSrs'); $properties->Add($polygonProperty); $idProperties = $bufferClass->GetIdentityProperties(); $idProperties->Add($idProperty); $bufferClass->SetDefaultGeometryPropertyName('BufferGeometry'); $bufferSchema = new MgFeatureSchema('BufferLayerSchema', 'temporary schema to hold a buffer'); $bufferSchema->GetClasses()->Add($bufferClass); $sdfParams = new MgCreateSdfParams('defaultSrs', $wkt, $bufferSchema); $featureService->CreateFeatureSource($bufferFeatureResId, $sdfParams);
To display features from a temporary feature source in a map, create a layer definition that refers to the feature source. Use the techniques described in Modifying Maps and Layers on page 57.
To execute the commands, call MgFeatureService::UpdateFeatures(). The feature class name and property names in any of the feature commands must match the class name and property names in the feature source. For example, to delete all features in a feature class with an identity property ID, execute the following:
$commands = new MgFeatureCommandCollection(); $deleteCommand = new MgDeleteFeatures($className, "ID like '%'"); $commands->Add($deleteCommand); $featureService->UpdateFeatures($featureSource, $commands, false);
To insert features, create an MgPropertyCollection object that contains the properties of the new feature. Create an MgInsertFeatures object and add this to the MgFeatureCommandCollection object. For example, to add a new feature with a single geometry property, execute the following:
$commands = new MgFeatureCommandCollection(); $properties = new MgPropertyCollection(); $agfByteStream = $agfReaderWriter->Write($geometry); $geometryProperty = new MgGeometryProperty($propertyName, $agfByteStream); $properties->Add($geometryProperty); $insertCommand = new MgInsertFeatures($className, $properties); $commands->Add($insertCommand); $featureService->UpdateFeatures($featureSource, $commands, false);
To update existing features, create an MgPropertyCollection object that contains the new values for the properties and a filter expression that selects the correct feature or features. See Querying Feature Data on page 38 for details about filter expressions.
Creating a Buffer
To create a buffer around a feature, use the MgGeometry::Buffer() method. This returns an MgGeometry object that you can use for further analysis. For example, you could display the buffer by creating a feature in a temporary feature source and adding a new layer to the map. You could also use the buffer geometry as part of a spatial filter. For example, you might want to find all the features within the buffer zone that match certain criteria, or you might want to find all roads that cross the buffer zone. To create a buffer, get the geometry of the feature to be buffered. If the feature is being processed in an MgFeatureReader as part of a selection, this requires getting the geometry data from the feature reader and converting it to an MgGeometry object. For example:
$geometryData = $featureReader->GetGeometry($geometryName); $featureGeometry = $agfReaderWriter->Read($geometryData);
If the buffer is to be calculated using coordinate system units, create an MgCoordinateSystemMeasure object from the coordinate system for the map. For example:
$mapWktSrs = $currentMap->GetMapSRS(); $coordSysFactory = new MgCoordinateSystemFactory(); $srs = $coordSysFactory->Create($mapWktSrs); $srsMeasure = new MgCoordinateSystemMeasure($srs);
Use the coordinate system measure to determine the buffer size in the coordinate system, and create the buffer object from the geometry to be buffered.
$srsDist = $srs->ConvertMetersToCoordinateSystemUnits($bufferDist); $bufferGeometry = $featureGeometry->Buffer($srsDist, $srsMeasure);
Create a feature source for the buffer. Insert a buffer feature in the feature source. Create a layer that references the feature source. Add the layer to the map and make it visible.
To use the buffer as part of a query, create a spatial filter using the buffer geometry, and use this in a call to MgFeatureService::SelectFeatures(). For example, the following code selects parcels inside the buffer area that are of type MFG. You can use the MgFeatureReader to perform tasks like generating a report of the parcels, or creating a new layer that puts point markers on each parcel.
$queryOptions = new MgFeatureQueryOptions(); $queryOptions->SetFilter("RTYPE = 'MFG'"); $queryOptions->SetSpatialFilter('SHPGEOM', $bufferGeometry, MgFeatureSpatialOperations::Inside); $featureResId = new MgResourceIdentifier( "Library://Samples/Sheboygan/Data/Parcels.FeatureSource"); $featureReader = $featureService->SelectFeatures($featureResId, "Parcels", $queryOptions);
Creating a Buffer | 83
Example
This example builds on the example from Working With the Active Selection on page 48. Instead of listing the parcels in the selection, it creates a series of concentric buffers around the selection, showing increasing distance. The code sections below contain the significant additions in this example. The complete source code is available with the Developers Guide samples. Because this example modifies the map, it must refresh the map when it loads, by executing a JavaScript function. Add the function to the page.
<script language="javascript"> function OnPageLoad() { parent.parent.Refresh(); } </script>
The example uses a temporary map layer named Buffer to store the buffer feature. It creates a feature source and the layer if it does not exist. Otherwise, it deletes any existing features before creating the new buffer. The functions CreateBufferFeatureSource() and CreateBufferLayer() are in bufferfunctions.php, which is described below.
include 'bufferfunctions.php'; $bufferRingSize = 100; // measured in metres $bufferRingCount = 5; // Set up some objects for coordinate conversion $mapWktSrs = $map->GetMapSRS(); $agfReaderWriter = new MgAgfReaderWriter(); $wktReaderWriter = new MgWktReaderWriter(); $coordinateSystemFactory = new MgCoordinateSystemFactory(); $srs = $coordinateSystemFactory->Create($mapWktSrs); $srsMeasure = new MgCoordinateSystemMeasure($srs); // // // // Check for a buffer layer. If it exists, delete the current features. If it does not exist, create a feature source and a layer to hold the buffer.
try { $bufferLayer = $map->GetLayers()->GetItem('Buffer'); $bufferFeatureResId = new MgResourceIdentifier( $bufferLayer->GetFeatureSourceId()); $commands = new MgFeatureCommandCollection(); $commands->Add(new MgDeleteFeatures('BufferClass', "ID like '%'")); $featureService->UpdateFeatures($bufferFeatureResId, $commands, false); } catch (MgObjectNotFoundException $e) { // When an MgObjectNotFoundException is thrown, the layer // does not exist and must be created. $bufferFeatureResId = new MgResourceIdentifier("Session:" . $mgSessionId . "//Buffer.FeatureSource"); CreateBufferFeatureSource($featureService, $mapWktSrs, $bufferFeatureResId); $bufferLayer = CreateBufferLayer($resourceService, $bufferFeatureResId, $mgSessionId); $map->GetLayers()->Insert(0, $bufferLayer);
Example | 85
The geometries for the selected features are merged into a single multi-geometry. Then a series of concentric buffers is created and added to the feature source. The style for the layer, which is set when function CreateBufferLayer() processes bufferlayerdefinition.xml, should define the buffer features to be partly transparent. When they are drawn on the map, the rings get progressively darker towards the center of the buffer area.
// Process each item in the MgFeatureReader. // Merge them into a single feature. $inputGeometries = new MgGeometryCollection(); while ($featureReader->ReadNext()) { $featureGeometryData = $featureReader->GetGeometry('SHPGEOM'); $featureGeometry = $agfReaderWriter->Read($featureGeometryData); $inputGeometries->Add($featureGeometry); } $geometryFactory = new MgGeometryFactory(); $mergedFeatures = $geometryFactory-> CreateMultiGeometry($inputGeometries); // Add buffer features to the temporary feature source. // Create multiple concentric buffers to show area. $commands = new MgFeatureCommandCollection(); for ($bufferRing = 0; $bufferRing < $bufferRingCount; $bufferRing++) { $bufferDist = $srs-> ConvertMetersToCoordinateSystemUnits($bufferRingSize * ($bufferRing + 1)); $bufferGeometry = $mergedFeatures->Buffer($bufferDist, $srsMeasure); $properties = new MgPropertyCollection(); $properties->Add(new MgGeometryProperty('BufferGeometry', $agfReaderWriter->Write($bufferGeometry))); $commands->Add(new MgInsertFeatures('BufferClass', $properties)); } $results = $featureService->UpdateFeatures($bufferFeatureResId, $commands, false); $bufferLayer->SetVisible(true); $bufferLayer->ForceRefresh(); $bufferLayer->SetDisplayInLegend(true);
Example | 87
$map->Save($resourceService);
The functions CreateBufferFeatureSource() and CreateBufferLayer() are in bufferfunctions.php. CreateBufferFeatureSource() creates a temporary feature source, with a single feature class, BufferClass. The feature class has two properties, ID and BufferGeometry. ID is autogenerated, so it does not need to be added with a new feature. CreateBufferLayer() modifies a layer definition from an external file and saves it to the repository. For more details, see Modifying Maps and Layers on page 57.
function CreateBufferFeatureSource($featureService, $wkt, $bufferFeatureResId) { $bufferClass = new MgClassDefinition(); $bufferClass->SetName('BufferClass'); $properties = $bufferClass->GetProperties(); $idProperty = new MgDataPropertyDefinition('ID'); $idProperty->SetDataType(MgPropertyType::Int32); $idProperty->SetReadOnly(true); $idProperty->SetNullable(false); $idProperty->SetAutoGeneration(true); $properties->Add($idProperty); $polygonProperty = new MgGeometricPropertyDefinition('BufferGeometry'); $polygonProperty-> SetGeometryTypes(MgFeatureGeometricType::Surface); $polygonProperty->SetHasElevation(false); $polygonProperty->SetHasMeasure(false); $polygonProperty->SetReadOnly(false); $polygonProperty->SetSpatialContextAssociation('defaultSrs'); $properties->Add($polygonProperty); $idProperties = $bufferClass->GetIdentityProperties(); $idProperties->Add($idProperty); $bufferClass-> SetDefaultGeometryPropertyName('BufferGeometry'); $bufferSchema = new MgFeatureSchema('BufferLayerSchema', 'temporary schema to hold a buffer'); $bufferSchema->GetClasses()->Add($bufferClass); $sdfParams = new MgCreateSdfParams('defaultSrs', $wkt, $bufferSchema); $featureService->CreateFeatureSource($bufferFeatureResId, $sdfParams); } function CreateBufferLayer($resourceService, $bufferFeatureResId, $sessionId) { // Load the layer definition template into // a PHP DOM object, find the "ResourceId" element, and // modify its content to reference the temporary // feature source. $doc = DOMDocument::load('bufferlayerdefinition.xml'); $featureSourceNode = $doc->getElementsByTagName(
Example | 89
'ResourceId')->item(0); $featureSourceNode->nodeValue = $bufferFeatureResId->ToString(); // Get the updated layer definition from the DOM object // and save it to the session repository using the // ResourceService object. $layerDefinition = $doc->saveXML(); $byteSource = new MgByteSource($layerDefinition, strlen($layerDefinition)); $byteSource->SetMimeType(MgMimeType::Xml); $tempLayerResId = new MgResourceIdentifier("Session:" . $sessionId . "//Buffer.LayerDefinition"); $resourceService->SetResource($tempLayerResId, $byteSource->GetReader(), null); // Create an MgLayer object based on the new layer definition // and return it to the caller. $bufferLayer = new MgLayer($tempLayerResId, $resourceService); $bufferLayer->SetName("Buffer"); $bufferLayer->SetLegendLabel("Buffer"); $bufferLayer->SetDisplayInLegend(true); $bufferLayer->SetSelectable(false); return $bufferLayer; }
There is an additional example in the Developers Guide samples. It queries the parcels in the buffer area and selects parcels that match certain criteria. The selection is done using a query that combines a basic filter and a spatial filter.
$bufferDist = $srs-> ConvertMetersToCoordinateSystemUnits($bufferRingSize); $bufferGeometry = $mergedGeometries->Buffer($bufferDist, $srsMeasure); // Create a filter to select parcels within the buffer. Combine // a basic filter and a spatial filter to select all parcels // within the buffer that are of type "MFG". $queryOptions = new MgFeatureQueryOptions(); $queryOptions->SetFilter("RTYPE = 'MFG'"); $queryOptions->SetSpatialFilter('SHPGEOM', $bufferGeometry, MgFeatureSpatialOperations::Inside);
It creates an additional feature source that contains point markers for each of the selected parcels.
// // // // // //
Get the features from the feature source, determine the centroid of each selected feature, and add a point to the ParcelMarker layer to mark the centroid. Collect all the points into an MgFeatureCommandCollection, so they can all be added in one operation.
$featureResId = new MgResourceIdentifier( "Library://Samples/Sheboygan/Data/Parcels.FeatureSource"); $featureReader = $featureService->SelectFeatures($featureResId, "Parcels", $queryOptions); $parcelMarkerCommands = new MgFeatureCommandCollection(); while ($featureReader->ReadNext()) { $byteReader = $featureReader->GetGeometry('SHPGEOM'); $geometry = $agfReaderWriter->Read($byteReader); $point = $geometry->GetCentroid(); // Create an insert command for this parcel. $properties = new MgPropertyCollection(); $properties->Add(new MgGeometryProperty('ParcelLocation', $agfReaderWriter->Write($point))); $parcelMarkerCommands->Add( new MgInsertFeatures('ParcelMarkerClass', $properties)); } $featureReader->Close(); if ($parcelMarkerCommands->GetCount() > 0) { $featureService->UpdateFeatures($parcelFeatureResId, $parcelMarkerCommands, false); } else { echo '</p><p>No parcels within the buffer area match.'; }
Example | 91
92
Introduction
TIP The Digitizing and Redlining sample, in the Developers Guide samples, demonstrates concepts from this chapter. This chapter describes digitizing (capturing the users clicks on the map and converting the locations to map coordinates) and redlining (drawing items such as lines or rectangles on the map in response to the users clicks).
Digitizing
The Viewer API has a number of functions for digitizing user input. For an example of how these can be used, see task_pane_digitizing.php in the digitizing_features directory in the Developer Guide samples. In this example, if the user clicks the button to digitize a point
<input type="button" value=" Point " onclick="DigitizePoint();">
which in turn calls the DigitzePoint() method of the Viewer API in the map frame. It also passes the name of a callback function, OnPointDigitized, which is defined in the current script. DigizitzePoint() calls this function after it has digitized the point and passes it the digitized coordinates of the point.
93
You can use this callback function to process the digitized coordinates as you wish. In this example, the script simply displays them in the task pane.
function OnPointDigitized(point) { ShowResults("X: " + point.X + ", Y: " + point.Y); }
Redlining
There are three main steps involved in redlining: 1 Pass the digitized coordinates from the client to the server. 2 Create a temporary feature source. This will be used to draw the lines on. 3 Create a layer to display that temporary feature source. For example, see task_pane_redlining.php in the digitizing_features directory in the Developer Guide samples.
Passing Coordinates
The digitizing functions in the Viewer API provide us with the digitized coordinates on the client, but we usually need to pass them to a server side script. This can be done with the Viewer API, using the Submit() method of the formFrame.
function OnLineDigitized(line) { // Send the Javascript variables to 'draw_line.php', // via the form frame var params = new Array("x0", line.Point(0).X, "y0", line.Point(0).Y, "x1", line.Point(1).X, "y1", line.Point(1).Y, "SESSION", "<?= $sessionId ?>", "MAPNAME", "<?= $mapName ?>"); parent.parent.formFrame.Submit( "/mapguide/samplesphp/digitizing_features/draw_line.php", params, "scriptFrame"); }
This submits the coordinates to the server-side function to draw the line. It uses the hidden scriptFrame so the page output is not visible.
// Create a temporary feature source to draw the lines on // Create a feature class definition for the new feature // source $classDefinition = new MgClassDefinition(); $classDefinition->SetName("Lines"); $classDefinition->SetDescription("Lines to display."); $geometryPropertyName="SHPGEOM"; $classDefinition-> SetDefaultGeometryPropertyName( $geometryPropertyName); // Create an identify property $identityProperty = new MgDataPropertyDefinition("KEY"); $identityProperty->SetDataType(MgPropertyType::Int32); $identityProperty->SetAutoGeneration(true); $identityProperty->SetReadOnly(true); // Add the identity property to the class definition $classDefinition->GetIdentityProperties()-> Add($identityProperty); $classDefinition->GetProperties()->Add($identityProperty); // Create a name property $nameProperty = new MgDataPropertyDefinition("NAME"); $nameProperty->SetDataType(MgPropertyType::String); // Add the name property to the class definition $classDefinition->GetProperties()->Add($nameProperty); // Create a geometry property $geometryProperty = new MgGeometricPropertyDefinition($geometryPropertyName); $geometryProperty-> SetGeometryTypes(MgFeatureGeometricType::Surface); // Add the geometry property to the class definition $classDefinition->GetProperties()->Add($geometryProperty); // Create a feature schema $featureSchema = new MgFeatureSchema("SHP_Schema", "Line schema"); // Add the feature schema to the class definition $featureSchema->GetClasses()->Add($classDefinition); // Create the feature source $wkt = $map->GetMapSRS();
Creating A Layer
The final step is to create a new layer to display the feature source, the same way it was done in Adding Layers To A Map on page 68.
Creating A Layer | 97
98
Custom Output
Introduction
TIP The Custom Output sample, in the Developers Guide samples, demonstrates concepts from this chapter. MapGuide includes services for saving map representations for use in external programs. To save a map as a bit-mapped image (PNG or GIF), use the Rendering Service. To save a map as a Design Web Format (DWF), use the Mapping Service. DWF files can be saved in two variations. An eMap DWF contains metadata that describes the current map view, not the map data itself. This is a compact format, but it requires access to the map agent to view the map. It is not suitable for offline viewing, and it requires a current MapGuide session. An ePlot DWF is designed for offline viewing or printing. It can contain multiple sheets, where each sheet is a complete map image that can be viewed offline using Autodesk Design Review. Each sheet in an ePlot DWF is a static representation of a single map view state. Characteristics of bit-mapped images:
Images can be in PNG or GIF formats. An image displays a portion of the the map view state at a particular scale. The image is static with a fixed resolution. Zooming in creates a pixelated image. Images are cross-platform.
99
Images are suitable for use in HTML pages, word processor documents, or graphics editing programs.
A single ePlot can contain multiple sheets. Each sheet shows a single image, showing a portion of the map view at a particular scale. The ePlot area and scale are static, but geometric features are stored as vector graphics, so zooming is smooth. Some interactive features of the MapGuide DWF Viewer are available, such as the ability to turn layers on and off. The ePlot requires the Autodesk Design Review, either standalone or as a plug-in for Internet Explorer. Images can be copied to the Windows clipboard and used in other applications. Autodesk Design Review is a free program that is only available on Windows. Visit http://www.autodesk.com to download.
An eMap DWF is dynamic, with all the zooming and panning capabilities of the MapGuide DWF Viewer. Because the eMap Viewer uses the map agent, the entire map is available for smooth zooming and panning. The layer stylization rules apply. The eMap requires the Autodesk Design Review, either standalone or as a plug-in for Internet Explorer. The eMap requires an active MapGuide session. If the session times out the map cannot be displayed. Individual views from an eMap DWF can be saved as ePlot DWFs. Autodesk Design Review is a free program that is only available on Windows.
Rendering Service
The Rendering Service creates bit-mapped images of a map suitable for displaying in a browser or saving to a file. The image is returned as an MgByteReader object, which can be sent to a browser or saved to a file. For example, to create a PNG image of a map area, perform the following operations. Note that the aspect ratio of the envelope should match the image dimensions or the image will be distorted.
$byteReader = $renderingService->RenderMap($map, $selection, $envelope, $imageWidth, $imageHeight, $color, 'PNG'); header("Content-type: " . $byteReader->GetMimeType() ); $buffer = ''; while ($byteReader->Read($buffer, 50000) != 0) { echo $buffer; }
Mapping Service
The Mapping Service creates eMap and ePlot DWFs. Generating an eMap DWF requires the DWF version and the URI of the map agent. Note that the HTTP header must include content length information, as in the following example.
$dwfVersion = new MgDwfVersion("6.01", "1.2"); $mapAgentUri = 'http://localhost:8008/mapguide/mapagent/mapagent.exe'; $byteReader = $mappingService->GenerateMap($map, $mapAgentUri, $dwfVersion); $outputBuffer = ''; $buffer = ''; while ($byteReader->Read($buffer, 50000) != 0) { $outputBuffer .= $buffer; } header('Content-Type: ' . $byteReader->GetMimeType()); header('Content-Length: ' . strlen($outputBuffer)); echo $outputBuffer;
An ePlot DWF is designed primarily for offline viewing or printing. It includes an MgPlotSpecification that defines the page size and margins. It can also include an optional MgLayout that defines additional components to include in the plot, like a legend or a custom logo. The layout is based on a print layout in the repository. For a description of the PrintLayout schema, see the MapGuide Web API Reference. To create an ePlot DWF with more than one sheet, use an MgMapPlotCollection, where each item in the collection is an MgMapPlot that describes a single sheet. NOTE The map name becomes the sheet name in the multi-plot DWF. Because each sheet in the DWF must have a unique name, you must create a separate MgMap object for each sheet in the DWF. The following example creates a multi-plot DWF with two sheets. The second sheet displays the same map area as the first, but it adds the title and legend information from the print layout.
$dwfVersion = new MgDwfVersion("6.01", "1.2"); $plotSpec = new MgPlotSpecification(8.5, 11, MgPageUnitsType::Inches); $plotSpec->SetMargins(0.5, 0.5, 0.5, 0.5); $plotCollection = new MgMapPlotCollection(); $plot1 = new MgMapPlot($map, $plotSpec, $layout); $plotCollection->Add($plot1); // Create a second map for the second sheet in the DWF. This // second map uses the print layout // to display a page title and legend. $map2 = new MgMap(); $map2->Create($resourceService, $map->GetMapDefinition(), 'Sheet 2'); $layoutRes = new MgResourceIdentifier( "Library://Samples/Sheboygan/Layouts/SheboyganMap.PrintLayout"); $layout = new MgLayout($layoutRes, "City of Sheboygan", MgPageUnitsType::Inches); $plot2 = new MgMapPlot($map2, $map->GetViewCenter()->GetCoordinate(), $map->GetViewScale(), $plotSpec, $layout); $plotCollection->Add($plot2); $byteReader = $mappingService-> GenerateMultiPlot($plotCollection, $dwfVersion); // Now output the resulting DWF. $outputBuffer = ''; $buffer = ''; while ($byteReader->Read($buffer, 50000) != 0) { $outputBuffer .= $buffer; } header('Content-Type: ' . $byteReader->GetMimeType()); header('Content-Length: ' . strlen($outputBuffer)); echo $outputBuffer;
104
Index
$CurrentSelection 46 CRS 76 custom commands, in web layouts 7
A
active selection 4546, 48, 50, 5253 AJAX Viewer 52 DWF Viewer 50 in Web API 48 sending to Web Server 46 setting with Web API 53 AGF 73 AJAX Viewer 5, 30, 45, 48 active selection 48 and base layer groups 30 and selection 45 arbitrary X-Y coordinates 76 authentication 12
D
deleting features 81 digitizing 93 DISJOINT 41 distance, measuring 77 Document Object Model DOM 58 drawing order 30 DWF Viewer 5, 45, 49 active selection 49 and selection 45 DWF, saving map as 99
58
B
base layer groups 30 basic selection filters 39 bit-mapped images 99 buffer polygon 78 buffer, creating 82 buffer, example of creating buffers 77
E
eMap 99 ePlot 99 EQUALS 41 examples, preparing for
84
F
feature class definition 78 feature classes 37 feature readers 3738 feature schema 78 feature service 13 feature source, temporary 78 features 37, 41, 43, 81 getting geometry from 41 inserting, deleting, and updating 81 listing selected 43 formFrame 47 formFrame, in Viewer 18 frame parent 20
C
callback functions 93 commands, in web layouts 7 constants.php 9 CONTAINS 41 coordinate reference system 76 coordinate systems 7677 transforming between 77 COVEREDBY 41 creating geometry from feature 41 credentials 12 CROSSES 41
Index | 105
G
geographic coordinates 76 geometry 75 comparing spatial relationships 75 geometry types 74 GEOMFROMTEXT() 41 GetSelectionXML() 49 GIF, saving map as 99 great circle calculation, in measuring distance 77
43
M
map 4 map definition 4 map state, run-time 4 maparea frame, in Viewer 18 mapFrame, in Viewer 18 MapGuide Server Page 8 MapGuide session 5 MAPNAME 47 mapping service 101 measuring distance 77 MgAgfReaderWriter 74 MgClassDefinition 78 MgCoordinateSystem 76 MgCoordinateSystemTransform 77 MgCurvePolygon 74 MgCurveString 74 MgFeatureReader 38 MgFeatureSchema 78 MgGeometry 41, 7374 creating from feature 41 MgLayer objects 29 MgLayerCollection 30 GetItem() 30 MgLayerCollection object 30, 32 MgLineString 74 MgMap 30 GetLayers() 30 MgMap object 4 MgMultiCurvePolygon 75 MgMultiCurveString 75 MgMultiGeometry 75 MgMultiLineString 74 MgMultiPoint 74 MgMultiPolygon 75 MgPoint 74 MgPolygon 74 MgWktReaderWriter 74 MSP 8 MSP processing flow 9
H
hellomap.php 10 home task 8 HTML frames, in Viewers 17 HTML page, with MapGuide Viewer
25
I
inserting features 81 INSIDE 41 INTERSECTS 41 Invoke Script command 21 Invoke Script command, passing parameters 47 Invoke URL command type 8 Invoke URL command, additional parameters 46
L
latitude/longitude coordinates 76 layer definition, and style 31 layer groups 30 layer name 29 layer properties 29 layer style 31 layer visibility 31 layer visibility, and layer groups 30 layerdefinitionfactory.php 60 layers 2930 base groups 30 Library repository 4
106 | Index
O
onClick event 48 OVERLAPS 41
P
parent frame 20 password 12 PNG, saving map as 99 printing map 99 projected coordinates 76 properties, of layers 29
spatial reference systems, in feature sources 79 spatial relationships, between geometry objects 75 SRS 76 Studio 1 style, of layers 31
T
task pane 8, 22 and Viewer API 22 task pane frame, passing parameters from 47 taskArea, in Viewer 18 taskBar, in Viewer 18 taskFrame, in Viewer 18 taskListFrame, in Viewer 18 taskPaneFrame, in Viewer 18 tbFrame, in Viewer 18 temporary feature source 78 tiling, of map image 30 TOUCHES 41 transforming coordinate systems 77
R
redlining 93 rendering service 99, 101 repositories 3 resource service 13 resources 3 run-time map state 4
S
sample code 2 sbFrame, in Viewer 18 script frame, and Viewer API scriptFrame, in Viewer 18 selecting 39, 45 with the Viewer 45 with the Web API 39 selecting, with Viewer 45 selection filters 3940 basic 39 spatial 40 services 13 session 5 SESSION 47 Session repository 4 site connection 12 spatial filters 40 spatial operators 41 spatial reference system 76
U
21 updating features 81 user credentials 12 user id 12
V
Viewer API 19, 2122, 46 and script frame 21 and task pane 22 Viewer commands 1 Viewer frames 17, 20 Viewer, embedded in HTML page Viewers 5, 4546 and map state 46 selecting features 45 visibility 3031 of base layer groups 30 rules 31
25
Index | 107
W
web layout 5 web layout, defining 8
108 | Index