Supported with: ArcGIS Engine, ArcGIS Desktop, ArcGIS Server
Library dependencies: System, SystemUI
Additional library information: Contents, Object Model Diagram
This content is also available in versions that specifically target .NET and Java developers. Click on the appropriate link to view either version.
.NET overview of the Geometry assembly
Java overview of the Geometry package
The Geometry library provides vector representations for Points, MultiPoints, Polylines, Polygons, and Multipatches. Geometries are used by the geodatabase and graphic element systems to define the shapes of features and graphics. They supply operations that are used by the Editor and map symbology systems to define and symbolize features. Spatial References describe where these geometries are located on the earth. They also define the resolution and valid values for the coordinates used by these geometries. Almost every system in ArcObjects uses geometries and spatial references in some way.
To use geometries accurately, consistently and predictably, you need to understand how geometries and spatial references work together.
In addition to the top level geometries (Points, Multipoints, Polylines and Polygons), Paths, Rings and Segments serve as building blocks for polylines and polygons. Polylines contain paths and polygons contain rings. Paths and Rings are sequences of vertices connected by segments. A Segment is a parametric function that defines the shape of the curve connecting its vertices. Segment types include CircularArc, Line, EllipticArc, and BezierCurve. In addition to the X and Y coordinates for each vertex in a geometry, additional vertex attributes can be defined: M (measure), Z (elevation) and ID (foreign key). Envelopes describe the spatial extent of other geometries, and GeometryBags provide operations on collections of geometries.
Geometry objects are not meant to be extended by developers.
Multipoint, polyline and polygon geometries have constraints on their shapes. For example, a polygon must have its interior clearly defined and separated from its exterior. When all constraints are satisfied, a geometry is said to be simple. When a constraint is violated, or it is not known if the constraint is met, then the geometry is said to be non-simple. The ITopologicalOperator, IPolygonN and IPolylineN interfaces provide operations for testing and enforcing simplicity. The SDK documentation for the Simplify method of the ITopologicalOperator describes these rules precisely.
Each vertex of a geometry, in addition to its X and Y coordinates, can optionally have additional attributes, called vertex attributes. The Z vertex attribute is a double precision value that can be used to represent heights or depths relative to a vertical coordinate system. The M vertex attribute, also called a measure, is a double precision value that can be used to establish a linear reference system on a geometry (usually a polyline), such as the exits along a highway. The ID vertex attribute, also called a point ID, is a signed integer that can be used as a foreign database key to associate additional information with each vertex such as survey measurements. Vertex attributes can be added to or removed from any geometry at any time and in any combination. For example, a polyline could start out with no vertex attributes, have Zs added to it, then have IDs added to it, then have its Zs removed. When a geometry is aware of its vertex attributes, those attributes will be persisted as part of the geometry, and will be included in the output of topological operations that involve that geometry. If a geometry is not aware of its attributes, then those attributes will be ignored when the geometry is persisted and the attributes will not appear in the output of a topological operation involving that geometry. The attribute awareness of a geometry is controlled by one of the interfaces IZAware, IMAware, and IPointIDAware. The attribute values are not actually removed from a geometry if its awareness is disabled. One of the polyline examples below illustrates use of the point ID attribute.
Geometries, especially the segment types, have a rich set of methods for defining their location. For examine, look at the IConstructCircularArc interface to see the different ways in which you can define a circular arc segment. Typically, interfaces or methods that include the word 'Construct' in their name use a set of input parameters (including other geometries) to completely define the target geometry. The inputs are not altered.
Top level geometries support the classical set-theoretic operations for generating new geometries including union, intersection, difference, and symmetric difference. These operations are exposed on the ITopologicalOperator interface and usually operate on a pair of geometries at a time. ITopologicalOperator::ConstructUnion can operate on more than two. New geometries are created to represent the results. Top level geometries also support the IRelationalOperator interface, which can perform a variety of tests on a pair of geometries such as disjoint, contains, and touches.
Both of these interfaces use the spatial reference associated with the input geometries when determining the answer. Two important properties of a spatial reference (as described next) are its coordinate grid and its XY tolerance. Different values for these properties can cause the relational and topological operators to produce different results.
Geometries are georeferenced to the real world through a spatial reference. A spatial reference includes the coordinate system and several coordinate grids. A coordinate system includes such information as the unit of measure, the earth model used and, sometimes, how the data was projected. The coordinate grids are mathematical functions that define the XY, Z, and M resolution values along with the corresponding domain extents. Each spatial reference also has a set of tolerance values. A geometry's coordinates (or vertex attributes) must fall within the domain extent and be rounded to the resolution. The tolerance values are used by geometric operations that relate coordinates or compute new ones.
XY values can be georeferenced with a geographic or projected coordinate system. A geographic coordinate system (GCS) is defined by a datum, an angular unit of measure usually either degrees or grads, and a prime meridian. A projected coordinate system (PCS) consists of a linear unit of measure usually meters or feet, a map projection, the specific parameters used by the map projection, and a geographic coordinate system. A PCS or GCS can have a vertical coordinate system as an optional property. A vertical coordinate system (VCS) georeferences Z values. A vertical coordinate system (VCS) includes either a geodetic or vertical datum, a linear unit of measure, an axis direction, and a vertical shift. M, or measure, values do not have a coordinate system.
A spatial reference that includes an unknown coordinate system (UCS) includes a grid (domain extent) and a tolerance only. It is not possible to georeference a geometry associated with a UCS. If at all possible, you should not use a UCS. When a GCS or PCS is used, appropriate default XY domain extent, resolution, and tolerance values can be calculated. All grid and tolerance information for coordinates and attributes is associated with the PCS, GCS or UCS. A VCS georeferences Z coordinates but does not have a well-defined default grid.
The resolution and domain extent values determine how the coordinates of a geometry is stored. Resolution values are in the same units as the associated coordinate system. For example, if a spatial reference is using a projected coordinate system with units of meters, the XY resolution value is defined in meters. For many applications, a resolution value of 0.0001 meters (1/10 mm) is appropriate. You should use a resolution value that is at least 10 times smaller than the accuracy of the data. If a coordinate system is unknown, or for Ms, you will have to set appropriate resolution values according to the data without knowing the unit of measure.
The following equation is used to generate integers for feature data sources that persist coordinate values as integers.
Persisted coordinate = Round( (map coordinate - minimum domain extent) / resolution) (1)
Here, the left side of the equation is the integer value to be persisted. Round is a function that rounds its double precision floating point operand to the nearest 53 bit integer. "Snapping a coordinate to a grid" means applying the equation (1) listed above, followed by applying its inverse, to generate a double precision coordinate rounded to the specified resolution and corresponding to an integer grid point. Personal geodatabases, for example, persist coordinates as double precision values, but those values have been "snapped". Coordinates are not snapped when working with a shapefile.
If you wish to compare coordinates, you have several options. If your coordinates have not yet been "seen" by ArcGIS in any way, then the method of comparison is up to you. Coordinates that have been processed by a topological operator (Simplify, Intersect) or that have been stored into a personal, file, or enterprise geodatabase, however, have been "snapped", as described above. In that case, you have the following options for coordinate comparison:
IRelationalOperator::Equals is a tolerance-based comparison operator. It uses the XY tolerance property of the spatial reference associated with the geometries being compared to determine if two (x,y) coordinate values are equal. This method does not compare Zs, Ms, or point ID vertex attributes.
IClone::IsEqual is also a tolerance-based comparison operator, but compares vertex attributes, using the Z and M tolerances when comparing Z and M attributes. There is no tolerance for the point ID attribute.
IGeometry::SnapToSpatialReference moves the coordinates of a geometry to their closest grid points (see the discussion of snapping above). ISpatialReference2::ApplyPrecision is a low level method which does the same thing but operates on arrays of point structures (WKSPoints) rather than on geometry objects. ISpatialReference2GEN::ApplyPrecision is available for those languages that cannot pass C-style arrays to ArcObjects methods. It is implemented on the SpatialReferenceEnvironment object and delegates to ISpatialReference2::ApplyPrecision. It is important to understand that snapping is a stable operation. The floating point representation of a coordinate may change the first time it has been snapped, but not thereafter.
Use SnapToSpatialReference or ApplyPrecision if you wish to compare double precision quantities exactly (i.e., if you wish to avoid use of the tolerance property). In general, it is difficult to predict if an unsnapped double precision value will compare exactly with a snapped value, even if they appear to be equal when printed as a sequence of base 10 digits. A good reference for gaining a precise understanding of the behavior of double precision quantities is "What Every Computer Scientist Should Know About Floating-Point Arithmetic", by David Goldberg, published in the March, 1991 issue of Computing Surveys. Copyright 1991, Association for Computing Machinery, Inc. One recommendation is to keep the minimum domain X, Y and Z values as close as possible to the extent of the data. This will minimize the exponent shifting that has to occur during the floating point subtraction operation in equation (1) above, and also allow for better compression of the integer versions of the coordinates, as described below.
In addition to the integerization of map coordinates, ArcSDE and file geodatabases compress the resulting integer coordinates by removing leading zeroes among a few other things. Coordinates with large numeric values after integerization don't compress as well as those with smaller numeric values, so coordinates clustered near the upper right corner of the domain extent will not compress as well as those near the lower left, or minimum domain extent.
If you've worked with geometries prior to version 9.2, the resolution values are the inverse of the precision values. The precision values are also known as the xyUnits, zUnits, and mUnits or the scale factor. At 9.2, the terms resolution and precision are often treated as synonyms. There may be parts of the API or documentation that still refer to precision or scale factor when it should use the term resolution instead. The word precision also is used to describe a spatial reference with an enhanced grid, as discussed next.
The coordinate values of a geometry must fall within the appropriate XY, Z, and M domain extents. The largest legal map coordinate value is the upper right of the domain extent. This coordinate value must also be representable as an integer according to (1) above. The domain extents and resolution values are connected. Together they form a grid mesh with the resolution defining the mesh separation, or cell size. Internally, the resolution and domain extents are used to define an integer grid.
At 9.1 and before, each integer coordinate was allotted 31 bits. At 9.2, 53 bits are provided for data sources created and managed by 9.2. Thus for a given resolution, the domain extent can be much larger, or alternatively, for a given domain extent, the resolution can be much smaller than is possible for data using a low precision spatial reference. A data source that stores 53 bit coordinates is always associated with a high precision spatial reference. Existing data sets have not had their spatial references upgraded are always associated with low precision spatial references.
As an example, if the minimum domain value is 0 and the resolution is 1, the maximum domain value for a high precision data source is 9007199254740990 or 253-2. If the resolution is 0.0001, the maximum domain value is 900719925474.0990. These values are for high precision spatial references which are new at version 9.2. Prior to this release, spatial references were what we now call low precision. A low precision spatial reference uses maximum domain values of 2147483647 or 231-1. If the same resolution value of 0.0001 and a minimum domain extent of zero are used, the largest value that a geometry could have is 214748.3647. That is too small for many projected coordinate systems, like UTM and State Plane. So, when you have to work with low precision spatial references, you have to carefully balance the tradeoff between domain extent and the resolution or precision values.
If possible you should always work with high precision spatial references. By default using version 9.2, a new spatial reference is high precision. If you are editing or creating data for a geodatabase (of any type) that has not had its spatial reference upgraded, you will have continue to work with low precision spatial references. New COM interfaces are available on the various spatial reference objects to determine whether one is low or high precision. A new interface is provided on the SpatialReferenceEnvironment object to convert between high and low precision spatial references using certain assumptions.
In addition to the resolution and domain extent properties of a spatial reference's coordinate grid, the XY tolerance property is also extremely important. The XY tolerance is applied to X and Y coordinates during relational and topological operations. The XY tolerance property of a spatial reference describes the minimum allowable separation between points in a simple geometry. The minimum allowable tolerance value is twice the resolution (or 2.0/scale factor). The Z tolerance property is used when validating topologies in a geodatabase. Different tolerance values can produce different answers for relational and topological operations. For example, two geometries might be classified as disjoint (no points in common) with the minimum tolerance, but a larger tolerance might cause them to be classified as touching.
To achieve precise and predictable results using the geometry library, it is essential that the spatial reference of geometries within a workflow is well defined. When performing a spatial operation using two or more geometries, for example an intersection, the coordinate systems of the two geometries must be equal. If the coordinate systems of the geometries are different or undefined, the operation could produce unexpected results. Prior to version 9.2, the resolution (precision) determined the tolerance value used in a geometry operation. Now, a spatial reference should have explicitly defined tolerance values. In two-at-a-time geometry operations such as the methods found on the IRelationalOperator and ITopologicalOperator interfaces, the tolerance value of the left operand geometry is used. If the tolerance property of the spatial reference is undefined, or there is no spatial reference associated with a geometry, a default grid guaranteed to contain the operands, and the minimum allowable tolerance based on the grid, are used.
The spatial reference is not defined when creating a new instance of a geometry. It is the developer's responsibility to define a spatial reference that makes sense for the geometry and for the operation. If an existing geometry is coming from a feature class then usually the spatial reference is well defined and the geometry can be used directly or projected without problems.
Descriptions and code samples for the majority of objects supplied by the geometry system are given below.
GeometryEnviroment provides a way of creating geometries from different inputs and setting or getting global variables for controlling the behavior of geometry methods. It also provides Java and .NET friendly versions of methods originally defined on other geometry objects (see the IGeometryBridge and IGeometryBridge2 interfaces). The GeometryEnvironment object is a singleton object, so calling "new" several times doesn't create a new object each time. Instead, it returns a reference to the existing GeometryEnvironment.
This example uses the IGeometryBridge2 interface on the GeometryEnvironment singleton object to define a polyline from an array of WKSPoint structures. It also uses the SpatialReferenceEnvironment singleton object to create a predefined projected coordinate system. Some of the concepts discussed in the introduction above are used here.
Option Explicit
Public Sub GeometryEnvironment_Test()
Dim pBridge As IGeometryBridge2
Set pBridge = New esriGeometry.GeometryEnvironment
Dim pSRFactory As ISpatialReferenceFactory
Set pSRFactory = New SpatialReferenceEnvironment
Dim pPolyline As IPolyline
Set pPolyline = New esriGeometry.Polyline
' Create a projected coordinate system and define its domain, resolution and xy tolerance
Dim pSRR As ISpatialReferenceResolution
Set pSRR = pSRFactory.CreateProjectedCoordinateSystem(esriSRProjCS_NAD1983UTM_11N)
pSRR.ConstructFromHorizon
Dim pSRT As ISpatialReferenceTolerance
Set pSRT = pSRR
pSRT.SetDefaultXYTolerance
Set pPolyline.SpatialReference = pSRR
' Create an array of WKSPoint structures starting in the middle of the XY domain of the
' projected coordinate system
Dim xmin As Double, xmax As Double, ymin As Double, ymax As Double
Dim pSR As ISpatialReference
Set pSR = pSRR
pSR.GetDomain xmin, xmax, ymin, ymax
Dim m As WKSPoint
m.X = (xmin + xmax) * 0.5
m.Y = (ymin + ymax) * 0.5
Dim aWKS(1 To 10) As WKSPoint
Dim i As Long
For i = 1 To 10
aWKS(i).X = m.X + i
aWKS(i).Y = m.Y + i
Next i
pBridge.AddWKSPoints pPolyline, aWKS
End Sub
For many applications, the coordinates of a geometry are treated as existing in a planar (Cartesian) coordinate space. An Envelope is a rectangle with sides parallel to that space defining the spatial extent of a geometry. It can also describe the extent of the geometry's Z, ID and M vertex attributes. You can obtain (copies of) envelopes of other geometries or create envelopes directly. In the first case, the spatial reference of the envelope is the spatial reference of its defining geometry.
This example determines the spatial extent of the union of two geometries.
Sub Envelope_Example() Dim pE As IEnvelope Dim pGeo1 As IGeometry, pGeo2 As IGeometry Set pGeo1 = 'Obtain geometry from somewhere Set pGeo2 = 'Obtain another geometry Set pE = pGeo1.Envelope 'pE is a copy of pGeo1 envelope pE.Union pGeo2.Envelope 'pE is modified to become the union of the extents of pGeo1 and pGeo2 Debug.Print pE.XMin, pE.YMin, pE.XMax, pE.YMax End Sub
GeometryBag is a set of references to other geometry objects supporting the IGeometry interface. Objects of any level (Segments, Polylines, or Polygons) can be added to the GeometryBag via the IGeometryCollection interface. However, placing objects of different geometry types may not be suitable when using GeometryBag in some topological operations. For example, a GeometryBag must contain strictly polygons, strictly polylines or strictly envelopes when using it as a parameter to the ITopologicalOperator::ConstructUnion. Also, Project/ProjectEx methods should not be applied on GeometryBag if it contains object type of segments.
Like other geometries, a geometry bag has a spatial reference property. A geometry added to a bag will reference the same spatial reference as the bag. If the bag has no spatial reference, then neither will the added geometry after it is added to the bag. This is usually an error. Take care to define the spatial reference of the bag before adding geometries to it.
This example constructs a polygon representing the topological union of several polygons. The source polygons come from a feature class. References to the polygons are inserted into a geometry bag. The geometry bag then is used as the input parameter to the ConstructUnion method. Note that the spatial reference of the geometry bag is defined before adding geometries to it.
Sub GeometryBag_Example()
Dim pFeatureCursor As IFeatureCursor
Dim pGDS As IGeoDataset
Dim pFeatureClass As IFeatureClass
Dim pQueryFilter As ISpatialFilter
Dim pBag As IGeometry
Set pFeatureClass = 'Obtain a reference to a polygon feature class from somewhere
Set pGDS = pFeatureClass
Set pQueryFilter = new SpatialFilter
'Set the properties of the spatial filter *here*
Set pBag = new GeometryBag
'Define the spatial reference of the bag before adding geometries to it
Set pBag.SpatialReference = pGDS.SpatialReference
'Use a non-recycling cursor so each returned geometry is a separate object
Set pFeatureCursor = pFeatureClass.Search(pQueryFilter, False)
Dim pF as IFeature
Set pF = pFeatureCursor.NextFeature
Dim pGC as IGeometryCollection
Set pGC = pBag
While Not pF is Nothing
pGC.AddGeometry pF.Shape 'Add a reference to this feature's geometry into the bag
Set pF = pFeatureCursor.NextFeature
Wend
' Create the polygon that will be the union of the features returned from the search cursor.
' The spatial reference of this feature does not need to be set ahead of time - the
' ConstructUnion method defines the constructed polygon's spatial reference to be the same as
' the input geometry bag.
Dim pUnionedPolygon As ITopologicalOperator
Set pUnionedPolygon = new esriGeometry.Polygon
pUnionedPolygon.ConstructUnion pBag
End Sub
The transformation objects can be used to apply various linear coordinate transformations
to top-level geometries (Points, Multipoints, Polylines, Polygons). Typically, you create a
particular kind of transformation object, define its properties and then pass it to the
geometry being transformed in order to perform the transform on that geometry. Only occasionally
will you need to extract the points from the geometry and transform them directly, or
transform arrays of WKSPoints directly.
AffineTransformation2D is a 3x3 matrix that implements conformal (angle preserving) affine and general affine transformations. A minimum of 2 pairs of points are required to exactly define a conformal affine transformation. A 2D conformal transformation is also called a Helmert transformation. A minimum of 3 pairs of points are required to define a general affine transformation. Additional points are required to determine RMS error information for the transformation. One use for an AffineTransformation2D is to register a paper map into a known coordinate system when digitizing.
The projective transformation requires a minimum of four pairs of points to define the transformation. The projective transformation is only used to transform coordinates digitized directly off high altitude aerial photography or aerial photographs of relatively flat terrain assuming that there is no systematic distortion in the air photos. The projective transformation uses eight parameters.
The 3D version of AffineTransformation2D is a 4x4 matrix. Supports definition of general affine transformations from control points. It will not determine conformal affine transformations.
This example first uses an affine transformation to transform a digitized geometry into ground (projected) coordinates. The same transformation is then applied to an array of double precision raw coordinate values. You may be interested in the latter approach when transforming large numbers of coordinates coming from a text file, binary file, or some other large source of raw coordinates. This avoids the processing overhead of creating COM Point objects for every coordinate.
Sub AffineTransformation2D_Example()
Dim pAff2D As IAffineTransformation2D
Set pAff2D = New AffineTransformation2D
Dim aGroundPoints(1 to 10) As IPoint
Dim aDigitizerPoints(1 to 10) As IPoint
aDigitizerPoints = 'Get the digitizer control point values from somewhere
aGroundPoints = 'Get the ground control coordinate values from somewhere
'(aGroundPoints(i) is the ground point corresponding to aDigitizerPoints(i)
pAff2D.DefineFromControlPoints 10, aDigitizerPoints(1), aGroundPoints(1)
Dim fromToRMS As Double, toFromRMS As Double
pAff2D.GetRMSError fromToRMS, toFromRMS
If fromToRMS > 0.05 Then
Debug.Print "RMS error is too large; please redigitize control points"
Exit Sub
Endif
Dim pDigitizedGeometry As IGeometry
Set pDigitizedGeometry = 'Get geometry to be transformed from digitizer input
Dim pTransformee As ITransform2D
Set pTransformee = pDigitizedGeometry
pTransformee.Transform esriTransformForward, pAff2D
'pDigitizedGeometry is now in the destination coordinate system and should be assigned a
'spatial reference
'Now we will apply the same transformation directly to an array of double precision values
'representing (x,y) points.
'The x,y values are assumed to be interleaved in the array: aFromPoints(1) is the x coordinate
'for the first point, aFromPoints(2) is the y coordinate, etc.
Dim aFromPoints(1 to 50) As Double, aToPoints(1 to 50) As Double
aFromPoints = 'Read array of points from a file
pAff2D.TransformPointsFF esriTransformForward, 50, aFromPoints(1), aToPoints(1)
End Sub
A two dimensional point, optionally with measure (M), height (Z), and ID
attributes.
This example creates a point, associates it with the spatial reference of a feature class, positions it in the center of the domain of that spatial reference, then snaps its coordinates to the spatial reference's coordinate grid.
Sub Point_Example() Dim pSR As ISpatialReference Dim pFC As IFeatureClass Dim pGDS As IGeoDataset Set pFC = 'Get a feature class from somewhere Set pGDS = pFC Set pSR = pGDS.SpatialReference Dim pPoint As IPoint Set pPoint = New esriGeometry.Point Set pPoint.SpatialReference = pSR 'The IPoint interface inherits from the IGeometry interface 'Assign to the point the mathematical (i.e., full double precision resolution) center of 'the XY domain of this spatial reference. Dim xmin As Double, ymin As Double, xmax As Double, ymax As Double pSR.GetDomain xmin, xmax, ymin, ymax pPoint.X = (xmin + xmax) * 0.5 pPoint.Y = (ymin + ymax) * 0.5 ' Snap the double precision center of the domain to a location representable in the domain. ' Specifically, a multiple of the resolution and offset from the xmin, ymin of the domain. Debug.Print "Before snapping: " & CStr(pPoint.X) & ", " & CStr(pPoint.y) pPoint.SnapToSpatialReference Debug.Print "After snapping: " & CStr(pPoint.X) & ", " & CStr(pPoint.y) End Sub
An ordered collection of points; optionally has measure (M), height (Z), and ID
attributes.The IPointCollection interface implemented by a multipoint object provides direct
access to its point elements. This is different than how IPointCollection behaves when that
interface is used to provide access to the vertices of a polyline or polygon. In that case, you are
working with copies of the points.
This example creates a multipoint with point elements being copies of the vertices of an existing polyline. It then offsets those elements 5 units to the right using one transformation method, then offsets them up another 5 units.
Sub Point_Example() Dim pPolyline As IGeometry Dim pPolylinePoints As IPointCollection Dim pMultipoint As IGeometry Dim pMultipointPoints As IPointCollection Set pPolyline = 'Get a polyline from somewhere Set pPolylinePoints = pPolyline Set pMultipoint = New esriGeometry.Multipoint Set pMultipoint.SpatialReference = pPolyline.SpatialReference Set pMultipointPoints = pMultipoint 'Add copies of the polyline vertices to the multipoint pMultipointPoints.AddPointCollection pPolylinePoints Dim pShiftBy5 As IAffineTransformation2D Set pShiftBy5 = New esriGeometry.AffineTransformation pShiftBy5.Move 5, 0 Dim pTransformee As ITransform2D Set pTransformee = pMultipoint pTransformee.Transform esriTransformForward, pShiftBy5 'Shift up by 5 pTransformee.Move 0, 5 pTransformee.Transform esriTransformForward, pShiftBy5 End Sub
The following sample illustrates how to create Multipoint objects.
An ordered collection of paths; optionally has measure (M), height (Z), and ID attributes. The IPointCollection interface on a Polyline manipulates copies of its vertices. Use the IGeometryCollection interface to directly access its paths and the ISegmentCollection interface to directly access its segments. Note that IPointCollection and ISegmentCollection interfaces are also available on Path objects and are characterized the same way.

This example uses an existing polyline to define a new, multipart polyline. In the image below, the input polyline is shown in the background and the new polyline is shown in dark green with its vertices marked. Each part of the new polyline is a single segment normal to a segment from the original polyline, incident at its midpoint, and 1/3 its length.

Public Sub constructpolyline()
Dim pInputG As IGeometry
Set pInputG = 'Get the input polyline from somewhere
Dim pSC As ISegmentCollection
Set pSC = pInputG
Dim pNewG As IGeometry
Set pNewG = New esriGeometry.Polyline
'Always associate new top level geometries with an appropriate spatial reference
Set pNewG.SpatialReference = pInputG.SpatialReference
Dim pNewGC As IGeometryCollection
Set pNewGC = pNewG
Dim pEnumSegs As IEnumSegment
'Iterate over existing polyline segments using a segment enumerator
Set pEnumSegs = pSC.EnumSegments
Dim pS As ISegment
Dim pPart As Long, pSegment As Long
pEnumSegs.Next pS, pPart, pSegment
While Not pS Is Nothing
Dim pN As ILine
Set pN = New esriGeometry.Line
'Geometry methods with _Query_ in their name expect to modify existing geometries.
'In this case, the QueryNormal method modifies an existing line segment (pN) to be the normal vector to
'pS at the specified location along pS
pS.QueryNormal esriNoExtension, 0.5, True, pS.Length / 3, pN
Dim pNewPath As ISegmentCollection
Set pNewPath = New esriGeometry.Path 'Since each normal vector is not connected to others, create a new path for each one
pNewPath.AddSegment pN
pNewGC.AddGeometry pNewPath 'The spatial reference associated with pNewG will be assigned to all incoming paths and segments
pEnumSegs.Next pS, pPart, pSegment
Wend
'pNewG now contains the new, multipart polyline
End Sub
This example shows how to make an existing polyline point ID aware, and efficiently define ID values for each of its vertices. The example assumes that an edit session exists on the workspace containing the feature class whose features are being iterated over.
Public Sub AddPointIDs()
Dim pFC As IFeatureClass
Set pFC = 'Get a feature class from somewhere; it needs to be within an edit session
Dim pCursor As IFeatureCursor
Set pCursor = pFC.Search(Nothing, True)
Dim pFeature As IFeature
Set pFeature = pCursor.NextFeature
While Not pFeature Is Nothing
Dim pID As IPointIDAware
Set pID = pFeature.Shape
pID.PointIDAware = True
'The polyline is now point ID aware. It will persist its point IDs the next
'time it is saved.
Dim pEnumSegs As IEnumSegment
Dim pSegs As ISegmentCollection
Set pSegs = pID
Set pEnumSegs = pSegs.EnumSegments
Dim pSegment As ISegment
Dim lngPart As Long, lngSegment As Long
pEnumSegs.Next pSegment, lngPart, lngSegment
While Not pSegment Is Nothing
Dim sID As ISegmentID
Set sID = pSegment
sID.SetIDs lngSegment, lngSegment + 1
pEnumSegs.Next pSegment, lngPart, lngSegment
Wend
Set pFeature.Shape = pID
pFeature.Store
Set pFeature = pCursor.NextFeature
Wend
End Sub
The following sample illustrates how to create Polyline objects.
A collection of rings ordered by their containment relationship; optionally has measure (M), height (Z) and ID attributes. Each ring is a collection of segments. The IPointCollection interface on polygons and rings manipulates copies of vertices. Use the IGeometryCollection and ISegmentCollection interfaces to access rings and segments directly.

This example builds two multipart polygons in two different ways. The first
polygon is built segment by segment. The second is built by defining its vertices
as an array of WKSPoint structures. The first approach gives you the most control
if you are using advanced construction techniques or curved segments (circular
arcs, bezier curves, etc). The second approach is recommended for efficiently
building polygons from bulk coordinate data that have vertices connected with
straight lines only. The techniques shown here can also be applied to polyline
construction. The first polygon should look something like the following:

Const pi As Double = 3.14159265358979
Public Sub ConstructPolygons()
'Build a polygon segment-by-segment
Dim pSegmentPoly As IPolygon
Set pSegmentPoly = New esriGeometry.Polygon
Set pSegmentPoly.SpatialReference = 'Always define the spatial reference of new top level geometries
'Create the segments and rings - if this were a single part polygon we could add
'segments directly to the polygon and it would create the ring internally.
'You cannot re-use the same ring object; also, when rings are added to the polygon
'it takes ownership of them. You cannot then reuse a ring for building another polygon.
'These same restrictions also apply to segments.
Dim c As ICircularArc
Set c = New esriGeometry.CircularArc
Dim b As IBezierCurve
Set b = New esriGeometry.BezierCurve
Dim r1 As ISegmentCollection, r2 As ISegmentCollection
Set r1 = New esriGeometry.Ring
Set r2 = New esriGeometry.Ring
r1.AddSegment c
r2.AddSegment b
Dim pGC As IGeometryCollection
Set pGC = pSegmentPoly
pGC.AddGeometry r1
pGC.AddGeometry r2
'At this point, we have constructed a _shell_ geometry. It consists of one
'polygon containing two rings, each of which contains one segment.
'However, the coordinates of those segments have not yet been defined.
'Because we still have references to those segments, we can define their
'coordinates now.
Dim cp As IPoint
Set cp = New esriGeometry.Point
cp.X = -10
cp.Y = 0
c.PutCoordsByAngle cp, 0, 2 * pi, 10#
Dim controlPoints(0 To 3) As IPoint
Dim i As Long
For i = 0 To 3
Set controlPoints(i) = New esriGeometry.Point
Next i
controlPoints(0).X = 10
controlPoints(0).Y = 0
controlPoints(1).X = 10
controlPoints(1).Y = 10
controlPoints(2).X = 20
controlPoints(2).Y = 10
controlPoints(3).X = 10
controlPoints(3).Y = 0
b.PutCoords 4, controlPoints(0)
'pPolygon has now been defined. When changing segment coordinates directly
'like this, we need to be careful to let the top level geometry know that
'things have changed underneath it, so that it can delete any cached properties
'that it might be maintaining, such as envelope, length, area, etc.
'Note that when you use certain methods on the top-level geometry implementation
'of IGeometryCollection interface, like AddGeometry, it will automatically
'invalidate any cached properties.
pGC.GeometriesChanged
'Build another polygon from a bunch of points. As before, we will assume that
'two parts (rings) need to be created. If the polygon was single part, we could
'add the points directly to the polygon without first creating a ring.
'At 9.2, the recommended way to add arrays of points to a geometry is to use
'the IGeometryBridge2 interface on the GeometryEnvironment singleton object.
Dim pGBridge As IGeometryBridge2
Set pGBridge = New esriGeometry.GeometryEnvironment
Dim pPointPoly As IGeometryCollection
Set pPointPoly = New esriGeometry.Polygon
Set pPointPoly.Geometry(1).SpatialReference = 'Define the spatial reference of the new polygon
Set r1 = New esriGeometry.Ring 'As noted above, the rings used for the first polygon cannot be reused
Set r2 = New esriGeometry.Ring
Dim aWKSPointBuffer() as WKSPoint
Dim cPoints1 As Long, cPoints2 As Long
cPoints1 = 'The number of points in the first part
ReDim aWKSPointBuffer(0 to cPoints1-1)
aWKSPointBuffer = 'Read cPoints1 into the point buffer
pGBridge.SetWKSPoints r1, aWKSPointBuffer
cPoints2 = 'The number of points in the second part
ReDim aWKSPointBuffer(0 to cPoints2-1)
aWKSPointBuffer = 'Read cPoints2 into the point buffer
pGBridge.SetWKSPoints r2, aWKSPointBuffer
pPointPoly.AddGeometry r1
pPointPoly.AddGeometry r2
'pPointPoly has now been defined
End Sub
The following sample illustrates how to create Polygon objects.
The MultiPatch geometry type was initially developed to address the needs for a 3D Polygon geometry type--unconstrained by 2D validity rules. Without eliminating the constraints that rule out 'vertical walls', for example, representing extruded 2D lines and footprint-polygons for 3D visualization would not be possible. Besides eliminating 2D constraints, MultiPatches provide better control over polygon face orientations, and a better definition of polygon face interiors.
Since version 9.0, MultiPatches have also been extended to provide advanced geometric representations for 3D features. These complex 3D objects can be part of a Synthetic Landscape Model, stored in a geodatabase. The target of these extensions is improved visualization quality.
One key new capability since version 9.0 is that of supporting per-vertex normals that improve the quality of shading under illumination. Another key capability is that of precise image/texture mapping on to the MultiPatch geometry, via explicit texture coordinates. The geometry of a MultiPatch is in-lined with a GeometryMaterialList, which contains one or more GeometryMaterials. These GeometryMaterials can be a color, a texture (image), or both. The new class for this functionality is GeneralMultiPatchCreator, which is used to construct a MultiPatch.
The relationship between objects used in MultiPatch construction is illustrated below:

Another key improvement to MultiPatches is the support of the new Triangles part. This extends the original MultiPatch parts (i.e., Triangle Strip, Triangle Fan, Outer Ring, Inner Ring, First Ring, and Ring). The Triangles part is introduced to complete the range of vertex-based part types and facilitate capturing the output results of different triangle-mesh tessellators or 3D object importers (e.g., from 3D Studio models), which contain non-connected triangles, into a MultiPatch geometry. Of course, developers can also make use of the Triangles part as a useful addition to the initial MultiPatch part types offered.
A single Triangles part represents a collection of triangular faces. Each consecutive triplet of vertices defines a new triangle. The size of a Triangles part must be a multiple of three (see the following diagram).

Regarding the use of rings, the following are important notes about MultiPatch geometries:
To construct a textured MultiPatch geometry starting at ArcGIS version 9.0, it is recommended that you use the new interface IGeneralMultiPatchCreator even though the old interface IEncode3DProperties that includes the PackTexture2D method still works. With the introduction of explicit vertex normals and texture coordinates, the usage of IEncode3DProperties is now deprecated.
The following shows a simple example of constructing a textured MultiPatch geometry using a TriangleStrip that resembles a vertical polygon, assuming it is 300 (width) x 100 (height) in size.
'Prepare the geometry material list:
Dim pTexture As IGeometryMaterial
Set pTexture = New GeometryMaterial
pTexture.TextureImage = "C:\Temp\MyImage.bmp"
Dim pMaterialList As IGeometryMaterialList
Set pMaterialList = New GeometryMaterialList
pMaterialList.AddMaterial pTexture
'Create the multipatch:
Dim pMPCreator As IGeneralMultiPatchCreator
Set pMPCreator = New GeneralMultiPatchCreator
pMPCreator.Init 4, 1, False, False, False, 4, pMaterialList
'Set the texture coordinates for a panel:
Dim pTxLL As WKSPoint, pTxLR As WKSPoint, pTxUR As WKSPoint, pTxUL As WKSPoint
pTxUL.X = 0#: pTxUL.Y = 0#: pTxUR.X = 1#: pTxUR.Y = 0#
pTxLL.X = 0#: pTxLL.Y = 1#: pTxLR.X = 1#: pTxLR.Y = 1#
Dim pUL As WKSPointZ, pUR As WKSPointZ
Dim pLL As WKSPointZ, pLR As WKSPointZ
pUL.X = 0#: pUL.Y = 0#: pUL.Z = 0#: pUR.X = 300: pUR.Y = 0#: pUR.Z = 0#
pLL.X = 0#: pLL.Y = 0#: pLL.Z = -1 * 100: pLR.X = 300: pLR.Y = 0#: pLR.Z = -1 * 100
With pMPCreator
'Set up part:
.SetPatchType 0, esriPatchTypeTriangleStrip 'could also use a Ring or a TriangleFan
.SetMaterialIndex 0, 0
.SetPatchPointIndex 0, 0
.SetPatchTexturePointIndex 0, 0
'Set real world points:
.SetWKSPointZ 0, pUR
.SetWKSPointZ 1, pLR
.SetWKSPointZ 2, pUL
.SetWKSPointZ 3, pLL
'Set texture points:
.SetTextureWKSPoint 0, pTxUR
.SetTextureWKSPoint 1, pTxLR
.SetTextureWKSPoint 2, pTxUL
.SetTextureWKSPoint 3, pTxLL
End With
Dim pPatch As IMultiPatch
Set pPatch = pMPCreator.CreateMultiPatch
SpatialReferenceEnvironment is a singleton object used for creating, loading, and storing entire spatial references. Spatial References are often cloned and copied internally. Setting up the SpatialReferenceEnvironment as a singleton object conserves resources and makes it less likely that a spatial reference is deleted completely before it is no longer in use. The SpatialReferenceEnvironment can also create predefined components used for building spatial references (projections, datums, prime meridians, etc). Finally, you can use it to convert between low and high precision spatial references. The following examples demonstrate these capabilities.
ArcObjects includes a vast array of predefined spatial reference systems and building blocks for spatial reference systems. Each predefined object is identified by a factory code. Factory codes are defined enumeration sets that begin with 'esriSR'. Use the enumeration macro rather than the integer value it represents. Occasionally, the code value for which an enumeration stands may change. This is because many of the values are from the EPSG database (see http://www.epsg.org) which is becoming an industry standard. This example shows how to create predefined spatial reference objects and use them as input to geodatabase operations.
Dim pSpatRefFact As ISpatialReferenceFactory Set pSpatRefFact = New SpatialReferenceEnvironment Dim pPCS As IProjectedCoordinateSystem Set pPCS = pSpatRefFact.CreateProjectedCoordinateSystem(esriSRProjCS_WGS1984UTM_11N)
The ISpatialReferenceFactory interface provides methods that use the FactoryCode to generate predefined factory spatial reference objects. There are three types of functions on this interface: those that return single objects, those that return a set of objects of the same type, and those that are used to import and export SpatialReference objects to and from a PRJ file or a PRJ string representation. For example, the CreateGeographicCoordinateSystem function takes as its only parameter an integer that represents the FactoryCode of a predefined geographic coordinate system. The function returns a fully instantiated GCS object that can then be queried for its properties and classes.
Thousands of coordinate system related objects are available through macros. The enumerations all begin with "esriSR". Use the enumeration macro rather than the integer value it represents. Many of the FactoryCode values are based on an external standard and the values may change.
The next type of function on the ISpatialReferenceFactory interface returns a complete Set of objects. For example, the following code shows how the CreatePredefinedProjections function returns a set that contains all the available Projection objects. The set is iterated through, and the name of each Projection with the set is obtained. These type of functions are useful for developers who may wish to populate a pulldown selection list of available SpatialReference objects.
Dim pProjection As IProjection
Dim pProjectionSet As ISet
Dim pSpatialRefFact As ISpatialReferenceFactory
Set pSpatialRefFact = New SpatialReferenceEnvironment
Set pProjectionSet = pSpatialRefFact.CreatePredefinedProjections
Debug.Print pProjectionSet.Count
Dim i As Integer
pProjectionSet.Reset
For i = 0 To pProjectionSet.Count - 1
Set pProjection = pProjectionSet.Next
Debug.Print pProjection.Name
Next i
The third type of function supported by ISpatialReferenceFactory deals with PRJ files and strings. CreateESRISpatialReferenceFromPRJFile takes an old or new style PRJ file and creates either a geographic or projected coordinate system from it, depending on the file contents. The old style PRJ is used with coverages, TINs, and GRIDs. CreateESRISpatialReferenceFromPRJ is used to create a SpatialReference based on the string buffer of an old style PRJ file. While CreateESRISpatialReference is similar, the string buffer must be in the format of a new PRJ file. This code sample shows how to create a SpatialReference coordinate system directly from a PRJ file (both old and new style files are supported):
Dim pSpatialRefFact As ISpatialReferenceFactory
Set pSpatialRefFact = New SpatialReferenceEnvironment
Dim pProjCoordSys As IProjectedCoordinateSystem
Set pProjCoordSys = _
pSpatialRefFact.CreateESRISpatialReferenceFromPRJFile("C:\Data\UKData\county.prj")
This example creates a predefined projected coordinate system, defines its coordinate grid and tolerance values, then exports and imports it 2 different ways. First it exports the coordinate system to a .prj file, then uses the contents of the .prj file to create a second projected coordinate system.
At the end of this process you might expect that both projected coordinate systems will be identical, but they aren't. PRJ files do not store coordinate grid information, so recreating a spatial reference from a PRJ file will lose any coordinate grid and tolerance information that might have been defined for it.
Complete equality of spatial references (equal coordinate systems and equal coordinate grids) cannot be checked with one method. IClone::IsEqual compares coordinate systems but not coordinate grids. You need to use other methods to do the latter.
Sub ImportExportSR_Example()
'Instantiate a predefined spatial reference and set its coordinate grid information
Dim pSRF as ISpatialReferenceFactory
Set pSRF = new esriGeometry.SpatialReferencEnvironment
Dim pPCS as IProjectedCoordinateSystem
Set pPCS = pSRF.CreateProjectedCoordinateSystem(esriSRProjCS_WGS1984UTM_10N)
Dim pSRR as ISpatialReferenceResolution
Dim pSRT as ISpatialReferenceTolerance
Set pSRR = pPCS
Set pSRT = pPCS
pSRR.ConstructFromHorizon
pSRT.SetDefaultXYTolerance
'Export the pcs to a prj file
Dim fileName as String
fileName = "c:\temp\utm10.prj"
pSRF.ExportESRISpatialReferenceToPRJFile(fileName, pPCS)
'Re-hydrate it as a new spatial reference object
Dim pPCS2 as ISpatialReference
Set pPCS2 = pSRF.CreateESRISpatialReferenceFromPRJFile(fileName)
'See if they're equal
Dim pCompare as IClone
Set pCompare = pPCS
'Should be true, but we haven't checked coordinate grid information yet!
Debug.Print pCompare.IsEqual(pPCS2)
Dim pComparePrecisions as ISpatialReference2
Set pComparePrecisions = pPCS
'Should be false, PRJ files do not persist coordinate grid information
Debug.Print pComparePrecisions.IsXYPrecisionEqual(pPCS2)
End Sub
Dim pSR As ISpatialReference2
Dim pSRF As ISpatialReferenceFactory3
Dim pSR3 As ISpatialReference3
Dim pSRInfo As ISpatialReferenceInfo
Dim pSRResolution As ISpatialReferenceResolution
Dim pSRTolerance As ISpatialReferenceTolerance
Dim pControlPrecision2 As IControlPrecision2
Dim XMin As Double
Dim XMax As Double
Dim YMin As Double
Dim YMax As Double
Set pSRF = New SpatialReferenceEnvironment
Set pSR = pSRF.CreateESRISpatialReferenceFromPRJFile("D:\ArcGIS\Coordinate Systems\Geographic Coordinate Systems\World\WGS 1984.prj")
Set pSRResolution = pSR
Set pControlPrecision2 = pSR
pControlPrecision2.IsHighPrecision = True 'Flip this to false if low precision
pSRResolution.ConstructFromHorizon 'this is the KEY, Construct Horizon THEN
pSRResolution.SetDefaultXYResolution 'Set Default
pSR.GetDomain XMin, XMax, YMin, YMax
Debug.Print "Domain : "; XMin, XMax, YMin, YMax
This example illustrates one way to convert a pre 9.1 low precision spatial reference to a 9.2 high precision spatial reference. The original spatial reference is not modified. A copy is made and altered.
In general, you can construct a high precision spatial reference in any way that makes sense for your 9.1 data. The approach shown here is used for compatibility with ArcSDE dual-resolution data layers, which have a constraint on the relationship between the low and high precision scale factors.
Sub LoHiConversion_Example()
Dim pFC91 as IFeatureClass
Set pFC91 = 'get a feature class from a pre 9.2 geodatabase somehow
Dim pGDS91 as IGeoDataset
Set pGDS91 = pFC91
Dim pSR91 as ISpatialReference
Set pSR91 = pGDS91.SpatialReference
Dim fx as double, fy as double, s as double
pSR91.GetFalseOriginAndUnits fx, fy, s
Debug.Print "low precision coordinate grid definition:"
Debug.Print "false x: " & CStr(fx) & ", false y: " & CStr(fy) & ", scale factor: " & CStr(s)
Dim pSRE as ISpatialReferenceFactory3
Set pSRE = new esriGeometry.SpatialReferenceEnvironment
Dim pSR92 as ISpatialReference
Set pSR92 = pSRE.ConstructHighPrecisionSpatialReference(pSR91, -1, -1, -1)
pSR92.GetFalseOriginAndUnits fx, fy, s
Debug.Print "high precision coordinate grid definition:"
Debug.Print "false x: " & CStr(fx) & ", false y: " & CStr(fy) & ", scale factor: " & CStr(s)
End Sub
A geographic coordinate system includes a name, angular unit of measure, datum (which includes a spheroid), and a prime meridian. It is a model of the earth in a three dimensional coordinate system. Latitude-longitude, or lat/lon, data is in a geographic coordinate system. You can access the majority of the properties and methods through IGeographicCoordinateSystem interface with a few more properties are available in IGeographicCoordinateSystem2. Although most developers will not need to create a custom geographic coordinate system, the IGeographicCoordinateSystemEdit contains the Define and DefineEx methods.
The following code demonstrates how to use the Define method to create a user-defined geographic coordinate system. The ISpatialReferenceFactory allows you to create the Datum, PrimeMeridian, and AngularUnit component parts. These components can also be created using a similar Define method available on their classes.
Dim pUserDefinedGeogCS As IGeographicCoordinateSystem
Dim pSpatRefFact As ISpatialReferenceFactory
Set pSpatRefFact = New SpatialReferenceEnvironment
Dim pDatum As IDatum
Set pDatum = pSpatRefFact.CreateDatum(esriSRDatum_OSGB1936)
Dim pPrimeMeridian As IPrimeMeridian
Set pPrimeMeridian = pSpatRefFact.CreatePrimeMeridian(esriSRPrimeM_Greenwich)
Dim pUnit As IUnit
Set pUnit = pSpatRefFact.CreateUnit(esriSRUnit_Degree)
Dim pGCSEdit As IGeographicCoordinateSystemEdit
Set pGCSEdit = New GeographicCoordinateSystem
pGCSEdit.Define "UserDefined Geographic Coordinate System", _
"UserDefined GCS", "UserDefined", _
"User Defined Geographic Coordinate System based on OSGB1936", _
"Suitable for the UK", pDatum, pPrimeMeridian, pUnit
' QI for the result
Set pUserDefinedGeogCS = pGCSEdit
The following C++ code shows how the DefineEx method can be used. It uses a SpatialReferenceFactory to create the Datum, PrimeMeridian, and Unit components.
// Smart pointer variables used
IDatumPtr ipDatum;
IPrimeMeridianPtr ipPrimeMeridian;
IUnitPtr ipUnit;
IAngularUnitPtr ipAngularUnit;
// Create the factory and the component parts
ISpatialReferenceFactoryPtr
ipFactory(CLSID_SpatialReferenceEnvironment);
ipFactory->CreateDatum(esriSRDatum_OSGB1936,&ipDatum);
ipFactory->CreatePrimeMeridian(esriSRPrimeM_Greenwich,&ipPrimeMeridian);
ipFactory->CreateUnit(esriSRUnit_Degree,&ipUnit);
IGeographicCoordinateSystemEditPtr
ipGeoCSEdit(CLSID_GeographicCoordinateSystem);
IGeographicCoordinateSystemPtr ipGCS;
// QI for the AngularUnit from the Unit
// - this is achieved by the SmartPointers
ipAngularUnit = ipUnit;
// Make the string descriptions
CComBSTR name(_T("User Defined Geographic Coordinate System"));
CComBSTR alias(_T("UserDefined"));
CComBSTR abbreviation(_T("User"));
CComBSTR remarks(_T("User Define GCS based on OSGB1936"));
CComBSTR useage(_T("Suitable for the UK"));
// Make the call
HRESULT hr;
hr = ipGeoCSEdit->DefineEx(name, alias, abbreviation,
remarks, useage, ipDatum, ipPrimeMeridian, ipAngularUnit);
// QI for the result
ipGCS = ipGeoCSEdit;
To access the hundreds of predefined geographic coordinate systems, ISpatialReferenceFactory has the CreateGeographicCoordinateSystem method. The predefined geographic coordinate systems are listed in the esriSRGeoCSType, esriSRGeoCS2Type, and esriSRGeoCS3Type enumerations. The parts of a geographic coordinate system, such as the datum, angular unit, and prime meridian, are objects as well. All support ISpatialReference2 and ISpatialReferenceFactory. Make use of the predefined objects available in the various esriSR* enumerations.
The IGeographicCoordinateSystem2 interface supplies the AngularConversionFactor method, which will return a value that converts the units of measure between two geographic coordinate systems.
The ExtentHint, LeftLongitude, and RightLongitude properties are interrelated. Usually, data in a geographic coordinate system has longitude values between -180 and 180 if the unit of measure is degrees. Some datasets are designed to use a minimum longitude value of 0 or -360. The LeftLongitude property controls whether the data is considered as -360 to 0, -180 to 180, or 0 to 360. You only need to worry about this is you're inverse projecting projected coordinates for storage in a GCS-based feature class that has a non-standard longitude range. The ArcObjects framework usually deals with this detail for you. Note that the left longitude property is not considered when comparing two GCS for equality.
GetHorizon returns a WKSEnvelope describing the extent of a geographic coordinate system based on its unit of measure and the LeftLongitude. This method can be used to define a standard coordinate grid for the GCS. It is used internally by the ISpatialReferenceResolution::ConstructFromHorizon method.
The following samples illustrate the use of the GeographicCoordinateSystem objects.
A projected coordinate system includes a name, linear unit of measure, geographic coordinate system, map projection, and any parameters required by map projection. Using the term 'projection' for a coordinate system is imprecise. The term 'projection' should be used for the actual mathematical function. Transverse Mercator and Lambert Conformal Conic are map projections. UTM and State Plane are projected coordinate systems that are based on particular map projections. Each projected coordinate system must include a geographic coordinate system. Map projection parameters can be linear, angular, or unitless. A unitless parameter includes scale factor and option. Angular parameters are the central meridian, standard parallels and latitude of origin. Linear parameters are false easting and false northing. Use the GetDefaultParameters method on the IProjection interface to determine which parameters a particular map projection expects.
The parts of a projected coordinate system, such as the projection, linear unit, and geographic coordinate system, are objects as well. All support ISpatialReference2 and ISpatialReferenceFactory. When defining a custom projected coordinate system, make use of the predefined objects available in the various esriSR* enumerations.
You can access the majority of the properties and methods through IProjectedCoordinateSystem2 interface although a few more properties are available in IProjectedCoordinateSystem3 and IProjectedCoordinateSystem4. The IProjectedCoordinateSystemEdit contains the Define method which allows you to define a custom projected coordinate system. To access the hundreds of predefined projected coordinate systems, ISpatialReferenceFactory has the CreateProjectedCoordinateSystem method. The predefined projected coordinate systems are listed in the esriSRProjCSType, esriSRProjCS2Type, esriSRProjCS3Type, and esriSRProjCS4Type enumerations.
The IProjectedCoordinateSystemEdit interface provides you with the Define method to create your own PCS object based on parameters such as Name, GeographicCoordinateSystem, projectedUnit, Projection and, if necessary, projection Parameters.
'Create a factory
Dim pSpatRefFact As ISpatialReferenceFactory2
Set pSpatRefFact = New SpatialReferenceEnvironment
'Create a projection, gcs and unit using the factory
Dim pProjection As IProjection
Dim pGCS As IGeographicCoordinateSystem
Dim pUnit As IUnit
Dim pLinearUnit As ILinearUnit
Set pProjection = pSpatRefFact.CreateProjection(esriSRProjection_Sinusoidal)
Set pGCS = pSpatRefFact.CreateGeographicCoordinateSystem(esriSRGeoCS_WGS1984)
Set pUnit = pSpatRefFact.CreateUnit(esriSRUnit_Meter)
Set pLinearUnit = pUnit
'Get the default parameters from the Projection
Dim pParams(16) As IParameter
pProjection.GetDefaultParameters pParams(0)
'Create a projected coordinate system using the Define method
Dim pProjCoordSysEdit As IProjectedCoordinateSystemEdit
Dim pProjCoordSys As IProjectedCoordinateSystem
Set pProjCoordSysEdit = New ProjectedCoordinateSystem
pProjCoordSysEdit.Define "Newfoundland", _
"NF_LAB", "NF", "Most Eastern Province in Canada", _
"When making maps of Newfoundland", pGCS, _
pLinearUnit, pProjection, pParams
The following samples illustrate the use of the ProjectedCoordinateSystem objects.
Parameters are required by both projected coordinate systems and geographic transformations. For example, to define a Lambert Azimuthal Equal Area projected coordinate system, only the central meridian and latitude of origin parameters are required by the mathematical algorithm that actually performs the projection.
The IParameter interface has an Index and a Value. The value is self-explanatory and refers to the internal array that holds the parameters for a projected coordinate system or a geographic transformation. The ISpatialReferenceFactory can be used to create new parameters. Here is an example of how to use the CreateParameter method and the esriSR_ParameterType enumeration. The SpatialReferenceFactory provides default values for each type of parameter. The values can easily be changed.
Dim pSpatRefFact As ISpatialReferenceFactory2 Set pSpatRefFact = New SpatialReferenceEnvironment Dim pParameter As IParameter Set pParameter = pSpatRefFact.CreateParameter(esriSRParameter_LatitudeOfOrigin) Debug.Print pParameter.Name Debug.Print pParameter.Index Debug.Print pParameter.Value pParameter.Value = 45 Debug.Print pParameter.Value
The following code demonstrates how to get the parameters from a projected coordinate system. It assumes that the projected coordinate is already defined. These parameters are passed to the client by reference; it is then possible to modify the value of the parameters directly. If this is done, then the Changed method on the ProjectedCoordinateSystem must be called.
'pPcs is the projected coordinate system object
'Create an array of IParameters with 16 elements
Dim pParams(16) As IParameter
'Pass the address of the first element of the array and get the parameters
pPcs.GetParameters pParams(0)
Dim pParam As IParameter
'Iterate through the array of Parameters
Dim i As Integer
For i = 0 To 15
Set pParam = pParams(i)
If Not (pParam Is Nothing) Then
Debug.Print pParam.Name, pParam.Index, pParam.Value
End If
Next i
The following code shows how to change a Parameter using the same variables.
'Pass the address of the first element of the array and get the parameters pPcs.GetParameters pParams(0) Dim pParam As IParameter 'Get the Central Meridian Parameter Set pParam = pParams(2) 'Set the new value pParam.Value = 123 'Tell the projected coordinate system that it has changed pPcs.Changed
The following example uses the GetDefaultParameters method on the IProjection interface to retrieve a set of the required parameters for a projection. Next, set some values and create a new projected coordinate system using these parameters, then make a call to IProjectedCoordinateSystem::GetParameters to verify that the parameters have been set.
'Create a factory
Dim pSpatRefFact As ISpatialReferenceFactory2
Set pSpatRefFact = New SpatialReferenceEnvironment
'Create a projection, gcs and unit using the factory
Dim pProjection As IProjection
Dim pGCS As IGeographicCoordinateSystem
Dim pUnit As IUnit
Dim pLinearUnit As ILinearUnit
Set pProjection = pSpatRefFact.CreateProjection(esriSRProjection_Sinusoidal)
Set pGCS = pSpatRefFact.CreateGeographicCoordinateSystem(esriSRGeoCS_WGS1984)
Set pUnit = pSpatRefFact.CreateUnit(esriSRUnit_Meter)
Set pLinearUnit = pUnit
'Get the default parameters from the Projection
Dim i As Integer
Dim pParameter As IParameter
Dim pParams(16) As IParameter
pProjection.GetDefaultParameters pParams(0)
'Iterate through the Parameters and print out their name and value
For i = 0 To 15
Set pParameter = pParams(i)
If Not (pParameter Is Nothing) Then
Debug.Print pParameter.Name, pParameter.Index, pParameter.Value
End If
Next i
'Reset one of the parameter values
Set pParameter = pParams(2)
pParameter.Value = 45
'Create a projected coordinate system using the Define method
Dim pProjCoordSysEdit As IProjectedCoordinateSystemEdit
Dim pProjCoordSys As IProjectedCoordinateSystem
Set pProjCoordSysEdit = New ProjectedCoordinateSystem
pProjCoordSysEdit.Define "Newfoundland", "NF_LAB", "NF", _
"Most eastern Province in Canada", "When making maps of Newfoundland", _
pGCS, pLinearUnit, pProjection, pParams
Set pProjCoordSys = pProjCoordSysEdit
'Get the parameters from your new projected coordinate system and verify
'that the parameter value was changed.
pProjCoordSys.GetParameters pParams(0)
'Iterate through the Parameters and print their name and value
For i = 0 To 15
Set pParameter = pParams(i)
If Not (pParameter Is Nothing) Then
Debug.Print pParameter.Name, pParameter.Index, pParameter.Value
End If
Next i
A vertical coordinate system includes a name, linear unit of measure, a vertical or geodetic (horizontal) datum, a direction, and optionally, a vertical shift. A vertical coordinate system defines the origin of Z coordinate values. A common application is for Z values to represent elevations or depths. If Z values increase 'up' (against the direction of gravity) or 'down' (in the direction of gravity). You can access the majority of the properties and methods through IVerticalCoordinateSystem interface. Although most developers will not need to create a custom vertical coordinate system, the IVerticalCoordinateSystemEdit contains the Define method.
The following two code samples demonstrate how to use the Define method to create user-defined vertical coordinate systems. The ISpatialReferenceFactory interface allows you to create the Datum, VerticalDatum, and LinearUnit component parts. These components can also be created using a similar Define method available on their classes. The first sample creates a gravity-related vertical coordinate system that uses a vertical datum, while the second one creates an ellipsoid-based vertical coordinate system.
'Creates a gravity-related vertical coordinate system.
Dim pVerticalCoordinateSystemEdit As IVerticalCoordinateSystemEdit
Set pVerticalCoordinateSystemEdit = New VerticalCoordinateSystem
Dim pVerticalCS As IVerticalCoordinateSystem
Dim pVerticalDatum As IVerticalDatum
'Create the SpatialReferenceFactory to access existing component parts.
Dim pSRF As ISpatialReferenceFactory3
Dim pSRI As ISpatialReferenceInfo
Set pSRF = New SpatialReferenceEnvironment
Set pVerticalDatum = pSRF.CreateVerticalDatum(esriSRVertDatum_Taranaki)
'Because a VCS can be based upon Datum or VerticalDatum, IHVDatum is used
'when defining a vertical coordinate system.
Dim pHVDatum As IHVDatum
Set pHVDatum = pVerticalDatum
Dim plunit As ILinearUnit
Set plunit = pSRF.CreateUnit(esriSRUnit_Meter)
'The Direction is set to -1 and the VerticalShift is set to 40.
pVerticalCoordinateSystemEdit.Define "New VCoordinateSystem",
"VCoordinateSystem alias", "abbr", "Test for options",
"New Zealand", pHVDatum, plunit, 40, -1
Set pVerticalCS = pVerticalCoordinateSystemEdit
'Creates an ellipsoid-based vertical coordinate system.
Dim pVCSe As IVerticalCoordinateSystem
Dim pHVDatume As IHVDatum
Dim pDatum As IDatum
Dim pLUnite As ILinearUnit
Dim pVCSEdit As IVerticalCoordinateSystemEdit
Set pVCSEdit = New VerticalCoordinateSystem
Set pLUnite = pSRF.CreateUnit(esriSRUnit_Foot)
Set pDatum = pSRF.CreateDatum(esriSRDatum_WGS1984)
Set pHVDatume = pDatum
'Direction is again positive down, while the vertical shift is 0.4839
pVCSEdit.Define "WGS84 vcs", "WGS84 ellipsoid", "w84 3d",
"WGS84 ell-based vcs", "everywhere!",
pHVDatume, pLUnite, 0.4839, -1
Set pVCSe = pVCSEdit
To access the predefined vertical coordinate systems and datums, ISpatialReferenceFactory3 has the CreateVerticalCoordinateSystem and CreateVerticalDatum methods. The predefined vertical datums and coordinate systems are listed in the esriSRVerticalDatumType and esriSRVerticalCSType enumerations.
Moving your data between projected coordinate systems may also involve transforming between geographic coordinate systems. Because the geographic coordinate systems contain datums that are based on spheroids, a geographic transformation also changes the underlying spheroid. Other frequently used terms for a geographic transformation include datum shift and geodetic transformation.
A geographic transformation is a mathematical operation that takes the coordinates of a point in one geographic coordinate system and returns the coordinates of the same point in another geographic coordinate system. There is also an inverse transformation to allow coordinates to be put back to the first coordinate system from the second. There are many different types of mathematical operations used to achieve this task.
To illustrate the above, consider the following scenario. You have a known geographic position in the State of Kansas: 97.32 W, 37.68 N. This same location, when displayed with UTM Grid Zone 14N for Kansas (based on the NAD1927 geographic coordinate system), will have planar coordinates of 648147.22m E, 4171434.25m N. The exact same geographic location when using the UTM Grid Zone 14N (based on the NAD1983 geographic coordinate system) will have planar coordinates of 648115.09m E, 4171640.19m N. This is a difference of -12.13 meters in the Eastings and 204.86 meters in the Northings.
Thus, if you have two datasets that are projected, they may be on different projected coordinate systems, and their respective coordinate systems may be based on different geographic coordinate systems. It might not be enough to simply change the parameters of the projected coordinate system. You may experience a misalignment between the two datasets even when both are displayed using a common projected coordinate system. The magnitude of the error will vary depending on the geographic coordinate systems used and the relative accuracy of the data. A geographic transformation should minimize these inaccuracies.
Older geographic coordinate systems are usually 'local' systems. They are designed for a particular region or country. As measuring techniques and data became available, new geographic coordinate systems have often been defined for the same area. A geographic transformation converts data between two geographic coordinate systems. A GeoTransformation includes a name, two geographic coordinate systems (from and to), a method or type, and any parameters required for the method. Each method or type is a class. The available transformation types are:
The interfaces on these classes allow you to set any parameters needed by the transformation type. The HARN, NADCON, and NTv2 transformations are grid-based. They use a file on-disk to calculate the data shifts. Use the IGridTransformation interface to access the on-disk information.
Use the IGeoTransformation interfaces to set the from and to spatial references. A GeoTransformation is always defined in a particular direction--FROM geographic coordinate system 1 TO geographic coordinate system 2. The ProjectEx method on IGeometry2 has a direction parameter. Set it to esriTransformForward if you want apply the GeoTransformation in the order that it is defined. If you want to apply it in the opposite direction, use esriTransformReverse.
To access the hundreds of predefined geographic transformations, ISpatialReferenceFactory has the CreateGeoTransformation method. The predefined geographic transformations are listed in the esriSRGeoTransformationType, esriSRGeoTransformation2Type, and esriSRGeoTransformation3Type enumerations. The following code illustrates creating a geotransformation using the spatial reference factory and the GetSpatialReferences methods.
Dim pSpatRefFact As ISpatialReferenceFactory2 Set pSpatRefFact = New SpatialReferenceEnvironment Dim pGeotrans As IGeoTransformation Dim pFromSR As ISpatialReference Dim pToSR As ISpatialReference 'Mean for Great Britain Set pGeotrans = pSpatRefFact.CreateGeoTransformation(esriSRGeoTransformation_OSGB1936_To_WGS1984_1) pGeotrans.GetSpatialReferences pFromSR, pToSR Debug.Print pGeotrans.Name
Debug.Print pFromSR.Name, pToSR.Name
A CompositeGeoTransformation is a multistep geotransformation. Use the ICompositeGeoTransformation interface when you need to define a geographic transformation operation that requires the use of an intermediate geographic coordinate system. For example, no direct path from one geographic coordinate system to another exists, but you can use a third geographic coordinate system to get from one to another. For example, Cameroon uses both the Adindan and Minna geographic coordinate systems. While it is not possible to convert directly between Adindan and Minna, you can convert both to WGS 1984. So, you can go from Adindan to WGS 1984, and then from WGS 1984 to Minna. The transformation method actually goes from Minna to WGS 1984, so you need to state that you want to go in the reverse direction (WGS 1984 to Minna). To specify the direction of a transformation, use the esriTransformDirection enumerations (esriTransformForward and esriTransformReverse).
The forward direction through this composite geotransformation takes you from Adindan to Minna. The reverse direction through this geotransformation takes you from Minna to Adindan. This composite geotransformation has two components. That is, it has two (direction, geotransformation) pairs:
Going forward through the composite geotransformation is the same as going forward through the first component geotransformation and backward through the second component geotransformation. Going reverse through the composite geotransformation is the same as going forward through the second geotransformation and backward through the first geotransformation.
In other words, you need the component directions and component ordering to define what forward and reverse mean at the composite level. The order is important. Once you build the composite transformation, it acts just like a regular transformation.
The following samples illustrate the use of the Tranformations objects.