[Microstation CE u13] ElementGraphicsProcessor example in C#

Hi all,

I am trying to extract all of the elements contained within a paramteric cell, and it was suggested that I use the ElementGraphicsProcessor abstract class to achieve this. The objective is to to return all graphical elements from the cell instance in their true location (with the same geometry), along with their associated symbology. Essentially this would have a similar outcome as dropping the cell however the typical workflow for dropping an element programmatically doesn't seem to work on parametric cells unfortunately. Does anyone have any examples or documentation that could enlighten me on how to achieve this?

Thanks!


Ed

Parents
  • Hi Edward,

    and it was suggested that I use the ElementGraphicsProcessor abstract class to achieve this

    Er ... no, in fact. I recommend to use ElementGraphicsProcessor to obtain geometry, not elements! It's important to distinguish between these two different information ;-)

    The objective is to to return all graphical elements from the cell instance in their true location (with the same geometry)

    In general, some objects allow to access internal elements, some not. There is even a method called ExposeChildren to determine whether this functionality is supported. My feeling is that general concept of new API is to do not expose internal elements (as elements), because it's implementation / persistence detail, but to prefer to use the object geometry everywhere it's possible.

    Whereas e.g. plain cell is the example of the element exposing children, parametric cell is black bock and it's not possible to access original elements (at lest in the current API version). What is not clear whether it's "by design" or it's just "not implemented yet" feature, because constraints-based modeling is still under development and new features are added.

    the typical workflow for dropping an element programmatically doesn't seem to work on parametric cells unfortunately

    I think the drop tool does not work well with parametric cells in general, not only in API.

    Does anyone have any examples or documentation that could enlighten me on how to achieve this?

    There is, the processor is used in some example delivered with SDK and when you will search this forum, you will find discussion about different aspects of this (great and clever!) object ... also because it seems in some situations the wrapper around native processor does not work as expected.

    The code can be similar to this one:

        internal class Demo
        {
            public void IterateAllElements()
            {
                ParametricCellProcessor processor = new ParametricCellProcessor();
    
                DgnModel model = Session.Instance.GetActiveDgnModel();
    
                ModelElementsCollection elements = model.GetGraphicElements();
    
                foreach (Element element in elements)
                {
                    if (element is ParametricCellElement instance)
                    {
                        MessageCenter.Instance.StatusMessage = $"Parametric cell: {instance.CellDefinition.CellName}";
                        ElementGraphicsOutput.Process(instance, processor);
                    }
                }
            }
        }
    
        internal class ParametricCellProcessor : ElementGraphicsProcessor
        {
            public override bool ProcessAsBody(bool isCurved)
            {
                return false;
            }
    
            public override bool ProcessAsFacets(bool isPolyface)
            {
                return false;
            }
    
            public override BentleyStatus ProcessCurveVector(CurveVector curves, bool isFilled)
            {
                return BentleyStatus.Error;
            }
    
            public override BentleyStatus ProcessCurvePrimitive(CurvePrimitive curve, bool isClosed, bool isFilled)
            {
                MessageCenter.Instance.StatusMessage = $"{curve.GetCurvePrimitiveType()}";
                return BentleyStatus.Success;
            }
    
            public override bool WantClipping()
            {
                return false;
            }
        }

    I recommend (in fact, I think you have to) to read ElementGraphicsProcessor description in native MicroStatioAPI doc, because it's crucial to understand what "bool returning" methods should be overridden to obtain what result.

    When you are interested in symbology (or other "not geometry info), override proper AnnounceXYZ method.

    With regards,

      Jan

  • Thanks Jan,

    use ElementGraphicsProcessor to obtain geometry, not elements!

    You're right, poor choice of words! I need to obtain the geometry of the parametric cell in order to build the (new) elements.

    In general, some objects allow to access internal elements, some not. There is even a method called ExposeChildren to determine whether this functionality is supported

    This is actually what I attempted at first, but quickly realised that there were no children that could be exposed within a Parametric Cell Element. If only it were that easy!

    I think the drop tool does not work well with parametric cells in general, not only in API

    If attempting to do this manually using the 'Drop Element' tool with just the 'Application Elements' ticked everything works as I'd hoped it would, dropping them to their original elements:

    Which makes me wonder if perhaps their is a simpler method to drop Application Elements to their primitives/breps?

    I recommend (in fact, I think you have to) to read ElementGraphicsProcessor description in native MicroStatioAPI doc, because it's crucial to understand what "bool returning" methods should be overridden to obtain what result

    Thanks for the code sample, I'll test that out. With regards to the documentation; when reading through the API docs and forum posts, I didn't quite understand how the geometry is returned to the main script. Am I right in assuming I should read the geometry output from the MessageCenter and use that info to build all the required geometry, through the use of Bentley.GeometryNET library? Looking through the GeometryNET library there are a vast array of methods for each element type; and it looks like a very arduous task if I need to write a script to use the correct methods for drawing an arc, line etc. for all the possible permutations that may occur! Hopefully this is not the case and my interpretation is wrong... What seemed like an easy task in order to finish my GC Node has turned into a full day of struggling to get nowhere lol.
    I really appreciate all the advice to help make sense of this!

    Thanks,

    Ed

  • If only it were that easy!

    Maybe easy for developers, but wrong in terms of data structures.

    It's my subjective feeling, but I see a movement from "C data structures" to "object abstraction using handlers (services)". Whereas it was normal in DGN V7 and also in V8 times to go inside structures and to change directly different parts (which often ended in strange or even corrupted elements), now it's more like "here is a handler, call services (queries) that you need, but do not care about implementation details".

    As written in C++ documentation, every handler should be very careful about providing a list of children elements, because in such case the handler has not any control over them. So for some objects it's possible, for some not.

    If attempting to do this manually using the 'Drop Element' tool with just the 'Application Elements' ticked everything works as I'd hoped it would, dropping them to their original elements:

    I guess there is no problem with 2D constraints, but I tried it with some 3D objects and the results were bad.

    Which makes me wonder if perhaps their is a simpler method to drop Application Elements to their primitives/breps?

    There is Drop structure available in C++, but I think it's not available in managed API (yet?).

    I didn't quite understand how the geometry is returned to the main script.

    I am not sure what you are asking about.

    What processor method is called and how (in what format) the geometry is provided depends on the processor configuration (what type of geometry are you interested in).

    What you will do next with received geometry is completely up to you (e.g. list of geometries added to a list injected to processor?) and does not relate to API itself.

    Looking through the GeometryNET library

    Why? At first, look at examples delivered with MicroStation SDK, at second, search in this forum, at third, read this community blogs (even when there is not many articles). In my opinion, after several years of CE API existence, all typical activities / workflows have been discussed and snippets provided.

    and use that info to build all the required geometry, through the use of Bentley.GeometryNET library?

    Not at all. GeometryNET library is mostly internal aspect of API and usually there is no reason to use it for anything (only to reference the assembly when required).

    To create elements from existing topology / geometry data, use DraftinElementSchema class.

    and it looks like a very arduous task if I need to write a script to use the correct methods for drawing an arc, line etc. for all the possible permutations that may occur!

    If your code ends with such state, something is probably wrong and it means you do not use OOP abstraction provided by API properly. For many requirements, specialized (single focused) class probably exists in API.

    What seemed like an easy task in order to finish my GC Node has turned into a full day of struggling to get nowhere lol.

    Sorry, but such comparison is complete nonsense in my opinion. There is no reason compare platform MicroStation NET API and specialized GC environment. They are different tools developed for different purposes.

    GC were implemented using platform API and it's why the platform API exists: Namely C++ API is ready to solve nearly any requirement and allows to implement nearly anything including all other discipline-specific product APIs. The low-level and flexible API typically requires to write more code ... similarly when you will try to compare C++ (powerful but seriously complicated) and Python (more user oriented and not so flexible, but more friendly).

    With regards,

      Jan

  • I need to obtain the geometry of the parametric cell in order to build the (new) elements.

    One more comment: You should be aware that using ElementGraphicsProcessor, it's not ensured you will be able to create exact copy of the source element. For 2D elements, you can expect that a curveVector equals to source element, but in the case of ParametricCell its structure is variable controlled by values.

    DropGeometry struct available in C++ API is closer to a concept of "splitting source element to individual children".

    So in summary, there are at least 3 different concepts (methods or classes) available:

    • GetChildren ... when it's supported
    • DropGeometry ... probably not available in NET now
    • ElementGraphicsProcessor

    For complete overview, see Geometry Collectors chapter in C++ API documentation.

    Regards,

      Jan

Reply Children
No Data