[mapguide-commits] r4212 - in trunk/MgDev/Common: CoordinateSystem Geometry/CoordinateSystem Geometry/GeometryConsoleTest Geometry/Spatial

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Tue Sep 8 18:16:32 EDT 2009


Author: NormOlsen
Date: 2009-09-08 18:16:31 -0400 (Tue, 08 Sep 2009)
New Revision: 4212

Modified:
   trunk/MgDev/Common/CoordinateSystem/CoordSysGrids.cpp
   trunk/MgDev/Common/CoordinateSystem/CoordSysGrids.h
   trunk/MgDev/Common/CoordinateSystem/CoordSysMgrs.cpp
   trunk/MgDev/Common/CoordinateSystem/CoordSysMgrs.h
   trunk/MgDev/Common/CoordinateSystem/CoordSysMgrsZone.cpp
   trunk/MgDev/Common/CoordinateSystem/CoordSysMgrsZone.h
   trunk/MgDev/Common/CoordinateSystem/CoordSysOneGrid.cpp
   trunk/MgDev/Common/CoordinateSystem/CoordSysOneGrid.h
   trunk/MgDev/Common/CoordinateSystem/CoordSysTransform.cpp
   trunk/MgDev/Common/CoordinateSystem/CoordSysTransform.h
   trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemFactory.cpp
   trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemFactory.h
   trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemGrids.h
   trunk/MgDev/Common/Geometry/GeometryConsoleTest/GeometryConsoleTest.cpp
   trunk/MgDev/Common/Geometry/Spatial/MathUtility.cpp
   trunk/MgDev/Common/Geometry/Spatial/MathUtility.h
   trunk/MgDev/Common/Geometry/Spatial/SpatialUtility.cpp
   trunk/MgDev/Common/Geometry/Spatial/SpatialUtility.h
Log:
This submission includes most of the grid/graticule package per RFC 76.  This version has been significantly debugged and, to a large degree, works as advertised.  While no 100%, the code is being submitted to support other developers who need the updated portions of this API in order to continue their development efforts.

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysGrids.cpp
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysGrids.cpp	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysGrids.cpp	2009-09-08 22:16:31 UTC (rev 4212)
@@ -15,11 +15,12 @@
 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-#include "Spatial/MathUtility.h"
 #include "GeometryCommon.h"
 #include "CoordSysCommon.h"
 #include "CoordSysUtil.h"
 #include "CriticalSection.h"
+#include "Spatial/MathUtility.h"
+#include "Spatial/SpatialUtility.h"
 
 #include "CoordSys.h"
 #include "CoordSysGrids.h"
@@ -145,21 +146,29 @@
 void CCoordinateSystemGridSpecification::SetGridBase(double eastingBase,double northingBase)
 {
     m_EastingBase = eastingBase;
-    m_NorthingBase = m_EastingBase;
+    m_NorthingBase = northingBase;
 }
 void CCoordinateSystemGridSpecification::SetGridIncrement(double eastingIncrement,double northingIncrement)
 {
     m_EastingIncrement = eastingIncrement;
-    m_NorthingIncrement = m_EastingIncrement;
+    m_NorthingIncrement = northingIncrement;
 }
 void CCoordinateSystemGridSpecification::SetTickIncrements(double eastingIncrement,double northingIncrement)
 {
     m_TickEastingIncrement = eastingIncrement;
-    m_TickNorthingIncrement = m_TickEastingIncrement;
+    m_TickNorthingIncrement = northingIncrement;
 }
 void CCoordinateSystemGridSpecification::SetUnits (INT32 unitCode,INT32 unitType)
 {
-    //TODO:   Should verify the validty of the two parameters.
+    bool codeOk;
+    INT32 lclUnitType;
+
+    codeOk = GetUnitInfo(unitCode,&lclUnitType,NULL);
+    if (!codeOk || unitType != lclUnitType)
+    {
+        throw new MgInvalidCoordinateSystemUnitsException(L"MgCoordinateSystemGridSpecification.SetUnits", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
     m_UnitCode = unitCode;
     m_UnitType = unitType;
 }
@@ -168,86 +177,196 @@
     m_CurvePrecision = curvePrecision;
 }
 
-// The following function are identical to the published version, with the
+// The following functions are identical to the published version, with the
 // exception that the value returned are always converted to the units of
 // the provided coordinate system.  Typically, the coodinate system
 // provided as an argument will be that of the "grid" coordinate system.
 double CCoordinateSystemGridSpecification::GetEastingBase (MgCoordinateSystem* gridCS)
 {
+    INT32 gridUnitType;
+    INT32 gridCrsUnitCode;
+    double unitConversion;
+
     MgCoordinateSystemCatalog* catalogPtr = gridCS->GetCatalog ();
     MgCoordinateSystemUnitInformation* unitInfoPtr = catalogPtr->GetUnitInformation ();
+    gridCrsUnitCode = gridCS->GetUnitCode ();
+    
+    // Verify that the unit type of the specification match the unit type
+    // of the grid coordinate system of the grid object.
+    GetUnitInfo(gridCrsUnitCode,&gridUnitType,NULL);
+    if (gridUnitType != m_UnitType)
+    {
+        throw new MgInvalidCoordinateSystemUnitsException(L"MgCoordinateSystemGridSpecification.GetEastingBase", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
 
-    // TODO:
-    // Should verify that the unit types of the "this" object and the provided
-    // coordinate system are the same.
-    double unitConversion = 1.0 / gridCS->GetUnitScale ();
+    // Calculate the appropriate units conversion factor.
     if (m_UnitType == MgCoordinateSystemUnitType::Linear)
     {
-        unitConversion *= unitInfoPtr->GetLinearUnitScale (m_UnitCode);
+        unitConversion = unitInfoPtr->GetLinearUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetLinearUnitScale (gridCrsUnitCode);
     }
     else
     {
-        unitConversion *= unitInfoPtr->GetAngularUnitScale (m_UnitCode);
+        unitConversion = unitInfoPtr->GetAngularUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetAngularUnitScale (gridCrsUnitCode);
     }
     return (m_EastingBase * unitConversion);
 }
 double CCoordinateSystemGridSpecification::GetNorthingBase (MgCoordinateSystem* gridCS)
 {
+    INT32 gridUnitType;
+    INT32 gridCrsUnitCode;
+    double unitConversion;
+
     MgCoordinateSystemCatalog* catalogPtr = gridCS->GetCatalog ();
     MgCoordinateSystemUnitInformation* unitInfoPtr = catalogPtr->GetUnitInformation ();
+    gridCrsUnitCode = gridCS->GetUnitCode ();
 
-    // TODO:
-    // Should verify that the unit types of the "this" object and the provided
-    // coordinate system are the same.
-    double unitConversion = 1.0 / gridCS->GetUnitScale ();
+    // Verify that the unit type of the specification match the unit type
+    // of the grid coordinate system of the grid object.
+    GetUnitInfo(gridCrsUnitCode,&gridUnitType,NULL);
+    if (gridUnitType != m_UnitType)
+    {
+        throw new MgInvalidCoordinateSystemUnitsException(L"MgCoordinateSystemGridSpecification.GetNorthingBase", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Calculate the appropriate units conversion factor.
     if (m_UnitType == MgCoordinateSystemUnitType::Linear)
     {
-        unitConversion *= unitInfoPtr->GetLinearUnitScale (m_UnitCode);
+        unitConversion = unitInfoPtr->GetLinearUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetLinearUnitScale (gridCrsUnitCode);
     }
     else
     {
-        unitConversion *= unitInfoPtr->GetAngularUnitScale (m_UnitCode);
+        unitConversion = unitInfoPtr->GetAngularUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetAngularUnitScale (gridCrsUnitCode);
     }
     return (m_NorthingBase * unitConversion);
 }
 double CCoordinateSystemGridSpecification::GetEastingIncrement(MgCoordinateSystem* gridCS)
 {
+    INT32 gridUnitType;
+    INT32 gridCrsUnitCode;
+    double unitConversion;
+
     MgCoordinateSystemCatalog* catalogPtr = gridCS->GetCatalog ();
     MgCoordinateSystemUnitInformation* unitInfoPtr = catalogPtr->GetUnitInformation ();
+    gridCrsUnitCode = gridCS->GetUnitCode ();
 
-    // TODO:
-    // Should verify that the unit types of the "this" object and the provided
-    // coordinate system are the same.
-    double unitConversion = 1.0 / gridCS->GetUnitScale ();
+    // Verify that the unit type of the specification match the unit type
+    // of the grid coordinate system of the grid object.
+    GetUnitInfo(gridCrsUnitCode,&gridUnitType,NULL);
+    if (gridUnitType != m_UnitType)
+    {
+        throw new MgInvalidCoordinateSystemUnitsException(L"MgCoordinateSystemGridSpecification.GetEastingIncrement", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Calculate the appropriate units conversion factor.
     if (m_UnitType == MgCoordinateSystemUnitType::Linear)
     {
-        unitConversion *= unitInfoPtr->GetLinearUnitScale (m_UnitCode);
+        unitConversion = unitInfoPtr->GetLinearUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetLinearUnitScale (gridCrsUnitCode);
     }
     else
     {
-        unitConversion *= unitInfoPtr->GetAngularUnitScale (m_UnitCode);
+        unitConversion = unitInfoPtr->GetAngularUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetAngularUnitScale (gridCrsUnitCode);
     }
     return (m_EastingIncrement * unitConversion);
 }
 double CCoordinateSystemGridSpecification::GetNorthingIncrement(MgCoordinateSystem* gridCS)
 {
+    INT32 gridUnitType;
+    INT32 gridCrsUnitCode;
+    double unitConversion;
+
     MgCoordinateSystemCatalog* catalogPtr = gridCS->GetCatalog ();
     MgCoordinateSystemUnitInformation* unitInfoPtr = catalogPtr->GetUnitInformation ();
+    gridCrsUnitCode = gridCS->GetUnitCode ();
 
-    // TODO:
-    // Should verify that the unit types of the "this" object and the provided
-    // coordinate system are the same.
-    double unitConversion = 1.0 / gridCS->GetUnitScale ();
+    // Verify that the unit type of the specification match the unit type
+    // of the grid coordinate system of the grid object.
+    GetUnitInfo(gridCrsUnitCode,&gridUnitType,NULL);
+    if (gridUnitType != m_UnitType)
+    {
+        throw new MgInvalidCoordinateSystemUnitsException(L"MgCoordinateSystemGridSpecification.GetNorthingIncrement", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Calculate the appropriate units conversion factor.
     if (m_UnitType == MgCoordinateSystemUnitType::Linear)
     {
-        unitConversion *= unitInfoPtr->GetLinearUnitScale (m_UnitCode);
+        unitConversion = unitInfoPtr->GetLinearUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetLinearUnitScale (gridCrsUnitCode);
     }
     else
     {
-        unitConversion *= unitInfoPtr->GetAngularUnitScale (m_UnitCode);
+        unitConversion = unitInfoPtr->GetAngularUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetAngularUnitScale (gridCrsUnitCode);
     }
     return (m_NorthingIncrement * unitConversion);
 }
+double CCoordinateSystemGridSpecification::GetTickEastingIncrement(MgCoordinateSystem* gridCS)
+{
+    INT32 gridUnitType;
+    INT32 gridCrsUnitCode;
+    double unitConversion;
+
+    MgCoordinateSystemCatalog* catalogPtr = gridCS->GetCatalog ();
+    MgCoordinateSystemUnitInformation* unitInfoPtr = catalogPtr->GetUnitInformation ();
+    gridCrsUnitCode = gridCS->GetUnitCode ();
+
+    // Verify that the unit type of the specification match the unit type
+    // of the grid coordinate system of the grid object.
+    GetUnitInfo(gridCrsUnitCode,&gridUnitType,NULL);
+    if (gridUnitType != m_UnitType)
+    {
+        throw new MgInvalidCoordinateSystemUnitsException(L"MgCoordinateSystemGridSpecification.GetTickEastingIncremen", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Calculate the appropriate units conversion factor.
+    if (m_UnitType == MgCoordinateSystemUnitType::Linear)
+    {
+        unitConversion = unitInfoPtr->GetLinearUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetLinearUnitScale (gridCrsUnitCode);
+    }
+    else
+    {
+        unitConversion = unitInfoPtr->GetAngularUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetAngularUnitScale (gridCrsUnitCode);
+    }
+    return (m_TickEastingIncrement * unitConversion);
+}
+double CCoordinateSystemGridSpecification::GetTickNorthingIncrement(MgCoordinateSystem* gridCS)
+{
+    INT32 gridUnitType;
+    INT32 gridCrsUnitCode;
+    double unitConversion;
+
+    MgCoordinateSystemCatalog* catalogPtr = gridCS->GetCatalog ();
+    MgCoordinateSystemUnitInformation* unitInfoPtr = catalogPtr->GetUnitInformation ();
+    gridCrsUnitCode = gridCS->GetUnitCode ();
+
+    // Verify that the unit type of the specification match the unit type
+    // of the grid coordinate system of the grid object.
+    GetUnitInfo(gridCrsUnitCode,&gridUnitType,NULL);
+    if (gridUnitType != m_UnitType)
+    {
+        throw new MgInvalidCoordinateSystemUnitsException(L"MgCoordinateSystemGridSpecification.GetTickNorthingIncrement", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Calculate the appropriate units conversion factor.
+    if (m_UnitType == MgCoordinateSystemUnitType::Linear)
+    {
+        unitConversion = unitInfoPtr->GetLinearUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetLinearUnitScale (gridCrsUnitCode);
+    }
+    else
+    {
+        unitConversion = unitInfoPtr->GetAngularUnitScale (m_UnitCode) /
+                         unitInfoPtr->GetAngularUnitScale (gridCrsUnitCode);
+    }
+    return (m_TickNorthingIncrement * unitConversion);
+}
 double CCoordinateSystemGridSpecification::GetCurvePrecision (MgCoordinateSystem* gridCS)
 {
     double precisionInCsUnits (1.0);
@@ -289,17 +408,15 @@
     delete this;
 }
 
-//=============================================================================
-// CCoordinateSystemGridBoundary -- The boundary of the grid or graticule.
-//
-// In the case of geographic coordinates, internal longitude ordinates may
-// exceed 180 and latitude ordinates may exceed 90 to support wrap around in
-// a rational fashion.
-//
-// In this initial release, the boundary will be a rectangle, and this will
-// be enforced by the constructors which are supported.  Expansion to support
-// more complex boundaries will be added by providing more constructors.
-//
+///////////////////////////////////////////////////////////////////////////////
+///<summary>
+/// The boundary of the grid or graticule.  In the case of geographic
+/// coordinates, internal longitude ordinates may exceed 180 and latitude
+/// ordinates may exceed 90 to support wrap around in a rational fashion.
+/// In this initial release, the boundary will be a rectangle, and this will
+/// be enforced by the constructors which are supported.  Expansion to support
+/// more complex boundaries will be added by providing more constructors.
+///</summary>
 const INT32 CCoordinateSystemGridBoundary::MaxCurvePoints = 511;
 CCoordinateSystemGridBoundary::CCoordinateSystemGridBoundary () : MgCoordinateSystemGridBoundary (),
                                                                   m_Large                        (false),
@@ -449,17 +566,20 @@
             }
         }
         result = new MgPolygon (exteriorRing,interiorRings);
-    MG_CATCH_AND_THROW(L"MgCoordinateSystemGridBoundary.GetBoundaryExtents")
+    MG_CATCH_AND_THROW(L"MgCoordinateSystemGridBoundary.GetBoundary")
     return result.Detach ();
 }
 MgLineStringCollection* CCoordinateSystemGridBoundary::ClipLineString (MgLineString* lineString) const
 {
     MgGeometryFactory factory;
     Ptr<MgLineStringCollection> collection;
+    Ptr<MgCoordinateIterator> polyItr;
+    Ptr<MgCoordinateIterator> lineItr;
 
     MG_TRY()
-        collection = new MgLineStringCollection ();
-        collection->Add (lineString);
+        polyItr = m_GridBoundary->GetCoordinates ();
+        lineItr = lineString->GetCoordinates ();
+        collection = MgSpatialUtility::ClipStringToPolygon (polyItr,lineItr);
     MG_CATCH_AND_THROW(L"MgCoordinateSystemGridBoundary.ClipLineString")
     return collection.Detach ();
 }
@@ -485,7 +605,7 @@
     MG_TRY ()
         // NOTE:  Boundaries are required to proceed in a counterclockwise
         // direction, but this function will be used to transform both
-        // exterior and interior rings.  SO in this function we cannot count
+        // exterior and interior rings.  So in this function we cannot count
         // on any specific order.  We should be able to rely on the fact that
         // each ring presented to us is indeed closed.
 
@@ -493,31 +613,36 @@
         // create an empty MgCoordinateCollection, and then spend most of our
         // time adding points to this collection.  The primary source of these
         // points will be the MgLineStrings returned by the
-        // MgCoordinateSystemTransform::GridLIne object.  Perhaps that function
+        // MgCoordinateSystemTransform::GridLine object.  Perhaps that function
         // should be modified to return an MgCoordinateCollection?  Probably
         // doesn't make much difference as you can't (at least at thie time)
         // add one coordinate collection to another.  Too Bad!!!
         targetCollection = new MgCoordinateCollection ();
-        
+
         ringItr = linearRing->GetCoordinates ();
         ringItr->MoveNext ();
-        curFromPnt = ringItr->GetCurrent ();
-        copyBufr = transform->Transform (curFromPnt);
+        curToPnt = ringItr->GetCurrent ();
+        copyBufr = transform->Transform (curToPnt);
         targetCollection->Add (copyBufr);
         while (ringItr->MoveNext ())
         {
             // Convert the current segment.
+            curFromPnt = curToPnt;
             curToPnt = ringItr->GetCurrent ();
             convertedSegment = transform->GridLine (curFromPnt,curToPnt,curvePrecision,m_MaxCurvePoints);
-            
+
             // Copy the converted segment to the target coordinate collection.
             lineItr = convertedSegment->GetCoordinates ();
-            
-            // To prevent duplicate points, we always skip adding the initial point
-            // of a converted line string.  We dealt with the initial point of the
-            // first segment above.
+
+            // To prevent duplicate points, we always skip adding the initial
+            // point of a converted line string.  We dealt with the initial
+            // point of the first segment above.  The first point of each
+            // additional line segment will have been processed as the "to"
+            // point of the last segment processed.  Always adding the last
+            // point of each segment means we don't need to worry about an
+            // extra point when we are done.
             lineItr->MoveNext ();
-            
+
             // Copy the remainder of the converted line segment.
             while (lineItr->MoveNext ())
             {

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysGrids.h
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysGrids.h	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysGrids.h	2009-09-08 22:16:31 UTC (rev 4212)
@@ -57,6 +57,8 @@
     double GetNorthingBase (MgCoordinateSystem* gridCS);
     double GetEastingIncrement(MgCoordinateSystem* gridCS);
     double GetNorthingIncrement(MgCoordinateSystem* gridCS);
+    double GetTickEastingIncrement(MgCoordinateSystem* gridCS);
+    double GetTickNorthingIncrement(MgCoordinateSystem* gridCS);
     double GetCurvePrecision(MgCoordinateSystem* gridCS);
 
 protected:
@@ -84,26 +86,148 @@
 class CCoordinateSystemGridBoundary : public MgCoordinateSystemGridBoundary
 {
 public:
+   ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Default value representing the limit at which curve generation will
+    /// always stop so as to reduce the possibility of an infinite loop.  The
+    /// limit is applied after each generation cycle, so the actual number of
+    /// points in a line may be as much as twice this value.  All GridBoundary
+    /// objects will have there m_MaxCurvePoints member variable initialized
+    /// to this value.
     static const INT32 MaxCurvePoints;
-    // Contrary to other envelope objects, the first of these overloads specifically
-    // requires that the southwest argument indeed be southwest of the northeast
-    // argument.  Necessary to support geographic coordinate systems (i.e. +/- 180).
+
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Default Constructor.  Use one of the two SetBoundary overlaods defined
+    /// below in order to create a valid GridBoundary object after using this
+    /// default constructor.
+    CCoordinateSystemGridBoundary (void);
+
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Primary Constructor.  Contrary to other envelope objects, this
+    /// particular overload specifically requires that the southwest argument
+    /// indeed be southwest of the northeast argument.  (The assumption here is
+    /// that the X coordinate is the easting and the Y coordinate is the
+    /// northing.)  This is necessary to support geographic coordinate systems
+    /// (i.e. +/- 180).  To support future development plans, the boundary is
+    /// maintained as an arbitrary MgPolygon object.  In the initial release,
+    /// only rectangular boundaries will be tested and officially supported.
+    /// \param southwest
+    /// Southwest corner of the boundary in which a grid is to be drawn.  This
+    /// point must be southwest of the northeast location.
+    /// \param northeast
+    /// Northeast corner of the boundary in which a grid is to be drawn.
+    /// This point must be northeast of the southwest location.
+    /// \remarks
+    /// Externally, parameters are typically in frame coordinates; internally,
+    /// may be in internal coordinates (such as UTM when used internal to the
+    /// MGRS object).
     CCoordinateSystemGridBoundary (MgCoordinate* southwest,MgCoordinate* northeast);
+
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Secondary Constructor.  This particular overload simply adds a reference
+    /// to provided polygon as the boundary.
     CCoordinateSystemGridBoundary (MgPolygon* boundary);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Destructor, no surprises here.
     ~CCoordinateSystemGridBoundary (void);
 
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Resets the grid boundary to that specified by the two arguments.
+    /// \param southwest
+    /// Southwest corner of the boundary in which a grid is to be drawn.  This
+    /// point must be southwest of the northeast location.
+    /// \param northeast
+    /// Northeast corner of the boundary in which a grid is to be drawn.
+    /// This point must be northeast of the southwest location.     
     void SetBoundaryExtents (MgCoordinate* southwest,MgCoordinate* northeast);
+
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Resets the grid boundary to that specified by the polygon argument.
+    /// \param boundary
+    /// Polygon which defines the new grid boundary.
     void SetBoundaryExtents (MgPolygon* boundary);
+
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the current grid boundary in the form of an MgPolygon object.
+    /// \remarks
+    /// While initially, grid boundaries are simple rectangels, during grid
+    /// generation a boundary may be converted from one coordinate system
+    /// to another.  In so doing, the straight lines of the initial rectangle
+    /// a often replaced with a complex curve representing the boundary in
+    /// the new coordinate system.
     MgPolygon* GetBoundary (void) const;
-    CCoordinateSystemGridBoundary (void);
 
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the extents of the grid boundary.
+    /// \param eastMin
+    /// The minimum easting (i.e. X) ordinate value is returned here.
+    /// \param eastMax
+    /// The maximum easting (i.e. X) ordinate value is returned here.
+    /// \param northMin
+    /// The minimum northing (i.e. Y) ordinate value is returned here.
+    /// \param northMax
+    /// The maximum northing (i.e. Y) ordinate value is returned here.
+    /// \remarks
+    /// Especially useful after the internal boundary is converted to a
+    /// different coordinate system.
     void GetBoundaryExtents (double& eastMin,double& eastMax,double& northMin,double& northMax) const;
+    
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the internal grid boundary, in the form of an MgPolygon object,
+    /// after the boundary hbas been converted using the provided coordinate
+    /// system transform.
+    /// \param transform
+    /// The transformation used to convert the grid boundary.
+    /// \param precision
+    /// A value which indicates, in target coordinate system units, how
+    /// precisely any complex curve approximation generated must match the
+    /// the true complex curve. 
+    /// \remarks
+    /// The transformation must be a coordinate system transformation.  The
+    /// existing grid boundary is assumed to be defined in terms of the
+    /// transformation's source coordinate system, and is converted to the
+    /// transformation's target coordinate system.  In the conversion process,
+    /// a straight line segment is usually replaced with a multi-segment
+    /// approximation.  The maximum distance (in target system units) will
+    /// not exceed the value specified by the precision parameter.  Regardless
+    /// of the precision specification, the curve generation process shuts down
+    /// when the number of segments exceeds the value specified by the
+    /// m_MaxCurvePoints member variable.
     MgPolygon* GetBoundary (MgCoordinateSystemTransform* transform,double precision = 1.0);
+
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the result of clipping the provided line string to the internal
+    /// region (exterior ring) of the grid boundary.
+    /// \param lineString
+    /// A line string in the same coordinate system as the grid boundary.
+    /// \remarks
+    /// The result is a <b>collection</b> of line strings, thus supporting the
+    /// proper clipping of a line string which enters and leaves the grid
+    /// boundary more than once.  The algorithm is <b>slow</b> as it is written
+    /// to handle arbitrary polygons.  The algoirthm is designed to support
+    /// concave polygons, but this has not bee tested.  Interior rings in the
+    /// internal polygon object are ignored at this time.
     MgLineStringCollection* ClipLineString (MgLineString* lineString) const;
 protected:
+
+    ////////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Satifies the pur virtual function of the MgDispose base class from which
+    /// this object is derived.  Essentially causes the destructor to be called.
     void Dispose (void);
 private:
-    // The transform used in the folloing function is more sophisicated than the
+    // The transform used in the following function is more sophisicated than the
     // standard Transform function.
     MgLinearRing* TransformLinearRing (MgLinearRing* linearString,
                                        MgCoordinateSystemTransform* transformation,

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysMgrs.cpp
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysMgrs.cpp	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysMgrs.cpp	2009-09-08 22:16:31 UTC (rev 4212)
@@ -337,7 +337,11 @@
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 void CCoordinateSystemMgrs::SetBoundary(MgCoordinateSystemGridBoundary* pGridBoundary)
 {
+    // Save the boundary.
     m_GridBoundary = SAFE_ADDREF (pGridBoundary);
+    
+    // Create a CCoordinateSystemOneGrid which is appropriate for generating
+    // MGRS graticule requests.
     m_ZoneCollection = FrameBoundaryToZones (m_GridBoundary,m_pCsTarget,m_bUseFrameDatum);
 }
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -349,25 +353,52 @@
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 MgCoordinateSystemGridLineCollection* CCoordinateSystemMgrs::GetGridLines (MgCoordinateSystemGridSpecification* specification)
 {
+    bool specIsGrid;
+
     INT32 index;
+    INT32 unitType;
     INT32 zoneCount;
     Ptr<CCoordinateSystemMgrsZone> mgrsZoneGrid;
+    Ptr<MgCoordinateSystemGridLineCollection> aGridLineCollection;
     Ptr<CCoordinateSystemGridLineCollection> theGridLineCollection;
 
     MG_TRY ()
         theGridLineCollection = new CCoordinateSystemGridLineCollection ();
-        zoneCount = m_ZoneCollection->GetCount ();
-        for (index = 0;index < zoneCount;index += 1)
+        unitType = specification->GetUnitType();
+        specIsGrid = (unitType ==  MgCoordinateSystemUnitType::Linear);
+        if (specIsGrid)
         {
-            mgrsZoneGrid = m_ZoneCollection->GetItem (index);
-            Ptr<MgCoordinateSystemGridLineCollection> aGridLineCollection;
-            aGridLineCollection = mgrsZoneGrid->GetGridLines (specification);
-            theGridLineCollection->AddCollection (aGridLineCollection);
+            // The specification calls for a grid.
+            zoneCount = m_ZoneCollection->GetCount ();
+            for (index = 0;index < zoneCount;index += 1)
+            {
+                mgrsZoneGrid = m_ZoneCollection->GetItem (index);
+                aGridLineCollection = mgrsZoneGrid->GetGridLines (specification);
+                theGridLineCollection->AddCollection (aGridLineCollection);
+            }
         }
+        else
+        {
+            // The specification calls for a graticule.
+            if (m_GraticuleUtm)
+            {
+                aGridLineCollection = m_GraticuleUtm->GetGridLines (specification);
+                theGridLineCollection->AddCollection (aGridLineCollection);
+            }
+            if (m_GraticuleUpsNorth)
+            {
+                aGridLineCollection = m_GraticuleUpsNorth->GetGridLines (specification);
+                theGridLineCollection->AddCollection (aGridLineCollection);
+            }
+            if (m_GraticuleUpsSouth)
+            {
+                aGridLineCollection = m_GraticuleUpsSouth->GetGridLines (specification);
+                theGridLineCollection->AddCollection (aGridLineCollection);
+            }
+        }
     MG_CATCH_AND_THROW(L"MgCoordinateSystemMgrs::GetGridLines")
     return static_cast<MgCoordinateSystemGridLineCollection*>(theGridLineCollection.Detach());
 }
-
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 MgCoordinateSystemGridRegionCollection* CCoordinateSystemMgrs::GetGridRegions (MgCoordinateSystemGridSpecification* specification)
 {
@@ -392,23 +423,50 @@
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 MgCoordinateSystemGridTickCollection* CCoordinateSystemMgrs::GetGridTicks (MgCoordinateSystemGridSpecification* specification)
 {
+    bool specIsGrid;
+
     INT32 index;
+    INT32 unitType;
     INT32 zoneCount;
     Ptr<CCoordinateSystemMgrsZone> mgrsZoneGrid;
+    Ptr<MgCoordinateSystemGridTickCollection> aGridTickCollection;
     Ptr<CCoordinateSystemGridTickCollection> theGridTickCollection;
 
     MG_TRY ()
         theGridTickCollection = new CCoordinateSystemGridTickCollection ();
-        zoneCount = m_ZoneCollection->GetCount ();
-        for (index = 0;index < zoneCount;index += 1)
+        unitType = specification->GetUnitType();
+        specIsGrid = (unitType ==  MgCoordinateSystemUnitType::Linear);
+        if (specIsGrid)
         {
-            mgrsZoneGrid = m_ZoneCollection->GetItem (index);
-            Ptr<MgCoordinateSystemGridTickCollection> aGridTickCollection;
-            aGridTickCollection = mgrsZoneGrid->GetBoundaryTicks (specification);
-            theGridTickCollection->AddCollection (aGridTickCollection);
-            // TODO:  Need to remove from the collection any grid ticks which are
-            // internal to the m_GridBoundary object of this object. 
+            zoneCount = m_ZoneCollection->GetCount ();
+            for (index = 0;index < zoneCount;index += 1)
+            {
+                mgrsZoneGrid = m_ZoneCollection->GetItem (index);
+                aGridTickCollection = mgrsZoneGrid->GetBoundaryTicks (specification);
+                theGridTickCollection->AddCollection (aGridTickCollection);
+            }
         }
+        else
+        {
+            if (m_GraticuleUtm)
+            {
+                aGridTickCollection = m_GraticuleUtm->GetBoundaryTicks (specification);
+                theGridTickCollection->AddCollection (aGridTickCollection);
+            }
+            else if (m_GraticuleUtm)
+            {
+                aGridTickCollection = m_GraticuleUpsNorth->GetBoundaryTicks (specification);
+                theGridTickCollection->AddCollection (aGridTickCollection);
+            }
+            else if (m_GraticuleUtm)
+            {
+                aGridTickCollection = m_GraticuleUpsSouth->GetBoundaryTicks (specification);
+                theGridTickCollection->AddCollection (aGridTickCollection);
+            }
+        }
+        // TODO:  Need to remove from the collection any grid ticks which are
+        // internal to the m_GridBoundary object of this object.  This will be
+        // tricky, as the tick positions will usually be right on the boundary.
     MG_CATCH_AND_THROW(L"MgCoordinateSystemMgrs::GetGridRTicks")
     return static_cast<MgCoordinateSystemGridTickCollection*>(theGridTickCollection.Detach());
 }
@@ -606,9 +664,10 @@
 {
     m_bExceptionsOn = bOn;
 }
-// Returns a collection of CCoordinateSYstemMgrsZone objects.
-// These objects derive from OneGrid, so they have both coordinate systems in them.
-// 
+///////////////////////////////////////////////////////////////////////////////
+// This member returns a collection of CCoordinateSystemMgrsZone objects.
+// These objects derive from CCoordinateSystemOneGrid, so they have both
+// the grid and frame coordinate systems in them.
 CCoordinateSystemMgrsZoneCollection* CCoordinateSystemMgrs::FrameBoundaryToZones (MgCoordinateSystemGridBoundary* frameBoundary,
                                                                                   MgCoordinateSystem* frameCRS,
                                                                                   bool useFrameDatum)
@@ -619,18 +678,18 @@
 
     double cm;                      // central meridian;
     double eastLimit, westLimit;    // limits of a UTM zone
-    double eastMin, eastMax;        // frame boundary extrema
-    double northMin, northMax;      // frame boundary extrema
+    double eastMin, eastMax;        // frame boundary extrema in 'LL84' (or 'LL')
+    double northMin, northMax;      // frame boundary extrema in 'LL84' (or 'LL')
 
     Ptr<MgPolygon> pPolygon;
     Ptr<MgCoordinate> pSouthwest;
     Ptr<MgCoordinate> pNortheast;
-    Ptr<MgCoordinateSystem> llCS;
+    Ptr<MgCoordinateSystem> llCRS;
     Ptr<MgCoordinateSystem> utmCRS;
-    Ptr<MgCoordinateSystemTransform> llTransform;
-    Ptr<MgCoordinateSystemTransform> utmTransform;
-    Ptr<MgCoordinateSystemGridBoundary> utmBoundary;
+    Ptr<MgCoordinateSystemTransform> toLlTransform;               // frame to 'LL' transform
+    Ptr<MgCoordinateSystemTransform> toFrameTransform;            // 'LL' to frame transform
     Ptr<MgCoordinateSystemGridBoundary> llBoundary;
+    Ptr<MgCoordinateSystemGridBoundary> reducedFrameBoundary;
     Ptr<CCoordinateSystemMgrsZone> mgrsZoneGrid;
     Ptr<CCoordinateSystemMgrsZoneCollection> zoneCollection;
     STRING utmCsCode;
@@ -643,9 +702,10 @@
 
         // Convert the polygon portion of the Grid Boundary object to long/lat
         // coordinates and extract the min/max from the resulting polygon.
-        llCS = csFactory->CreateFromCode (L"LL");
-        llTransform = csFactory->GetTransform(frameCRS,llCS);
-        pPolygon = frameBoundary->GetBoundary (llTransform,1.0E-05);
+        llCRS = csFactory->CreateFromCode (useFrameDatum ? L"LL" : L"LL84");
+        toLlTransform = csFactory->GetTransform(frameCRS,llCRS);
+        toFrameTransform = csFactory->GetTransform(llCRS,frameCRS);
+        pPolygon = frameBoundary->GetBoundary (toLlTransform,1.0E-05);
         llBoundary = csFactory->GridBoundary (pPolygon);
         llBoundary->GetBoundaryExtents (eastMin,eastMax,northMin,northMax);
 
@@ -654,109 +714,122 @@
         {
             // There is a portion of the frame boundary in the south polar region.
             zoneNbr = -61;
-            utmCsCode = ZoneNbrToUtmCs (zoneNbr);
-            utmCRS = csFactory->CreateFromCode (utmCsCode);
-            utmTransform = csFactory->GetTransform (llCS,utmCRS);
             pSouthwest->SetX (eastMin);
             pSouthwest->SetY (northMin);
             pNortheast->SetX (eastMax);
             pNortheast->SetY (-80.0);
             llBoundary = csFactory->GridBoundary (pSouthwest,pNortheast);
-            pPolygon = llBoundary->GetBoundary (utmTransform,1.0);
-            utmBoundary = csFactory->GridBoundary (pPolygon);
-            mgrsZoneGrid = new CCoordinateSystemMgrsZone (utmBoundary,zoneNbr,useFrameDatum,frameCRS,m_nLetteringScheme);
+            pPolygon = llBoundary->GetBoundary (toFrameTransform,1.0);
+            reducedFrameBoundary = csFactory->GridBoundary (pPolygon);
+            mgrsZoneGrid = new CCoordinateSystemMgrsZone (reducedFrameBoundary,zoneNbr,useFrameDatum,frameCRS,m_nLetteringScheme);
             zoneCollection->Add (mgrsZoneGrid);
+
+            // Construct the m_GraticuleUpsSouth member, it may be needed.
+            m_GraticuleUpsSouth = new CCoordinateSystemOneGrid (reducedFrameBoundary,llCRS,frameCRS);
         }
         if (northMax > 84.0)
         {
-            // There is a portion of the frame boundary in the south polar region.
+            // There is a portion of the frame boundary in the north polar region.
             zoneNbr = 61;
-            utmCsCode = ZoneNbrToUtmCs (zoneNbr);
-            utmCRS = csFactory->CreateFromCode (utmCsCode);
-            utmTransform = csFactory->GetTransform (llCS,utmCRS);
             pSouthwest->SetX (eastMin);
             pSouthwest->SetY (84.0);
             pNortheast->SetX (eastMax);
             pNortheast->SetY (northMax);
             llBoundary = csFactory->GridBoundary (pSouthwest,pNortheast);
-            pPolygon = llBoundary->GetBoundary (utmTransform,1.0);
-            utmBoundary = csFactory->GridBoundary (pPolygon);
-            mgrsZoneGrid = new CCoordinateSystemMgrsZone (utmBoundary,zoneNbr,useFrameDatum,frameCRS,m_nLetteringScheme);
+            pPolygon = llBoundary->GetBoundary (toFrameTransform,1.0);
+            reducedFrameBoundary = csFactory->GridBoundary (pPolygon);
+            mgrsZoneGrid = new CCoordinateSystemMgrsZone (reducedFrameBoundary,zoneNbr,useFrameDatum,frameCRS,m_nLetteringScheme);
             zoneCollection->Add (mgrsZoneGrid);
+
+            // Construct the m_GraticuleUpsNorth member, it may be needed.
+            m_GraticuleUpsNorth = new CCoordinateSystemOneGrid (reducedFrameBoundary,llCRS,frameCRS);
         }
         if (northMax > -80.0 && northMin < 84.0)
         {
-            // There is a portion of the frame boundary in the non-polar region
-            // covered by normal UTM zones.  These can be either northern zones,
-            // or southern zones; perhaps both.  We'll do the northern zones
-            // first.
+            // A portion of the frame boundary is in the region covered by the
+            // normal (i.e. non-polar) UTM zones.  Determine the particular UTM
+            // zones we need to generate.
+            zoneMin = ((static_cast<INT32>(eastMin) + 180) / 6) + 1;
+            zoneMax = ((static_cast<INT32>(eastMax) + 180) / 6) + 1;
+
             if (northMax > 0.0)
             {
-                // There are some northern zones.  The northMin and northMax
-                // are the same for all of these.  What changes is the central
-                // meridian which means the eastern and western limits change.
-                zoneMin = ((static_cast<INT32>(eastMin) + 180) / 6) + 1;
-                zoneMax = ((static_cast<INT32>(eastMax) + 180) / 6) + 1;
+                // There are some northern zones.
 
-                pSouthwest->SetY ((northMin <=  0.0) ?  0.0 : northMin);
-                pNortheast->SetY ((northMax >= 84.0) ? 84.0 : northMax);
+                // We will need to generate, for each UTM zone, the extents
+                // of that particular UTM zone trimmed to the extents of the
+                // provided frame boundary.  The north/south portions
+                // are the same for each zone, so we do that once here outside
+                // the loop.
+                pSouthwest->SetY ((northMin <  0.0) ?  0.0 : northMin);
+                pNortheast->SetY ((northMax > 84.0) ? 84.0 : northMax);
+
+                // OK, generate a CCoordinateSystemMgrsZone object for each
+                // UTM zone which intersects the frame boundary provided.
+                // Usually only one, but we must be able to handle the
+                // multiple zone case.
                 for (zoneNbr = zoneMin;zoneNbr <= zoneMax;zoneNbr += 1)
                 {
-                    // Here once for each normal UTM zone in the northern
-                    // hemisphere which intersects the provided frame grid
-                    // boundary.
-                    utmCsCode = ZoneNbrToUtmCs (zoneNbr);
-                    utmCRS = csFactory->CreateFromCode (utmCsCode);
-                    utmTransform = csFactory->GetTransform (llCS,utmCRS);
+                    // 1> Compute the 'LL' boundary of this UTM zone.
+                    //    North/South done above, here we need only deal
+                    //    with east/west.
                     cm = static_cast<double>((zoneNbr * 6) - 183);
                     westLimit = cm - 3.0;
+                    eastLimit = cm + 3.0;
+
+                    // 2> Apply the extents of the provided frame boundary.
                     if (westLimit < eastMin) westLimit = eastMin;
-                    eastLimit = cm + 3.0;
                     if (eastLimit > eastMax) eastLimit = eastMax;
+                    
+                    // 3> Create, in terms of LL coordinates, the frame
+                    //    boundary as is appropriate for this particular zone.
                     pSouthwest->SetX (westLimit);
                     pNortheast->SetX (eastLimit);
+
+                    // 4> Convert this reduced frame boundary back to frame
+                    //    coordinates.
+                    // TODO:  We should not use a hard coded curve precision value here.
                     llBoundary = csFactory->GridBoundary (pSouthwest,pNortheast);
-                    pPolygon = llBoundary->GetBoundary (utmTransform,1.0);
-                    utmBoundary = csFactory->GridBoundary (pPolygon);
-                    mgrsZoneGrid = new CCoordinateSystemMgrsZone (utmBoundary,zoneNbr,useFrameDatum,frameCRS,m_nLetteringScheme);
+                    pPolygon = llBoundary->GetBoundary (toFrameTransform,1.0);
+                    reducedFrameBoundary = csFactory->GridBoundary (pPolygon);
+                    mgrsZoneGrid = new CCoordinateSystemMgrsZone (reducedFrameBoundary,zoneNbr,useFrameDatum,frameCRS,m_nLetteringScheme);
                     zoneCollection->Add (mgrsZoneGrid);
-                }
+                 }
             }
             if (northMin < 0.0)
             {
-                // There are some southern zones.  The northMin and northMax
-                // are the same for all of these.  What changes is the central
-                // meridian which means the eastern and western limits change.
-                // There are some northern zones.  The northMin and northMax
-                // are the same for all of these.  What changes is the central
-                // meridian which means the eastern and western limits change.
-                zoneMin = ((static_cast<INT32>(eastMin) + 180) / 6) + 1;
-                zoneMax = ((static_cast<INT32>(eastMax) + 180) / 6) + 1;
-
+                // Pretty much the same as the northern zones processed
+                // above, but without the laborious comments.
                 pSouthwest->SetY ((northMin < -80.0) ? -80.0 : northMin);
                 pNortheast->SetY ((northMax >   0.0) ?   0.0 : northMax);
                 for (zoneNbr = zoneMin;zoneNbr <= zoneMax;zoneNbr += 1)
                 {
-                    // Here once for each normal UTM zone in the southern
-                    // hemisphere which intersects the provided frame grid
-                    // boundary.
-                    utmCsCode = ZoneNbrToUtmCs (-zoneNbr);
-                    utmCRS = csFactory->CreateFromCode (utmCsCode);
-                    utmTransform = csFactory->GetTransform (llCS,utmCRS);
                     cm = static_cast<double>((zoneNbr * 6) - 183);
                     westLimit = cm - 3.0;
+                    eastLimit = cm + 3.0;
                     if (westLimit < eastMin) westLimit = eastMin;
-                    eastLimit = cm + 3.0;
                     if (eastLimit > eastMax) eastLimit = eastMax;
                     pSouthwest->SetX (westLimit);
                     pNortheast->SetX (eastLimit);
+
                     llBoundary = csFactory->GridBoundary (pSouthwest,pNortheast);
-                    pPolygon = llBoundary->GetBoundary (utmTransform,1.0);
-                    utmBoundary = csFactory->GridBoundary (pPolygon);
-                    mgrsZoneGrid = new CCoordinateSystemMgrsZone (utmBoundary,zoneNbr,useFrameDatum,frameCRS,m_nLetteringScheme);
+                    pPolygon = llBoundary->GetBoundary (toFrameTransform,1.0);
+                    reducedFrameBoundary = csFactory->GridBoundary (pPolygon);
+                    mgrsZoneGrid = new CCoordinateSystemMgrsZone (reducedFrameBoundary,zoneNbr,useFrameDatum,frameCRS,m_nLetteringScheme);
                     zoneCollection->Add (mgrsZoneGrid);
                 }
             }
+
+            // Need a CCoordinateSystemOneGrid object which can produce the 6 x 8 graticule
+            // for the entire regon.
+            pSouthwest->SetX (eastMin);
+            pNortheast->SetX (eastMax);
+            pSouthwest->SetY ((northMin < -80.0) ? -80.0 : northMin);
+            pNortheast->SetY ((northMax >  84.0) ?  84.0 : northMax);
+            llBoundary = csFactory->GridBoundary (pSouthwest,pNortheast);
+            pPolygon = llBoundary->GetBoundary (toFrameTransform,1.0);
+            reducedFrameBoundary = csFactory->GridBoundary (pPolygon);
+            m_GraticuleUpsNorth = new CCoordinateSystemOneGrid (reducedFrameBoundary,llCRS,frameCRS);
         }
     MG_CATCH_AND_THROW(L"MgCoordinateSystemOneGrid::GetGridLines")
     return zoneCollection.Detach ();

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysMgrs.h
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysMgrs.h	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysMgrs.h	2009-09-08 22:16:31 UTC (rev 4212)
@@ -122,6 +122,16 @@
     Ptr<MgCoordinateSystemGridBoundary> m_GridBoundary;
     Ptr<CCoordinateSystemMgrsZoneCollection> m_ZoneCollection;
 
+    // The following CCoordinateSystemOneGrid objects are used to generate
+    // graticules, and thus have a grid CRS which is geographic as opposed
+    // to projective.  Thus, these are somewhat special objects.  These
+    // pointers may be null if they are not needed which is usually the
+    // case for the polar regions.  The "need" is based on the frame
+    // boundary.
+    Ptr<CCoordinateSystemOneGrid> m_GraticuleUtm;
+    Ptr<CCoordinateSystemOneGrid> m_GraticuleUpsNorth;
+    Ptr<CCoordinateSystemOneGrid> m_GraticuleUpsSouth;
+
 private:
     CCoordinateSystemMgrs();
     CCoordinateSystemMgrs(const CCoordinateSystemMgrs&);

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysMgrsZone.cpp
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysMgrsZone.cpp	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysMgrsZone.cpp	2009-09-08 22:16:31 UTC (rev 4212)
@@ -45,17 +45,24 @@
     STRING utmZoneCode = CCoordinateSystemMgrs::ZoneNbrToUtmCs (m_UtmZone);
     utmZoneCRS = csFactory.CreateFromCode (utmZoneCode);
     SetUp (frameBoundary,utmZoneCRS,frameCRS);
+    
+    SetUserID (m_UtmZone);
 }
 CCoordinateSystemMgrsZone::~CCoordinateSystemMgrsZone (void)
 {
 }
-
 CCoordinateSystemGridRegionCollection* CCoordinateSystemMgrsZone::GetGridRegions (MgCoordinateSystemGridSpecification* specification)
 {
     BuildRegionCollection (specification);
     return SAFE_ADDREF(m_RegionCollection.p);
 }
-
+INT32 CCoordinateSystemMgrsZone::GetUtmZoneNbr (void)
+{
+    // m_UtmZoneNbr is positive for northern hemisphere, negative for the
+    // southern hemisphere.  Polar regions are assigned the value of 61.  Zero
+    // is the uninitialized/unknown/error value.
+    return m_UtmZone;
+}
 void CCoordinateSystemMgrsZone::BuildRegionCollection (MgCoordinateSystemGridSpecification* specification)
 {
     double curvePrecision;
@@ -114,7 +121,7 @@
             lngMax = centralMeridian + 3.0;
 
             // Need to account for the fact that the frame boundary may cross
-            // a MGRS Gris Zone Designation boundary (i.e. the 8 degree chunks
+            // an MGRS Grid Zone Designation boundary (i.e. the 8 degree chunks
             // of latitude).  Thus, there may be more than just one major region.
             delta = fabs (fmod (latMin,8.0));
             firstLat = static_cast<INT32>(latMin - ((latMin >= 0.0) ? delta : (8.0 - delta)));

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysMgrsZone.h
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysMgrsZone.h	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysMgrsZone.h	2009-09-08 22:16:31 UTC (rev 4212)
@@ -40,10 +40,12 @@
 // * If useFrameDatum is true, the Grid coordinate system will be adjusted
 //   to use the datum of the provided frame coordinate system.  Otherwise,
 //   the Grid datum is hardcoded to WGS84.
+// * Is used only to generate projected grids.  Graticules are handled
+//   separately.  Thus, the grid coordinate system is always a projected
+//   coordinate system.
 class CCoordinateSystemMgrsZone : public CCoordinateSystemOneGrid
 {
 public:
-    //
     CCoordinateSystemMgrsZone (MgCoordinateSystemGridBoundary* frameBoundary,
                                INT32 utmZoneNbr,
                                bool useFrameDatum,
@@ -52,12 +54,18 @@
     ~CCoordinateSystemMgrsZone (void);
 
     CCoordinateSystemGridRegionCollection* GetGridRegions (MgCoordinateSystemGridSpecification* specification);
+    INT32 GetUtmZoneNbr (void);
+ 
 protected:
     void BuildRegionCollection (MgCoordinateSystemGridSpecification* specification);
 private:
     void BuildMajorRegions (double boundaryPrecision);
     void BuildMinorRegions (double boundaryPrecision);
+    ///////////////////////////////////////////////////////////////////////////
     // Data members
+    // m_UtmZoneNbr is positive for northern hemisphere, negative for the
+    // southern hemisphere.  Polar regions are assigned the value of 61.
+    // Zero is the uninitialized/unknown/error value.
     INT32 m_UtmZone;
     INT8 m_LetteringScheme;
     Ptr<CCoordinateSystemGridRegionCollection> m_RegionCollection;

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysOneGrid.cpp
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysOneGrid.cpp	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysOneGrid.cpp	2009-09-08 22:16:31 UTC (rev 4212)
@@ -33,7 +33,7 @@
 CCoordinateSystemOneGrid::CCoordinateSystemOneGrid () : MgGuardDisposable   (),
                                                         m_UserID            (0),
                                                         m_MaxCurvePoints    (MaxCurvePoints),
-                                                        m_RegionLabel       (),
+                                                        m_Label             (),
                                                         m_GridCRS           (),
                                                         m_FrameCRS          (),
                                                         m_ToFrameXform      (),
@@ -51,7 +51,7 @@
                                                     MgGuardDisposable   (),
                                                     m_UserID            (0),
                                                     m_MaxCurvePoints    (MaxCurvePoints),
-                                                    m_RegionLabel       (),
+                                                    m_Label             (),
                                                     m_GridCRS           (),
                                                     m_FrameCRS          (),
                                                     m_ToFrameXform      (),
@@ -80,14 +80,31 @@
     m_FrameCRS = SAFE_ADDREF (frameCRS);
     m_ToFrameXform = csFactory.GetTransform (m_GridCRS,m_FrameCRS);
     m_ToGridXform = csFactory.GetTransform (m_FrameCRS,m_GridCRS);
-}                                      
+}
+bool CCoordinateSystemOneGrid::IsGeographic (void)
+{
+    bool isGeographic;
+    INT32 projectionCode;
+
+    projectionCode = m_GridCRS->GetProjectionCode ();
+    isGeographic = (projectionCode == MgCoordinateSystemProjectionCode::LL);    
+    return isGeographic;
+}
+INT32 CCoordinateSystemOneGrid::GetUserID (void)
+{
+    return m_UserID;
+}
 STRING CCoordinateSystemOneGrid::GetLabel (void)
 {
-    return m_RegionLabel;
+    return m_Label;
 }
+void CCoordinateSystemOneGrid::SetUserID (INT32 userID)
+{
+    m_UserID = userID;
+}
 void CCoordinateSystemOneGrid::SetLabel (CREFSTRING label)
 {
-    m_RegionLabel = label;
+    m_Label = label;
 }
 MgCoordinate* CCoordinateSystemOneGrid::ConvertToGrid (MgCoordinate* frameCoordinate)
 {
@@ -99,6 +116,7 @@
 }
 MgCoordinateSystemGridLineCollection* CCoordinateSystemOneGrid::GetGridLines (MgCoordinateSystemGridSpecification* specs)
 {
+    INT32 lineStringCount;
     double value;
     double delta;
     double increment;
@@ -116,6 +134,7 @@
     Ptr<CCoordinateSystemGridLineCollection> gridLineCollection = new CCoordinateSystemGridLineCollection ();
 
     MG_TRY()
+        CCoordinateSystemGridSpecification* mySpecPtr = dynamic_cast<CCoordinateSystemGridSpecification*>(specs);
         coordinate = new MgCoordinateXY ();
         fromPnt    = new MgCoordinateXY ();
         toPnt      = new MgCoordinateXY ();
@@ -124,7 +143,7 @@
         // value has been changed, reproduce the m_GridBoundary
         // member from the m_FrameBoundary member.  At this point, we
         // need the curve precision value in Grid system units.
-        precision = specs->GetCurvePrecision ();
+        precision = mySpecPtr->GetCurvePrecision ();
         GenerateGridBoundary (precision);
 
         // Get the extents of the frame boundary, and then convert them to
@@ -135,36 +154,42 @@
         // Adjust so the the grid limits are exact values with regard to the
         // specified increments.  Do this in an expansive way so the the grid
         // limits always get larger, never smaller.
-        increment = specs->GetEastingIncrement();
+        //
+        // Note that we need to have the increments and base values in terms
+        // of the grid coordinate system, regardless of the units used to
+        // specify them.
+        increment = mySpecPtr->GetEastingIncrement(m_GridCRS);
         delta = fabs(fmod (eastMin,increment));
         eastMin -= (eastMin >= 0.0) ? delta : (increment - delta);
         delta = fabs(fmod (eastMax,increment));
         eastMax += (eastMax >= 0.0) ? (increment - delta) : delta;
  
-        increment = specs->GetNorthingIncrement();
+        increment = mySpecPtr->GetNorthingIncrement(m_GridCRS);
         delta = fabs(fmod (northMin,increment));
         northMin -= (northMin >= 0.0) ? delta : (increment - delta);
         delta = fabs(fmod (northMax,increment));
         northMax += (northMax >= 0.0) ? (increment - delta) : delta;
 
         // Adjust for the base.  Again, we always enlarge, never shrink.
-        if (specs->GetEastingBase () > 0.0)
+        if (mySpecPtr->GetEastingBase () > 0.0)
         {
-            increment = specs->GetEastingIncrement ();
-            delta = fmod (specs->GetEastingBase(),increment);
+            increment = mySpecPtr->GetEastingIncrement (m_GridCRS);
+            delta = fmod (mySpecPtr->GetEastingBase(m_GridCRS),increment);
             eastMin  += delta - increment;
             eastMax  += delta + increment;
         }
-        if (specs->GetNorthingBase () > 0.0)
+        if (mySpecPtr->GetNorthingBase () > 0.0)
         {
-            increment = specs->GetNorthingIncrement ();
-            delta = fmod (specs->GetNorthingBase(),increment);
+            increment = mySpecPtr->GetNorthingIncrement (m_GridCRS);
+            delta = fmod (mySpecPtr->GetNorthingBase(m_GridCRS),increment);
             northMin  += delta - increment;
             northMax  += delta + increment;
         }
 
         // Given the specification, we double loop, generating lines.
-        increment = specs->GetNorthingIncrement ();
+        // Forst loop, generatinf west/east lines starting at the southern edge
+        // proceeding to the north.
+        increment = mySpecPtr->GetNorthingIncrement (m_GridCRS);
         for (value = northMin;value <= northMax;value += increment)
         {
             fromPnt->SetX (eastMin);
@@ -177,16 +202,20 @@
             // actually leave, and then reenter, the grid boundary, so the
             // result can be a multi-line sting.
             lineStringCollection = m_FrameBoundary->ClipLineString (lineString);
-
-            // Construct the Grid Line object and add it to the grid
-            // line collection object.
-            gridLine = new CCoordinateSystemGridLine (MgCoordinateSystemGridOrientation::NorthSouth,value);
-            gridLine->SetSegmentCollection (lineStringCollection);
-            gridLineCollection->Add (gridLine);
+            lineStringCount = lineStringCollection->GetCount ();
+            if (lineStringCount > 0)
+            {
+                // Construct the Grid Line object and add it to the grid
+                // line collection object.
+                gridLine = new CCoordinateSystemGridLine (MgCoordinateSystemGridOrientation::NorthSouth,value);
+                gridLine->SetSegmentCollection (lineStringCollection);
+                gridLineCollection->Add (gridLine);
+            }
         }
 
-        // Given the specification, we double loop, generating lines.
-        increment = specs->GetEastingIncrement ();
+        // Second loop, the south/north lines, starting at the western edge
+        // proceeding to the east.
+        increment = mySpecPtr->GetEastingIncrement (m_GridCRS);
         for (value = eastMin;value <= eastMax;value += increment)
         {
             fromPnt->SetX (value);
@@ -197,14 +226,17 @@
 
             // Clip the line to the frame boundary.  The grid line may
             // actually leave, and then re-enter, the grid boundary, so the
-            // result can be a multi-line sting.
+            // result can be a multi-line string.
             lineStringCollection = m_FrameBoundary->ClipLineString (lineString);
-  
-            // Construct the Grid Line object and add it to the grid
-            // line collection object.
-            gridLine = new CCoordinateSystemGridLine (MgCoordinateSystemGridOrientation::EastWest,value);
-            gridLine->SetSegmentCollection (lineStringCollection);
-            gridLineCollection->Add (gridLine);
+            lineStringCount = lineStringCollection->GetCount ();
+            if (lineStringCount > 0)
+            {
+                // Construct the Grid Line object and add it to the grid
+                // line collection object.
+                gridLine = new CCoordinateSystemGridLine (MgCoordinateSystemGridOrientation::EastWest,value);
+                gridLine->SetSegmentCollection (lineStringCollection);
+                gridLineCollection->Add (gridLine);
+            }
         }
     MG_CATCH_AND_THROW(L"MgCoordinateSystemOneGrid::GetGridLines")
 
@@ -235,38 +267,39 @@
 
     MG_TRY ()
     
+        CCoordinateSystemGridSpecification* mySpecPtr = dynamic_cast<CCoordinateSystemGridSpecification*>(specs);
         tickCollection = new CCoordinateSystemGridTickCollection ();
 
         // Get the grid extents.
-        curvePrecision = specs->GetCurvePrecision();
+        curvePrecision = mySpecPtr->GetCurvePrecision();
         GetGridExtents (eastMin,eastMax,northMin,northMax,curvePrecision);
 
         // Expand the extents to become the lowest and highest tick values
         // for each of the ordinates.
-        increment = specs->GetTickEastingIncrement();
+        increment = mySpecPtr->GetTickEastingIncrement(m_GridCRS);
         delta = fabs(fmod (eastMin,increment));
         eastMin -= (eastMin >= 0.0) ? delta : (increment - delta);
         delta = fabs(fmod (eastMax,increment));
         eastMax += (eastMax >= 0.0) ? (increment - delta) : delta;
 
-        increment = specs->GetTickNorthingIncrement();
+        increment = mySpecPtr->GetTickNorthingIncrement(m_GridCRS);
         delta = fabs(fmod (northMin,increment));
         northMin -= (northMin >= 0.0) ? delta : (increment - delta);
         delta = fabs(fmod (northMax,increment));
         northMax += (northMax >= 0.0) ? (increment - delta) : delta;
 
         // Adjust for the base.  Again, we always enlarge, never shrink.
-        if (specs->GetEastingBase () > 0.0)
+        if (mySpecPtr->GetEastingBase () > 0.0)
         {
-            increment = specs->GetEastingIncrement ();
-            delta = fmod (specs->GetEastingBase(),increment);
+            increment = mySpecPtr->GetEastingIncrement (m_GridCRS);
+            delta = fmod (mySpecPtr->GetEastingBase(m_GridCRS),increment);
             eastMin  += delta - increment;
             eastMax  += delta + increment;
         }
-        if (specs->GetNorthingBase () > 0.0)
+        if (mySpecPtr->GetNorthingBase () > 0.0)
         {
-            increment = specs->GetNorthingIncrement ();
-            delta = fmod (specs->GetNorthingBase(),increment);
+            increment = mySpecPtr->GetNorthingIncrement (m_GridCRS);
+            delta = fmod (mySpecPtr->GetNorthingBase(m_GridCRS),increment);
             northMin  += delta - increment;
             northMax  += delta + increment;
         }
@@ -287,7 +320,7 @@
 
             // Do the easting ticks; that is tickmarks whose value is an
             // easting ordinate value.
-            increment = specs->GetTickEastingIncrement ();
+            increment = mySpecPtr->GetTickEastingIncrement (m_GridCRS);
             orientation = MgCoordinateSystemGridOrientation::EastWest;
             for (ordinateValue = eastMin;ordinateValue <= eastMax;ordinateValue += increment)
             {
@@ -313,9 +346,9 @@
                 }
             }
 
-            // Do the easting ticks; that is tickmarks whose value is an
-            // easting ordinate value.
-            increment = specs->GetTickNorthingIncrement ();
+            // Do the northing ticks; that is tickmarks whose value is an
+            // northing ordinate value.
+            increment = mySpecPtr->GetTickNorthingIncrement (m_GridCRS);
             orientation = MgCoordinateSystemGridOrientation::NorthSouth;
             for (ordinateValue = northMin;ordinateValue <= northMax;ordinateValue += increment)
             {

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysOneGrid.h
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysOneGrid.h	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysOneGrid.h	2009-09-08 22:16:31 UTC (rev 4212)
@@ -43,23 +43,28 @@
 public:
     static const INT32 MaxCurvePoints;
     CCoordinateSystemOneGrid (void);
-	CCoordinateSystemOneGrid (MgCoordinateSystemGridBoundary* frameBoundary,
-	                          MgCoordinateSystem* gridCRS,
-	                          MgCoordinateSystem* frameCRS);
-	~CCoordinateSystemOneGrid (void);
+    CCoordinateSystemOneGrid (MgCoordinateSystemGridBoundary* frameBoundary,
+                              MgCoordinateSystem* gridCRS,
+                              MgCoordinateSystem* frameCRS);
+    ~CCoordinateSystemOneGrid (void);
 
     void SetUp (MgCoordinateSystemGridBoundary* frameBoundary,
                 MgCoordinateSystem* gridCRS,
                 MgCoordinateSystem* frameCRS);
 
+    // Returns true if the grid coordinate system is geographic; use this to
+    // determine if this is a graticule (as opposed to a grid).
+    bool IsGeographic (void);
+    INT32 GetUserID (void);
     STRING GetLabel (void);
+    void SetUserID (INT32 userID);
+    void SetLabel (CREFSTRING label);
+
     MgCoordinate* ConvertToGrid (MgCoordinate* frameCoordinate);
     MgCoordinate* ConvertToFrame (MgCoordinate* gridCoordinate);
     MgCoordinateSystemGridLineCollection* GetGridLines (MgCoordinateSystemGridSpecification* specs);
     CCoordinateSystemGridTickCollection* GetBoundaryTicks (MgCoordinateSystemGridSpecification* specs);
 
-    void SetLabel (CREFSTRING label);
-
 protected:
     MgCoordinateSystem* GetFrameCRS (void);
     MgCoordinateSystem* GetGridCRS (void);
@@ -68,9 +73,9 @@
     void GetGridExtents (double& eastMin,double& eastMax,double& northMin,double& northMax,double precision = 0.25);
     void Dispose (void);
 
-    INT32 m_UserID;                                        // For user convenience (i.e. UTM zone)
+    INT32 m_UserID;                                      // For user convenience (i.e. UTM zone)
     INT32 m_MaxCurvePoints;
-    STRING m_RegionLabel;                                // For user conveinence (i.e. MGRS)
+    STRING m_Label;                                      // For user conveinence (i.e. MGRS)
     Ptr<MgCoordinateSystem> m_GridCRS;                   // The grid coordinate system
     Ptr<MgCoordinateSystem> m_FrameCRS;                  // The frame coordinate system
     Ptr<MgCoordinateSystemTransform> m_ToFrameXform;     // Converts grid coordinates to frame coordinates

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysTransform.cpp
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysTransform.cpp	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysTransform.cpp	2009-09-08 22:16:31 UTC (rev 4212)
@@ -1266,8 +1266,8 @@
             deltaY = gridTo->GetY () - gridFrom->GetY ();
             // We do not try to place northing ticks on a line which more horizontal than it
             // is vertical; and vice versa.
-            if (deltaX > deltaY && orientation == MgCoordinateSystemGridOrientation::EastWest ||
-                deltaY > deltaX && orientation == MgCoordinateSystemGridOrientation::NorthSouth)
+            if ((deltaX > deltaY) && (orientation == MgCoordinateSystemGridOrientation::EastWest) ||
+                (deltaY > deltaX) && (orientation == MgCoordinateSystemGridOrientation::NorthSouth))
             {
                 // Use some simple geomtery to calculate the approximate position of the
                 // the point on the provided line segment at which the indicated ordinate

Modified: trunk/MgDev/Common/CoordinateSystem/CoordSysTransform.h
===================================================================
--- trunk/MgDev/Common/CoordinateSystem/CoordSysTransform.h	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/CoordinateSystem/CoordSysTransform.h	2009-09-08 22:16:31 UTC (rev 4212)
@@ -52,7 +52,6 @@
     virtual INT32 GetLastTransformStatus();
     virtual void ResetLastTransformStatus();
 
-
 INTERNAL_API:
     ///////////////////////////////////////////////////////////////////////////
     /// \brief

Modified: trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemFactory.cpp
===================================================================
--- trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemFactory.cpp	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemFactory.cpp	2009-09-08 22:16:31 UTC (rev 4212)
@@ -571,9 +571,9 @@
     return gridSpecification;
 }
 MgCoordinateSystemGridSpecification* MgCoordinateSystemFactory::GridSpecification (double increment,
-                                                                INT32 subdivisions,
-                                                                INT32 unitCode,
-                                                                double curvePrecision)
+                                                                                   double tickIncrement,
+                                                                                   INT32 unitCode,
+                                                                                   double curvePrecision)
 {
     Ptr<MgCoordinateSystemGridSpecification> gridSpecification;
 
@@ -585,7 +585,7 @@
             // all the parameters added and throw an exception if an error.
             gridSpecification->SetGridBase (0.0,0.0);
             gridSpecification->SetGridIncrement (increment,increment);
-            gridSpecification->SetGridIncrement (subdivisions,subdivisions);
+            gridSpecification->SetGridIncrement (tickIncrement,tickIncrement);
             gridSpecification->SetUnits (unitCode,MgCoordinateSystemUnitType::Linear);
             gridSpecification->SetCurvePrecision (curvePrecision);
         }

Modified: trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemFactory.h
===================================================================
--- trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemFactory.h	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemFactory.h	2009-09-08 22:16:31 UTC (rev 4212)
@@ -151,42 +151,390 @@
     virtual bool IsValid(CREFSTRING wkt);
 
     // Grids and Graticules -- General
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Constructs a grid boundary object.  Externally, grid objects are in
+    /// viewport coordinates and define the extents of the region within
+    /// which a grid is to be drawn.  Such objects are often simple
+    /// rectangles, but his is not a requirement.
+    /// </summary>
+    /// <param name="southwest">
+    /// The coordinates of the the southwest corner of a rectangular region
+    /// which represents the grid region.  This point <b>MUST</b> indeed be
+    /// sothwest of the coordinate provided by the <c>northeast</c> parameter.
+    /// </param>
+    /// <param name="northeast">
+    /// The coordinates of the the northeast corner of a rectangular region
+    /// which represents the grid region.  This point <b>MUST</b> indeed be
+    /// northeast of the coordinate provided by the <c>southwest</c> parameter.
+    /// </param>
+    /// <returns>
+    /// Returns the grid boundary in the ofrm used by the grid/graticule
+    /// sub-system.
+    /// </returns>
+    /// <exception cref="MgOutOfMemoryException">
+    /// Thrown in the event of heap memory allocation failure.
+    /// </exception>
+    /// <remarks>
+    /// Internally, the grid boundary is maintained as an MgPolygon object
+    /// with no interior rings.  Otfen this is in the form of a rectangle,
+    /// but his should not be relied on.
+    /// </remarks>
     virtual MgCoordinateSystemGridBoundary* GridBoundary(MgCoordinate* southwest,
                                                          MgCoordinate* northeast);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Constructs a grid boundary object.  Externally, grid objects are in
+    /// viewport coordinates and define the extents of the region within
+    /// which a grid is to be drawn.  Such objects are often simple
+    /// rectangles, but his is not a requirement.
+    /// </summary>
+    /// <param name="boundary">
+    /// The grid boundary in the form of a MgPolygon with no interior rings.
+    /// </param>
+    /// <returns>
+    /// Returns the boundary in the form used by the grid/graticule sub-system.
+    /// </returns>
+    /// <exception cref="MgOutOfMemoryException">
+    /// Thrown in the event of heap memory allocation failure.
+    /// </exception>
+    /// <remarks>
+    /// </remarks>
     virtual MgCoordinateSystemGridBoundary* GridBoundary(MgPolygon* boundary);
 
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Constructs a grid specification object with all specifications set to
+    /// <b>invalid</b> values.
+    /// </summary>
+    /// <returns>
+    /// An object which carries all of the several parameter which determine
+    /// nature of a grid or graticule and any sub-feature tereof.
+    /// </returns>
+    /// <exception cref="std::bad_alloc">
+    /// Thrown in the event of a heap memory allocation failure.
+    /// </exception>
     virtual MgCoordinateSystemGridSpecification* GridSpecification (void);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Constructs a grid specification object with all specifications set to
+    /// the values indicated by the supplied parameters.
+    /// </summary>
+    /// <param name="increment">
+    /// The distance between grid lines of a grid or graticule.  This value is
+    /// used for both the easting and northing grid lines; and the value must
+    /// be in the units specified by the <c>unitCode</c> parameter.
+    /// </param>
+    /// <param name="tickIncrement">
+    /// The distance between tick marks of a grid or graticule.  This value is
+    /// used for both the easting and northing tick marks; and the value must
+    /// be in the units specified by the <c>unitCode</c> parameter.
+    /// </param>
+    /// <param name="unitCode">
+    /// One of the values defined by the MgCoordinateSystemUnitCode object
+    /// which indicates the units in which the <c>increment</c>,
+    /// <c>tickIncrement</c>, and <c>curvePrecision</c> parameters are
+    /// specified.
+    /// </param>
+    /// <param name="curvePrecision">
+    /// In the units indicated by the <c>unitCode</c> parameter, the
+    /// <b>desired</b> maximum distance between the true complex curve and
+    /// the multi-segment approximation of the complex curve of any grid or
+    /// graticule line generated using this specification.
+    /// </param>
+    /// <returns>
+    /// A fully initialized grid specification object.
+    /// </returns>
+    /// <exception cref="std::bad_alloc">
+    /// Thrown in the event of a heap memory allocation failure.
+    /// </exception>
+    /// <remarks>
+    /// This particular overload is designed for the most common situations.
+    /// It presumes the units used are of thelinear type, and thus this
+    /// particular overload cannot be used to generate a specification
+    /// object for use in graticule generation.
+    /// </remarks>
     virtual MgCoordinateSystemGridSpecification* GridSpecification (double increment,
-                                                                    INT32 subdivisions,
+                                                                    double tickIncrement,
                                                                     INT32 unitCode,
                                                                     double curvePrecision);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Constructs a grid specification object with all specifications set to
+    /// the values indicated by the supplied parameters.
+    /// </summary>
+    /// <param name="gridType">
+    /// A value defined by the MgCoordinateSystemGridSpecializationType object
+    /// which indicates the Type of specialized grid desired.
+    /// </param>
+    /// <param name="gridLevel">
+    /// A value which indicates the density of the grid desired.  The exact
+    /// value of this parameter is dependent upon the value of the
+    /// <c>gridType</c> argument.  See Remarks below.
+    /// </param>
+    /// <returns>
+    /// Returns a fully initialized grid specification structure.
+    /// </returns>
+    /// <exception cref="std::bad_alloc">
+    /// Thrown in the event of a heap memory allocation failure.
+    /// </exception>
+    /// <remarks>
+    /// The value of the <c>gridLevel</c> parameter is depenent upon the
+    /// <c>gridType</c> argument.  For each type of grid, there exists
+    /// a different set legal values for the <c>gridLevel</c> parameter.
+    /// For example, the most common usgae would have the <c>gridType</c>
+    /// parameter set to MgCoordinateSystemGridSpecializationType::MGRS
+    /// and therefore the value of the <c>gridLevel</c> argument would
+    /// need to be a value defined by the MgCoordinateSystemMgrsGridLevel
+    /// object.
+    /// </remarks>
     virtual MgCoordinateSystemGridSpecification* GridSpecification (INT32 gridType,
                                                                     INT32 gridLevel);
                                                                    
     // Grids and Graticules -- Generic
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Manufactures generic grid object.  A generic grid is one which simply
+    /// draws isolines of one coordinate system (the Grid coordinate system)
+    /// into the drawing space of another (the frame system).
+    /// </summary>
+    /// <param name="sGridCs">
+    /// The coordinate system code name of the grid coordinate system.
+    /// </param>
+    /// <param name="sFrameCs">
+    /// The coordinate system code name of the frame coordinate system.
+    /// </param>
+    /// <param name="bSetExceptionsOn">
+    /// <c>true</c> indicates that exceptions are to be thrown on all
+    /// exceptional conditions.
+    /// </param>
+    /// <returns>
+    /// Returns a disposable pointer to the abstract interface class from which the
+    /// generic grid object (and all other grid objects) derive.
+    /// object derive.
+    /// </returns>
+    /// <exception cref="MgOutOfMemoryException">
+    /// Thrown on heap memory allocation failure.
+    /// </exception>
+    /// <remarks>
+    /// Refer to <see cref="MgCoordinateSystemFactory::CreateFromCode"> for
+    /// additional exception information.
+    /// </remarks>
     virtual MgCoordinateSystemGridBase* GenericGrid (CREFSTRING sGridCs,
                                                      CREFSTRING sFrameCs,
                                                      bool bSetExceptionsOn);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Manufactures generic grid object.  A generic grid is one which simply
+    /// draws isolines of one coordinate system (the Grid coordinate system)
+    /// into the drawing space of another (the frame system).
+    /// </summary>
+    /// <param name="pGridCs">
+    /// The grid coordinate system.
+    /// </param>
+    /// <param name="pFrameCs">
+    /// The frame coordinate system.
+    /// </param>
+    /// <param name="bSetExceptionsOn">
+    /// <c>true</c> indicates that exceptions are to be thrown on all
+    /// exceptional conditions.
+    /// </param>
+    /// <returns>
+    /// Returns a disposable pointer to the abstract interface class from which the
+    /// generic grid object (and all other grid objects) derive.
+    /// object derive.
+    /// </returns>
+    /// <exception cref="MgOutOfMemoryException">
+    /// Thrown on heap memory allocation failure.
+    /// </exception>
+    /// <remarks>
+    /// Refer to <see cref="MgCoordinateSystemFactory::CreateFromCode"> for
+    /// additional exception information.
+    /// </remarks>
     virtual MgCoordinateSystemGridBase* GenericGrid (MgCoordinateSystem* pGridCs,
                                                      MgCoordinateSystem* pFrameCs,
                                                      bool bSetExceptionsOn);
 
     // Grids and Graticules -- MGRS
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Manufactures an MGRS grid object.  The returned object is suitable only
+    /// for use in simple coordinate <-> MGRS string calculations.
+    /// </summary>
+    /// <param name="dEquatorialRadius">
+    /// Equatorial radius of the ellipsod upon which conversions to and from
+    /// MGRS strings are to be based.
+    /// </param>
+    /// <param name="dEccentricy">
+    /// Eccentricity of the ellipsod upon which conversions to and from
+    /// MGRS strings are to be based.
+    /// </param>
+    /// <param name="nLetteringScheme">
+    /// A value as defined in the <c>MgCoordinateSystemMgrsLetteringScheme</c>
+    /// object which specifies the lettering scheme to be used on MGRS
+    /// string conversions.
+    /// </param>
+    /// <param name="bSetExceptionsOn">
+    /// <c>true</c> indicates that exceptions are to be thrown on coordinate
+    /// conversions which fail for any reason.
+    /// </param>
+    /// </param>
+    /// <returns>
+    /// Returns a disposable pointer to an <c>MgCoordinateSystemMgrs</c>
+    /// object which is suitable <b>only</b> for MGRS string conversions.
+    /// </returns>
+    /// <exception cref="MgOutOfMemoryException">
+    /// Thrown on heap memory allocation failure.
+    /// </exception>
     virtual MgCoordinateSystemMgrs* GetMgrs(double dEquatorialRadius,double dEccentricity,
                                                                      INT8 nLetteringScheme,
                                                                      bool bSetExceptionsOn);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Manufactures an MGRS grid object.  The returned object is suitable only
+    /// for use in simple coordinate <-> MGRS string calculations.
+    /// </summary>
+    /// <param name="sEllispoidCode">
+    /// Dictionary code name of the ellipsoid upon which conversions to and from
+    /// MGRS strings are to be based.
+    /// </param>
+    /// <param name="nLetteringScheme">
+    /// A value as defined in the <c>MgCoordinateSystemMgrsLetteringScheme</c>
+    /// object which specifies the lettering scheme to be used on MGRS
+    /// string conversions.
+    /// </param>
+    /// <param name="bSetExceptionsOn">
+    /// <c>true</c> indicates that exceptions are to be thrown on coordinate
+    /// conversions which fail for any reason.
+    /// </param>
+    /// <returns>
+    /// Returns a disposable pointer to an <c>MgCoordinateSystemMgrs</c>
+    /// object which is suitable <b>only</b> for MGRS string conversions.
+    /// </returns>
+    /// <exception cref="MgOutOfMemoryException">
+    /// Thrown on heap memory allocation failure.
+    /// </exception>
     virtual MgCoordinateSystemMgrs* GetMgrsEllipsoid(CREFSTRING sEllipsoidCode,
                                                      INT8 nLetteringScheme,
                                                      bool bSetExceptionsOn);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Manufactures an MGRS grid object.  The returned object is suitable only
+    /// for use in simple coordinate <-> MGRS string calculations.
+    /// </summary>
+    /// <param name="sDatumCode">
+    /// Dictionary code name of the datum whose referenced ellipsoid is to be
+    /// used for all conversions to and from MGRS strings.
+    /// </param>
+    /// <param name="nLetteringScheme">
+    /// A value as defined in the <c>MgCoordinateSystemMgrsLetteringScheme</c>
+    /// object which specifies the lettering scheme to be used on MGRS
+    /// string conversions.
+    /// </param>
+    /// <param name="bSetExceptionsOn">
+    /// <c>true</c> indicates that exceptions are to be thrown on coordinate
+    /// conversions which fail for any reason.
+    /// </param>
+    /// <returns>
+    /// Returns a disposable pointer to an <c>MgCoordinateSystemMgrs</c>
+    /// object which is suitable <b>only</b> for MGRS string conversions.
+    /// </returns>
+    /// <exception cref="MgOutOfMemoryException">
+    /// Thrown on heap memory allocation failure.
+    /// </exception>
+    /// <remarks>
+    /// The datum specification is simply a means of specifying the ellipsoid
+    /// upon which the calculations are to be based.  It does <b>not</b> mean
+    /// that any datum shift calculations will be performed.
+    /// </remarks>
     virtual MgCoordinateSystemMgrs* GetMgrsDatum(CREFSTRING sDatumCode,
                                                  INT8 nLetteringScheme,
                                                  bool bSetExceptionsOn);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Manufactures an MGRS grid object which is suitable for generating an
+    /// actual MGRS grid.
+    /// </summary>
+    /// <param name="pFrameCs">
+    /// The frame coordinate system.
+    /// </param>
+    /// <param name="bUseFrameDatum">
+    /// <c>true</c> causes the frame datum to be used for all geodetic calculations
+    /// neccessary to generate the grid; otherwise WGS84 is assumed.
+    /// <param name="nLetteringScheme">
+    /// A value as defined in the <c>MgCoordinateSystemMgrsLetteringScheme</c>
+    /// object which specifies the lettering scheme to be used on MGRS
+    /// string conversions.
+    /// </param>
+    /// <param name="bSetExceptionsOn">
+    /// <c>true</c> indicates that exceptions are to be thrown on coordinate
+    /// conversions which fail for any reason. This applies only to MGRS string
+    /// conversions.
+    /// </param>
+    /// <returns>
+    /// Returns a disposable pointer to the abstract interface class from which the
+    /// MGRS grid object (and all other grid objects) derive.
+    /// object derive.
+    /// </returns>
+    /// <exception cref="MgOutOfMemoryException">
+    /// Thrown on heap memory allocation failure.
+    /// </exception>
+    /// <remarks>
+    /// Refer to <see cref="MgCoordinateSystemFactory::CreateFromCode"> for
+    /// additional exception information.<para>
+    /// Coordinate system transformation exceptions are always suppressed during
+    /// grid generation.
+    /// </remarks>
     virtual MgCoordinateSystemGridBase* MgrsGrid (MgCoordinateSystem* pFrameCs,
-                                                  bool bUseTargetDatum,
+                                                  bool bUseFrameDatum,
                                                   INT8 nLetteringScheme,
                                                   bool bSetExceptionsOn);
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Manufactures an MGRS grid object which is suitable for generating an
+    /// actual MGRS grid.
+    /// </summary>
+    /// <param name="sFrameCs">
+    /// The dictionary code name of the frame coordinate system.
+    /// </param>
+    /// <param name="bUseFrameDatum">
+    /// <c>true</c> causes the frame datum to be used for all geodetic calculations
+    /// neccessary to generate the grid; otherwise WGS84 is assumed.
+    /// <param name="nLetteringScheme">
+    /// A value as defined in the <c>MgCoordinateSystemMgrsLetteringScheme</c>
+    /// object which specifies the lettering scheme to be used on MGRS
+    /// string conversions.
+    /// </param>
+    /// <param name="bSetExceptionsOn">
+    /// <c>true</c> indicates that exceptions are to be thrown on coordinate
+    /// conversions which fail for any reason. This applies only to MGRS string
+    /// conversions.
+    /// </param>
+    /// <returns>
+    /// Returns a disposable pointer to the abstract interface class from which the
+    /// MGRS grid object (and all other grid objects) derive.
+    /// object derive.
+    /// </returns>
+    /// <exception cref="MgOutOfMemoryException">
+    /// Thrown on heap memory allocation failure.
+    /// </exception>
+    /// <remarks>
+    /// Refer to <see cref="MgCoordinateSystemFactory::CreateFromCode"> for
+    /// additional exception information.<para>
+    /// Coordinate system transformation exceptions are always suppressed during
+    /// grid generation.
+    /// </remarks>
     virtual MgCoordinateSystemGridBase* MgrsGrid (CREFSTRING sFrameCs,
-                                                  bool bUseTargetDatum,
+                                                  bool bUseFrameDatum,
                                                   INT8 nLetteringScheme,
                                                   bool bSetExceptionsOn);
 

Modified: trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemGrids.h
===================================================================
--- trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemGrids.h	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/Geometry/CoordinateSystem/CoordinateSystemGrids.h	2009-09-08 22:16:31 UTC (rev 4212)
@@ -17,9 +17,7 @@
 
 //=============================================================================
 // Class declararations
-class MgCoordinateSystemGridBoundary;           // MgPolygon based extents of the grid;
-                                                // currently only rectangles are
-                                                // supported.
+class MgCoordinateSystemGridBoundary;           // MgPolygon based extents of the grid
 class MgCoordinateSystemGridBase;               // abstract interface between grid generator
                                                 // and grid consumer
 class MgCoordinateSystemGridGeneric;            // derives from MgCoordinateSystemGridBase
@@ -49,10 +47,19 @@
                                                 // as a double
 
 
-//=============================================================================
-// An enumeration of the various types of specialized grids/graticules
-// currently supported.  A specialized grid is one for which specific standards
-// exist to which the results of this feature are compliant with.
+
+///////////////////////////////////////////////////////////////////////////////
+/// <summary>
+/// An enumeration of the various types of specialized grids/graticules
+/// currently supported.  A specialized grid is one for which specific
+/// standards exist to which the results of this feature are compliant with.
+/// A generic grid is a simple non-standardized grid of a coordinate system
+/// drawn in a viewport based on another coordinate system. <p>
+/// The values assigned are intended to support grouping standardized grids
+/// with similar features and is currently entirely arbitrary.  Using a
+/// numeric literal instead of thes names of the defined constants is a sure
+/// way to write code that will get broken in the future.
+/// </summary>
 class MgCoordinateSystemGridSpecializationType
 {
 PUBLISHED_API:
@@ -64,18 +71,19 @@
     static const INT32 Unknown           = (65366);     // indicates a failure of an algorithm
 };
 
-//=============================================================================
-// An enumeration of the supported values for the 'm_Orientation' member of
-// several objects related to grids and graticules.
-//
-// This value is used to qualify objects which are of the "iso" type.  I.e. a
-// grid line is referred to as an isoline as it is the locus of points which
-// have a specific value for either the easting or the northing.  It is this
-// value which indicates which.  Thus, a grid line which is classified as
-// having an "EastWest" orientation will be a isoline which is the locus of
-// points which share a common easting value, and the "m_Value" element of
-// that object will be an easting value.
-//
+///////////////////////////////////////////////////////////////////////////////
+/// <summary>
+/// An enumeration of the supported values for the <c>m_Orientation</c> member
+/// of several objects related to grids and graticules. <p>
+/// This value is used to qualify objects which are of the "iso" type.  I.e. a
+/// grid line is referred to as an isoline as it is the locus of points which
+/// have a specific value for either the easting or the northing.  It is this
+/// value which indicates which.  Thus, a grid line which is classified as
+/// having an "EastWest" orientation will be a isoline which is the locus of
+/// points which share a common <b>easting</b> value, and the "m_Value" element
+/// of that object will be an <b>easting</b> value.  Note that in this example,
+/// the line is typically a vertical line.
+/// </summary>
 class MgCoordinateSystemGridOrientation
 {
 PUBLISHED_API:
@@ -85,51 +93,519 @@
     static const INT8 Unknown = 3;          // indicates a failure of an algorithm
 };
 
-//=============================================================================
-// MgCoordinateSystemGridSpecification
-//
-// This object is used to convey all the parameters necessary for the
-// generation of a grid/graticule lumped into a single object for convenience.
-// Thus, adding a parameter determined to be necessary does not alter a lot of
-// calling sequences.
+///////////////////////////////////////////////////////////////////////////////
+/// <summary>
+/// <c>MgCoordinateSystemGridSpecification</c> is an object that is used to
+/// convey all the parameters necessary for the generation of a grid/graticule
+/// lumped into a single object for convenience.  Thus, adding a parameter
+/// determined to be necessary at a later time does not alter a lot of calling
+/// sequences.<p>
+/// Note that this interface is an abstract interface.  There is code
+/// associated with the implementation of this interface which is used to
+/// handle the conversion of parameters between the various unit systems.
+/// Thus, one obtains a <c>MgCoordinateSystemGridSpecification</c> from the
+/// <c>MgCoordinateSystemFactory</c> object.<p>
+/// Note that all values are provided in the units specified within the object.
+/// The units used in this object do <b>not</b> need to be the same as any
+/// coordinate system involved in the generation of a grid, although the 
+/// <b>type</b> of unit must be consistent with the type of grid being drawn.
+/// That is, specifying a Angular unit type when drawing a UTM grid will cause
+/// an exception at the time the request for (say) grid lines is issued.
+/// </summary>
 class MG_GEOMETRY_API MgCoordinateSystemGridSpecification : public MgGuardDisposable
 {
 PUBLISHED_API:
-    virtual double GetEastingBase (void)=0;             // the base value from which easting grid line values are computed.
-    virtual double GetNorthingBase (void)=0;            // the base value from which northing grid line values are computed.
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the easting base value.
+    /// </summary>
+    /// <returns>
+    /// Returns the current value of the easting base member.
+    /// </returns>
+    /// <remarks>
+    /// The base value is the base upon which grid values are determined.
+    /// Thus, a grid with and increment of, say, two degrees, can actually
+    /// start at one (the base) yielding grid lines at 1, 3, 5, 7, etc.
+    /// </remarks>
+    virtual double GetEastingBase (void)=0;
+    
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Gets the northing base value.
+    /// </summary>
+    /// <returns>
+    /// Returns the current value of the northing base member.
+    /// </returns>
+    /// <remarks>
+    /// The base value is the base upon which grid values are determined.
+    /// Thus, a grid with and increment of, say, two degrees, can actually
+    /// start at one (the base) yielding grid lines at 1, 3, 5, 7, etc.
+    /// </remarks>
+    virtual double GetNorthingBase (void)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the easting increment value.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual double GetEastingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual double GetEastingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual double GetEastingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns the current value of the easting increment member.
+    ///
+    /// \remarks
+    /// The distance between grid lines representing easting values.
+    ///
     virtual double GetEastingIncrement(void)=0;         // the interval between easting grid lines
-    virtual double GetNorthingIncrement(void)=0;        // the interval between northing grid lines
-    virtual double GetTickEastingIncrement(void)=0;     // number of tic subdivisions between grid increments in the east/west direction
-    virtual double GetTickNorthingIncrement(void)=0;    // number of tic subdivisions between grid increments in the north/south direction
-    virtual INT32 GetUnitType(void)=0;                  // a value from MgCoordinateSystemUnitType indicating the type of units of the
-                                                        // base and interval specifications
-    virtual INT32 GetUnitCode(void)=0;                  // a value from MgCoordinateSystemUnitCode indicating the units of the
-                                                        // base and interval specifications
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the northing increment value.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual double GetNorthingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual double GetNorthingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual double GetNorthingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns the current value of the northing increment member.
+    ///
+    /// \remarks
+    /// The distance between grid lines representing northing values.
+    ///
+    virtual double GetNorthingIncrement(void)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the tick easting increment value.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual double GetTickEastingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual double GetTickEastingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual double GetTickEastingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns the current value of the tick easting increment member.
+    ///
+    /// \remarks
+    /// The distance between ticks representing specific easting values.
+    ///
+    virtual double GetTickEastingIncrement(void)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the tick northing increment value.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual double GetTickNorthingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual double GetTickNorthingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual double GetTickNorthingIncrement ();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns the current value of the tick northing increment member.
+    ///
+    /// \remarks
+    /// The distance between ticks representing specific northing values.
+    ///
+    virtual double GetTickNorthingIncrement(void)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the current unit type setting.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int GetUnitType();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int GetUnitType();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int GetUnitType();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns the current unit type setting.
+    ///
+    /// \remarks
+    /// The value returned is one of the values defined in the
+    /// MgCoordinateSystemUnitType object and essentially specifies if the unit
+    /// specification is of the linear or angular type.
+    ///
+    virtual INT32 GetUnitType(void)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the current unit code setting.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual int GetUnitCode();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual int GetUnitCode();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual int GetUnitCode();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns the current unit code setting.
+    ///
+    /// \remarks
+    /// The value returned is one of the values defined in the
+    /// MgCoordinateSystemUnitCode object and essentially specifies the unit in
+    /// which the base, increment (line and tick), and curve precision values
+    /// are specified. 
+    ///
+    virtual INT32 GetUnitCode(void)=0;
+    
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Determines if two MgCoordinateSystemGridSpecification objects are the
+    /// same.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual bool IsSameAs (MgCoordinateSystenGridSpecification secondObject);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual bool IsSameAs (MgCoordinateSystenGridSpecification secondObject);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual bool IsSameAs (MgCoordinateSystenGridSpecification secondObject);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param specification (MgCoordinateSystemGridSpecification)
+    /// The second object to which the host object is to be compared to.
+    ///
+    /// \return
+    /// Returns true if the objects are identical.
+    ///
+    /// \remarks
+    /// Objects with a different unit settings are automatically considered
+    /// different.  Therefore the intelligence necessary to compare values which
+    /// are identical in different units is <b>not</b> present.
+    ///
     virtual bool IsSameAs(MgCoordinateSystemGridSpecification* specification)=0;
-    virtual double GetCurvePrecision(void)=0;           // the maximum difference between true complex curve and the polyline
-                                                        // approximation thereof, in the same units used to specify the
-                                                        // base and increment values (i.e. UnitCode).
-                                                        // If left unspecified (or set to zero) a value is automatically selected to be,
-                                                        // approximately, the equivalent of 1 meter in target system units.
 
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Get the current curve precision value.
+    /// same.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual double GetCurvePrecision ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual double GetCurvePrecision ();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual double GetCurvePrecision ();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \return
+    /// Returns the current curve precision value.
+    ///
+    /// \remarks
+    /// The curve precision value specifies the desired maximum distance between
+    /// a complex curve approximation and the actual complex curve.  This value
+    /// may be left at zero, and a suitable default value will be choosen by the
+    /// grid generation engine at grid line generation time.
+    ///
+    virtual double GetCurvePrecision(void)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Sets the easting and northing base values.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual void SetGridBase (double eastingBase, double northingBase);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual void SetGridBase (double eastingBase, double northingBase);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual void SetGridBase (double eastingBase, double northingBase);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param eastingBase (double)
+    /// The base value to be used in calculating the easting grid and tick
+    /// values.
+    ///
+    /// \param northingBase (double)
+    /// The base value to be used in calculating the northing grid and tick
+    /// values.
+    ///
+    /// \remarks
+    /// While the increment values determine the distance between grid lines
+    /// and ticks, the base value specifies the base value at which the
+    /// initial grid line/tick is positioned.  Actually, the base for any
+    /// grid is the algebraically highest value which is less than the
+    /// grid boundary minimum and which, when mod'ed with base, produces zero.
+    ///
+    /// That is, for example, an increment of 2 and a base of 1 will produce
+    /// grid values of 1, 3, 5, 7, etc.
+    ///
     virtual void SetGridBase(double eastingBase,double northingBase) = 0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Sets the easting and northing grid line increment values.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual void SetGridIncrement (double eastingIncrement, double northingIncrement);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual void SetGridIncrement (double eastingIncrement, double northingIncrement);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual void SetGridIncrement (double eastingIncrement, double northingIncrement);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param eastingIncrement (double)
+    /// The distance between easting grid lines.
+    ///
+    /// \param northingIncrement (double)
+    /// The distance between northing grid lines.
+    ///
+    /// \remarks
+    /// In this context, easting refers to grid lines which represent a specific
+    /// easting value; the resulting lines usually being vertical (i.e. south to
+    /// north) grid lines.  Northing refers to grid lines which represent a
+    /// specific northing value; the resulting lines usually being horizontal
+    /// (i.e. west to east).
+    ///
+    /// \bugs
+    /// This function should be named SetGridIncrements to be consistent with the
+    /// rest of the interface.
+    ///
     virtual void SetGridIncrement(double eastingIncrement,double northingIncrement) = 0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Sets the easting and northing tick increment values.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual void SetTickIncrements (double eastingIncrement, double northingIncrement);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual void SetTickIncrements (double eastingIncrement, double northingIncrement);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual void SetTickIncrements (double eastingIncrement, double northingIncrement);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param eastingIncrement (double)
+    /// The distance between easting tick marks.
+    ///
+    /// \param northingIncrement (double)
+    /// The distance between northing tick marks.
+    ///
     virtual void SetTickIncrements(double eastingIncrement,double northingIncrement) = 0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Sets the units used to define the desired grid.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual void SetUnits (int unitCode, int unitType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual void SetUnits (int unitCode, int unitType);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual void SetUnits (int unitCode, int unitType);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param unitCode (int)
+    /// One of the integer values defined in the MgCoordinateSystemUnitCode
+    /// object which indicates the units used to define the grid parameters. 
+    ///
+    /// \param unitType (int)
+    /// One of the integer values defined in the MgCoordinateSystemUnitType
+    /// object which indicates the type of units (linear vs angular) used to
+    /// define the grid parameters.
+    ///
+    /// \remarks
+    /// The unitCode and unitType parameters must be consistent with each other
+    /// or an exception is thrown.  Also, the unit tyupe must be consistent
+    /// with the type of grid being requested or an exception will be thrown.
+    /// That is, you may not define a graticule (i.e. a grid of geographic
+    /// coordinates on a projected coordinate system map) using linear units.
+    /// SImilarly, you cannot use angular units to define a grid of a projected
+    /// coordinate system on a projected coordinate system map.
+    ///
     virtual void SetUnits (INT32 unitCode,INT32 unitType) = 0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Sets the desired precision of complecx curve approximations.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// virtual void SetCurvePrecision (double curvePrecision);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// virtual void SetCurvePrecision (double curvePrecision);
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// virtual void SetCurvePrecision (double curvePrecision);
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    /// \param curvePrecision (double)
+    /// The desired maximum distance between an approximation of a complex curve
+    /// and the true curve.
+    ///
+    /// \remarks
+    /// Please note the term desired in this description.  The generation of a
+    /// complex curve approximation is also controlled by a variable usually
+    /// called the MaximumCurvePoints.  Thus, if this criteria is exceeded in 
+    /// the curve generation process, the curve precision can and will often be
+    /// less than that requested.  This provision is implemented to reduce the
+    /// probability of a runaway grid which consumes the entire machine.
+    ///
+    /// \bugs
+    /// The maximum curve point variable should be a part of this object.
+    ///
     virtual void SetCurvePrecision (double curvePrecision) = 0;
 
 INTERNAL_API:
-    // The following function identically to the published version, with the
-    // exception that the value returned is converted to the units of the
-    // provided coordinate system.  Typically, the provided coordinate system
-    // is either the grid coordinate system OR the frame coordinate system.
-    virtual double GetEastingBase (MgCoordinateSystem* gridCS)=0;
-    virtual double GetNorthingBase (MgCoordinateSystem* gridCS)=0;
-    virtual double GetEastingIncrement (MgCoordinateSystem* gridCS)=0;
-    virtual double GetNorthingIncrement (MgCoordinateSystem* gridCS)=0;
-    virtual double GetCurvePrecision (MgCoordinateSystem* gridCS)=0;
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the easting base value after conversion from the units
+    /// of this specification object to the units of the provided coordinate
+    /// system.
+    ///
+    /// \param gridCRS
+    /// The return value is converted to the units of this coordinate system.
+    ///
+    /// \return
+    /// Easting base value in units of the provided coordinate system.
+    ///
+    /// \exception
+    /// Will throw if the unit types of this specification and the provided
+    /// coordinate system are not the same.
+    ///
+    virtual double GetEastingBase (MgCoordinateSystem* gridCRS)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the northing base value after conversion from the units
+    /// of this specification object to the units of the provided coordinate
+    /// system.
+    ///
+    /// \param gridCRS
+    /// The return value is converted to the units of this coordinate system.
+    ///
+    /// \return
+    /// Northing base value in units of the provided coordinate system.
+    ///
+    /// \exception
+    /// Will throw if the unit types of this specification and the provided
+    /// coordinate system are not the same.
+    ///
+    virtual double GetNorthingBase (MgCoordinateSystem* gridCRS)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the easting grid increment value after conversion from the
+    /// units of this specification object to the units of the provided
+    /// coordinate system.
+    ///
+    /// \param gridCRS
+    /// The return value is converted to the units of this coordinate system.
+    ///
+    /// \return
+    /// Easting grid increment value in units of the provided coordinate system.
+    ///
+    /// \exception
+    /// Will throw if the unit types of this specification and the provided
+    /// coordinate system are not the same.
+    ///
+    virtual double GetEastingIncrement (MgCoordinateSystem* gridCRS)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the northing grid increment value after conversion from the
+    /// units of this specification object to the units of the provided
+    /// coordinate system.
+    ///
+    /// \param gridCRS
+    /// The return value is converted to the units of this coordinate system.
+    ///
+    /// \return
+    /// Northing grid increment value in units of the provided coordinate system.
+    ///
+    /// \exception
+    /// Will throw if the unit types of this specification and the provided
+    /// coordinate system are not the same.
+    ///
+    virtual double GetNorthingIncrement (MgCoordinateSystem* gridCRS)=0;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Returns the curve precision value after conversion from the units
+    /// of this specification object to the units of the provided coordinate
+    /// system.
+    ///
+    /// \param gridCRS
+    /// The return value is converted to the units of this coordinate system.
+    ///
+    /// \return
+    /// Curve precision value in units of the provided coordinate system.
+    ///
+    /// \exception
+    /// Will throw if the unit types of this specification and the provided
+    /// coordinate system are not the same.
+    ///
+    /// \remarks
+    /// If this specification object's curve precision value has not been set
+    /// or is otherwise set to zero, this function will manufacture a curve
+    /// precision value consistent with the coordinate system provided.  Note
+    /// that this default value will be more liberal than conservative.
+    ///
+    /// \bugs
+    /// The automatically calculated curve precision value should be a function
+    /// of the Grid Boundary object which known how much geography is to be
+    /// included in the grid and is thus in a better position to determine
+    /// what the default value should be.
+    ///
+    virtual double GetCurvePrecision (MgCoordinateSystem* gridCRS)=0;
+
 protected:
-    INT32 GetClassId(){return m_cls_id;};
+     INT32 GetClassId(){return m_cls_id;};
 CLASS_ID:
     static const INT32 m_cls_id = CoordinateSystem_CoordinateSystemGridSpecification;
 };
@@ -137,6 +613,17 @@
 //=============================================================================
 // External to this interface, boundary objects are always in the viewport
 // (i.e. target) coordinate system.
+/// <summary>
+/// This object is used to maintain the definition of the boundary of a
+/// specific grid or graticule.  Externally, a
+/// <c>MgCoordinateSystemGridBoundary</c> object will be in viewport
+/// coordinates.  Internally, objects of this type are oftyen used to the
+/// carry grid boundaries in grid coordinates, and also greographic
+/// coordinates.<p>
+/// Grid boundaries iusually start out as rectangles, but are often converted
+/// to a series of complex curves approximated by multi-segment lines (i.e.
+/// line strings).
+/// </summsry>
 class MG_GEOMETRY_API MgCoordinateSystemGridBoundary : public MgGuardDisposable
 {
 PUBLISHED_API:

Modified: trunk/MgDev/Common/Geometry/GeometryConsoleTest/GeometryConsoleTest.cpp
===================================================================
--- trunk/MgDev/Common/Geometry/GeometryConsoleTest/GeometryConsoleTest.cpp	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/Geometry/GeometryConsoleTest/GeometryConsoleTest.cpp	2009-09-08 22:16:31 UTC (rev 4212)
@@ -16,12 +16,15 @@
     INT32 index3;
     INT32 index4;
     INT32 tickCount;
+    INT32 orientation;
     INT32 regionCount;
     INT32 gridLineCount;
     INT32 lineSegmentCount;
     
     double xx;
     double yy;
+    double uu;
+    double vv;
     double value;
 
     MgCoordinateSystemFactory factory;
@@ -40,9 +43,6 @@
     MgCoordinateSystemGridTick* pGridTick;
     MgCoordinateSystemGridTickCollection* pGridTicks;
 
-    MgCoordinate* southWestXY = new MgCoordinateXY (600000.0,3900000.0);
-    MgCoordinate* northEastXY = new MgCoordinateXY (900000.0,4100000.0);
-
     pGridSpecification = factory.GridSpecification ();
     pGridSpecification->SetGridBase (0.0,0.0);
     pGridSpecification->SetGridIncrement (1.0,1.0);
@@ -50,12 +50,17 @@
     pGridSpecification->SetUnits (MgCoordinateSystemUnitCode::Degree,MgCoordinateSystemUnitType::Angular);
     pGridSpecification->SetCurvePrecision (1.0E-05);
 
-    pGenericGrid = factory.GenericGrid (L"LL84",L"UTM83-13",true);
+    pGenericGrid = factory.GenericGrid (L"LL84",L"CA83-IIF",true);
+
+    MgCoordinate* southWestXY = new MgCoordinateXY (6.49E+06,1.99E+06);
+    MgCoordinate* northEastXY = new MgCoordinateXY (6.61E+06,2.11E+06);
     pGridBoundary = factory.GridBoundary (southWestXY,northEastXY);
     southWestXY->Release ();
     northEastXY->Release ();
 
     pGenericGrid->SetBoundary (pGridBoundary);
+    pGridBoundary->Release ();
+
     pGridLines = pGenericGrid->GetGridLines (pGridSpecification);
     gridLineCount = pGridLines->GetCount ();
     for (index1 = 0;index1 < gridLineCount;index1 += 1)
@@ -86,6 +91,16 @@
     for (index4 = 0;index4 < tickCount;index4 += 1)
     {
         pGridTick = pGridTicks->GetItem (index4);
+        value = pGridTick->GetValue ();
+        orientation = pGridTick->GetTickOrientation ();
+        pCoordinate = pGridTick->GetPosition ();
+        xx = pCoordinate->GetX ();
+        yy = pCoordinate->GetY ();
+        pCoordinate->Release ();
+        pCoordinate = pGridTick->GetDirectionVector ();
+        uu = pCoordinate->GetX ();
+        vv = pCoordinate->GetY ();
+        pCoordinate->Release ();
         pGridTick->Release ();
     }
     pGridTicks->Release ();    
@@ -95,8 +110,24 @@
 
     pGridSpecification = factory.GridSpecification (MgCoordinateSystemGridSpecializationType::MGRS,
                                                     MgCoordinateSystemMgrsGridLevel::Mgrs1Km);
-    pMgrs = factory.MgrsGrid (L"UTM84-13N",false,MgCoordinateSystemMgrsLetteringScheme::Normal,true);
+
+    pGridSpecification = factory.GridSpecification ();
+    pGridSpecification->SetGridBase (0.0,0.0);
+    pGridSpecification->SetGridIncrement (100.0,100.0);
+    pGridSpecification->SetTickIncrements  (10.0,10.0);
+    pGridSpecification->SetUnits (MgCoordinateSystemUnitCode::Kilometer,MgCoordinateSystemUnitType::Linear);
+    pGridSpecification->SetCurvePrecision (0.5);
+
+    southWestXY = new MgCoordinateXY (6.49E+06,1.99E+06);
+    northEastXY = new MgCoordinateXY (6.61E+06,2.11E+06);
+    pGridBoundary = factory.GridBoundary (southWestXY,northEastXY);
+    southWestXY->Release ();
+    northEastXY->Release ();
+
+    pMgrs = factory.MgrsGrid (L"CA83-IIF",false,MgCoordinateSystemMgrsLetteringScheme::Normal,true);
     pMgrs->SetBoundary (pGridBoundary);
+    pGridBoundary->Release ();
+
     pGridLines = pMgrs->GetGridLines (pGridSpecification);
     gridLineCount = pGridLines->GetCount ();
     for (index1 = 0;index1 < gridLineCount;index1 += 1)
@@ -136,13 +167,22 @@
     for (index4 = 0;index4 < tickCount;index4 += 1)
     {
         pGridTick = pGridTicks->GetItem (index4);
+        value = pGridTick->GetValue ();
+        orientation = pGridTick->GetTickOrientation ();
+        pCoordinate = pGridTick->GetPosition ();
+        xx = pCoordinate->GetX ();
+        yy = pCoordinate->GetY ();
+        pCoordinate->Release ();
+        pCoordinate = pGridTick->GetDirectionVector ();
+        uu = pCoordinate->GetX ();
+        vv = pCoordinate->GetY ();
+        pCoordinate->Release ();
         pGridTick->Release ();
     }
     pGridTicks->Release ();
 
     pMgrs->Release ();
 
-    pGridBoundary->Release ();
     pGridSpecification->Release ();
 
     return 0;

Modified: trunk/MgDev/Common/Geometry/Spatial/MathUtility.cpp
===================================================================
--- trunk/MgDev/Common/Geometry/Spatial/MathUtility.cpp	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/Geometry/Spatial/MathUtility.cpp	2009-09-08 22:16:31 UTC (rev 4212)
@@ -211,3 +211,42 @@
 
     return interpolated;
 }
+
+bool MgMathUtility::DblCmp (double first,double second)
+{
+	int exp1, exp2;
+	int deltaExp;
+	double mant1,mant2;
+
+	mant1 = frexp (first ,&exp1);
+	mant2 = frexp (second,&exp2);
+	deltaExp = exp1 - exp2;
+	if (abs (deltaExp) >= 2) return false;
+
+	// Need to deal with the case where the difference between the exponents
+	// is +/-1.  This is necessary as the two values may be infinitesimally
+	// greater and less than an even true binary value like 0.5.  In this
+	// case, they would be equal, but the exponents would not be the same.
+	if (deltaExp == 1)
+	{
+		// exp of first is bigger than exp of second.   Adjust exp2 and mant2
+		// so that they still represent the same value, but exp2 is now the
+		// same as exp1.  Note, this de-normalizes the numbers,  but that
+		// does not affect the comparison result in any way.
+		exp2 += 1;
+		mant2 *= 0.5;
+	}
+	else if (deltaExp == -1)
+	{
+		exp1 += 1;
+		mant1 *= 0.5;
+	}
+
+	// Now, if the exponents are not equal, obviously the original values
+	// are not equal; not even close.
+	if (exp1 != exp2) return false;
+
+	// Since the exponents are equal, then we can simply compare the mantissas.
+	// We ignore any difference in the last few bits.
+	return (fabs (mant1 - mant2) < 5.0E-13);
+}

Modified: trunk/MgDev/Common/Geometry/Spatial/MathUtility.h
===================================================================
--- trunk/MgDev/Common/Geometry/Spatial/MathUtility.h	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/Geometry/Spatial/MathUtility.h	2009-09-08 22:16:31 UTC (rev 4212)
@@ -91,6 +91,24 @@
     /// It is allowable to pass NaN for any parameter, in which case the return
     /// value is also a (quiet) NaN.
     static double LinearInterpolate(double start, double end, double proportion);
+
+    /////////////////////////////////////////////////////////////////////////// 
+    /// <summary>
+    /// Reliably compares two doubles, providing that neither of the two values
+    /// is a hard zero, ignoring differences in the least significant bits of
+    /// the mantissa which are unreliable if either of the values being
+    /// compared are the result of some serious calculations.
+    /// </summary>
+    /// <param name="first">
+    /// The first of two doubles to be compared.  Must not be a hard zero.
+    /// </param>
+    /// <param name="second">
+    /// The second of two doubles to be compared.  Must not be a hard zero.
+    /// </param>
+    /// <returns>
+    /// Returns <c>true</c> for "essentially equal".
+    /// </returns>
+    static bool DblCmp (double first,double second);
 };
 /// \endcond
 

Modified: trunk/MgDev/Common/Geometry/Spatial/SpatialUtility.cpp
===================================================================
--- trunk/MgDev/Common/Geometry/Spatial/SpatialUtility.cpp	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/Geometry/Spatial/SpatialUtility.cpp	2009-09-08 22:16:31 UTC (rev 4212)
@@ -514,3 +514,375 @@
 
     return retGeomComp.Detach();
 }
+
+//////////////////////////////////////////////
+///<summary>
+/// Calculates the two dimensional intersection of two line segments.
+/// 
+///</summary>
+
+///////////////////////////////////////////////////////////////////////////////
+//
+INT32 MgSpatialUtility::SegmentIntersection (MgCoordinate* result,MgCoordinate* seg1From,
+                                                                  MgCoordinate* seg1To,
+                                                                  MgCoordinate* seg2From,
+                                                                  MgCoordinate* seg2To)
+{
+    INT32 status (-7);          // until we know different.
+
+    double delX1, delY1;
+    double delX2, delY2;
+    double denom1, denom2;
+    double num, denom;          // numerator and denominator
+
+    CHECKNULL(result,   L"MgSpatialUtility.SegmentIntersection")
+    CHECKNULL(seg1From, L"MgSpatialUtility.SegmentIntersection")
+    CHECKNULL(seg1To,   L"MgSpatialUtility.SegmentIntersection")
+    CHECKNULL(seg2From, L"MgSpatialUtility.SegmentIntersection")
+    CHECKNULL(seg2To,   L"MgSpatialUtility.SegmentIntersection")
+
+    // Compute the denominator which also tells us if the lines are collinear.
+    delX1 = seg1To->GetX () - seg1From->GetX ();
+    delY1 = seg1To->GetY () - seg1From->GetY ();
+    delX2 = seg2To->GetX () - seg2From->GetX ();
+    delY2 = seg2To->GetY () - seg2From->GetY ();
+    denom1 = delX2 * delY1;
+    denom2 = delX1 * delY2;
+    if (MgMathUtility::DblCmp (denom1,denom2))
+    {
+        // Collinear or parallel, there is no intersection.
+        status = -1;
+    }
+    else
+    {
+        // OK, we have a stable geometry and an intersection of some sort should exist.
+        // Compute the intersection point.
+        status = 0;
+        denom = denom1 - denom2;
+        num = delX1 * delX2 * (seg2From->GetY() - seg1From->GetY()) +
+              delX2 * delY1 *  seg1From->GetX() -
+              delX1 * delY2 *  seg2From->GetX();
+        result->SetX (num / denom);
+
+        num = delY1 * delY2 * (seg2From->GetX() - seg1From->GetX()) +
+              delY2 * delX1 *  seg1From->GetY() -
+              delY1 * delX2 *  seg2From->GetY();
+        result->SetY (num / -denom);
+
+        // Now to compute the location of the intersection point relative to the
+        // line segments involved. This is often very important.
+        if (fabs (delX1) > fabs (delY1))
+        {
+            // Segment one is more horizontal than vertical. We will use the X
+            // value to test if the resulting point is on the segment.  Notice
+            // that an interscetion point which resides (relatively) precisely
+            // on the 'to' point is not considered to be on the segment.
+            if (delX1 >= 0.0)
+            {
+                // X increases from the 'from' point to the 'to' point.
+                if (result->GetX() > seg1From->GetX() && result->GetX() <= seg1To->GetX())
+                {
+                    status |= 1;
+                }
+            }
+            else
+            {
+                // X decreases from the 'from' point to the 'to' point.
+                if (result->GetX() < seg1From->GetX() && result->GetX() >= seg1To->GetX())
+                {
+                    status |= 1;
+                }
+            }
+        }
+        else
+        {
+            // First segment is more verical than horizontal. We will use the y
+            // value to test if the resulting point is on the segment.
+            if (delY1 >= 0.0)
+            {
+                // Y increases from the 'from' point to the 'to' point.
+                if (result->GetY() > seg1From->GetY() && result->GetY() <= seg1To->GetY())
+                {
+                    status |= 1;
+                }
+            }
+            else
+            {
+                // Y increases from the 'from' point to the 'to' point.
+                if (result->GetY() < seg1From->GetY() && result->GetY() >= seg1To->GetY())
+                {
+                    status |= 1;
+                }
+            }
+        }
+
+        // Same stuff with the second segment, sans comments.
+        if (fabs (delX2) > fabs (delY2))
+        {
+            if (delX2 >= 0.0)
+            {
+                if (result->GetX() > seg2From->GetX() && result->GetX() <= seg2To->GetX())
+                {
+                    status |= 2;
+                }
+            }
+            else
+            {
+                if (result->GetX() < seg2From->GetX() && result->GetX() >= seg2To->GetX())
+                {
+                    status |= 2;
+                }
+            }
+        }
+        else
+        {
+            if (delY2 >= 0.0)
+            {
+                if (result->GetY() > seg2From->GetY() && result->GetY() <= seg2To->GetY())
+                {
+                    status |= 2;
+                }
+            }
+            else
+            {
+                if (result->GetY() < seg2From->GetY() && result->GetY() >= seg2To->GetY())
+                {
+                    status |= 2;
+                }
+            }
+        }
+    }
+    return status;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// <summary>
+/// Returns a list of coordinates with all of the intersection points of the
+/// provided segment with the polygon provided by the first argument.  Note
+/// that the first argument is a CoordinateIterator; so it doesn't have to be
+/// an MgPolygon.  However, this function ASSUMES that the iterator does indeed
+/// point to a closed ring.
+/// </summary>
+MgCoordinateCollection* MgSpatialUtility::PolySegIntersection (MgCoordinateIterator* polyItr,MgCoordinate* segFrom,
+                                                                                             MgCoordinate* segTo)
+{
+    int status;
+    Ptr<MgCoordinateCollection> coordinateCollection;
+    Ptr<MgCoordinate> intersection;
+    Ptr<MgCoordinate> polyFrom;
+    Ptr<MgCoordinate> polyTo;
+    
+    CHECKNULL(polyItr, L"MgSpatialUtility.PolySegIntersection")
+    CHECKNULL(segFrom, L"MgSpatialUtility.PolySegIntersection")
+    CHECKNULL(segTo,   L"MgSpatialUtility.PolySegIntersection")
+  
+    // Create the return object.  Quite often it gets returned empty, but we
+    // will always return a "new" object (i.e. refCount == 1).  Create a work
+    // point we can use.
+    coordinateCollection = new MgCoordinateCollection ();
+    intersection = new MgCoordinateXY ();
+
+    // Reset the iterator so we know for sure what its state is.
+    polyItr->Reset ();
+    polyItr->MoveNext ();
+
+    // Loop through each segment in the polygon.  If its an exterior ring,
+    // as is usually the case, it should be in counterclockwise order.
+    polyTo = polyItr->GetCurrent ();
+    while (polyItr->MoveNext ())
+    {
+        polyFrom = polyTo;
+        polyTo = polyItr->GetCurrent ();
+        status = SegmentIntersection (intersection,polyFrom,polyTo,segFrom,segTo);
+        if (status == 3)
+        {
+            // We have an intersection of interest to us.  We need to add a
+            // point which will still be on the heap when we are done, so we
+            // definitely do not want to add the intersection point.
+            Ptr<MgCoordinate> newPoint = new MgCoordinateXY (intersection->GetX(),intersection->GetY());
+            coordinateCollection->Add(newPoint);
+
+            // The line segment can, and often does, have more than one
+            // intersection point with the polygon.  SO we keep trucking.
+        }
+    }
+    
+    // We return the generated collection, which will often be empty.
+    return coordinateCollection.Detach ();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// <summary>
+/// Returns true if the provided query point is inside of, or on, the closed
+/// ring provided by the polyItr argument.
+/// </summary>
+bool MgSpatialUtility::PointIsInPolygon (MgCoordinateIterator* polyItr,MgCoordinate* queryPoint)
+{
+    bool isInside;
+
+    INT32 count;
+
+    double minX, maxX;
+    double minY, maxY;
+    double outX, outY;
+
+    Ptr<MgCoordinate> tmpCoord;
+    Ptr<MgCoordinate> outPoint;
+    Ptr<MgCoordinateCollection> coordinateCollection;
+
+    // Accunulate min/max;
+    polyItr->Reset ();
+    minX = minY = +9.9E+100;
+    maxX = maxY = -9.9E+100;
+    while (polyItr->MoveNext ())
+    {
+        tmpCoord = polyItr->GetCurrent ();
+        if (tmpCoord->GetX() < minX) minX = tmpCoord->GetX ();
+        if (tmpCoord->GetY() < minY) minY = tmpCoord->GetY ();
+        if (tmpCoord->GetX() > maxX) maxX = tmpCoord->GetX ();
+        if (tmpCoord->GetY() > maxY) maxY = tmpCoord->GetY ();
+    }
+
+    // Create a from point known to be outside of the polygon.
+    outX = (minX >= 0.0) ? -minX : minX * 2.0;
+    outY = (minY >= 0.0) ? -minY : minY * 2.0;
+    outPoint = new MgCoordinateXY (outX,outY);
+
+    // Get all the intersections between the "outPoint" amd the query Point.
+    coordinateCollection = PolySegIntersection (polyItr,outPoint,queryPoint);
+    count = coordinateCollection->GetCount ();
+
+    // If the number of intersections is odd, the query point is inside.
+    // Otherwise it is outside. (Zero is an even number, isn't it?)
+    isInside = ((count & 1) != 0);
+    
+    return isInside;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// <summary>
+/// Returns a collection of line strings which represents those portions of the
+/// provided line string which are inside of the provided closed ring.
+/// </summary>
+MgLineStringCollection* MgSpatialUtility::ClipStringToPolygon (MgCoordinateIterator* polyItr,
+                                                               MgCoordinateIterator* lineItr)
+{
+    bool inside;
+
+    INT32 index;
+
+    Ptr<MgCoordinate> lineFrom;
+    Ptr<MgCoordinate> lineTo;
+    Ptr<MgCoordinateCollection> curCollection;
+    Ptr<MgLineString> newLineString;
+    Ptr<MgLineStringCollection> lineCollection;
+
+    // Need to create an empty collections, the factory doesn't do this.
+    curCollection = new MgCoordinateCollection ();
+    lineCollection = new MgLineStringCollection ();
+
+    // Set up the line string iterator.  It is the primary control loop
+    // for this operation.
+    lineItr->Reset ();
+    lineItr->MoveNext ();
+    lineTo = lineItr->GetCurrent ();
+    
+    // We need to know in what state we are starting in.  lineTo currently
+    // has the coordinates of the first point, which will become the
+    // lineFrom point once the main loop gets started.
+    inside = PointIsInPolygon (polyItr,lineTo);
+    
+    // If we are starting inside the polgon, we push the first point
+    // onto the current point collection.
+    if (inside)
+    {
+        curCollection->Add (lineTo);
+    }
+
+    while (lineItr->MoveNext ())
+    {
+        lineFrom = lineTo;              // TODO: does this work without screwing up the reference counts.
+        lineTo = lineItr->GetCurrent ();
+        
+        // Intersect this segment with the polygon.
+        Ptr<MgCoordinateCollection> segCollection;
+        segCollection = PolySegIntersection (polyItr,lineFrom,lineTo);
+        INT32 segCount = segCollection->GetCount ();
+
+        // If the segment count is zero, there were no intersections.  If we were
+        // inside, we're still inside.
+        if (segCount == 0)
+        {
+            if (inside)
+            {
+                curCollection->Add (lineTo);
+            }
+        }
+        else
+        {
+            // There is at least one intersection, so there will some state changing going on here.
+            for (index = 0;index < segCount;index += 1)
+            {
+                Ptr<MgCoordinate> newPoint = segCollection->GetItem (index);
+
+                // Terminate the current state, and initate the new state.
+                // At this point, the state switches for each point in the
+                // intersection list.
+                if (inside)
+                {
+                    // We're inside.  Switch to outside state.  sewPoint is the
+                    // location where we left the inside of the polygon.
+                    curCollection->Add (newPoint);
+
+                    // Make a line string out of the current point collection,
+                    // and add it to the line string collection which contains
+                    // the clipped segments.
+                    newLineString = new MgLineString (curCollection);
+                    lineCollection->Add (newLineString);
+
+                    // Clear curCollection inpreparation for the nex segment if
+                    // there is one.
+                    curCollection->Clear ();
+
+                    // We're outside of the polygon now.
+                    inside = false;
+                }
+                else
+                {
+                    // We were outside the polgon.  The intersection point
+                    // is the point at which we reenterd the polygon.
+                    curCollection->Add (newPoint);
+
+                    // We're back inside now.
+                    inside = true;
+                }
+            }
+            // At this point, if we end up inside, there will be a point in
+            // curCollection which will be the point at which we re-entered
+            // the last time.  Since we are inside, we need to add the
+            // lineTo point to the collection.
+            if (inside)
+            {
+                curCollection->Add (lineTo);
+            }
+
+            // Now we do something which might appear strange: we leave the
+            // curCollection object alone.  In this manner, we should eliminate
+            // a lot of contiguous line strings in the line string collection.
+            // Hope it works out that way.  It should, as if we are inside now,
+            // the first point of the segment from the line string should also
+            // be inside.
+        }
+    }
+    
+    // If we ended this mess in the inside state, curCollection should _NOT_ be
+    // empty.  In this case, we need to add this final point collection as the
+    // final line stting in the line string collection.
+    if (inside)
+    {
+        lineCollection->Add (newLineString);
+    }
+    
+    // Looks pretty simple, maybe that means it will work good; often does.
+    return lineCollection.Detach ();
+}

Modified: trunk/MgDev/Common/Geometry/Spatial/SpatialUtility.h
===================================================================
--- trunk/MgDev/Common/Geometry/Spatial/SpatialUtility.h	2009-09-08 21:26:17 UTC (rev 4211)
+++ trunk/MgDev/Common/Geometry/Spatial/SpatialUtility.h	2009-09-08 22:16:31 UTC (rev 4212)
@@ -109,6 +109,137 @@
     static MgLinearRing* CurveRingToLinearRing(MgCurveRing* curveRing, double maxSpacing, double maxOffset);
     static MgLinearSegment* ArcSegmentToLinearSegment(MgArcSegment* segment, double maxSpacing, double maxOffset);
 
+    ///////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Computes the intersection of two 2D line segments.  Intersection point,
+    /// if any, is returned in the provided result coordinate which (of course)
+    /// must already exist.
+    /// </summary>
+    /// <param name="result">
+    /// The calculated intersection point is returned in this variable which,
+    /// of course, must exist.
+    /// <param name="seg1From">
+    /// The initial point of the first line segment.
+    /// <param name="seg1To">
+    /// The end point of the first line segment.
+    /// <param name="seg2From">
+    /// The initial point of the second line segment.
+    /// <param name="seg2To">
+    /// The end point of the second line segment.
+    /// <returns>
+    /// Return status:
+    /// <list type="table">
+    /// <listheader>
+    ///     <term>Status</term>
+    ///     <description>Meaning</description>
+    /// </listheader>
+    /// <item>
+    ///     <term>-1</term>
+    ///     <description>no intersection, segments are parallel or collinear or
+    ///        a segemnt is of zero length; result remains unchanged
+    ///     </description>
+    /// </item>
+    /// <item><term> 0</term><desription>intersection exists, intersection point is not on either line</description></item>
+    /// <item><term> 1</term><desription>intersection exists, intersection point is on segment 1 only</description></item>
+    /// <item><term> 2</term><desription>intersection exists, intersection point is on segment 2 only</description></item>
+    /// <item><term> 3</term><desription>intersection exists, intersection point is on both segments</description></item>
+    /// </list>
+    /// <remarks>
+    /// In determining if the intersection point resides on a line, an intersection
+    /// point identical to the 'to' point is considered on the line, but an
+    /// intersection point identical to the 'from' point is _NOT_ considered to be
+    /// on the line.  Such a convention is necessary to avoid the appearance
+    /// of two intersections when indeed there is only one when processing a
+    /// a line string, for example.
+    /// </remarks>
+    /// <exception cref="MgNullReferenceException">
+    /// Thrown if any argument is null
+    /// </exception>
+    static INT32 SegmentIntersection (MgCoordinate* result,MgCoordinate* seg1From,
+                                                           MgCoordinate* seg1To,
+                                                           MgCoordinate* seg2From,
+                                                           MgCoordinate* seg2To);
+
+    ///////////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Returns a collection of coordinates with all of the intersection points of
+    /// the provided segment with the polygon provided by the first argument.
+    /// </summary>
+    /// <param name="polyItr">
+    /// An iterator of the closed ring to which the provided segment is
+    /// intersected.
+    /// </param>
+    /// <param name="segFrom">
+    /// The initial point of the line segment to be intersected with the provided
+    /// closed ring.
+    /// </param>
+    /// <param name="segTo">
+    /// The ending point of the line segment to be intersected with the provided
+    /// closed ring.
+    /// </param>
+    /// <returns>
+    /// A 2D coordinate collection of all intersection points; can and often is
+    /// an empty collection.
+    /// </returns>
+    /// <remarks>
+    /// This is a 2D function only, Z and M coordinates are ignored; the returned
+    /// point collection is a collection of <c>MgCoordinateXY</c> objects.<para>
+    /// Note that the first argument is a CoordinateIterator; so it doesn't have to be
+    /// an <c>MgPolygon</c>.  However, this function assumes that the iterator does indeed
+    /// point to a closed ring.
+    /// </remarks>
+    static MgCoordinateCollection* PolySegIntersection (MgCoordinateIterator* polyItr,
+                                                        MgCoordinate* segFrom,
+                                                        MgCoordinate* segTo);
+
+    ///////////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Determines if the provided point is inside (or actually on) the closed
+    /// ring provided bythe polyItr argument.
+    /// </summary>
+    /// <param name="polyItr">
+    /// An iterator of the closed ring which is the subject polygon.
+    /// </param>
+    /// <param name="queryPoint">
+    /// The 2D point whose status is to be determined.
+    /// </param>
+    /// <returns>
+    /// Returns true if the query point is inside or on the provided closed
+    /// ring.
+    /// </returns>
+    /// <remarks>
+    /// Currently, this function calculates the envelope of the provided closed
+    /// ring in order to determine a point which is known to be outside of the
+    /// closed ring.  An overloaded function which accepts a point known to be
+    /// outside the closed ring would be a lot faster.
+    /// </remarks>
+    static bool PointIsInPolygon (MgCoordinateIterator* polyItr,MgCoordinate* queryPoint);
+
+    ///////////////////////////////////////////////////////////////////////////////
+    /// <summary>
+    /// Clips a line string to an arbitrary polygon returning a collection of line
+    /// strings which represent the portions of the the provided line string which
+    /// are inside the provided closed ring.
+    /// </summary>
+    /// <param name="polyItr">
+    /// An iterator to the closed ring to which the provided line string is to be
+    /// clipped.
+    /// </param>
+    /// <param name="lineItr">
+    /// An iterator for the line string which is to be clipped.
+    /// </param>
+    /// <returns>
+    /// A collection of line string objects which represents the portions of the
+    /// provided line string which are inside of the provided closed ring.  This
+    /// collection may be empty.
+    /// </returns>
+    /// <remarks>
+    /// This is a pure 2D function.  The line strings generated will contain
+    /// collections of <c>MgCoordinateXY</c> objects.
+    /// </remarks>
+    static MgLineStringCollection* ClipStringToPolygon (MgCoordinateIterator* polyItr,
+                                                        MgCoordinateIterator* lineItr);
+                                                                                            
 protected:
 
     MgSpatialUtility() {};



More information about the mapguide-commits mailing list