Monday, January 5, 2009

Issues when working with ArcGIS Engine in .NET

1. First, be prepared for the lack of documentation or that on many occasions you’ll be looking for a .NET example and you’ll find a VBA example. Or, if for one reason or another JavaScript is disabled some links in the Help just won’t work.

2. T o get to anything related to the map, scene or globe you first access it via the control itself which will have some interface it supports. For example, to get access to many of the basic interfaces for the globe control you return the globe control’s object reference which is the IGlobeControl interface. From there you can get to other basic interfaces like IBasicMap.

3. All classes have the word Class on the end of them. For example, the point class isn’t just called Point, it’s called PointClass. Example: IPoint point = new PointClass();

4. The Engine runtime must be installed on all client machines in order to run your application or they must have ArcGIS Desktop.

5. Whenever you want to specify a missing argument in VB you could just supply Nothing but with .NET you must create an object of Type.Missing. This is accomplished by first creating the object like this: object missing = Type.Missing and then supplying “missing” as an argument.

6. Many properties and methods have their own .NET implementation. For example, to set the name of a field you use IFieldEdit::Name_2 as opposed to just Name. For some methods the methods is prefixed with “get_”. For example, a point collection’s point is used in this manner: IPointCollection.get_Point(i);

7. There isn’t an equivalent to using GxDialog because Engine doesn’t come with ArcCatalog libraries per se. You need to build your own dialogs for your application. However, when building a simple app there is an Add Data tool that you can use to quickly add data.

8. You can use an ArcGIS Desktop license to run an Engine application. See this article.


9. You can control how you interact with the license manager via the LicenseControl or AoInitializeClass.


10. COM types that are not OLE automation compliant require you to use different classes altogether. For example you can’t use the IEnvelope interface but you can use IEnvelopeGEN interface on the EnvelopClass.


11. Watch out for Singleton objects. If you try to instantiate them more than once you will get an error. See here for a list of all the singletons. Also, if you forget to kill them they will be pinned in memory.

12. To use OLE StdFont and StdPicture you must add Stdole.dll as a reference in your project.


13. When creating a new command or tool you can also get a reference to the basic interfaces via the HookHelper. This is very useful for creating commands and tools that work in Scene, Map and Globe.

14. Lastly, just be aware that although under the hood ArcObjects is basically the same there are some bugs unique to Engine that you will come across.

Friday, January 2, 2009

Creating 3D Geometry

To create 3D geometry is pretty straight forward using ArcObjects. Any time you create a piece of geometry it is at first only 2 dimensional. Once you have a 2D geometry the next step is to make it Z Aware. Once accomplished you set the Z value. For example, to make a 3D point, you first create the point and then via casting (or Query Interface in COM speak) you then make the geometry Z Aware. Here is an example:



IPoint pPoint1 = new PointClass();

pPoint1.PutCoords (x, y);

((IZAware)pPoint1).ZAware = true;

pPoint1.Z = 1000;



From this simple example more complex geometry can be created. To create a line using two points is quite straight forward. Create two points, make them Z-Aware and assign the Z values, and create a new line and then construct the new line using the two points. You don’t need to make the line Z-Aware because it will inherit the Z values of the points. Here is another example:

IPoint pPoint1 = new PointClass();

pPoint1.PutCoords (x, y);

((IZAware)pPoint1).ZAware = true;

pPoint1.Z = 1000;



IPoint pPoint2 = new PointClass();

pPoint2.PutCoords (x, y);

((IZAware)pPoint2).ZAware = true;

pPoint2.Z = 1000;



ILine = pLine = new LineClass();

pLine.PutCoords(pPoint1, pPoint2);

So far so good. You can now use that line in many ways. However, the most important thing to know is that in order to create more complex geometry you must now make the more complex geometry also Z-Aware. Let’s create a polygon that is Z-Aware. In order to do that you must first create segments from the lines, and then make the segments Z-Aware, then create a ring, then create a polygon and make it Z-Aware and lastly add the Z-Aware segments to the ring. Here is a simple square polygon:

IPoint point1 = new PointClass();

IPoint point2 = new PointClass();

IPoint point3 = new PointClass();

IPoint point4 = new PointClass();



point1.PutCoords(1, 1);

point2.PutCoords(1, 2);

point3.PutCoords(2, 2);

point4.PutCoords(2, 1);



ILine line1 = new LineClass();

ILine line2 = new LineClass();

ILine line3 = new LineClass();

ILine line4 = new LineClass();

line1.PutCoords(point1, point2);

line2.PutCoords(point2, point3);

line3.PutCoords(point3, point4);

line4.PutCoords(point4, point1);



ISegmentZ line1SegmentZ = line1 as ISegmentZ;

line1SegmentZ.SetZs(1000, 1000);

ISegmentZ line2SegmentZ = line2 as ISegmentZ;

line2SegmentZ.SetZs(1000, 1000);

ISegmentZ line3SegmentZ = line3 as ISegmentZ;

line3SegmentZ.SetZs(1000, 1000);

ISegmentZ line4SegmentZ = line4 as ISegmentZ;

line4SegmentZ.SetZs(1000, 1000);



IPolygon polygon = new PolygonClass();

((IZAware)polygon).ZAware = true;



ISegmentCollection ring = new RingClass();



object missing = Type.Missing;

ring.AddSegment((ISegment)line1SegmentZ, ref missing, ref missing);

ring.AddSegment((ISegment)line2SegmentZ, ref missing, ref missing);

ring.AddSegment((ISegment)line3SegmentZ, ref missing, ref missing);

ring.AddSegment((ISegment)line4SegmentZ, ref missing, ref missing);



IGeometryCollection geometryCollection = polygon as IGeometryCollection;

geometryCollection.AddGeometry((IGeometry)ring, ref missing, ref missing);



polygon.Close();

polygon.SimplifyPreserveFromTo();



That’s it! We now have a complete polygon. In this case the polygon will float at 1000 units. Notice that at the end the ring was added to a geometry collection, the polygon was closed and lastly the from/to points of the polygon were preserved because the precise order of the points was established when the lines were created. From this point, this polygon could be drawn in ArcMap, ArcScene or ArcGlobe or stored in a geodatabase if the featureclass is also Z-Aware. There are of course other ways to create a polygon too like just using a point collection.