The MicroStation Development Library (MDL) and MicroStationAPI provide APIs for developers wanting to create custom applications for MicroStation® from Bentley Systems. We create a MicroStation application as a DLL, written using C++ and built with the Microsoft C++ compiler and linker provided with Visual Studio.
When editing your source code, you can choose whether to use Microsoft Visual Studio, Microsoft Visual Studio Code, or one of your favourite text editors.
When building your app, you can use Visual Studio or the Bentley Systems make (bmake) tools.
A common task is to select graphic elements while editing a DGN model. The delivered examples are quite complex. The MicroStationAPI help documentation is concise and not written to help a new developer. I wanted a simple example of element location. In particular, I want to show how to select elements in various ways …
The Simple Locate Tool is a C++ project that uses the MicroStationAPI.
In particular, it shows a simple implementation using the DgnElementSetTool
as a base class.
DgnElementSetTool
provides a class used to locate elements prior to editing or modification.
DgnElementSetTool
Base Class
DgnElementSetTool
is quite versatile:
it is designed to be used as a base class that your custom tool will inherit.
It lets you create a location tool with numerous options.
Options are invoked by overriding methods in the DgnElementSetTool
class.
However, it is not always obvious which methods we should override to obtain a desired functionality. Nor is it always clear what values should be returned by our overrides to obtain the correct behaviour.
The Simple Locate Tool is small and simple. It has three commands …
Command | Comment |
---|---|
EXAMPLE QUERY ACTIVE | User can locate elements in the active model, but not in reference attachments |
EXAMPLE QUERY REFERENCE | User can locate elements in the active model and in reference attachments |
EXAMPLE FILE EXIT | Unloads the application |
The application is aware of Selection Sets and Fences.
When user has created a fence or selection set, the EXAMPLE QUERY XXX
asks for a data point to confirm the operation, then process the elements in the fence or selection set.
This gives you the opportunity to examine and modify the selected elements using
the overridden DgnElementSetTool::_FilterAgendaEntries
.
When you want your tool to accept a user-defined fence, add this to your class …
virtual UsesFence _AllowFence () override { return USES_FENCE_Check; }
When you want your tool to accept a user-defined selection set, add this to your class …
virtual UsesSelection _AllowSelection () override { return USES_SS_Check; }
The values returned above tell your tool to check whether a fence or selection set is active. If so, process that multiple selection; otherwise, let the use choose a single element.
When you want your tool to accept a user-drag, add this to your class …
virtual UsesDragSelect _AllowDragSelect () override { return USES_DRAGSELECT_Line; }
Available options are …
USES_DRAGSELECT_None
USES_DRAGSELECT_Line
USES_DRAGSELECT_Box
If you need to know how elements are selected, call DgnElementSetTool::_GetElemSource
.
Here's an example from the overridden _OnElementModify
method …
StatusInt ExampleQueryTool::_OnElementModify (EditElementHandleR eeh) { ElemSource source = _GetElemSource (); WString sourceDescr; switch (source) { case SOURCE_Pick: sourceDescr = L"Pick"; break; case SOURCE_Fence: sourceDescr = L"Fence"; break; case SOURCE_SelectionSet: sourceDescr = L"SelectionSet"; break; } const StatusInt& ElementUnchanged = PermitReference ()? ERROR: SUCCESS; return ElementUnchanged; }
This tool, as with other primitive tools you may write, uses an ElementAgenda
to store a list of interesting elements.
MicroStationAPI help tells us:
Typically, ElementAgendas are created by MicroStation from sources that work on multiple elements such as the SelectionSet and Fences.
However, as a general-purpose bvector of EditElemHandles,
ElementAgendas can be created by applications for other purposes as well.
ElementAgendas are themselves reference counted.
DgnElementSetTool::_FilterAgendaEntries
provides an opportunity to reject selected elements.
For example, a user fence may contain elements in the active model, which you want to modify.
That same fence may contain elements in referenced models, which you can't modify.
You can invalidate members of the ElementAgenda
so that they are not
presented to your modification code.
// Return true to tell DgnElementSetTool to removed invalidated entries from the ElementAgenda bool ExampleQueryTool::_FilterAgendaEntries() { if (PermitReference ()) return false; EditElementHandleP curr = GetElementAgenda ().GetFirstP (); EditElementHandleP end = curr + GetElementAgenda ().GetCount (); bool changed = false; for (; curr != end; ++curr) { // For this example, remove elements in reference attachments if (mdlModelRef_isReference (curr->GetModelRef ())) { curr->Invalidate (); changed = true; } } return changed; }
DgnElementSetTool
is intended to be the base class for your element modification tool.
By default, it lets the user select elements only in the active model.
You can override one of its methods to allow the user to choose an element in a reference …
virtual bool _IsModifyOriginal () override { return false; }
That return value false
tells DgnElementSetTool
that you won't modify a located element.
Bentley Systems senior MicroStation developer Brien Bastings provided these additional hints & tips on the MicroStation Programming Forum.
Just wanted to add a couple things that probably aren't obvious.
DgnElementSetTool
establishes the locate criteria in _SetLocateCriteria
(which is called from _BeginPickElements
for pick and _BuildAgenda
for fences and selection sets).
This is the place to add any tool specific locate criteria as opposed to _OnPostInstall
.
Returning false from _IsModifyOriginal
allows locked/reference elements to be selected as it puts
DgnElementSetTool
into copy mode.
For a query-only tool this can have the undesirable side-effect of cloning styles,
etc. from the source to the destination.
To avoid this, a query tool should override _OnPreElementModify
.
If you return SUCCESS
without calling __super
,
_OnElementModify
will still be called if that's where you want to have your logic to
extract information from the selected elements.
// Query tool doesn't modify elements …
virtual StatusInt _OnElementModify (EditElementHandleR eeh) override {return ERROR;}
// Don't copy styles, etc. from reference to active …
virtual StatusInt _OnPreElementModify (EditElementHandleR eeh) override {return SUCCESS;}
// Allow selection of locked/reference elements …
virtual bool _IsModifyOriginal () override {return false;}
You can download the Simple Locate Example Project. The project is built using the Bentley Make build tool (BMake). It uses the C++ compiler and linker installed with Visual Studio 2013.
Post questions about C++ and the MicroStationAPI to the MicroStation Programming Forum.