Python

Q How do I count elements by level using MicroStation Python? To ask that another way: How do I count the number of elements on a particular level?

A Here's a small Python program that counts elements by level.

Python Implementation

The Count Elements on Level example borrows from Python articles and examples delivered with MicroStation Python.

We get a list of DGN elements (as elementRef) in a DGN model using DgnModel.GetGraphicElements(). Next we enumerate the list and analyse each elementRef …

After executing the above we have a Counter, which is a specialised dictionary, populated with the count of each level found on each element. If an element is complex, the code has obtained the level ID from a nested graphic element.

Here's the Python class DgnElementCounter used to get a list of elements and analyse each one in method CountElements …

class DgnElementLevelCounter:
    """A class to count DGN elements on one or more levels in a DGN model.

    For example, count elements on level 'Areas'.
    By default, collects elements from the active model.
    For each element, it adds its level ID to a Counter object.
    """

    def __init__(self, dgnModel: DgnModel = ISessionMgr.ActiveDgnModelRef.GetDgnModel()):
    	# DgnElementLevelCounter by default searches the active DGN model
        self._dgnModel = dgnModel
        self._elementCount = 0
        # Instantiate a Counter object to store level IDs and the count of each level
        self._levelCounter = Counter()

    def EnumerateElements(self)->int:
        nElements = 0
        for elemRef in self._dgnModel.GetGraphicElements():
            nElements += 1
            CollectLevels (elemRef, self._dgnModel, self._levelCounter)

        return nElements

    @property
    def LevelCounter (self):
        # Get the level counter object
        return self._levelCounter

    @property
    def DgnModelName (self):
        # Get the name of the DGN model that contains elements to be counted
        if (self._dgnModel is None):
            return "unknown"
        else:
            return self._dgnModel.GetModelName()

    def __str__(self):
        return f"Element count {self._elementCount} in model '{self.DgnModelName()}'"

    def __repr__(self):
        return 'CountElements(Level ID List)'

Function CollectLevels() fills the Counter with each found level, along with the count of the number of elements assigned that level ….

def CollectLevels (elemRef: PersistentElementRef, dgnModel: DgnModel, levelCounter: Counter):
    """Get level(s) from an element, and insert into a Counter keyed by level ID.
    This function calls itself recursively to investigate complex elements such as cells."""

    eh = ElementHandle (elemRef, dgnModel)
    handler = eh.GetHandler()
    description = getElementDescription(eh)
    MessageCenter.ShowDebugMessage(f"CollectLevels found {description} ComplexElementHandler={handler in ComplexElementHandlers}",
        f"CollectLevels found {description}  in ComplexElementHandlers={handler in ComplexElementHandlers}", False)
    #   If this is a complex element  (e.g. a cell or grouped hole)
    if isinstance (handler, ComplexElementHandlers):
        component = ChildElemIter(eh, ExposeChildrenCount)
        while component.IsValid():
            handler = component.GetHandler()
            if isinstance (handler, ComplexElementHandlers):
                CollectLevels (component.GetElementRef(), dgnModel, levelCounter)
            else:
                levelId = component.GetElement().ehdr.level
                levelCounter.update ((levelId, ))

            component = component.ToNext()
    else:
        levelId = eh.GetElement().ehdr.level
        count = levelCounter[levelId]
        MessageCenter.ShowDebugMessage(f"CollectLevels found {count} level ID {levelId}", f"CollectLevels found level ID {levelId}", False)
        levelCounter.update ((levelId, ))

Once all elements have been investigated, we're left with a Counter filled with the found levels and the count of each level. Ask for the count of a level like this …

nLevels = counter.LevelCounter[levelId]

The Python source code of Count Elements is available for download.

Usage

Count Elements is intended to be used by your Python code. Import it as a module …

import la_solutions_elements_count_by_level

You can test it as stand-alone code from the MicroStation Python manager. You'll find these lines in the project …

if __name__ == "__main__":  # check if this script is being run directly (not imported as a module)
    counter = DgnElementCounter()

Everything after those lines will be executed from a Python prompt or in MicroStation's Python Manager.

Download la_solutions_count_elements_by_level.zip

Unpack the ZIP file and copy the Python file into a folder that MicroStation knows about.

Python Manager

Use MicroStation's Python Manager to find and execute the script.

Questions

Post questions about MicroStation programming to the MicroStation Programming Forum.