Hello,
I need some help to programmatically add dimensions into a 3D model where the dimension vertices are associated with edges or vertices of on or more smart solids contained within shared cells. This is easily accomplished manually however, due to the size and volume of work, I need to place the dimensions programmatically within a C#.NET Addin for MicroStation CONNECT edition.
I apologise for the amount of detail in this question but I'm trying to do something quite specific and would rather pinpoint the problem than waste people's time with a question like "can you design me software to do something".
Context
- I have a large 3D cell library that needs to verified
- the cell library consists of component cells and assembly cells
- the component cells are 3d models which typically contain a single smart solid element
- the assembly cells are 3d models which typically contain shared cell instances where the shared cell definitions are component cells
- the verification process requires the cell to be referenced into a 3D verification model and dimensions added to confirm the design parameters (see illustration below)
A sample of the verification output is provided in the screenshot below. There are three dimensions that have been added manually The first is a linear dimension associated to vertices of two different shared cell instances (albeit from the same shared cell definition). The second is a linear size dimension associated with an edge of one of the shared cell instances and the third dimension is a radial dimension associated with an edge of one of the shared cell instances.
Problem
I have been able to programmatically place associated dimensions on a component cell (which is a model containing a smart solid element). However, the assembly cells are models which contain shared cell instances and I have been unable to obtain a reference to any geometry within any shared cell instance to use as a keypoint or arc association point for the dimension (see code sample below for components).
Solutions Investigated
For the component cell verification, my process is:
- Get the smart solid element as a BrepCellHeaderElement
- Convert the BrepCellHeaderElement to a COM element
- Call GetSubElements().BuildArrayFromContents() to get an array of BREP edges / elements
- Convert the COM sub-elements back to DgnPlatform elements
- Identify the DPoint3ds for the dimension vertices from the child elements of the BrepCellHeaderElement
- Create association points using the IDs of the child elements of the BrepCellHeaderElement (e.g. a line endpoint or an arc centre)
- Create the dimension and use InsertPoint() with the relevant dimension vertex (DPoint3d) and association point.
I would like to skip the COM conversion steps 2-4 but to date, I have been unable to access the children of a Type2Element (or SharedCellElement) any other way.
The only way I have been able to create association points for the features of a Smart Solid is to use the ElementIDs of the sub-elements of the BrepCellHeaderElement. I am aware that there is a method to use a SnapPath for creating association points but the API documentation provides very little explanation or examples how to do this. If someone can provide sample code to achieve that, it would be greatly appreciated to help my understanding of this API.
However, this approach does not work with shared cell instances.
The only Bentley Community article that I could find which might be related to my difficulties with shared cell instances is https://communities.bentley.com/products/programming/microstation_programming/f/microstation-programming---forum/180853/connect-c-how-to-iterate-through-child-elements-of-a-sharedcellelement/526679#526679. The solution in that article refers to the ElementGraphicsProcessor but I have been unable to work out how to use this object from the API documentation. My initial approach was to try to use the COM conversion technique again but the sub-elements of a SharedCellElement instance have element IDs of zero so they can not be used to create association points. I suspect that it may require the SnapPath method but I do not know for sure.
Code Example for Component Cell Verification (Normal Cell with Smart Solid)
public void Verify3d(DgnModel model, DgnAttachment attachment) { // model is the verification 3D model // attachment is the component cell model containing the item to be verified // use LINQ to get the first SmartSolid element within the component cell var componentElem = attachment.GetDgnModel() .GetGraphicElements() .Where(x => x is BrepCellHeaderElement) .Cast<BrepCellHeaderElement>() .FirstOrDefault(); if (componentElem != null) { // extract the sub-elements of the SmartSolid for use with dimensions // note: GetComplexChildren() is a custom extension method workaround // to get the child elements of a Type2Element using COM Element[] brepChildren = componentElem.GetComplexChildren(); ArcElement[] arcEdges = brepChildren.Where(x => x is ArcElement) .Cast<ArcElement>() .ToArray(); LineElement[] lineEdges = brepChildren.Where(x => x is LineElement) .Cast<LineElement>() .ToArray(); // ... // other code omitted // ... // populate dimension vertices DPoint3d[] vertices = { lineEdges[1].GetStartPoint(), // custom extension method to get start point of a line element arcEdges[2].GetArcCentre(), // custom extension method to get the centre of an arc element }; // create associative points for the dimension AssociativePoint[] assocPoints = { // custom utility method to get a keypoint association at the start of the line GetKeypointAssociation(lineEdges[1], 0), // custom utility method to get an arc centre association GetArcAssociation(arcEdges[2],AssociativePoint.ArcLocation.Center) }; // create the linear dimension and associate to the start of line 1 and centre of arc 2 DimensionData dimData = new DimensionData(); DimensionElement dimElement = new DimensionElement(model, dimData, DimensionType.SizeArrow); DimensionStyle dimStyle = dimElement.GetDimensionStyle(); dimElement.InsertPoint(vertices[0], assocPoints[0], dimStyle, 0); dimElement.InsertPoint(vertices[1], assocPoints[1], dimStyle, 1); dimElement.AddToModel(); } }
public static BDPN.Element[] GetComplexChildren(this BDPN.ComplexHeaderElement elem) { if (elem == null) return null; BCOM.Element[] elements = elem.ConvertToCOMElement().AsComplexElement().GetSubElements().BuildArrayFromContents(); return elements.Select(e => e.ConvertToDgnPlatformNetElement()).ToArray(); }
Conclusion
If anyone can provide some snippets of code to better achieve what I am trying to do in the DgnPlatformNet way, it would be greatly appreciated.
Thank you in advance,
Trevor.