[ArcEngine] Drawing projected geometry

2556
16
Jump to solution
04-30-2012 07:51 AM
ManfredLauterbach
Occasional Contributor
Hi,

The documentation for the IGemetry.Project method : http://help.arcgis.com/en/sdk/10.0/arcobjects_cpp/componenthelp/index.html#/Project_Method/000w00000... shows how an object can be projected into another coordinate space.

Assuming that I am working with WGS84 referenced maps, I then want to draw a geometry (circle).
In the case of WGS84, drawing a 'circle' (with constant radius), will actually be visualized (projected) as an ellipsoid - see attached image.

My problem is that the following projection does not seem to be working :
          PointClass centroid = new PointClass() { X = 0, Y = 0};           PointClass permiterPoint = new PointClass() { X = 4, Y = 0 };           CircularArcClass circularArc = new CircularArcClass();           circularArc.PutCoords(centroid, permiterPoint, permiterPoint, esriArcOrientation.esriArcClockwise);            IPolygon polygon = new PolygonClass();           segmentCollection = polygon as ISegmentCollection;           segmentCollection.AddSegment(circularArc);            ISpatialReferenceFactory srFactory = new SpatialReferenceEnvironmentClass();           IGeographicCoordinateSystem cs1 = srFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_Clarke1880);           IGeographicCoordinateSystem cs2 = srFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984);           polygon.SpatialReference = cs1;            polygon.Project(cs2);            IGraphicTrackerSymbol graphicTrackerSymbol = graphicTracker.CreateSymbol(fillSymbol as ISymbol, null);           int graphicID = graphicTracker.Add(polygon, graphicTrackerSymbol);

(I have not added any maps yet, and have not set the any layer spacial relations).

The 'inner' circle is the result of the code above.
The 'outer' (shaded) ellipsoid is the result of another filled polygon (not in the code above) which is constructed by manually calculating the perimeter coordinates.

The source coordinate system is obviously not Clarke 1880, I just set it to Clarke to try and get a response out of the Project method.
What am I doing wrong in terms of the projection - why is the polygon not being projected into the ellipsical coordinates that are used to represent WGS 84?
0 Kudos
1 Solution

Accepted Solutions
ManfredLauterbach
Occasional Contributor
There seems to be insufficient information to diagnose this problem, forcing me to use a non-ESRI workaround :

I have downloaded and used a WMM (world magnetic model) library to calculate the correct coordinates whenever necessary and simply provide the correct coordinates to contruct ESRI geometries.

View solution in original post

0 Kudos
16 Replies
AlexanderGray
Occasional Contributor III
In my experience projecting large curves produces uneven results.  Same as projecting large features with few vertices.  In the case of large rectangles (several hundred KM sides), the corners are in the correct location but the sides are still straight when they should be curved to follow the projection change.  Same thing with curves the start and end and radius is correct but the edge is not skewed to follow the new projection.  If you convert your circle to a dense polyline (series of small straight segments) and then project it, the result should more closely resemble what you expect.
0 Kudos
ManfredLauterbach
Occasional Contributor
Thanks for the reply.

That does make sense, I've attached a quick test that includes densification, but I feel I'm missing the projection alltogether... (even the densified version should exhibit the elliptical distortion of the WGS 84 projection)?
0 Kudos
AlexanderGray
Occasional Contributor III
Yes it should but I don't know how much distortion you will get changing the datum between clark66 and wgs84...  You are still using the same coordinate system (geographic) and changing the datum.  If you project to a projected coordinate system, you should see more of a difference.  Usually building a circle implies using a radius, in geographic coordinate systems, the radius is provided as a distance in decimal degrees.  Decimal degrees are an angular unit so they don't make much sense as a distance.
0 Kudos
ManfredLauterbach
Occasional Contributor
In the process of learning how projections actually work the background knowledge really makes a great deal of sense:

When adding a new 2D map layer (without setting any spacial references), arc objects automatically assumes that we're working with a 2D plane (mercator projection?) and displays the maps correctly.
Straight line distances can literally be calculated with xy coordinates (instead of considering elliptical curves within 3 dimensions).

The problem now, is this:
Projected maps are displayed correctly, but when I draw a geometry using the map control (or using the graphic tracker) I still first need to project my 'theoretically 3 dimensional geometry' into the 2 dimensional map plane.
Example : a perfect circle (representing an constant range (radius) from a source point on the map at MSL) is defined in code using IPolyLine, but must then be projected onto a 2D mercator plane - this should then result in an ellipse as shown in the second attached image.

I assumed that I was trying to do this in my first post code sample, but it didn't work - I need to know why.

How do I create/define a source coordinate system that represents my geometry in 3D space, and then to which coordinate system do I convert for the WGS84 referenced maps?
(I had assumed that leaving the source coordinate system undefined, and specifying WGS84 as the target would work):
          ISpatialReferenceFactory srFactory = new SpatialReferenceEnvironmentClass();
          IGeographicCoordinateSystem cs = srFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984);
          polygon.Project(cs);

          graphicTracker.CreateSymbol....

..but since the documentation stated that the source coordinate system must also be defined, in order to perform a projection, I used with Clarke 1880.
However, even if we used Clarke 1880 there is no change in coordinates (not even a slight change we are expecting)
0 Kudos
ManfredLauterbach
Occasional Contributor
The following example comes straight from the EDN library : http://edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeometry/IGeometry_Project.htm

            //Create Spatial Reference Factory
            ISpatialReferenceFactory srFactory = new SpatialReferenceEnvironmentClass();
            ISpatialReference sr1;
            //GCS to project from 
            IGeographicCoordinateSystem gcs = srFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_NAD1983);
            sr1 = gcs;
            sr1.SetFalseOriginAndUnits(-180, -90, 1000000);
            //Projected Coordinate System to project into
            IProjectedCoordinateSystem pcs = srFactory.CreateProjectedCoordinateSystem((int)esriSRProjCSType.esriSRProjCS_NAD1983N_AmericaLambert);
            pcs.SetFalseOriginAndUnits(0, 0, 1000);
            ISpatialReference sr2;
            sr2 = pcs;
            //Point to project
            IPoint point = new PointClass() as IPoint;
            point.PutCoords(-117.17, 34.06);
            //Geometry Interface to do actual project
            IGeometry geometry;
            geometry = point;
            geometry.SpatialReference = sr1;
            geometry.Project(sr2);
            point = geometry as IPoint;
            double x;
            double y;
            point.QueryCoords(out x, out y);
            Debug.Print("X: " + x.ToString());
            Debug.Print("Y: " + y.ToString()); 


but the resulting coordinate returned seems to be grossly incorrect - what is wrong here?


Lat = -1830967.55192668
Lon = -397618.008585039

0 Kudos
AlexanderGray
Occasional Contributor III
Which transformation are you using to go from Clarke1866 to WGS84?  Keep in mind, this is not really projecting the data, Clarke1866 and WGS84 are ellipsoids (Well not WGS84 but that gets complicated)  They are not coordinate systems, you could have Geographic data NAD27 (Clarke1866), NAD83 (GRS80) or WGS84 (composite.)   I am not too sure what you mean by going from 3D to 2D coordinate systems.  3D coordinate systems usually store the elevation above mean sea level (which is a whole different problem since the sea isn't actually level.)  All map data is defined in 2D coordinate system because maps and computer screens are flat.  In order to do distance calculations over large areas, geodetic lines are used to calculate distances (along great circles.) or geodesiccircle to construct a circle that fits the ellipsoid.  The military analyst libraries has so methods for that.

I don't know if the lambert coordinates are correct or not.  It depends where you put the origin.  Lambert usually uses metres so depending where the central meridian is and where the vertical axis starts it could be correct.
0 Kudos
ManfredLauterbach
Occasional Contributor
1) That is also what I'm trying to figure out - what are the defaults that ArcObjects is working with when I initialize a brand new instance of the mapping control and draw a geometry to the map (or add it to the graphic tracker).

2) If you have a look at the ArcObjects geometries you will find that they have properties for all three dimensions (e.g. points have X, Y and Z).
What I mean with defining geometries in 3D is that even if I leave the 'Z' coordinate at zero, I assume this still means zero relative to MSN (mean sea level). In other words, the point is by default 3 dimensional and not a 2 dimensional projection - this is again the question I wish to confirm, what is the default when I create and draw a new geometry?

3) I have already explained previously that my initial understanding was incorrect.
This issue does not have anything to do with a conversion between WGS84 and some other system, say NAD27 - it has to do with the projection of geometry, or the 'translation'? of projection - I want to know what is being done by default, and what I have to do to project default geometry.

Example :
[-] I add a map to the map control (It is a WGS84 referenced map).
[-] The closer we get to the poles the more 'stretched out' the map image will be (e.g. Greenland is much larger that it should be relative to a country at the equator).
[-] If I wish to draw a perfect circle over the land mass at this point, it should not be a perfect circle visually, it should be 'stretched out' into an ellipsoid in the same proportion to which the maps are stretched, the closer we get to the poles. BUT!, -at the moment- my 'unconverted' / untranslated / unprojected geometry is still being drawn as a perfect circle over the map - which is telling me that we still need to perform the said conversion.
[-] The example of the (desired) 'stretched' ellipsoid at about 40 degrees North (in comparison to a real circle, that is currently being drawn) is attached in my first, and other posts.

The theory behind what has to be done seems clear. How do I get ArcObjects to do it (if the example code in previous posts is on the wrong track)?
0 Kudos
AlexanderGray
Occasional Contributor III
2) X,Y,Z coordinates are commonly referred to as 2.5D.  For points it doesn't make much of a difference but for polygons it does.  It means a polygon's topology is defined in 2D space and the Z just adds info, a polygon cannot loop back on itself in the 3rd dimension.  For example a cliff with an overhang cannot be modeled as X,Y,Z coordinates.  That means that for drawing purposes with a map control, the Z is ignored.  I am also pretty sure that transforming from one ellipsoid to another does not change the Z.

3) For greenland, you could use a stereographic projection to create the circle and then project it back out to mercator.  The problem is it the same stereographic projection cannot be applied everywhere .  The IConstructGeoddetic interface allows you to create geodetically correct circles.

You can also look at

http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//00010000021m000000

Military Analyst used to be free at some point I am not sure it is still the case.
0 Kudos
ManfredLauterbach
Occasional Contributor
What appears interesting from the code in the link that you specified (.\GeodesyMapControl\GeodesyMapControl.cs) is that it seems to be doing the same thing we have already tried...

PointClass centroid = new PointClass() { X = 0, Y = 60};
PointClass permiterPoint = new PointClass() { X = 4, Y = 60 };
CircularArcClass circularArc = new CircularArcClass();
circularArc.PutCoords(centroid, permiterPoint, permiterPoint, esriArcOrientation.esriArcClockwise);

IPolygon polygon = new PolygonClass();
segmentCollection = polygon as ISegmentCollection;
segmentCollection.AddSegment(circularArc);


ESRI.ArcGIS.Geometry.ISpatialReference2 pSpatRef; 
ESRI.ArcGIS.Geometry.ISpatialReferenceFactory2 pSpatRefFact = (ISpatialReferenceFactory2) new ESRI.ArcGIS.Geometry.SpatialReferenceEnvironment();
pSpatRef = (ISpatialReference2) pSpatRefFact.CreateSpatialReference((int) ESRI.ArcGIS.Geometry.esriSRGeoCSType.esriSRGeoCS_WGS1984);

polygon.Project(pSpatRef);

// .. Draw shape



and yet, if I run this code (using my own polygon definition), I still end up with a perfect circle at 60 degrees North?
0 Kudos