Select to view content in your preferred language

Getting the Line width of individual elements

740
3
Jump to solution
09-30-2022 03:21 AM
DavidMrázek
Frequent Contributor

Hi,

I have two Polyline layers that are made up of Unique Values ​​Symbology. And I would like to go through the two layers and find out the width of each one. Is it even possible?

Thanks for the advice and tips

David

0 Kudos
1 Solution

Accepted Solutions
CharlesMacleod
Esri Regular Contributor

So width is a slightly ambiguous term. If you mean the width of the line symbol being used then the answer is it depends. If your features are being symbolized with a "simple" line symbol, then yes. Simply access the stroke layer(s) and retrieve the (max) width. The width will be in points and will need to be converted to the units of the map if you want the width in map units. For more complicated line symbology with multiple layers and various geometric offsets applied, visual variables, etc, etc then it could be much more difficult.

So, this is the simple case, assuming a UVR and we are retrieving the overall max width - u will need to modify if u are interested in just the max width of a particular class (or group):

 

 

//access the layer CIM Definition
//QTR.Run(()=> ...
 var def = featLayer.GetDefinition() as CIMFeatureLayer;
 var uvr = def.Renderer as CIMUniqueValueRenderer;

 double maxWidth = 0.0;
 foreach (var group in uvr.Groups) {
   foreach (var valclass in group.Classes) {
     var symbol = valclass.Symbol as CIMLineSymbol;
     if (symbol == null) continue;
     var sym_layers = ((CIMLineSymbol)symbol).SymbolLayers.ToList();
     foreach (var sl in sym_layers) {
       //assuming no offsets, etc.
       if (sl is CIMStroke stroke) {
         maxWidth = Math.Max(maxWidth, stroke.GetWidth());

  //TODO - convert width in points to map units as needed


public static class CIMStrokeExtensions {
 public static double GetWidth(this CIMStroke cimstroke) {
  if (cimstroke is CIMSolidStroke)
    return ((CIMSolidStroke) cimstroke).Width;
  else if (cimstroke is CIMPictureStroke)
    return ((CIMPictureStroke)cimstroke).Width;
  else if (cimstroke is CIMGradientStroke)
    return ((CIMGradientStroke)cimstroke).Width;
  return 0;
 }

 

 

 

You could also attempt to calculate the width using the graphic outline - a polygon generated from the feature and its renderer that "matches" the graphical outline of the given feature (whether point, line, poly, or anno).  Essentially, the outline polygon is equivalent to the masking polygon for "that" feature. The mask polygon will take into consideration all aspects of the renderer + visual variables, etc. so it is much more sophisticated but...it is a polygon and it is not necessarily straightforward to derive the feature "width" depending on the underlying shape/curvature of a particular line.

To retrieve the graphical outline of a feature: featLayer.GetDrawingOutline(....)  (note: this was QueryDrawingOutline at 2.x but the usage was the same)

 

 

 

//QTR.Run(()=> ..
var outline = featLayer.QueryDrawingOutline(oid, MapView.Active, 
  DrawingOutlineType.Exact) as Polygon;

 

 

 

 

 

View solution in original post

3 Replies
CharlesMacleod
Esri Regular Contributor

So width is a slightly ambiguous term. If you mean the width of the line symbol being used then the answer is it depends. If your features are being symbolized with a "simple" line symbol, then yes. Simply access the stroke layer(s) and retrieve the (max) width. The width will be in points and will need to be converted to the units of the map if you want the width in map units. For more complicated line symbology with multiple layers and various geometric offsets applied, visual variables, etc, etc then it could be much more difficult.

So, this is the simple case, assuming a UVR and we are retrieving the overall max width - u will need to modify if u are interested in just the max width of a particular class (or group):

 

 

//access the layer CIM Definition
//QTR.Run(()=> ...
 var def = featLayer.GetDefinition() as CIMFeatureLayer;
 var uvr = def.Renderer as CIMUniqueValueRenderer;

 double maxWidth = 0.0;
 foreach (var group in uvr.Groups) {
   foreach (var valclass in group.Classes) {
     var symbol = valclass.Symbol as CIMLineSymbol;
     if (symbol == null) continue;
     var sym_layers = ((CIMLineSymbol)symbol).SymbolLayers.ToList();
     foreach (var sl in sym_layers) {
       //assuming no offsets, etc.
       if (sl is CIMStroke stroke) {
         maxWidth = Math.Max(maxWidth, stroke.GetWidth());

  //TODO - convert width in points to map units as needed


public static class CIMStrokeExtensions {
 public static double GetWidth(this CIMStroke cimstroke) {
  if (cimstroke is CIMSolidStroke)
    return ((CIMSolidStroke) cimstroke).Width;
  else if (cimstroke is CIMPictureStroke)
    return ((CIMPictureStroke)cimstroke).Width;
  else if (cimstroke is CIMGradientStroke)
    return ((CIMGradientStroke)cimstroke).Width;
  return 0;
 }

 

 

 

You could also attempt to calculate the width using the graphic outline - a polygon generated from the feature and its renderer that "matches" the graphical outline of the given feature (whether point, line, poly, or anno).  Essentially, the outline polygon is equivalent to the masking polygon for "that" feature. The mask polygon will take into consideration all aspects of the renderer + visual variables, etc. so it is much more sophisticated but...it is a polygon and it is not necessarily straightforward to derive the feature "width" depending on the underlying shape/curvature of a particular line.

To retrieve the graphical outline of a feature: featLayer.GetDrawingOutline(....)  (note: this was QueryDrawingOutline at 2.x but the usage was the same)

 

 

 

//QTR.Run(()=> ..
var outline = featLayer.QueryDrawingOutline(oid, MapView.Active, 
  DrawingOutlineType.Exact) as Polygon;

 

 

 

 

 

DavidMrázek
Frequent Contributor

Hi, thank you very much for the advice, it helped me a lot.

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

You can also use the CIMViewer add-in to inspect the composition of your layer symbology.  A download for 3.0 is available here:  Release ArcGIS Pro 3.0 SDK for .NET · Esri/arcgis-pro-sdk-cim-viewer (github.com)

If you run ArcGIS Pro 2.x you have to clone the CIMViewer repo's source code and build the 2.x esriaddinx.  The 2.x CIMViewer solution is called: CIMViewer.sln in the same GitHub repo.

0 Kudos