The MicroStation Development Library (MDL) provides an API for developers wanting to create custom applications for MicroStation® from Bentley Systems.
We usually create a MicroStation application as a DLL, written using C++ and built with
the Microsoft C++ compiler and linker.
You can choose whether to use
Microsoft Visual Studio
IDE or the Bentley Systems bmake tools.
We often want to locate a graphic element in a MicroStation DGN model. The locate operation may be interactive or non-interactive. That is, we want the user to locate an element, or we want to scan the model to find one or more elements.
As developers, we use the mdlLocate_api to write interactive locate logic
(although this is superseded by classes provided by the MicroStationAPI).
We use the mdlScanCriteria_api to write code that scans a model.
In a given application, we often want to write code that does each of the above at different times:
sometimes we want a user to locate an element, at other times we want to
scan a model and do something with the result set.
MDL's locate logic requires us to set a locate mask prior to choosing elements. The locate mask restricts MicroStation's logic to allow only certain element types to be chosen. Here's an example that lets us locate lines, line-strings, and shapes …
static int searchMask [] = { LINE_ELM,
LINE_STRING_ELM,
SHAPE_ELM,
};
mdlLocate_setElemSearchMask (sizeof (searchMask) / sizeof (searchMask [0]), searchMask);
MDL's scanning logic requires us to set scan criteria prior to searching for elements. Here's an example: pay particular attention to the lines that set the element type …
ScanCriteria* pCriteria = mdlScanCriteria_create ();
if (NULL != pCriteria
&&
SUCCESS == mdlScanCriteria_setModel (pCriteria, modelRef))
{
// Set the scan criteria element type test
UShort typeMask [6];
memset (typeMask, 0, sizeof (typeMask));
typeMask[0] = TMSK0_LINE | TMSK0_LINE_STRING | TMSK0_SHAPE;
mdlScanCriteria_setDrawnElements (pCriteria);
mdlScanCriteria_setElementTypeTest (pCriteria, typeMask, sizeof (typeMask));
// Perform the scan
mdlScanCriteria_setReturnType (pCriteria, MSSCANCRIT_ITERATE_ELMDSCR, FALSE, TRUE);
mdlScanCriteria_setElmDscrCallback (pCriteria, scan_callbackCreateShapeList, &args);
mdlScanCriteria_setStopFilePos (pCriteria, mdlModelRef_getEof (modelRef));
mdlScanCriteria_scan (pCriteria, NULL, NULL, NULL);
mdlScanCriteria_free (pCriteria);
}
The two code snippets above illustrate that the logic required to set up element type testing is
quite different, depending on whether you are locating or scanning for elements.
Even the element type macros (LINE_ELM for locate, TMSK0_LINE for scanning) have different names.
The problem with two different APIs is that it's hard to remember to keep them synchronised. If we want to add the ability to locate ellipses, then we modify one section of code. But we probably want to scan for ellipses as well, so we must modify another unrelated section of code. This is poor programming practise, forced on us by the history of MDL and the C programming language.
C++ class CSearchTypes hides the differences between MDL's location and scanning logic.
The MDL code above is hidden inside the class's private member functions.
You don't have to concern yourself with the different macros — you need only use the LINE_ELM macros.
CSearchTypes is designed to be inherited, so you can easily create a custom class
for exactly those element types that interest you.
Here's an extract from the header file …
// typedef clarifies subsequent code typedef std::vector<int> ElementTypeCollection; typedef ElementTypeCollection::iterator ElementTypeIterator; typedef ElementTypeCollection::const_iterator ElementTypeConstIterator; class CSearchTypes { protected: ElementTypeCollection types_; public: ////////////////////////////////////////////////////////////////// // Implementation UInt32 Count () const { return static_cast(types_.size ()); }; // Set MicroStation's locate search mask void SetLocateSearchMask () const; // Set MicroStation's scan criteria type mask bool SetScanCriteria (ScanCriteria* criteria) const; // Is an element accepted by this search type bool Acceptable (int type) const; virtual bool Acceptable (const ElementRef el) const; virtual bool Acceptable (MSElement const* el) const; virtual bool Acceptable (MSElementDescr const* el) const; ////////////////////////////////////////////////////////////////// // Construction CSearchTypes () {}; virtual ~CSearchTypes () {}; protected: UInt32 CreateTypeMask (UShort mask [], int size) const; };
You create your class that inherits from CSearchTypes for particular element types.
Here's an example of a class specialised for linear types …
class LinearTypes : public CSearchTypes
{
public:
//////////////////////////////////////////////////////////////////
// Construction
LinearTypes ();
~LinearTypes () {};
};
Not a lot to it, is there?
The key is in the LinearTypes constructor implementation …
//////////////////////////////////////////////////////////////////////
// class LinearTypes
//////////////////////////////////////////////////////////////////////
LinearTypes::LinearTypes ()
{
types_.push_back (LINE_ELM);
types_.push_back (LINE_STRING_ELM);
types_.push_back (ARC_ELM);
types_.push_back (CURVE_ELM);
types_.push_back (CMPLX_STRING_ELM);
types_.push_back (BSPLINE_CURVE_ELM);
types_.push_back (MULTILINE_ELM);
}
Whenever we instantiate a LinearTypes object, its internal list of element type(s) is created automatically.
Now it's very simple to set up your locate mask or scan criteria …
#include <SearchTypes.h> LinearTypes linearTypes; // Internal type list is initialised in the constructor … // Locate setup linearTypes.SetLocateSearchMask (); … // Scan Criteria setup ScanCriteria* pCriteria = mdlScanCriteria_create (); linearTypes.SetScanCriteria (pCriteria);
Download the CSearchTypes Source Code. You need Visual Studio 2005 to be installed in order to compile and link this code.
Return to MDL articles index.