In this topic
- About using IGeometryBridge to update dynamic geometries
- Updating an entire geometry on each update cycle
- Adding a single vertex to an existing geometry on each update cycle
About using IGeometry to update dynamic geometries
To implement a dynamic geographic information system (GIS) in the .NET environment—by design or due to the nature of the .NET platform—you might need to work in multiple threads. You might be required to update geometries on different events, such as timer events or other asynchronous callbacks. Also, you might have to share geometries across multiple threads (for an instance in an architecture where there is one rendering thread and other update threads).
Since ArcObjects geometries are Component Object Model (COM) components marked as a single threaded apartment (STA), if you call these geometries from any non-main thread in your application, you pay the penalty of cross apartment calls, which significantly affects the performance of your application.
To manage points data, there is a straightforward solution—manage your point as raw x,y coordinates, then update the point geometry on the main thread as required. However, with geometries, such as polylines and polygons, the problem becomes trickier to solve.
Before getting into the solution for these geometries, consider another factor that can affect the performance of your .NET application—the overhead of the COM interop when there is extensive allocation of new ArcObjects. For example, if you are creating ArcObjects geometries or updating existing ones, there are a number of calls across the interop layer. In particular, if you are creating ArcObjects in a tight loop, you repeatedly have the delay from crossing the interop layer, which drastically slows your application. For more information on the issues interacting with the COM interop, see Performance of ArcObjects.
To address the previous issues, IGeometryBridge is beneficial. It allows you to create and update your ArcObjects geometries using simple types, which means that sharing these geometries across multiple threads is no longer an issue, as well as reducing the issue of the interop overhead to an absolute minimum.
This is where the WKSPoint structure becomes beneficial. WKSPoint is defined as a simple C++ structure, which means it is treated by the .NET framework as a simple type (using it across multiple threads is permissible and there is almost no overhead for using it in a .NET environment).
By managing your geometries as arrays of WKSPoints, you can safely share them across multiple threads and avoid the overhead of allocating COM objects. Since most ArcObjects analysis and drawing methods require a standard ArcObjects geometry, the technique involves keeping a class member of one geometry together with an instance of a geometry bridge (GeometryEnvironement).
In most cases, there are two scenarios where you might be required to update geometries:
- When the entire geometry constantly changes and you do not know which of the vertices changed, as well as the overall number of vertices beforehand
- When only known vertices change on each update cycle
In the following sections, there are step-by-step instructions for implementing these two scenarios.
Updating an entire geometry on each update cycle
This scenario is possible when you are receiving geometries from an external feed and have to analyze or draw these geometries using ArcObjects. Any geometry is different from the other; therefore, you do not know any information on the geometry in advance. In such cases, you have to constantly update the entire ArcObjects geometry each time you get a new geometry from the external feed.
- In your class, add three additional class members to handle the geometry—a point collection that stores the ArcObjects geometry, an empty one-dimensional array of WKSPoints, and a geometry bridge. See the following code example:
private IPointCollection4 m_polygon=null;
private WKSPoint[] m_wksPoints=null;
private IGeometryBridge2 m_geometryBridge=null;
[VB.NET] Private m_polygon As IPointCollection4=Nothing
Private m_wksPoints() As WKSPoint=Nothing
Private m_geomeTryBridge As IGeomeTryBridge2=Nothing
- Instantiate the ArcObjects geometry and the geometry bridge. Make sure the instantiation is done on the application's main thread (must be defined as STA thread). See the following code example:
m_polygon=new PolygonClass();
// Create the geometry environment class instance.
m_geometryBridge=new GeometryEnvironmentClass();
[VB.NET] m_polygon=New PolygonClass()
' Create the geometry environment class instance.
m_geomeTryBridge=New GeomeTryEnvironmentClass()
- To update the ArcObjects geometry, populate the WKSPoint array and use the geometry bridge to replace all existing vertices of the ArcObjects geometry with the vertices for the WKSPoint array.
- Populate the WKSPoint array. You can update the WKSPoint array from anywhere in your code. You can also do this on a different thread, as long as you synchronize the threads. See the following code example:
int count=0;
double X;
double Y;
lock(m_wksPoints)
{
m_wksPoints=new WKSPoint[m_table.Rows.Count];
foreach (DataRow r in m_table.Rows)
{
//Get the item's coordinate.
X=Convert.ToDouble(r["X"]);
Y=Convert.ToDouble(r["Y");
// Update the geometry's array.
m_wksPoints[count].X=X;
m_wksPoints[count].Y=Y;
count++;
}
}
[VB.NET] Dim Count As Integer=0
Dim X As Double
Dim Y As Double
SyncLock m_wksPoints
m_wksPoints=New WKSPoint(m_table.Rows.Count - 1){}
For Each r As DataRow In m_table.Rows
' Get the item's coordinate.
X=Convert.ToDouble(r("X"))
Y=Convert.ToDouble(r("Y"))
' Update the geometry's array.
m_wksPoints(Count).X=X
m_wksPoints(Count).Y=Y
Count +=1
Next r
End SyncLock
- Update the ArcObjects geometry using the geometry bridge. Calling IGeometryBridge2.SetWKSPoints replaces all existing vertices with the one specified by the WKSPoint array. Again, if you are updating the WKSPoint array on a different thread, lock the array before. See the following code example:
// Update the ArcObjects geometry as needed.
lock(m_wksPoints)
{
m_geometryBridge.SetWKSPoints(m_polygon, ref m_wksPoints);
}
[VB.NET] ' Update the ArcObjects geometry as needed.
SyncLock m_wksPoints
m_geometryBridge.SetWKSPoints(m_polygon, m_wksPoints)
End SyncLock
- When you are done updating the geometry, use it as needed. See the following code example:
DynamicDisplay.DrawPolygon(m_polygon);
[VB.NET] DynamicDisplay.DrawPolygon(m_polygon)
Adding a single vertex to an existing geometry on each update cycle
In other cases, you will only need to update a single vertex at a time, either adding an additional vertex to your geometry (for an instance when drawing the trail of a moving object) or updating vertices at a known index inside the geometry. In such cases, you only need to manage a single WKSPoint and use IGeometryBridge2.InsertWKSPoints or IGeometryBridge2.AddWKSPoints. For more information, see Dynamic biking.
- In your class, add three additional class members to handle the geometry. A point collection that stores the ArcObjects geometry, a one-dimensional array of WKSPoints with one element in it, and a geometry bridge. See the following code example:
private IPointCollection4 m_bikeRouteGeometry=null;
private IGeometryBridge2 m_geometryBridge=null;
private WKSPoint[] m_wksPoints=new WKSPoint[1];
[VB.NET] Private m_bikeRouteGeometry As IPointCollection4=Nothing
Private m_geometryBridge As IGeometryBridge2=Nothing
Private m_wksPoints As WKSPoint()=New WKSPoint(0){}
- Instantiate the ArcObjects geometry and the geometry bridge. Make sure the instantiation is done on the application's main thread (must be defined as STA thread). See the following code example:
m_bikeRouteGeometry=new PolylineClass();
// Create the geometry environment class instance.
m_geometryBridge=new GeometryEnvironmentClass();
[VB.NET] m_bikeRouteGeometry=New PolylineClass()
' Create the geometry environment class instance.
m_geometryBridge=New GeometryEnvironmentClass()
- Populate the WKSPoint inside the array (array with one element). You can update the WKSPoint array from anywhere in your code. You can also do this on a different thread, as long as you synchronize the threads. See the following code example:
// Update the bike trail.
lock(m_wksPoints)
{
m_wksPoints[0].X=m_bikePositionInfo.position.X;
m_wksPoints[0].Y=m_bikePositionInfo.position.Y;
}
[VB.NET] ' Update the bike trail.
SyncLock m_wksPoints
m_wksPoints(0).X=m_bikePositionInfo.position.X
m_wksPoints(0).Y=m_bikePositionInfo.position.Y
End SyncLock
- Update the ArcObjects geometry using the geometry bridge. Calling IGeometryBridge2.AddWKSPoints adds the additional point at the end of the geometry. Again, if you are updating the WKSPoint array on a different thread, lock the array before. See the following code example:
// Update the ArcObjects geometry.
lock(m_wksPoints)
{
m_geometryBridge.AddWKSPoints(m_bikeRouteGeometry, ref m_wksPoints);
}
[VB.NET] ' Update the ArcObjects geometry.
SyncLock m_wksPoints
m_geometryBridge.AddWKSPoints(m_bikeRouteGeometry, m_wksPoints)
End SyncLock
- When you are done updating the geometry, use it as needed. See the following code example:
dynamicDisplay.DrawPolyline(m_bikeRouteGeometry);
[VB.NET] dynamicDisplay.DrawPolyline(m_bikeRouteGeometry)
See Also:
Using IGeometryBridge or IGeometryBridge2Performance of ArcObjects
Samples:
Development licensing | Deployment licensing |
---|---|
Engine Developer Kit | Engine |
ArcGIS Desktop Basic | ArcGIS Desktop Basic |
ArcGIS Desktop Standard | ArcGIS Desktop Standard |
ArcGIS Desktop Advanced | ArcGIS Desktop Advanced |