Vitals: ArcGIS-ArcView 10.0, Python 2.6.5, PythonWin, comtypes
I'll start with my main questions:
- How, using ArcObjects, do I go about creating non-feature-linked geodatabase annotation features that have a simple line callout format, and
- How do I set the anchor point so that the leader line remains functional, i.e. remains anchored on the point feature it references even when the annotation is moved?
I have a standalone Python script that accesses ArcObjects through comtypes wrappings of ArcGIS OLBs -- works great. Overall, this ArcMap automation script cursors through a point feature class, creating complex vector graphics (in map units in the data view) from attribute info in the points and loads each of those graphics (an IGroupElement) into a non-feature-linked annotation feature as the anno's graphic element. I want to have functional simple line callout leader lines, but the latter graphics-containing anno features won't support a simple line callout. So my idea is to create, for each of the graphic anno features, an underlying, transparent dummy text anno feature that will carry the leader line. I've tried a bunch of things, but I can't get a leader line to show up. I have defined separate annotation classes within the target annotation feature class for storage of graphic versus dummy text leader line anno features. The leader line anno class was defined with transparent text and a simple line callout symbology. Now, below are code excerpts that include the function I call to create each annotation feature, be it graphic or leader line dummy:
#make front leader text element ldrText = '|' pFLdrTextElement = BuildTextElement(ldrText, 'Leader', 'null', annoRefScale, False, (fX, fY)) #returns ITextElement pFLdrTxtElem = CType(pFLdrTextElement, esriCarto.IElement) pFLdrTxtElem.Geometry = pTweakedTxtPoint ... ldrannoclass = 1 CreateAnnoFeature(annoFC, pFLdrTxtElem, fOID, ldrannoclass) def BuildTextElement(s, signType, txtcolor, annoRefScale, has_outline, featPos=None): ... #separate out leader annotation text if signType == 'Leader': import comtypes.gen.esriGeometry as esriGeometry pTextColor = GetRGBColor(txtcolor) pSimpleLineCallout = NewObj(esriDisplay.SimpleLineCallout, esriDisplay.ISimpleLineCallout) anchorPoint = NewObj(esriGeometry.Point, esriGeometry.IPoint) anchorPoint.PutCoords(featPos, featPos) pSimpleLineCallout.AnchorPoint = anchorPoint pSimpleLineCallout.AutoSnap = True pLeaderLineSymbol = NewObj(esriDisplay.CartographicLineSymbol, esriDisplay.ILineSymbol) pLineColor = NewObj(esriDisplay.RgbColor, esriDisplay.IRgbColor) pLineColor.Red = 0 pLineColor.Green = 0 pLineColor.Blue = 0 pLeaderColor = CType(pLineColor, esriDisplay.IColor) pLeaderLineSymbol.Color = pLeaderColor pSimpleLineCallout.LineSymbol = pLeaderLineSymbol pSimpleLineCallout.LeaderTolerance = 0.0 pTextBackground = CType(pSimpleLineCallout, esriDisplay.ITextBackground) pTextSymbol.Background = pTextBackground pTextSymbol.Color = pTextColor pTextElement.Symbol = pTextSymbol pTextElement.Text = s pTextElement.ScaleText = True return pTextElement ... def CreateAnnoFeature(pAnnoFC, pElement, featID, annoclass): """Creates new annotation feature, loads the graphic into it, and inserts the new anno feature into the anno feature class""" import comtypes.gen.esriGeoDatabase as esriGeoDatabase import comtypes.gen.esriCarto as esriCarto #make Insert cursor and FeatureBuffer for use in InsertFeature method pFCursor = pAnnoFC.Insert(True) pFeatBuffer = pAnnoFC.CreateFeatureBuffer() pFeature = CType(pFeatBuffer, esriGeoDatabase.IFeature) #set annotation of anno feature pAnnotationFeature = CType(pFeature, esriCarto.IAnnotationFeature2) pAnnotationFeature.Annotation = pElement pAnnotationFeature.Status = esriCarto.esriAnnoStatusPlaced pAnnotationFeature.AnnotationClassID = annoclass pFeature = CType(pAnnotationFeature, esriGeoDatabase.IFeature) #insert the new anno feature pFeatOID = pFCursor.InsertFeature(CType(pFeature, esriGeoDatabase.IFeatureBuffer)) pFCursor.Flush() mxDoc.ActiveView.PartialRefresh(esriCarto.esriViewGraphics, None, None)
BuildTextElement() function contains the code to build either a plain text element or one with a simple line callout format including setting of the anchor point. (See code above for the latter.) The latter results in what looks like a simple line callout, but when the annotation is moved the leader line does not remain anchored on the point feature. The text and leader line are simply combined into a graphic that moves around as a whole with the anno. In the case of the plain text element, I was hoping that a leader line would show, because the simple line callout format is defined in the annotation class symbology.
In this case, how would I set the anchor point?
In fact, in either case the leader line dummy is created--the transparent text box is placed, but there is no leader line. I really don't have a good idea of whether I am going about this in the best way. I can't change the structure of looping through the point features one at a time, but how I go about building the annotation features can certainly change. For instance, using an
IFDOGraphicsLayer and related objects instead of an Insert Cursor might work.
A related desire on my part is to be able to populate attributes of each anno feature right after (as?) I create it. Some of the attribute info will come from the point feature and some will capture the state of some of the properties of the anno feature. I really don't know how to go about this efficiently.
What are some ways I might do this?
So, where in my code above can I get an
ISymbolCollectionElement and on what?
I gather I should be making an empty text element with only a point location geometry assigned, passing this into
CreateAnnoFeature(), and setting properties there through
ISymbolCollectionElement. Because I create the anno feature as a
FeatureBuffer from the anno feature class, the feature is an annotation feature; however, I don't think a feature supports ISymbolCollectionElement, and the TextElement I pass in is just a plain TextElement. It isn't the element of the anno feature until I set the Annotation property.
Can I get an ISymbolCollectionElement on the TextElement before I set it as the annotation element?
Assuming I can, I guess that all I would have to set is the text, the symbolID, and the anchor point. The leader line, text size, and transparency should be picked up through the symbology defined in the anno feature class.
On a related note, how do I know the
SymbolID to assign?
In my existing anno class properties, the symbology tab shows the symbology that is defined for each of the annotation classes. When I create an anno feature and assign it to an annotation class, does it pick up the annotation class' symbology or do I need to assign the
SymbolID explicitly (hence the first question above)? (Right now, I set the
TextElement properties through
ITextSymbol, so I imagine any link to the
SymbolCollection that may normally exist is broken.)