[mapguide-commits] r5583 - in trunk/MgDev/Doc/devguide/source: . images

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed Mar 2 11:23:17 EST 2011


Author: jng
Date: 2011-03-02 08:23:17 -0800 (Wed, 02 Mar 2011)
New Revision: 5583

Added:
   trunk/MgDev/Doc/devguide/source/images/layerdefinition.png
Modified:
   trunk/MgDev/Doc/devguide/source/analyzing_features.rst
   trunk/MgDev/Doc/devguide/source/custom_output.rst
   trunk/MgDev/Doc/devguide/source/digitizing_and_redlining.rst
   trunk/MgDev/Doc/devguide/source/interacting_with_layers.rst
   trunk/MgDev/Doc/devguide/source/introduction.rst
   trunk/MgDev/Doc/devguide/source/mapguide_ajax_viewer.rst
   trunk/MgDev/Doc/devguide/source/modifying_maps_and_layers.rst
   trunk/MgDev/Doc/devguide/source/working_with_feature_data.rst
Log:
#1614: Add remaining content from original devguide. Also start manually indexing the content.


Modified: trunk/MgDev/Doc/devguide/source/analyzing_features.rst
===================================================================
--- trunk/MgDev/Doc/devguide/source/analyzing_features.rst	2011-03-02 11:08:18 UTC (rev 5582)
+++ trunk/MgDev/Doc/devguide/source/analyzing_features.rst	2011-03-02 16:23:17 UTC (rev 5583)
@@ -1,35 +1,1144 @@
-.. index::
-   single: feature; analysis
-   
 Analyzing Features
 ==================
 
 Introduction
 ------------
 
+.. note::
+
+    The Analyzing Features sample, in the Developer's 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.
+
+.. index::
+    single: Geometry: Representations
+
 Representations 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.
+
+.. 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:
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $wktReaderWriter = new MgWktReaderWriter();
+    $geometry = wktReaderWriter->Read($wktGeometry);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgWktReaderWriter wktReaderWriter = new MgWktReaderWriter();
+    MgGeometry geometry = wktReaderWriter.Read(wktGeometry);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgWktReaderWriter wktReaderWriter = new MgWktReaderWriter();
+    MgGeometry geometry = wktReaderWriter.Read(wktGeometry);
+
+.. index::
+    single: MgGeometry
+
 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
+
+.. index::
+    single: Geometry; Comparison with other Geometries
+
 Comparing Geometry Objects
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. todo::
+    Update page number reference with section link
+
+The ``MgGeometry`` class contains methods for comparing different geometry
+objects. These are similar to the spatial filters described in Selecting with the
+Web API on page 39. Methods to test spatial relationships include:
+
+ * ``Contains()``
+ * ``Crosses()``
+ * ``Disjoint()``
+ * ``Equals()``
+ * ``Intersects()``
+ * ``Overlaps()``
+ * ``Touches()``
+ * ``Within()``
+
+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
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $line->Crosses($polygon)
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    line.Crosses(polygon)
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    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.
+
+.. index::
+    single: Coordinate Systems
+    single: Coordinate Systems; Creating from MgMap
+    single: MgCoordinateSystem
+
 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:
+
+ * Arbitrary X-Y
+ * Geographic, or latitude/longitude
+ * Projected
+
+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 WKT representation of the map coordinate system, using ``MgMap::GetMapSRS()``.
+ * Create an ``MgCoordinateSystem`` object, using ``MgCoordinateSystemFactory::Create()``.
+
+To create an ``MgCoordinateSystem`` object from a map layer,
+
+ * 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:
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $featureSource1 = $layer1->GetFeatureSourceId();
+    $contexts1 = $featureService->GetSpatialContexts($featureSource1, true);
+    $contexts1->ReadNext();
+    $srs1 = $contexts1->GetCoordinateSystemWkt();
+    $contexts1->Close();
+    $featureSource2 = $layer2->GetFeatureSourceId();
+    $contexts2 = $featureService->GetSpatialContexts($featureSource2, true);
+    $contexts2->ReadNext();
+    $srs2 = $contexts2->GetCoordinateSystemWkt();
+    $contexts2->Close();
+    $csFactory = new MgCoordinateSystemFactory();
+    $srcCs = $csFactory->Create($srs1);
+    $dstCs = $csFactory->Create($srs2);
+    $xform = $csFactory->GetTransform($srcCS, $dstCs);
+    $geometry1xform = $geometry1->Transform($xform);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgResourceIdentifier featureSource1 = layer1.GetFeatureSourceId();
+    MgSpatialContextReader contexts1 = featureService.GetSpatialContexts(featureSource1, true);
+    contexts1.ReadNext();
+    String srs1 = contexts1.GetCoordinateSystemWkt();
+    contexts1.Close();
+    MgResourceIdentifier featureSource2 = layer2.GetFeatureSourceId();
+    MgSpatialContextReader contexts2 = featureService.GetSpatialContexts(featureSource2, true);
+    contexts2.ReadNext();
+    String srs2 = contexts2.GetCoordinateSystemWkt();
+    contexts2.Close();
+    MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+    MgCoordinateSystem srcCs = csFactory.Create(srs1);
+    MgCoordinateSystem dstCs = csFactory.Create(srs2);
+    MgCoordianteSystemTransform xform = csFactory.GetTransform(srcCs, dstCs);
+    MgGeometry geometry1xform = geometry1.Transform(xform);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgResourceIdentifier featureSource1 = layer1.GetFeatureSourceId();
+    MgSpatialContextReader contexts1 = featureService.GetSpatialContexts(featureSource1, true);
+    contexts1.ReadNext();
+    String srs1 = contexts1.GetCoordinateSystemWkt();
+    contexts1.Close();
+    MgResourceIdentifier featureSource2 = layer2.GetFeatureSourceId();
+    MgSpatialContextReader contexts2 = featureService.GetSpatialContexts(featureSource2, true);
+    contexts2.ReadNext();
+    String srs2 = contexts2.GetCoordinateSystemWkt();
+    contexts2.Close();
+    MgCoordinateSystemFactory csFactory = new MgCoordinateSystemFactory();
+    MgCoordinateSystem srcCs = csFactory.Create(srs1);
+    MgCoordinateSystem dstCs = csFactory.Create(srs2);
+    MgCoordianteSystemTransform xform = csFactory.GetTransform(srcCs, dstCs);
+    MgGeometry geometry1xform = geometry1.Transform(xform);
+
+.. index::
+    single: Coordinate Systems; Measure Units
+    single: Measuring Distance
+
 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:
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $measure = $srs->GetMeasure();
+    $distInMapUnits = $a->Distance($b, $measure);
+    $distInMeters = $srs->ConvertCoordinateSystemUnitsToMeters($distInMapUnits);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgCoordinateSystemMeasure measure = srs.GetMeasure();
+    double distInMapUnits = a.Distance(b, measure);
+    double distInMeters = srs.ConvertCoordinateSystemUnitsToMeters(distInMapUnits);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgCoordinateSystemMeasure measure = srs.GetMeasure();
+    double distInMapUnits = a.Distance(b, measure);
+    double distInMeters = srs.ConvertCoordinateSystemUnitsToMeters(distInMapUnits);
+
+Another way to calculate the distance is to use ``MgCoordinateSystemMeasure::GetDistance()``, as in the following:
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $distInMapUnits = $measure->GetDistance($a, $b);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    double distInMapUnits = measure.GetDistance(a, b);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    double distInMapUnits = measure.GetDistance(a, b);
+
+.. index::
+    single: Feature Source; Temporary Feature Sources
+    single: MgClassDefinition
+    single: MgFeatureSchema
+    single: MgClassDefinition; Properties
+    single: MgDataPropertyDefinition
+    single: MgGeometryPropertyDefinition
+    single: MgObjectPropertyDefinition
+    single: MgRasterPropertyDefinition
+    
 Temporary Feature Sources
 -------------------------
 
+.. todo::
+    Update page number reference with section link
+
+Many geometric analysis operations require creating new features and new
+feature sources. For example, drawing a buffer around a point on a map requires
+a layer to display the buffer polygon, and the layer requires a feature source.
+
+To create a temporary feature source, perform the following steps:
+
+ * 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``
+ 
+.. note::
+
+    Unlike FDO, MapGuide does not currently support Association Properties
+
+``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
+feature's 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.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $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);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgClassDefinition bufferClass = new MgClassDefinition();
+    bufferClass.SetName("BufferClass");
+    MgPropertyDefinitionCollection properties = bufferClass.GetProperties();
+     
+    MgDataPropertyDefinition idProperty = new MgDataPropertyDefinition("ID");
+    idProperty.SetDataType(MgPropertyType.Int32);
+    idProperty.SetReadOnly(true);
+    idProperty.SetNullable(false);
+    idProperty.SetAutoGeneration(true);
+    properties.Add(idProperty);
+     
+    MgGeometricPropertyDefinition polygonProperty = new MgGeometricPropertyDefinition("BufferGeometry");
+    polygonProperty.SetGeometryTypes(MgFeatureGeometricType.Surface);
+    polygonProperty.SetHasElevation(false);
+    polygonProperty.SetHasMeasure(false);
+    polygonProperty.SetReadOnly(false);
+    polygonProperty.SetSpatialContextAssociation("defaultSrs");
+    properties.Add(polygonProperty);
+     
+    MgPropertyDefinitionCollection idProperties = bufferClass.GetIdentityProperties();
+    idProperties.Add(idProperty);
+     
+    bufferClass.SetDefaultGeometryPropertyName("BufferGeometry");
+    MgFeatureSchema bufferSchema = new MgFeatureSchema("BufferLayerSchema", "temporary schema to hold a buffer");
+    bufferSchema.GetClasses().Add(bufferClass);
+    MgCreateSdfParams sdfParams = new MgCreateSdfParams("defaultSrs", wkt, bufferSchema);
+    featureService.CreateFeatureSource(bufferFeatureResId, sdfParams);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgClassDefinition bufferClass = new MgClassDefinition();
+    bufferClass.SetName("BufferClass");
+    MgPropertyDefinitionCollection properties = bufferClass.GetProperties();
+     
+    MgDataPropertyDefinition idProperty = new MgDataPropertyDefinition("ID");
+    idProperty.SetDataType(MgPropertyType.Int32);
+    idProperty.SetReadOnly(true);
+    idProperty.SetNullable(false);
+    idProperty.SetAutoGeneration(true);
+    properties.Add(idProperty);
+     
+    MgGeometricPropertyDefinition polygonProperty = new MgGeometricPropertyDefinition("BufferGeometry");
+    polygonProperty.SetGeometryTypes(MgFeatureGeometricType.Surface);
+    polygonProperty.SetHasElevation(false);
+    polygonProperty.SetHasMeasure(false);
+    polygonProperty.SetReadOnly(false);
+    polygonProperty.SetSpatialContextAssociation("defaultSrs");
+    properties.Add(polygonProperty);
+     
+    MgPropertyDefinitionCollection idProperties = bufferClass.GetIdentityProperties();
+    idProperties.Add(idProperty);
+     
+    bufferClass.SetDefaultGeometryPropertyName("BufferGeometry");
+    MgFeatureSchema bufferSchema = new MgFeatureSchema("BufferLayerSchema", "temporary schema to hold a buffer");
+    bufferSchema.GetClasses().Add(bufferClass);
+    MgCreateSdfParams 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.
+
+.. index::
+    single: Features; Inserting Features
+    single: Features; Deleting Features
+    single: Features; Updating Features
+    single: MgDeleteFeatures
+    single: MgInsertFeatures
+    single: MgUpdateFeatures
+    single: MgFeatureService; UpdateFeatures
+
 Inserting, Deleting and Updating Features
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. todo::
+    Update page number reference with section link
+
+To change data in a feature source, create an MgFeatureCommandCollection
+object. This can contain commands to insert, delete, or update features in an
+FDO data source. The commands are executed sequentially. For FDO providers
+that support transaction processing, the commands can be treated as a single
+transaction.
+
+Feature commands can be one of the following:
+
+ * ``MgDeleteFeatures``
+ * ``MgInsertFeatures``
+ * ``MgUpdateFeatures``
+
+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:
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $commands = new MgFeatureCommandCollection();
+    $deleteCommand = new MgDeleteFeatures($className, "ID like '%'");
+    $commands->Add($deleteCommand);
+    $featureService->UpdateFeatures($featureSource, $commands, false);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgFeatureCommandCollection commands = new MgFeatureCommandCollection();
+    MgDeleteFeature deleteCommand = new MgDeleteFeatures(className, "ID like '%'");
+    commands.Add(deleteCommand);
+    featureService.UpdateFeatures(featureSource, commands, false);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgFeatureCommandCollection commands = new MgFeatureCommandCollection();
+    MgDeleteFeature 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:
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $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);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgFeatureCommandCollection commands = new MgFeatureCommandCollection();
+    MgPropertyCollection properties = new MgPropertyCollection();
+    MgByteReader agfByteStream = agfReaderWriter.Write(geometry);
+    MgGeometryProperty geometryProperty = new MgGeometryProperty(propertyName, agfByteStream);
+    properties.Add(geometryProperty);
+    
+    MgInsertFeatures insertCommand = new MgInsertFeatures(className, properties);
+    commands.Add(insertCommand);
+    
+    featureService.UpdateFeatures(featureSource, commands, false);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgFeatureCommandCollection commands = new MgFeatureCommandCollection();
+    MgPropertyCollection properties = new MgPropertyCollection();
+    MgByteReader agfByteStream = agfReaderWriter.Write(geometry);
+    MgGeometryProperty geometryProperty = new MgGeometryProperty(propertyName, agfByteStream);
+    properties.Add(geometryProperty);
+    
+    MgInsertFeatures 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.
+
+.. index::
+    single: Geometry; Buffering
+    single: Buffer; Creating
+
 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:
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $geometryData = $featureReader->GetGeometry($geometryName);
+    $featureGeometry = $agfReaderWriter->Read($geometryData);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgByteReader geometryData = featureReader.GetGeometry(geometryName);
+    MgGeometry featureGeometry = agfReaderWriter.Read(geometryData);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgByteReader geometryData = featureReader.GetGeometry(geometryName);
+    MgGeometry 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:
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $mapWktSrs = $currentMap->GetMapSRS();
+    $coordSysFactory = new MgCoordinateSystemFactory();
+    $srs = $coordSysFactory->Create($mapWktSrs);
+    $srsMeasure = $srs->GetMeasure();
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    String mapWktSrs = currentMap.GetMapSRS();
+    MgCoordinateSystemFactory coordSysFactory = new MgCoordinateSystemFactory();
+    MgCoordianteSystem srs = coordSysFactory.Create(mapWktSrs);
+    MgCoordinateSystemMeasure srsMeasure = srs.GetMeasure();
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    String mapWktSrs = currentMap.GetMapSRS();
+    MgCoordinateSystemFactory coordSysFactory = new MgCoordinateSystemFactory();
+    MgCoordianteSystem srs = coordSysFactory.Create(mapWktSrs);
+    MgCoordinateSystemMeasure srsMeasure = srs.GetMeasure();
+
+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.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $srsDist = $srs->ConvertMetersToCoordinateSystemUnits($bufferDist);
+    $bufferGeometry = $featureGeometry->Buffer($srsDist, $srsMeasure);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    double srsDist = srs.ConvertMetersToCoordinateSystemUnits(bufferDist);
+    MgGeometry bufferGeometry = featureGeometry.Buffer(srsDist, srsMeasure);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    double srsDist = srs.ConvertMetersToCoordinateSystemUnits(bufferDist);
+    MgGeometry bufferGeometry = featureGeometry.Buffer(srsDist, srsMeasure);
+
+.. index::
+    single: Buffer; Displaying in map
+
+To display the buffer in the map, perform the following steps:
+
+ * 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.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $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);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
+    queryOptions.SetFilter("RTYPE = 'MFG'");
+    queryOptions.SetSpatialFilter("SHPGEOM", bufferGeometry, MgFeatureSpatialOperations.Inside);
+    MgResourceIdentifier featureResId = new MgResourceIdentifier("Library://Samples/Sheboygan/Data/Parcels.FeatureSource");
+    MgFeatureReader featureReader = featureService.SelectFeatures(featureResId, "Parcels", queryOptions);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
+    queryOptions.SetFilter("RTYPE = 'MFG'");
+    queryOptions.SetSpatialFilter("SHPGEOM", bufferGeometry, MgFeatureSpatialOperations.Inside);
+    MgResourceIdentifier featureResId = new MgResourceIdentifier("Library://Samples/Sheboygan/Data/Parcels.FeatureSource");
+    MgFeatureReader featureReader = featureService.SelectFeatures(featureResId, "Parcels", queryOptions);
+
 Example
--------
\ No newline at end of file
+-------
+
+.. todo::
+    Update page number reference with section link
+
+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 Developer's 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.
+
+.. highlight:: javascript
+.. code-block:: javascript
+
+    <script language="javascript">
+    function OnPageLoad()
+    {
+        parent.parent.Refresh();
+    }
+    </script>
+
+Add an ``OnLoad`` command to the ``<body>`` element:
+
+.. highlight:: html
+.. code-block:: html
+
+    <body onLoad="OnPageLoad()">
+
+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.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    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 = $srs->GetMeasure();
+
+    // 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);
+    }
+    
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+
+.. index::
+    single: Geometry; Merging geometries
+
+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.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    // 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);
+    $map->Save($resourceService);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    
+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.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    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('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;
+    }
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    
+There is an additional example in the Developer's 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.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $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);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+
+It creates an additional feature source that contains point markers for each of
+the selected parcels.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    // 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.';
+    }
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
\ No newline at end of file

Modified: trunk/MgDev/Doc/devguide/source/custom_output.rst
===================================================================
--- trunk/MgDev/Doc/devguide/source/custom_output.rst	2011-03-02 11:08:18 UTC (rev 5582)
+++ trunk/MgDev/Doc/devguide/source/custom_output.rst	2011-03-02 16:23:17 UTC (rev 5583)
@@ -1,4 +1,5 @@
 .. index::
+   single: Custom Output
    
 Custom Output
 =============
@@ -9,8 +10,160 @@
 Introduction
 ------------
 
+.. tip::
+
+    The Custom Output sample, in the Developer's 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.
+
+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.
+ * Images are suitable for use in HTML pages, word processor documents, or graphics editing programs.
+
+Characteristics of an ePlot DWF:
+
+ * 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.
+
+.. index::
+   single: Custom Output; image
+   single: Rendering Service
+   single: MgRenderingService
+
 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.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $byteReader = $renderingService->RenderMap($map, $selection, $envelope, $imageWidth, $imageHeight, $color, 'PNG');
+    header("Content-type: " . $byteReader->GetMimeType() );
+    $buffer = '';
+    while ($byteReader->Read($buffer, 50000) != 0)
+    {
+        echo $buffer;
+    }
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+
+.. index::
+   single: Custom Output; dwf
+   single: Mapping Service
+   single: MgMappingService
+
 Mapping Service
----------------
\ No newline at end of file
+---------------
+
+The Mapping Service creates ePlot DWFs.
+
+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.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $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($siteConnection);
+    $map2->Create($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;
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace

Modified: trunk/MgDev/Doc/devguide/source/digitizing_and_redlining.rst
===================================================================
--- trunk/MgDev/Doc/devguide/source/digitizing_and_redlining.rst	2011-03-02 11:08:18 UTC (rev 5582)
+++ trunk/MgDev/Doc/devguide/source/digitizing_and_redlining.rst	2011-03-02 16:23:17 UTC (rev 5583)
@@ -1,23 +1,187 @@
-.. index::
-   single: digitizing; redlining
-   
 Digitizing and Redlining
 ========================
 
+.. index::
+    single: Digitizing; Introduction
+    single: Redlining; Introduction
+
 Introduction
 ------------
 
+.. tip::
+
+    The Digitizing and Redlining sample, in the Developer's Guide samples,
+    demonstrates concepts from this chapter.
+
+This chapter describes *digitizing* (capturing the user's 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 user's clicks).
+
+.. index::
+    single: Digitizing; Viewer API
+
 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
+
+.. highlight:: html
+.. code-block:: html
+
+    <input type="button" value=" Point " onclick="DigitizePoint();">
+
+the script calls the JavaScript function
+
+.. highlight:: javascript
+.. code-block:: javascript
+
+    function DigitizePoint() {
+        parent.parent.mapFrame.DigitizePoint(OnPointDigitized);
+    }
+
+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.
+
+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.
+
+.. highlight:: javascript
+.. code-block:: javascript
+
+    function OnPointDigitized(point) {
+        ShowResults("X: " + point.X + ", Y: " + point.Y);
+    }
+
+.. index::
+    single: Redlining; Process
+
 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.
+
+.. index::
+    single: Digitizing; Passing Coordinates
+
 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.
+
+.. highlight:: javascript
+.. code-block:: javascript
+
+    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.
+
+.. index::
+    single: Redlining; Creating a Feature Source
+    single: Feature Source; Creating
+
 Creating a Feature Source
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+The next step is create a feature source
+See ``draw_line.php`` in the ``digitizing_features`` directory in the Developer
+Guide samples.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    // 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();
+    $sdfParams = new MgCreateSdfParams("spatial context", $wkt, $featureSchema);
+    $featureService->CreateFeatureSource($resourceIdentifier, $sdfParams);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+
+.. index::
+    single: Redlining; Create a Layer
+
 Create a Layer
-^^^^^^^^^^^^^^
\ No newline at end of file
+^^^^^^^^^^^^^^
+
+.. todo::
+    Update page number reference with section link
+
+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.
\ No newline at end of file

Added: trunk/MgDev/Doc/devguide/source/images/layerdefinition.png
===================================================================
(Binary files differ)


Property changes on: trunk/MgDev/Doc/devguide/source/images/layerdefinition.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Modified: trunk/MgDev/Doc/devguide/source/interacting_with_layers.rst
===================================================================
--- trunk/MgDev/Doc/devguide/source/interacting_with_layers.rst	2011-03-02 11:08:18 UTC (rev 5582)
+++ trunk/MgDev/Doc/devguide/source/interacting_with_layers.rst	2011-03-02 16:23:17 UTC (rev 5583)
@@ -1,6 +1,3 @@
-.. index::
-   single: layers
-   
 Interacting With Layers
 =======================
 
@@ -14,7 +11,6 @@
 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
@@ -22,6 +18,9 @@
     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.
 
+.. index::
+    single: Layers; Basic Properties
+
 Basic Layer Properties
 ^^^^^^^^^^^^^^^^^^^^^^
 
@@ -47,6 +46,9 @@
 collection containing the layers in a map, then ``$layers->GetItem(0)`` returns
 the top-most layer.
 
+.. index::
+    single: Layer Groups
+
 Layer Groups
 ^^^^^^^^^^^^
 
@@ -68,6 +70,9 @@
 Each layer group in a map must have a unique name, even if it is nested within
 another group.
 
+.. index::
+    single: Base Layer Groups
+
 Base Layer Groups
 """""""""""""""""
 
@@ -99,6 +104,9 @@
     
     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.
 
+.. index::
+    single: Layers; Styles
+
 Layer Style
 ^^^^^^^^^^^
 
@@ -114,6 +122,9 @@
 dynamically using the Web Extensions API. See Modifying Maps and Layers
 on page 57 for details.
 
+.. index::
+    single: Layers; Visiblity
+
 Layer Visibility
 ^^^^^^^^^^^^^^^^
 
@@ -127,6 +138,9 @@
 for any group containing the layer must be on, and the layer must have a style
 setting defined for the current map view scale.
 
+.. index::
+    single: Layers; Actual Visiblity
+
 Example: Actual Visibility
 """"""""""""""""""""""""""
 
@@ -149,6 +163,10 @@
 | Off              | On               | 10000      | Off              |
 +------------------+------------------+------------+------------------+
 
+.. index::
+    single: Layers; Enumerating Map Layers
+    single: MgMap; Enumerating Layers
+
 Enumerating Map Layers
 ----------------------
 
@@ -239,6 +257,9 @@
     }
     response.getWriter().write("</p>");
 
+.. index::
+    single: Layers; Manipulation
+
 Manipulating Layers
 -------------------
 
@@ -250,6 +271,9 @@
 layer resources in the repository. For details, see Modifying Maps and Layers
 on page 57.
 
+.. index::
+    single: Layers; Changing Basic Properties
+
 Changing Basic Properties
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -344,6 +368,9 @@
     // Also be sure to refresh the map on page load.
     map.Save(resourceService);
 
+.. index::
+    single: Layers; Changing Visibility
+
 Changing Visibility
 ^^^^^^^^^^^^^^^^^^^
 

Modified: trunk/MgDev/Doc/devguide/source/introduction.rst
===================================================================
--- trunk/MgDev/Doc/devguide/source/introduction.rst	2011-03-02 11:08:18 UTC (rev 5582)
+++ trunk/MgDev/Doc/devguide/source/introduction.rst	2011-03-02 16:23:17 UTC (rev 5583)
@@ -1,5 +1,5 @@
 .. index::
-   single: introduction
+   single: Introduction
 
 Introduction
 ============
@@ -22,6 +22,9 @@
 is provided in the on-line MapGuide Web API Reference and MapGuide Viewer API
 Reference.
 
+.. index::
+    single: Essential Concepts
+
 Essential Concepts
 ------------------
 
@@ -76,6 +79,9 @@
 incomplete, lacking initialization and error-checking. For more complete
 versions, refer to the sample applications.
 
+.. index::
+    single: Application Development
+
 Application Development
 -----------------------
 
@@ -91,6 +97,10 @@
 Reading Apache log for PHP errors. Is there an equivalent for IIS? Other sources
 of log information?
 
+.. index::
+    single: Repositories
+    single: Resources
+
 Resources and Repositories
 --------------------------
 
@@ -114,6 +124,10 @@
  * Load Procedures
  * Print Layouts
 
+.. index::
+    single: Repositories; Library Repositories
+    single: Repositories; Session Repositories
+
 Library and Session
 ^^^^^^^^^^^^^^^^^^^
 
@@ -146,6 +160,9 @@
     remains alive, you can tick the "Keep Connection Alive" Web Layout option in Autodesk MapGuide Studio. A similar option exists in MapGuide Maestro's
     Web Layout editor.
 
+.. index::
+    single: MgMap; About
+
 Maps
 ^^^^
 
@@ -227,6 +244,9 @@
     MgResourceIdentifier mapId = new MgResourceIdentifier("Session:$sessionId//$mapName." + MgResourceType.Map);
     map.Save(resourceService, mapId);
 
+.. index::
+    single: Web Layout; Displaying
+
 Hello, Map - Displaying a Web Layout
 ------------------------------------
 
@@ -318,6 +338,9 @@
 
     Code sample coming soon!
 
+.. index::
+    single: Web Layout; Adding a Custom Command
+
 Hello, Map 2 - Adding a Custom Command
 --------------------------------------
 
@@ -330,6 +353,9 @@
 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.
 
+.. index::
+    single: Web Layout; Server Pages
+
 Web Layouts and MapGuide Server Pages
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -559,6 +585,9 @@
     However, this function does not need to be called if you are only using the 
     Geometry and Coordinate System components of the MapGuide API
 
+.. index::
+    single: Services
+
 Understanding Services
 ----------------------
 

Modified: trunk/MgDev/Doc/devguide/source/mapguide_ajax_viewer.rst
===================================================================
--- trunk/MgDev/Doc/devguide/source/mapguide_ajax_viewer.rst	2011-03-02 11:08:18 UTC (rev 5582)
+++ trunk/MgDev/Doc/devguide/source/mapguide_ajax_viewer.rst	2011-03-02 16:23:17 UTC (rev 5583)
@@ -470,4 +470,18 @@
             <frame src="common/Title.php?TitleText=<?= $title ?>" name="TitleFrame" scrolling="NO" noresize />
             <frame src="/mapguide/mapviewerajax/?SESSION=<?= $sessionId ?>&WEBLAYOUT=<?= $webLayout ?>" name="ViewerFrame" />
         </frameset>
-    </html>
\ No newline at end of file
+    </html>
+    
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    Code sample coming soon!
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    Code sample coming soon!
\ No newline at end of file

Modified: trunk/MgDev/Doc/devguide/source/modifying_maps_and_layers.rst
===================================================================
--- trunk/MgDev/Doc/devguide/source/modifying_maps_and_layers.rst	2011-03-02 11:08:18 UTC (rev 5582)
+++ trunk/MgDev/Doc/devguide/source/modifying_maps_and_layers.rst	2011-03-02 16:23:17 UTC (rev 5583)
@@ -1,32 +1,534 @@
-.. index::
-   single: map; layer
-
 Modifying Maps and Layers
 =========================
 
 Introduction
 ------------
 
+.. tip::
+
+    The Modifying Maps and Layers sample, in the Developer's Guide samples, demonstrates concepts from this chapter.
+
+This chapter describes how to modify maps and layers.
+
+.. index::
+    single: Layers; Adding an existing layer to a map
+
 Adding An Existing Layer To A Map
 ---------------------------------
 
+.. todo::
+    Update page number reference with section link
+
+If the layer already exists in the resource repository, add it to the map by getting
+the map's layer collection and then adding the layer to that collection.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $layerCollection = $map->GetLayers();
+    $layerCollection->Add($layer);
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgLayerCollection layerCollection = map.GetLayers();
+    layerCollection.Add(layer);
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgLayerCollection layerCollection = map.GetLayers();
+    layerCollection.Add(layer);
+
+
+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.
+
+.. index::
+    single: Layers; Creating layers by modifying XML
+
 Creating Layers by Modifying XML
 --------------------------------
 
+.. todo::
+    Update page number reference with section link
+
+The easiest way to programmatically create new layers is to
+
+ 1. Build a prototype layer through the UI. To make the scripting simpler, this layer should have as many of the correct settings as can be determined in advance.
+ 2. Use MapGuide Studio **Save as Xml** command or similar function in Maestro to save the layer as an XML file.
+ 3. Have the script load the XML file and then use the DOM (Document Object Model) to change the necessary XML elements.
+ 4. Add the modified layer to the map.
+
+The XML schema for layer definitions is defined by the
+``LayerDefinition-version.xsd`` schema, which is documented in the MapGuide Web API Reference. This 
+schema closely parallels the UI in the Layer Editor of MapGuide Studio and as described in the 
+*MapGuide Studio Help*, and the Layer Editor of MapGuide Maestro.
+
+This example
+
+ * 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*.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    // (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';
+        }
+    }
+    // ...
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+
+.. note::
+
+    Due to the abundance of various XML libraries available for .net and Java, the above examples should
+    be considered as one way for modifying XML. By no means is this the **definitive** way.
+
+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 user's session repository.
+ 2. Modify the layer and save it back to the session repository.
+ 3. Change the user's map to refer to the modified layer.
+
+See Adding Layers To A Map on page 68.
+
+.. index::
+    single: LayerDefinitionFactory
+
 Another Way to Create Layers
 ----------------------------
 
+.. todo::
+    Update Maestro API link
+
+The method described in the previous section is easy to use, but requires a
+layer definition be created first through the UI. An alternative approach is to
+use the methods defined in
+
+``C:\Program Files\OSGeo\MapGuide\Web\www\mapviewerphp\layerdefinitionfactory.php``
+
+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, or to use the strongly-typed resource classes
+in the Maestro API
+
+``CreateLayerDefinition($resourceId, $featureClass, $geometry, $featureClassRange)``
+
+ * ``$resourceId`` - The repository path of the feature source for the layer. For example: ``Library://Samples/Sheboygan/Data/Parcels.FeatureSource``
+ * ``$featureClass`` - The feature class to use. For example, ``SHP_Schema:Parcels``
+ * ``$geometry`` - The geometry to use from the feature class. For example, ``SHPGEOM``
+ * ``$featureClassRange`` - A scale range created by filling in a scale range template (``ScaleRange.templ``)
+ 
+``CreateScaleRange($minScale, $maxScale, $typeStyle)``
+
+ * ``$minScale`` - The minimum scale range to which this rule applies.
+ * ``$maxScale`` - The maximum scale range to which this rule applies.
+ * ``$typeStyle`` - A type style created by using ``CreateAreaTypeStyle()``, ``CreateLineTypeStyle()`` or ``CreatePointTypeStyle()``
+ 
+``CreateAreaTypeStyle($areaRules)``
+
+ * ``$areaRules`` - One or more area rules, created by ``CreateAreaRule()``
+ 
+``CreateAreaRule($legendLabel, $filterText, $foregroundColor)``
+
+ * ``$legendLabel`` - The text for the label shown beside this rule in the legend.
+ * ``$filterText`` - The filter expression that determines which features match this rule. For example ``SQFT >= 1 AND SQFT < 800``
+ * ``$foregroundColor`` - The color to be applied to areas that match this rule.
+
+``CreateTextSymbol($text, $fontHeight, $foregroundColor)``
+
+ * ``$text`` - The string for the text
+ * ``$fontHeight`` - The height for the font
+ * ``$foregroundColor`` - The foreground color
+ 
+``CreatePointTypeStyle($pointRule)``
+
+ * ``$pointRule`` - One or more point rules, created by ``CreatePointRule()``
+ 
+``CreatePointRule($legendLabel, $filter, $label, $pointSym)``
+
+ * ``$legendLabel`` - The label shown beside this rule in the legend.
+ * ``$filter`` - The filter expression that determines which features match this rule.
+ * ``$label`` - The text symbol, created by ``CreateTextSymbol()``
+ * ``$pointSym`` - A mark symbol created by ``CreateMarkSymbol()``
+
+``CreateMarkSymbol($resourceId, $symbolName, $width, $height, $color)``
+
+ * ``$resourceId`` - The resource ID of the symbol used to mark each point. For example ``Library://Samples/Sheboygan/Symbols/BasicSymbols.SymbolLibrary``
+ * ``$symbolName`` - The name of the desired symbol in the symbol library/
+ * ``$width`` - The width of the symbol (in points)
+ * ``$height`` - The height of the symbol (in points)
+ * ``$color`` - The color of the symbol.
+ 
+``CreateLineTypeStyle($lineRules)``
+ 
+ * ``$lineRules`` - One or more rules, created by ``CreateLineRule()`` 
+ 
+``CreateLineRule($color, $legendLabel, $filter)``
+
+ * ``$color`` - The color to be applied to lines that match this rule.
+ * ``$legendLabel`` - The label shown beside this rule in the legend.
+ * ``$filter`` - The filter expression that determines which features match this rule.
+
+For more information on these settings, see the MapGuide Studio Help.
+
+.. index::
+    single: LayerDefinitionFactory; Area Rules
+
 Example: Creating a layer that users Area Rules
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. todo::
+    Update page number reference with section link
+
+.. note::
+    
+    This example specifically uses the ``LayerDefinitionFactory`` class which is not available for .net and Java
+
+This example shows how to create a new layer using the factory. This layer
+uses three area rules to theme parcels by their square footage.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    // ...
+    /---------------------------------------------------//
+     $factory = new LayerDefinitionFactory();
+    /// Create three area rules for three different
+    // scale ranges.
+    $areaRule1 = $factory->CreateAreaRule( '1 to 800', 'SQFT &gt;= 1 AND SQFT &lt; 800', 'FFFFFF00');
+    $areaRule2 = $factory->CreateAreaRule( '800 to 1600','SQFT &gt;= 800 AND SQFT &lt; 1600', 'FFFFBF20');
+    $areaRule3 = $factory->CreateAreaRule('1600 to 2400', 'SQFT &gt;= 1600 AND SQFT &lt; 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.
+
+.. index::
+    single: LayerDefinitionFactory; Line Rules
+
 Example: Using Line Rules
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. note::
+    
+    This example specifically uses the ``LayerDefinitionFactory`` class which is not available for .net and Java
+
+Creating line-based rules is very similar.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    // ...
+    //---------------------------------------------------//
+    $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);
+    //---------------------------------------------------//
+    // ...
+
+.. index::
+    single: LayerDefinitionFactory; Point Rules
+
 Example: Using Point Rules
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. note::
+    
+    This example specifically uses the ``LayerDefinitionFactory`` class which is not available for .net and Java
+
+To create point-based rules, three methods are used.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    // ...
+    //---------------------------------------------------//
+    $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);
+    //---------------------------------------------------//
+
+.. index::
+    single: MgMap; Adding Layers
+
 Adding Layers to a Map
 ----------------------
 
+The preceding examples have created or modified the XML for layer definitions
+in memory. To add those layers to a map:
+
+1. Save the layer definition to a resource stored in the session repository.
+2. Add that resource to the map.
+
+This function adds takes a layer's XML, creates a resource in the session
+repository from it, and adds that layer resource to a map.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    <?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;
+    }
+
+This function adds a layer resource to a map.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    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;
+    }
+
+This function adds a layer to a legend's layer group.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    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);
+    }
+
+.. index::
+    single: Layers; Making permanent changes
+
 Making Changes Permanent
-------------------------
\ No newline at end of file
+------------------------
+
+So far, all the examples in this chapter have only affected the user's runtime
+version of the map. No other users see those changes, and when the current
+user logs out those changes will be lost.
+
+To make changes permanent, the script can save the modified layer back into
+the Library.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $byteSource = new MgByteSource($layerDefinition, strlen($layerDefinition));
+    $byteSource->SetMimeType(MgMimeType::Xml);
+    $resourceId = new MgResourceIdentifier("Library://LayerName.LayerDefinition");
+    $resourceService->SetResource($resourceId, $byteSource->GetReader(), null);
+
+.. note::
+
+    Due to security restrictions imposed on the Library repository. Make sure the 
+    resource service object was created from a site connection that was initialized by
+    a login or session id that has the appropriate permissions to write to the Library
+    repository. 
+    
+    The ``Anonymous`` user does not have write access to the Library repository
\ No newline at end of file

Modified: trunk/MgDev/Doc/devguide/source/working_with_feature_data.rst
===================================================================
--- trunk/MgDev/Doc/devguide/source/working_with_feature_data.rst	2011-03-02 11:08:18 UTC (rev 5582)
+++ trunk/MgDev/Doc/devguide/source/working_with_feature_data.rst	2011-03-02 16:23:17 UTC (rev 5583)
@@ -1,6 +1,3 @@
-.. index::
-   single: feature; data
-
 Working With Feature Data
 =========================
 
@@ -51,6 +48,8 @@
 The Web API Feature Service provides functions for querying and updating
 feature data.
 
+.. index::
+    single: Features; Querying
 
 Querying Feature Data
 ---------------------
@@ -58,6 +57,10 @@
 In order to work with feature data, you must first select the features you are
 interested in. This can be done with the Viewer or through Web API calls.
 
+.. index::
+    single: Feature Readers
+    single: MgFeatureReader
+
 Feature Readers
 ^^^^^^^^^^^^^^^
 
@@ -83,16 +86,25 @@
 Otherwise, call ``MgFeatureReader::GetPropertyName()`` and
 ``MgFeatureReader::GetPropertyType()`` before retrieving the value.
 
+.. index::
+    single: MgFeatureReader; Proper Cleanup
+
 .. note::
     You should always call ``Close()`` on your ``MgFeatureReader`` objects (or any object derived from ``MgReader`` for that matter)
     as memory leaks can happen because of unclosed reader objects. Another common pitfall is the ``Close()`` call not being called because
     the code before it threw an exception. For .net and Java, you can use the a ``try...finally`` block
     to ensure your reader will always be closed regardless of whether exceptions have been thrown or not. 
-    
+
+.. index::
+    single: MgFeatureReader; Checking Null Values
+   
 .. note::
     Always check if the property whose value you are trying to retrive is null using the ``IsNull()`` method before attempting to access the property value. 
     Attempting to access a null property value will cause the reader to throw a ``MgNullPropertyValueException``
 
+.. index::
+    single: Selections
+
 Selecting with the Web API
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -111,6 +123,10 @@
 Spatial filters are used to select features based on their geometry. For example,
 you could use a spatial filter to select all roads that intersect a certain area.
 
+.. index::
+    single: Filters; Basic Filters
+    single: MgFeatureQueryOptions; SetFilter
+    
 Basic Filters
 """""""""""""
 
@@ -118,6 +134,9 @@
 complex queries by combining expressions. Expressions use the comparison
 operators below:
 
+.. index::
+    single: Filters; Comparison Operators
+
 +------------+------------------------------------------+
 | Operator   | Meaning                                  |
 +============+==========================================+
@@ -167,6 +186,7 @@
 .. highlight:: csharp
 .. code-block:: csharp
 
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
     MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
     queryOptions.SetFilter("year > 2001");
 
@@ -175,6 +195,7 @@
 .. highlight:: java
 .. code-block:: java
 
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
     MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
     queryOptions.SetFilter("year > 2001");
 
@@ -193,6 +214,7 @@
 .. highlight:: csharp
 .. code-block:: csharp
 
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
     MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
     queryOptions.SetFilter("year >= 2001 and year <= 2004");
 
@@ -201,6 +223,7 @@
 .. highlight:: java
 .. code-block:: java
 
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
     MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
     queryOptions.SetFilter("year >= 2001 and year <= 2004");
 
@@ -219,6 +242,7 @@
 .. highlight:: csharp
 .. code-block:: csharp
 
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
     MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
     queryOptions.SetFilter("owner LIKE 'Davi%s'");
 
@@ -227,9 +251,14 @@
 .. highlight:: java
 .. code-block:: java
 
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
     MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
     queryOptions.SetFilter("owner LIKE 'Davi%s'");
 
+.. index::
+    single: Filters; Spatial
+    single: MgFeatureQueryOptions; SetSpatialFilter
+
 Spatial Filters
 """""""""""""""
 
@@ -255,6 +284,9 @@
 the feature property and the geometry. The spatial operations are defined in
 class ``MgFeatureSpatialOperations``.
 
+.. index::
+    single: Filters; Spatial Operations
+
 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:
@@ -276,6 +308,10 @@
     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.
 
+.. index::
+    single: Features; Creating Geometry Objects
+    single: MgAgfReaderWriter
+
 **Creating Geometry Objects from Features**
 
 You may want to use an existing feature as part of a spatial query. To retrieve
@@ -340,6 +376,9 @@
     MgAgfReaderWriter agfReaderWriter = new MgAgfReaderWriter();
     MgGeometry districtGeometry = agfReaderWriter.Read(districtGeometryData);
 
+.. index::
+    single: MgWktReaderWriter
+
 To convert an ``MgGeometry`` object into its WKT representation, use the ``MgWktReaderWriter::Write()`` method, as in the following example:
 
 **PHP**
@@ -370,52 +409,677 @@
 
 **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:
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $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')";
+
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //These code fragments assumes you have imported the OSGeo.MapGuide namespace
+    MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
+    queryOptions.SetFilter("RNAME LIKE 'SCHMITT%'");
+    queryOptions.SetSpatialFilter("SHPGEOM", testArea, MgFeatureSpatialOperations.Inside);
+
+    MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
+    queryOptions.SetFilter("RNAME LIKE 'SCHMITT%' AND SHPGEOM inside GEOMFROMTEXT('" + testAreaWkt + "')";
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //These code fragments assumes you have imported the org.osgeo.mapguide namespace
+    MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
+    queryOptions.SetFilter("RNAME LIKE 'SCHMITT%'");
+    queryOptions.SetSpatialFilter("SHPGEOM", testArea, MgFeatureSpatialOperations.Inside);
+
+    MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
+    queryOptions.SetFilter("RNAME LIKE 'SCHMITT%' AND SHPGEOM inside GEOMFROMTEXT('" + testAreaWkt + "')";
+
+
+.. index::
+    single: Selections; Listing Properties
+
 Example: Selection
 ^^^^^^^^^^^^^^^^^^
 
+The following example creates a selection, then lists properties from the
+selected features. See the Working With Feature Data sample, in the Developer's
+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.
+
 **PHP**
 
 .. highlight:: php
 .. code-block:: php
 
+    $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');
+    $featureReader->Close();
+     
+    // 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');
+        echo $val . '<br />';
+    }
+    $featureReader->Close();
+    echo '</p>';
+
 **.net (C#)**
 
 .. highlight:: csharp
 .. code-block:: csharp
 
+    // This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgMap map = new MgMap(siteConnection);
+    map.Open(mapName);
+    
+    // Get the geometry for the boundaries of District 1
+    MgFeatureQueryOptions districtQuery = new MgFeatureQueryOptions();
+    districtQuery.SetFilter("Autogenerated_SDF_ID = 1");
+    
+    MgLayer layer = (MgLayer)map.GetLayers().GetItem("Districts");
+    MgFeatureReader featureReader = layer.SelectFeatures(districtQuery);
+    featureReader.ReadNext();
+    MgByteReader districtGeometryData = featureReader.GetGeometry("Data");
+    featureReader.Close();
+    
+    // Convert the AGF binary data to MgGeometry
+    MgAgfReaderWriter agfReaderWriter = new MgAgfReaderWriter();
+    MgGeometry districtGeometry = agfReaderWriter.Read(districtGeometryData);
+    
+    // Create a filter to select the desired features.
+    // Combine a basic filter and spatial filter.
+    MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
+    queryOptions.SetFilter("RNAME LIKE 'SCHMITT%'");
+    
+    queryOptions.SetSpatialFilter("SHPGEOM", districtGeometry, MgFeatureSpatialOperations.Inside);
+    
+    // Select the features
+    layer = (MgLayer)map.GetLayers().GetItem("Parcels");
+    featureReader = layer.SelectFeatures(queryOptions);
+    
+    // For each selected feature, display the address
+    
+    Response.Write("<p>Properties owned by Schmitt ");
+    Response.Write("in District 1</p><p>");
+    
+    while (featureReader.ReadNext())
+    {
+        String val = featureReader.GetString("RPROPAD");
+        Response.Write(val + "<br/>");
+    }
+    featureReader.Close();
+    Response.Write("</p>");
+
 **Java**
     
 .. highlight:: java
 .. code-block:: java
 
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgMap map = new MgMap(siteConnection);
+    map.Open(mapName);
+    
+    // Get the geometry for the boundaries of District 1
+    MgFeatureQueryOptions districtQuery = new MgFeatureQueryOptions();
+    districtQuery.SetFilter("Autogenerated_SDF_ID = 1");
+    
+    MgLayer layer = (MgLayer)map.GetLayers().GetItem("Districts");
+    MgFeatureReader featureReader = layer.SelectFeatures(districtQuery);
+    featureReader.ReadNext();
+    MgByteReader districtGeometryData = featureReader.GetGeometry("Data");
+    featureReader.Close();
+    
+    // Convert the AGF binary data to MgGeometry
+    MgAgfReaderWriter agfReaderWriter = new MgAgfReaderWriter();
+    MgGeometry districtGeometry = agfReaderWriter.Read(districtGeometryData);
+    
+    // Create a filter to select the desired features.
+    // Combine a basic filter and spatial filter.
+    MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
+    queryOptions.SetFilter("RNAME LIKE 'SCHMITT%'");
+    
+    queryOptions.SetSpatialFilter("SHPGEOM", districtGeometry, MgFeatureSpatialOperations.Inside);
+    
+    // Select the features
+    layer = (MgLayer)map.GetLayers().GetItem("Parcels");
+    featureReader = layer.SelectFeatures(queryOptions);
+    
+    // For each selected feature, display the address
+    
+    response.getWriter().write("<p>Properties owned by Schmitt ");
+    response.getWriter().write("in District 1</p><p>");
+    
+    while (featureReader.ReadNext())
+    {
+        String val = featureReader.GetString("RPROPAD");
+        response.getWriter().write(val + "<br/>");
+    }
+    featureReader.Close();
+    response.getWriter().write("</p>");
 
+.. index::
+    single: Active Selection; About
 
 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 user's view of the map.
+
+.. note::
+
+    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.
+
+.. index::
+    single: Selections; Selecting with the viewer
+
 Selecting with the Viewer
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+In order for a feature to be selectable using the Viewer, the following criteria
+must be met:
+
+ * 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.
+
+.. index::
+    single: AJAX Viewer; Passing viewer information
+
 Passing Viewer Information to the Web Server
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. todo::
+    Talk about some parameters that are automatically passed for Invoke URL commands
+
+The stateless nature of HTTP means that when the Viewer makes a request to a MapGuide Server Page
+on the Web Server, it must often pass information as part of the request. Some
+common methods for passing this information are:
+
+ * 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.
+
+.. index::
+    single: Invoke URL Commands; Additional Parameters
+    
 Additional Parameters to an Invoke URL Command
 """"""""""""""""""""""""""""""""""""""""""""""
 
+.. todo:
+    Update page number references to section links
+
+With this release of MapGuide, the current selection is the only variable that
+can be passed as part of an Invoke URL command.
+
+To pass the current selection, edit the web layout. Define a new Invoke URL
+command. On the Additional Parameters tab, enter a key and value. The key
+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
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    $selection = $_POST['SEL'];
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    String selection = Request.Form["SEL"];
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    String selection = request.getParameter("SEL");
+
+gets the current selection, in XML format.
+
+See Working With the Active Selection on page 48 for details about using the
+XML data.
+
+.. note::
+
+    The AJAX automatically adds the following parameters for any Invoke URL command:
+    
+     * ``SESSION`` - The current session id
+     * ``MAPNAME`` - The name of the current map. Use this for the ``MgMap::Open()`` method
+
+.. index::
+    single: Invoke Script Commands; Passing Parameters
+
 Passing Parameters from an Invoke Script Command
 """"""""""""""""""""""""""""""""""""""""""""""""
 
+An Invoke Script command in a web layout can be used to pass custom
+parameters to a page. The parameters can be any values that are available via
+the Viewer API.
+
+To pass parameters, edit the web layout. Define a new Invoke Script command.
+On the Additional Parameters tab, enter the JavaScript code to retrieve the
+values to be passed. Add the command to the toolbar, context menu, or task
+bar menu.
+
+The JavaScript code can call Viewer API functions or other functions to retrieve
+values. To pass the parameters to a page, call the ``Submit`` method of the
+``formFrame`` with the parameters, the page URL, and the name of the target
+frame. Use ``taskPaneFrame`` or ``scriptFrame`` as the target frame, depending
+whether the loaded page should be visible or not.
+
+.. note::
+    
+    The parameters must include standard parameters like ``SESSION`` and ``MAPNAME``, if they are needed.
+
+.. index::
+    single: Task Pane; Passing Parameters
+
 Passing Parameters from the Task Pane frame
 """""""""""""""""""""""""""""""""""""""""""
 
+Passing parameters from the task pane frame is similar to passing them from
+an Invoke Script command. Use the Viewer API to retrieve values and call the
+``Submit`` method of the ``formFrame`` to pass the values to another page.
+
+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.
+
+.. highlight:: javascript
+.. code-block:: javascript
+
+    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:
+
+.. highlight:: html
+.. code-block:: html
+
+    <a href="#" onClick="submitRequest('/mapguide/devguide/custom_output/property_report.php'); return false;">Click for report</a>
+
+.. index::
+    single: Active Selection; Manipulating the Active Selection
+
 Working with the Active Selection
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+Whenever a selection is changed by the Viewer, the selection information is sent to the web server so the map can be re-generated.
+
+To retrieve and manipulate the active selection for a map (AJAX Viewer only):
+
+ 1. Create an ``MgSelection`` object for the map. Initialize it to the active selection.
+ 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. 
+ 
+.. index::
+    single: Active Selection; Listing Selected Features
+ 
 Example: Listing Selected Parcels
 """""""""""""""""""""""""""""""""
 
+The steps for listing the selected parcels for the DWF Viewer are nearly the
+same as for the AJAX Viewer. The major difference is you must pass the
+selection information from the Viewer to your page.
+
+One method to do this is to create a JavaScript function, then call this function
+from the Viewer using an Invoke Script command or as a result of an onClick
+event in the task pane. For example, the task pane of the Working With Feature
+Data sample contains a JavaScript function executed by an onClick event.
+
+.. todo::
+    We removed the DWF sample and simplified the AJAX one. Make sure the actual devguide sample if it exists matches this
+
+.. highlight:: javascript
+.. code-block:: javascript
+
+    function listSelection()
+    {
+        xmlSel = parent.parent.mapFrame.GetSelectionXML();
+        params = new Array(
+            "SESSION",parent.parent.mapFrame.GetSessionId(),
+            "MAPNAME", parent.parent.mapFrame.GetMapName());
+        pageUrl = "/mapguide/samplesphp/working_with_feature_data/listselection.php";
+        parent.parent.formFrame.Submit(pageUrl, params, "taskPaneFrame");
+    }
+
+This submits a request to listselection.php, which contains the following:
+
+.. todo::
+    The APIs have been simplified since this was last written. This sample has been updated to use conveience APIs introduced with RFC33. Verify this checks out
+
+**PHP (listselection.php)**
+
+.. highlight:: php
+.. code-block:: php
+
+    $map = new MgMap($siteConnection);
+    $map->Open($mapName);
+
+    $selection = new MgSelection($map);
+    $layers = $selection->GetLayers();
+
+    if ($layers && $layers->GetCount() > 0)
+    {
+        for ($i = 0; $i < $layers->GetCount(); $i++)
+        {
+            $layer = $layers->GetItem($i);
+
+            if ($layer && $layer->GetName() == 'Parcels')
+            {
+                $featureReader = $selection->GetSelectedFeatures($layer, $layer->GetFeatureClassName(), false);
+                // Process each item in the MgFeatureReader,
+                // displaying the owner name
+                while ($featureReader->ReadNext())
+                {
+                    $val = $featureReader->GetString('NAME') .
+                    '<br />&nbsp;&nbsp;' .
+                    $featureReader->GetString('RPROPAD');
+                    echo $val . '<br />';
+                }
+                $featureReader->Close();
+            }
+        }
+    }
+    else
+    {
+        echo 'No selected layers';
+    }
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+    MgMap map = new MgMap(siteConnetion);
+    map.Open(mapName);
+    
+    MgSelection selection = new MgSelection(map);
+    selection.Open(mapName);
+    MgLayerCollection layers = selection.GetLayers();
+    
+    if (layers != null && layers.GetCount() > 0)
+    {
+        for (int i = 0; i < layers.GetCount(); i++)
+        {
+            MgLayer layer = (MgLayer)layers.GetItem(i);
+            if (layer.GetName() == "Parcels")
+            {
+                MgFeatureReader featureReader = selection.GetSelectedFeatures(layer, layer.GetFeatureClassName(), false);
+                while (featureReader.ReadNext())
+                {
+                    String val = featureReader.GetString("NAME") + "<br/>&nbsp;&nbsp;" + featureReader.GetString("RPROPAD");
+                    Response.Write(val + "<br/>");
+                }
+                featureReader.Close();
+            }
+        }
+    }
+    else
+    {
+        Response.Write("No selected layers");
+    }
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
+    MgMap map = new MgMap(siteConnetion);
+    map.Open(mapName);
+    
+    MgSelection selection = new MgSelection(map);
+    selection.Open(mapName);
+    MgLayerCollection layers = selection.GetLayers();
+    
+    if (layers != null && layers.GetCount() > 0)
+    {
+        for (int i = 0; i < layers.GetCount(); i++)
+        {
+            MgLayer layer = (MgLayer)layers.GetItem(i);
+            if (layer.GetName() == "Parcels")
+            {
+                MgFeatureReader featureReader = selection.GetSelectedFeatures(layer, layer.GetFeatureClassName(), false);
+                while (featureReader.ReadNext())
+                {
+                    String val = featureReader.GetString("NAME") + "<br/>&nbsp;&nbsp;" + featureReader.GetString("RPROPAD");
+                    response.getWriter().write(val + "<br/>");
+                }
+                featureReader.Close();
+            }
+        }
+    }
+    else
+    {
+        response.getWriter().write("No selected layers");
+    }
+
+.. index::
+    single: Active Selection; Setting with Web API
+
 Setting the Active Selection with the Web API
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. todo::
+    Update page number reference with section link
+
+To set the run-time map selection using a query, perform the following steps:
+
+ * 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()``.
+
 Example: Setting the Active Selection
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
\ No newline at end of file
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. todo::
+    Update page number reference with section link
+
+The following example combines the pieces needed to create a selection using
+the Web API and pass it back to the Viewer where it becomes the active
+selection for the map. It is an extension of the example shown in Example:
+Selection on page 43.
+
+The PHP code in this example creates the selection XML. Following that is a
+JavaScript function that calls the ``SetSelectionXML()`` function with the
+selection. This function is executed when the page loads.
+
+**PHP**
+
+.. highlight:: php
+.. code-block:: php
+
+    <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&nbsp;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.
+        function OnPageLoad()
+        {
+            selectionXml = '<?php echo $selectionXml; ?>';
+        }
+    </script>
+
+**.net (C#)**
+
+.. highlight:: csharp
+.. code-block:: csharp
+
+    //This code fragment assumes you have imported the OSGeo.MapGuide namespace
+
+**Java**
+    
+.. highlight:: java
+.. code-block:: java
+
+    //This code fragment assumes you have imported the org.osgeo.mapguide namespace
\ No newline at end of file



More information about the mapguide-commits mailing list