ProSnippets Annotation - Esri/arcgis-pro-sdk GitHub Wiki

Language:              C#  
Subject:               Annotation  
Contributor:           ArcGIS Pro SDK Team <[email protected]>  
Organization:          esri, http://www.esri.com  
Date:                  10/22/2024  
ArcGIS Pro:            3.4  
Visual Studio:         2022  
.NET Target Framework: .Net 8  

Create Annotation Construction Tool

//In your config.daml...set the categoryRefID
//<tool id="..." categoryRefID="esri_editing_construction_annotation" caption="Create Anno" ...>

//Sketch type Point or Line or BezierLine in the constructor...
//internal class AnnoConstructionTool : MapTool  {
//  public AnnoConstructionTool()  {
//    IsSketchTool = true;
//    UseSnapping = true;
//    SketchType = SketchGeometryType.Point;
//

protected async override Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
    if (CurrentTemplate == null || geometry == null)
        return false;

    // Create an edit operation
    var createOperation = new EditOperation();
    createOperation.Name = string.Format("Create {0}", CurrentTemplate.Layer.Name);
    createOperation.SelectNewFeatures = true;

    // update the geometry point into a 2 point line
    //annotation needs at minimum a 2 point line for the text to be placed
    double tol = 0.01;
    var polyline = await CreatePolylineFromPointAsync((MapPoint)geometry, tol);

    // Queue feature creation
    createOperation.Create(CurrentTemplate, polyline);

    // Execute the operation
    return await createOperation.ExecuteAsync();
}

internal Task<Polyline> CreatePolylineFromPointAsync(MapPoint pt, double tolerance)
{
    return QueuedTask.Run(() =>
    {
    // create a polyline from a starting point
    //use a tolerance to construct the second point
    MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(pt.X + tolerance, pt.Y, pt.SpatialReference);
        return PolylineBuilderEx.CreatePolyline(new List<MapPoint>() { pt, pt2 });
    });
}

Update Annotation Text via attribute. Caveat: The TEXTSTRING Anno attribute must exist

//See "Change Annotation Text Graphic" for an alternative if TEXTSTRING is missing from the schema
await QueuedTask.Run(() =>
{
    //annoLayer is ~your~ Annotation layer...

    // use the inspector methodology
    var insp = new Inspector();
    insp.Load(annoLayer, oid);

    // make sure TextString attribute exists.
    //It is not guaranteed to be in the schema
    ArcGIS.Desktop.Editing.Attributes.Attribute att = insp.FirstOrDefault(a => a.FieldName == "TEXTSTRING");
    if (att != null)
    {
        insp["TEXTSTRING"] = "Hello World";

        //create and execute the edit operation
        EditOperation op = new EditOperation();
        op.Name = "Update annotation";
        op.Modify(insp);

        //OR using a Dictionary - again TEXTSTRING has to exist in the schema
        //Dictionary<string, object> newAtts = new Dictionary<string, object>();
        //newAtts.Add("TEXTSTRING", "hello world");
        //op.Modify(annoLayer, oid, newAtts);

        op.Execute();
    }
});

Rotate or Move the Annotation

await QueuedTask.Run(() =>
{
    //Don't use 'Shape'....Shape is the bounding box of the annotation text. This is NOT what you want...
    //
    //var insp = new Inspector();
    //insp.Load(annoLayer, oid);
    //var shape = insp["SHAPE"] as Polygon;
    //...wrong shape...

    //Instead, we must get the TextGraphic from the anno feature.
    //The TextGraphic shape will be the anno baseline...
    //At 2.1 the only way to retrieve this textLine is to obtain the TextGraphic from the AnnotationFeature
    QueryFilter qf = new QueryFilter()
    {
        WhereClause = "OBJECTID = 1"
    };

        //annoLayer is ~your~ Annotation layer

        using (var rowCursor = annoLayer.Search(qf))
        {
          if (rowCursor.MoveNext())
          {
using (var annoFeature = rowCursor.Current as 
            ArcGIS.Core.Data.Mapping.AnnotationFeature)
{
  var graphic = annoFeature.GetGraphic();
  var textGraphic = graphic as CIMTextGraphic;
  var textLine = textGraphic.Shape as Polyline;
  // rotate the shape 90 degrees
  var origin = GeometryEngine.Instance.Centroid(textLine);
  Geometry rotatedPolyline = GeometryEngine.Instance.Rotate(textLine, origin, System.Math.PI / 2);
  //Move the line 5 "units" in the x and y direction
  //GeometryEngine.Instance.Move(textLine, 5, 5);

  EditOperation op = new EditOperation();
  op.Name = "Change annotation angle";
  op.Modify(annoLayer, oid, rotatedPolyline);
  op.Execute();
}
          }
        }
      });

Get the Annotation Text Graphic

await QueuedTask.Run(() =>
{
    using (var table = annoLayer.GetTable())
    {
        using (var rc = table.Search())
        {
            rc.MoveNext();
            using (var af = rc.Current as AnnotationFeature)
            {
                var graphic = af.GetGraphic();
                var textGraphic = graphic as CIMTextGraphic;

                //Note: 
                //var outline_geom = af.GetGraphicOutline(); 
                //gets the anno text outline geometry...
            }
        }
    }
});

Get the Outline Geometry for an Annotation

var annoLayer = MapView.Active.Map.GetLayersAsFlattenedList()
                               .OfType<AnnotationLayer>().FirstOrDefault();
if (annoLayer == null)
    return;

QueuedTask.Run(() =>
{
    //get the first annotation feature...
    //...assuming at least one feature gets selected
    using (var fc = annoLayer.GetFeatureClass())
    {
        using (var rc = fc.Search())
        {
            rc.MoveNext();
            using (var af = rc.Current as AnnotationFeature)
            {
                var outline_geom = af.GetGraphicOutline();
                //TODO - use the outline...

                //Note: 
                //var graphic = annoFeature.GetGraphic(); 
                //gets the CIMTextGraphic...
            }
        }
    }
});

Get the Mask Geometry for an Annotation

var annoLayer = MapView.Active.Map.GetLayersAsFlattenedList()
                         .OfType<AnnotationLayer>().FirstOrDefault();
if (annoLayer == null)
    return;
var mv = MapView.Active;

QueuedTask.Run(() =>
{
    //get the first annotation feature...
    //...assuming at least one feature gets selected
    using (var fc = annoLayer.GetFeatureClass())
    {
        using (var rc = fc.Search())
        {
            rc.MoveNext();
            using (var row = rc.Current)
            {
                var oid = row.GetObjectID();

                //Use DrawingOutlineType.BoundingEnvelope to retrieve a generalized
                //mask geometry or "Box". The mask will be in the same SpatRef as the map.
                //The mask will be constructed using the anno class reference scale
                //At 2.x - var mask_geom = annoLayer.QueryDrawingOutline(oid, mv, DrawingOutlineType.Exact);

                var mask_geom = annoLayer.GetDrawingOutline(oid, mv, DrawingOutlineType.Exact);
            }
        }
    }
});
⚠️ **GitHub.com Fallback** ⚠️