MicroStation and Application Development

MicroStation® is a computer-aided-design (CAD) tool produced by Bentley Systems. It is used by engineers, architects, and draughting technicians to create 3D models and 2D drawings.

MicroStation can be customised. Bentley Systems themselves have many applications for specialised markets that use MicroStation as a platform. Third-parties likewise may use MicroStation as a platform on which to develop their application software. Bentley Systems provide the MicroStation Software Development Kit (SDK) that software developers use to create their applications.

The SDK has two libraries: the MicroStation Development Library (MDL) and the MicroStationAPI. The MicroStation Development Library contains thousands of functions that provide a C-language interface. The MicroStationAPI provides a C++ interface.

The MicroStationAPI for CONNECT is relatively recent and poorly understood by developers. This article attempts to clarify and explain the MicroStationAPI from a developer's viewpoint. In particular, it provides a commented code fragment that illustrates a common requirement: to provide a consistent way to enumerate a set of elements.

IElementSet

The MicroStationAPI provides the IElementSet interface definition. It's an abstract class, so you must inherit it and implement its pure virtual methods. Bentley staffer Paul Connelly commented: IElementSet is purposely opaque: user need neither know nor care how the elements are supplied.

ElementAgenda

ElementAgenda is a general-purpose class that stores a list of EditElementHandle. You'll find it implemented in DgnElementSet, among other classes.

ElementAgenda.BuildFromElementSet populates its internal list from any class that implements the IElementSet interface.

How to Implement IElementSet

Simple Example

Paul Connelly wrote this example to illustrate an implementation of IElementSet. This class contains a single ElementHandle, which is revealed by the IElementSet interface …

#include <ElementHandle.h>
class OneElement : public IElementSet
{
    ElementHandle eh_;
public:
    size_t        GetCount () override { return 1; }
    bool          GetFirst (ElementHandleR eh) override { eh = eh_; return true; }
    bool          GetNext (ElementHandleR) override { return false; }
};

Note how you use this class: call GetFirst() to get the first & only ElementHandle. GetNext() always returns false, making it easy to enumerate this minimalist container.

Container Example

Here's a more complex class that has a vector of ElementHandle. Now we must implement range checking when we assign the vector contents …

class MyCollection : public IElementSet
{
    size_t index_;
    bvector data_;

public:
    MyCollection () : index_ (0) {}
    size_t   GetCount () override { return data_.size (); }
    bool     GetFirst (ElementHandleR eh) override
    {
        index_ = 0;
        eh     = data [index_];
        return true;
    }

    bool     GetNext  (ElementHandleR eh) override
    {
        if (index_ != data_.size ())
        {
            eh = data [index_];
            ++index_;
            return true;
        }
        return false;
    }
};

How to Use IElementSet

Because we inherit IElementSet, our user find it easy to enumerate our class contents …

    //    Simplest Example
    OneElement  one;
     … populate data somehow
    //  Enumerate OneElement
    ElementHandle  eh;
    bool           valid  { one.GetFirst (eh) };
    while (valid)
    {
        //  Do something with ElementHandle
        valid = one.GetNext (eh);
    }
    //    Collection Example
    MyCollection  data;
     … populate data somehow
    //  Enumerate MyCollection
    ElementHandle  eh;
    bool           valid  { data.GetFirst (eh) };
    while (valid)
    {
        //  Do something with ElementHandle
        valid = data.GetNext (eh);
    }