[GIS] Getting an empty geometry when retrieving the envelope of a GroupElement in ArcObjects: what might be wrong

arcobjects

I am working in ArcGIS 10.0 (ArcMap) and Python 2.6.5 and in the Data View. I have an IGroupElement3 to which I add a TextElement and up to several RectangleElements. I want then to retrieve the envelope of the GroupElement, recenter that envelope, and set the envelope as the new geometry of the GroupElement. The intent is to reposition (translate) the GroupElement. Here is a snippet:

pGrpElem = CType(pGroupElementFull, esriCarto.IElement)
pEnv = pGrpElem.Geometry.Envelope
pEnv.CenterAt(pCtrPoint)
pGrpElem.Geometry = pEnv

When the code runs, I get an error on the CenterAt method, saying I am performing an operation on an empty geometry. I checked, and indeed the pEnv is empty. So I have a few questions:

(1) Is this a valid method for moving a GroupElement?

(2) If not, how should I be doing it?

(3) If so, then I have a problem elsewhere. Do I have to add the component elements – and the GroupElement for that matter – to the display's GraphicsContainer to get them to "gel" and have valid envelopes? I was trying to avoid the GraphicsContainer step, because I really don't want the graphics to draw to the screen. The GroupElement is really for loading into an annotation feature. When I use the GraphicsContainer the screen drawing can get messed up unnecessarily. The graphics draw anyway when they are added to annotation, so I don't need two copies onscreen.

(4) If, as described above, I need to do something in addition to simply adding elements to the GroupElement to make their geometries visible to the GroupElement, how might I do that and avoid drawing the graphics to the screen at the same time?

Thanks for the help, all.

Best Answer

This is a common gotcha when working with GroupElements. The best way to change position, size etc. of group elements is to use the ITransform2D interface which the GroupElement class implements.

So, to recenter a group element to another location, first retrieve its current envelope through IElement.QueryBounds, for example. This will allow you to determine the offset to move the element to the desired location, which you will then use when calling ITransform2D.Move.

This Python function using comtypes centers an element (of just about any type, including a group element) to the [x,y] location. display is an IDisplay reference, this will usually be IActiveView.ScreenDisplay on the map. objectFactory is IObjectFactory used to create out-of-process COM objects.

def centerElementAt(element, display, x, y, objectFactory):
    boundsEnvelope = CType(objectFactory.Create("esriGeometry.Envelope"), esriGeometry.IEnvelope)
    (CType(element, esriCarto.IElement)).QueryBounds(CType(display, esriDisplay.IDisplay), boundsEnvelope)
    currentCenterPoint = CType((CType(boundsEnvelope, esriGeometry.IArea)).Centroid, esriGeometry.IPoint)
    transform2D = CType(element, esriGeometry.ITransform2D)
    transform2D.Move(x - currentCenterPoint.X, y - currentCenterPoint.Y)
Related Question