Understanding the CIM A Guide for Developers

Preview:

Citation preview

Charlie Macleod

Understanding the CIM, a Guide for Developers

Understanding the CIM – A Guide for Developers

- Overview- Definition- How to retrieve and access the CIM- Transactional Model

- Practical Guidelines- Leveraging CIMViewer or CIM Serialization

- Recipe for developing custom CIM Code

• There are three major patterns within the Pro SDK - QueuedTask with async and await- MVVM (Model, View , View Model)

- …..and

- the CIM

Understanding the CIM

Understanding the CIM – CIM Definition and Purpose

• CIM or “Cartographic Information Model”:- It is a specification for persisting and transferring the state and

structure of all Pro model entities. Including:- Contents and relationships- Symbolization- Labelling- State: Visible, Editable, Selectable, etc..

- Models include Map, Layer, Layout, Report, Edit Template, etc.

Understanding the CIM – CIM Definition and Purpose

• Pro model entities provide “convenience” .NET properties for their most commonly used aspects- For the rest, we use the CIM- Much greater level of granularity than the models

- Allows the models to remain “clean”, more streamlined- Must use the CIM to manipulate renderers, symbols, text

- No model wrappers

Understanding the CIM – CIM Access

• All model entities contain a CIM representation.- Access via GetDefinition()

- Must be on the QueuedTask- Changes applied via SetDefinition()- Changes propagated back to the Pro view models via various internal “sync” events

- i.e. the various project panes and dockpanes

Understanding the CIM – CIM Characteristics

• The CIM entities themselves:- Reside in ArcGIS.Core.CIM namespace- All derive from CIMObject- Inherit serialize/deserialize to/from XML via CIMObject

- Deserialize to/from JSON available as of 2.4- Thread agnostic (can be manipulated on any thread)

- B-u-t…CIM definitions can only be retrieved/set [from/to models] via the QueuedTask

Understanding the CIM – Examples

• Transactional pattern for access – Get and Set- For example, accessing the CIM from a layer

- Note: use ToXml() to serialize to XML – useful for debugging

var streets = MapView.Active.Map.FindLayers("streets").First() as FeatureLayer;await QueuedTask.Run(() => {

//Use GetDefinition to retrieve the CIM Definition – ‘CIMFeatureLayer’//in this casevar def = streets.GetDefinition() as CIMFeatureLayer;

var str = def.ToXml();//Get the XML representation for Debug

//TODO Make changes to the CIM

//Commit changes backstreets.SetDefinition(def);

});

Understanding the CIM – Examples

• Changing feature layer selection color , hiding the legend, adding custom properties

var streets = MapView.Active.Map.FindLayers("streets").First() as FeatureLayer;await QueuedTask.Run(() =>{//access the layer CIM Definitionvar def = streets.GetDefinition() as CIMFeatureLayer;

//make changes - change the selection color, hide the legenddef.SelectionColor = ColorFactory.Instance.RedRGB;def.ShowLegends = false;

//add a custom propertyvar customProperties = new List<CIMStringMap>();customProperties.Add(new CIMStringMap() { Key = "My Property", Value = "My Value" });def.CustomProperties = customProperties.ToArray();

//set the CIM Definition backstreets.SetDefinition(def);

});

Understanding the CIM – Examples

• Updating Arrays- CIM Objects store their collection properties as arrays

- By product of CIM objects existing in .NET and Native code- Lacking “nice” List semantics for Add, Update, Remove- Many times when editing the CIM we want to update the collections (add, update, remove, etc)

Understanding the CIM – Examples

• Updating Arrays- Simplest approach is to use LINQ to convert array to List (“array.ToList()”)- Modify the list- Set the list back to the array property using “list.ToArray()”

- Also use list.ToArray() to assign a collection when the property is null

Understanding the CIM – CIM Viewer

• Diagnostic tool for examining CIM definitions:- Available on Github

https://github.com/esri/arcgis-pro-sdk-cim-viewer

- Leverages the XML nature of the CIM to view structure and values

Understanding the CIM – CIM Characteristics

• Demo

Understanding the CIM – Practical Guidelines

• When to use the CIM?- Model properties are insufficient

- You need to modify a setting not exposed on the model- You want to make multiple changes as a single transaction

- i.e. GetDefinition….changes….SetDefinition- There is no corresponding model

- Eg Renderers, Labelling, Symbology

Understanding the CIM – A Generic Approach

• Assume we need to update the CIM• Two common challenges:

- Which aspects of the CIM do we need to modify?- Translating that into our .NET code

- Can be tricky to figure out the right casts and assignments

- Toward deriving a generic or repeatable approach…we will use two examples….

Understanding the CIM – Usage Scenarios

- Mapping- Modify a (Unique Value) Renderer

- Add total counts per subtype for each legend class

Understanding the CIM – Usage Scenarios

- Layout- Customize a Layout map frame

- Use a polygon feature(s) as the map frame outline

Understanding the CIM – A Practical Approach

• How can we resolve what aspect of the CIM to modify?- 1. SDK Resources

- https://github.com/esri/arcgis-pro-sdk/wiki- https://github.com/Esri/arcgis-pro-sdk-community-samples/tree/master/Map-Authoring- https://community.esri.com/groups/arcgis-pro-sdk- https://pro.arcgis.com/en/pro-app/sdk/api-reference- https://github.com/esri/cim-spec

- Snippets, Samples, Geonet, API Reference

Understanding the CIM – A Practical Approach

• How can we resolve what aspect of the CIM to modify?- 2. Leverage the CIM Serialization to XML

- Allows us to examine the CIM for a given model- CIMViewer for “interactive” investigation or use XML Viewer of Visual Studio

- Edit the CIM, observe the changes on the UI

- “Translate” observations of the CIM XML back into code

Understanding the CIM – A Practical Approach

• Scenario 1- Customize the layer legend labels (UV Renderer)…assume SDK resources have been

consulted

• Select the layer (with the renderer)• Observe the layer definition in the CIM Viewer or in code (using “def.ToXml()”)

Understanding the CIM – Using the CIM Viewer

• Hone in on the top-level CIM characteristic you wish to modify.- The Renderer in this case

- eg “Ctrl + F” search for “Renderer”

Understanding the CIM – CIM Xml Elements

- Xml Element names correspond to the names of the CIM properties*- The “typens:” value gives you their (.NET) type.

- *Array properties identify the name. Each Child element identifies the type

Understanding the CIM – CIM Xml Elements

- Based on the XML “Build up” corresponding CIM “dot” property hierarchy based on the Xml in your code

var def = crimes.GetDefinition() as CIMFeatureLayer;var uvr = def.Renderer as CIMUniqueValueRenderer;

Understanding the CIM – A Practical Approach

• Find the value field(s) for which we want counts

Understanding the CIM – A Practical Approach

• Find where the labels are stored that we need to update

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – CIM Scenario 1

• Demo

Understanding the CIM – A Practical Approach

• Scenario 2- Customize the layout mapframe shape. Customize the border symbol

• Scenario 2- Change the shape- Change the symbol

Understanding the CIM – A Practical Approach

• Assume SDK Resources have been consulted…

• Select the layout• Observe the layout definition in the CIM Viewer or in code (using “def.ToXml()”)

Understanding the CIM – A Practical Approach

• Hone in on the top-level CIM characteristic you wish to modify.- The layout MapFrame in this case

Understanding the CIM – A Practical Approach

- Based on the XML “Build up” corresponding CIM “dot” property hierarchy based on the Xml in your code

Understanding the CIM – A Practical Approach

• Within the MapFrame we are looking for its border/frame and whatever symbol it is using…

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – A Practical Approach

Understanding the CIM – CIM Scenario 2

• Demo

Understanding the CIM – A Developer’s Guide

• Summary- Definition- Transactional Model for Get/Set- Hands-on Techniques for Developing Custom CIM code

- Covered use of CIM Viewer and/or Serialization to:- Examine the CIM- “Construct” our code (“transferring” the xml hierarchy to “dot” property notation)

ArcGIS Pro SDK for .NET – Technical Sessions

Date Time Session Location

Mon, Nov 04 1:00 pm – 1:45 pm Learning Customization and Extensibility Salon Durieux

Tue, Nov 05

9:00 am – 9:45 am Understanding the CIM, a Guide for Developers Salon Humboldt

2:00 pm – 2:45 pm Intermediate Editing Salon Durieux

4:00 pm – 4:45 pm Advanced Customization Patterns Salon Durieux

Wed, Nov 06 2:00 pm – 2:45 pm Learning Customization and Extensibility Salon Humboldt

Understanding the CIM – A Developer’s Guide

• Questions?

- https://github.com/esri/arcgis-pro-sdk/wiki/tech-sessions#2019-berlin

Complete answersand select “Submit”

Scroll down to find the feedback section

Select the session you attended

Download the Esri Events app and find your event

Please Take Our Survey on the App

Understanding the CIM – CIM Persistence

• Revisit CIMObject and Serialization/Deserialization to/from Xml, JSON- Already leveraged xml serialization in our debugging

- CIMViewer and/or Visual Studio Xml Viewer- Examine leveraging deserialization to complete persistence pattern:

- Cautionary notes regarding URIs

Understanding the CIM – CIMObject ToXml, FromXML(), ReadXml()

• Xml- All CIM classes derive from CIMObject

- Serialization via ToXml()- Deserialization either via ReadXml(XmlReader reader) or…- Concrete CIM classes have a static FromXml(string xml) method

Understanding the CIM –ToXML, FromXml()

• Xml Serialization, Deserialization

//Serialization / Deserialization with JSONvar mapframe = def.Elements.OfType<CIMMapFrame>().First();var xml = mapframe.ToXml();

//Deserialize using instance ReadXml method var mapframe2 = new CIMMapFrame();mapframe2.ReadXml(new XmlTextReader(new StringReader(xml)));

// Deserialize using matching concrete class “FromXml”var mapframe2 = CIMMapFrame.FromXml(xml);

Understanding the CIM –ToJson, FromJson()

• Json- All CIM classes derive from CIMObject

- Serialization via ToJSON()- Deserialization via concrete class static FromJson(string json) method only

Understanding the CIM –ToJson, FromJson()

• Json Serialization, Deserialization

//Serialization / Deserialization with JSONvar mapframe = def.Elements.OfType<CIMMapFrame>().First();

var settings = new JsonSerializationSettings() {PrettyPrint = true

};var json = mapframe.ToJson(settings);//Deserialize using matching concrete class “FromJson”var mapframe2 = CIMMapFrame.FromJson(json);

Understanding the CIM – A Practical Approach

• Demo

Understanding the CIM – CIM Serialization/Deserialization

• Caveats or “Fine Print”:- Avoid using CIM persistence to copy model object definition when there is a URI

- Primary examples are Maps, Layers, Layouts, Reports- Contain URIs which will be duplicated in the deserialized instances

- URIs are a primary key into the project- Duplicating URIs can have unintended consequences

- Use supported export format instead – map file, layer files, report files, etc

Understanding the CIM – A Developer’s Guide

• Summary- Definition- Transactional Model for Get/Set- Hands-on Techniques for Developing Custom CIM code

- Covered use of CIM Viewer and/or Serialization to:- Examine the CIM- “Construct” our code (“transferring” the xml hierarchy to “dot” property notation)

- CIM Persistence- ToXml and ReadXml, FromXml- ToJson and FromJson- Cautionary notes on CIM Uris and copying

Understanding the CIM – CIM Deserialization - Xml

• Deserialization via ReadXml(XmlReader reader) or static FromXML(xml)- Use a matching CIM type instance to consume the XML

- Use a map frame to deserialize a map frame- Use a scale bar to deserialize a scale bar- Use a renderer to deserialize a renderer- …etc

Understanding the CIM – CIM Serialization ToXml()

• Serialization via ToXml()- “regular” XML string (compatible with .NET xml apis).

Understanding the CIM – CIM Deserialization - Xml

• If we don’t know the type to use, examine “xsi:type=typens:CIMXyztype” attribute

- identifies “the” type to instantiate- For ReadXML:

- Use new + default ctor()- Call ReadXML on the newly constructed instance

- For static FromXML:- Call (static) FromXml directly on the appropriate type

Understanding the CIM – CIM Deserialization - Xml

Understanding the CIM – CIM Deserialization - Xml

• Optionally:- Use reflection to create the correct instance rather than new.

- Does allow for a more “generic” approach…suitable for “utility method” but….- Cast to the correct concrete type will most likely still be required at some point…

Understanding the CIM – Toward Copy or “Clone”

• Can leverage serialize/deserialization for purposes of Copy or Clone- Serialize the CIM Object to be cloned/copied via ToXml()- Deserialize it into a new instance using ReadXml(…)

Understanding the CIM – Toward Copy or “Clone”

- Use reflection to create the correct instance- .NET Extension method can add some additional syntactic “sugar”

Understanding the CIM – CIM Serialization/Deserialization

• Caveats or “Fine Print”:- Avoid CIM persistence/clone on the entire model object definition when there is a

URI- Primary examples are Maps, Layers, Layouts, Reports- Contain URIs which will be duplicated in the deserialized instances

- URIs are a primary key into the project- Duplicating URIs can have unintended consequences

- For persistence, use the supported export format instead – map file, layer files, report files, etc.

- Persistence, if done at all, is best suited to individual model object aspects like:- Renderers, Elements, Symbology, etc.

Understanding the CIM – Toward Clone

• Ideally, we can identify the CIM instance type we need from the xml- Instantiate that type auto-magically without the need to hardcode

Understanding the CIM – Toward Clone

• All serialized CIM objects carry a “xsi:type=typens:CIMXyztype” attribute

• Use that “typens:” type to identify the correct instance- Instantiate the new CIM instance using reflection- Eg System.Activator.CreateInstance(string assemblyName, string typeName)

Understanding the CIM – Toward Clone

• Example:

Understanding the CIM – A Practical Approach

Understanding the CIM – Symbology

• One of the primary uses of the CIM is in defining symbology:- Coarse-grained API available via SymbolFactory (ColorFactory for colors)- Creates a variety of “pre-cooked” symbols- Requires use of the CIM to create more specialized varieties

- As well as modify “pre-cooked” ones*

*Lots of code examples at https://github.com/esri/arcgis-pro-sdk/wiki/ProSnippets-Symbology

Understanding the CIM – Symbology

• Points, Lines, Polygons follow a very uniform structure:- Derive from CIMMultiLayerSymbol -> CIMSymbol

- Consists of one or more Symbol Layers - CIMSymbolLayer

public abstract class CIMMultiLayerSymbol : CIMSymbol {public CIMSymbolLayer[] SymbolLayers { get; set; }

Understanding the CIM – Symbology

• CIMSymbolLayer classes represent the Strokes, Fills, Markers that comprise the symbol- In simple cases, the symbol has a single layer

- Build more complex symbols using multiple layers- Can combine effects with a layer to create dots, dashes, offsets, etc.- Various options for line endings, joins, miter, etc,etc

var stroke = new CIMSolidStroke() { Color = ColorFactory.Instance.RedRGB, Width = 2 };var lineSymbol = new CIMLineSymbol() { SymbolLayers = new CIMSymbolLayer[1] { stroke } };

Understanding the CIM – Symbology

- Build more complex symbols using multiple layers- Can combine effects with a layer to create dots, dashes, offsets, etc.

- Various options for line endings, joins, miter, etc,etc

var stroke = new CIMSolidStroke() { Color = ColorFactory.Instance.RedRGB, Width = 2 };stroke.Effects = new CIMGeometricEffect[] {

new CIMGeometricEffectOffset() {Method = GeometricEffectOffsetMethod.Mitered, Offset = -3}};

var stroke2 = new CIMSolidStroke() { Color = ColorFactory.Instance.BlueRGB, Width = 1 };stroke2.Effects = new CIMGeometricEffect[] {new CIMGeometricEffectOffset() {Method = GeometricEffectOffsetMethod.Mitered, Offset = 3},new CIMGeometricEffectArrow() { ArrowType = GeometricEffectArrowType.Block, Width = 4}

};

var lineSymbol = new CIMLineSymbol() { SymbolLayers = new CIMSymbolLayer[] { stroke, stroke2 } };

Understanding the CIM – Symbology

• Points, Lines, Polygons follow a very uniform structure:- Derive from CIMMultiLayerSymbol -> CIMSymbol

- Consists of one or more Symbol Layers – CIMSymbolLayer- Layers represent the Strokes, Fills, Markers that comprise the symbol

- Consists of one or more Geometric Effects – CIMGeometricEffect- Effects are dashes, dots, line endings, offsets

- The layers represent the “primitives” used to represent the symbols- Strokes, fills, markers, etc. - CIMStroke, CIMFill, CIMMarker

- All* symbols use the same (mix of) layers- “Simple” symbols have a single layer- More complex symbols use multiple layers. Layers can be of different types

- For example – a line symbol can consist of: - A stroke, a circle marker, and a square marker

public abstract class CIMMultiLayerSymbol : CIMSymbol {public CIMGeometricEffect[] Effects { get; set; }

Understanding the CIM – Symbology

• Simple example:

Understanding the CIM – Symbology

• CIMSymbolLayer:- Marker, Stroke, Fill- Geometryic effects- To create a symbol create one or more layers- Use CIM Viewer to analyze existing symbols to “reverse engineer” how they are

created- Every CIM Symbol consists of one or more Symbol Layers - CIMSymbolLayer

- The layers represent the “primitives” used to represent the symbols- Strokes, fills, markers, etc.

- All symbols use the same (mix of) layers (Points, Lines, Polygons, Text*)- “Simple” symbols have a single layer- More complex symbols use multiple layers

- *Text can consist of multiple symbols – text itself, callout, halo, etc.

Understanding the CIM – Symbology

• Simple example

Understanding the CIM – Symbology

• Multi layer example

Understanding the CIM – Symbology

• Graphic- Combines symbol with a geometry- Use to place on the map in the overlay

- Points, lines, polygons, text

Understanding the CIM – Symbology

• Demo

Understanding the CIM – Symbology

- Clone- Deserialize from XML- Dealing with URI

Understanding the CIM – Symbology

- Demo

Understanding the CIM – Symbology

- Versioning- Typens in root elements

Understanding the CIM – CIM Access

• It is a transactional pattern- Retrieve the model’s CIM definition [Get]- Change the desired properties- Apply the changes back to the model [Set]

var def = layout.GetDefinition();//Change definition as needed//Commit changes backlayout.SetDefinition(def);

SymbolStyleItem si = . . .var symbol = si.Symbol;si.Symbol = symbol;

var renderer = ((FeatureLayer) layer).GetRenderer();((FeatureLayer)layer).SetRenderer(renderer);

AnnotationFeature feature = . . .var graphic = feature.GetGraphic();

Understanding the CIM

• Accessing the CIM:

public abstract class CIMMultiLayerSymbol : CIMSymbol {public CIMGeometricEffect[] Effects { get; set; }public CIMSymbolLayer[] SymbolLayers { get; set; }

Recommended