Questions similar to this appear on the Bentley Discussion Groups. This problem appeared in the MDL discussion group.
Q
A MicroStation's fence offers more than a simple boundary around interesting elements: it has topological analysis built-in! By topological analysis, we mean that, depending on the current fence mode in the Tool Settings dialog, MicroStation can perform a different extraction depending on the current fence mode. You can set the fence mode programmatically with MDL.
By contrast MDL's scanning logic is much simpler: it starts at the beginning of a model's element list, and checks each element against its scan criteria. Those criteria may include a range, so that an element whose geometry lies within the high and low range limits will be included. The scanner knows nothing about topological analysis.
With the above in mind, there are two answers to the question about fences and scan ranges …
Processing a fence is reasonably straightforward, even though the use of the MDL functions is not intuitive. The advantage of using fence processing functions is that you will receive only those elements that satisfy the current fence mode. That is, MicroStation has already performed a topological analysis of the relationship of each element to the fence boundary. You need not concern yourself whether the fence mode is INSIDE, VOID, OVERLAP, or some combination of those modes.
In your header file, define a struct to hold parameters to be used by your fence processing function.
The contents of this structure are entirely up to you: MicroStation doesn't use it.
Write a fence process callback function. This will be called for each element that satisfies the current
fence criteria. If you want to examine the element, call mdlElement_getFilePos (FILEPOS_CURRENT, ...)
to find the element's file position and model reference, then read into an elementRef, MSElement or MSElementDescr*.
typedef struct my_fence_params
{
int intValue;
double doubleValue;
char text [12];
} MY_FENCE_PARAMS, *LP_MY_FENCE_PARAMS;
int fenceFunction (LP_MY_FENCE_PARAMS param)
{
// Get the file position and model reference of the element
// currently being examined
DgnModelRefP modelRef = NULL;
ULong filePos = mdlElement_getFilePos (FILEPOS_CURRENT, &modelRef);
// Get the ID of the element
ElementRef elemRef = mdlModelRef_getElementRef (modelRef, filePos);
ElementID elemId = elementRef_getElemID (elemRef);
sprintf(msg, "Element ID %I64d intValue %d", elemId, arg->intValue);
mdlOutput_messageCenter (MESSAGE_DEBUG, msg, msg, FALSE);
// Increment our passed value
++(param->intValue);
return SUCCESS;
}
MY_FENCE_PARAMS param;// Set up parameter values for our fence process callback functionmemset (¶m, 0x00, sizeof (param)); param.intValue = 0;// Even though we're not using MicroStation's state machine, // we call mdlState_startFenceCommand to specify our // fence processing callback functionmdlState_startFenceCommand (fenceFunction, NULL, NULL, NULL, 0, 0, FENCE_NO_CLIP);// Set locate criteria to allow or prevent the processing // of elements in referenced modelsmdlLocate_init (); if (scanRefs) mdlLocate_allowLocked (); else mdlLocate_normal ();// Perform fence processing. The param argument is the address of // a struct that we have defined. For each element found during // fence processing, MicroStation calls our callback functionmdlFence_process (¶m);
You can download a sample MDL project. It contains the complete source code ProcessFenceContents.zip from which the above were extracted, plus a make file. It's ready to
You can extract the range of the current fence, then apply that to the ScanCriteria of a model scan. The scan returns only those elements that overlap or fall within the range. There are at least two disadvantages to this approach …
BoolInt extractScanRangeFromFence (ScanRange* scanRange)
{
BoolInt valid = (0 < tcb->fence);
if (valid)
{
*scanRange = tcb->fenceRange;
}
return valid;
}
ScanRange scanRange;
if (extractScanRangeFromFence (&scanRange))
{
ScanCriteria* pScanCriteria = mdlScanCriteria_create ();
mdlScanCriteria_setModel (pScanCriteria, modelRef /* ACTIVEMODEL, etc. */);
mdlScanCriteria_setDrawnElements (pScanCriteria);
mdlScanCriteria_setElemRefCallback (pScanCriteria, callbackFunction /* not defined here */, NULL);
mdlScanCriteria_setRangeTest (pScanCriteria, &scanRange);
mdlScanCriteria_setReturnType (pScanCriteria, MSSCANCRIT_ITERATE_ELMREF, FALSE, FALSE);
// Perform the scan
mdlScanCriteria_scan (pScanCriteria, NULL, NULL, NULL);
// Your callbackFunction() is called for each element inside or overlapping
// the ScanRange in the current model
mdlScanCriteria_free (pScanCriteria);
}
MicroStation can extract elements that are inside or outside, overlap, or don't overlap the current fence. As a MicroStation user, you choose the fence mode from the Tool Settings dialog when you start a fence command.
You can set the fence mode programmatically with MDL. With MicroStation V8 you can call mdlParams_setLock(), but
with MicroStation/J you must set explicit bits in the TCB.
// Turn Fence overlap on
mdlParams_setLock (1, ACTIVELOCK_FENCEOVERLAP);
// Turn Fence overlap off
mdlParams_setLock (0, ACTIVELOCK_FENCEOVERLAP);
void common_setFenceModeV7 ( int mode,// => FENCE_OVERLAP...int view// => view where fence proposed) { tcb->fenvw = view; switch (mode) { case FENCE_INSIDE: tcb->ext_locks.fenceVoid = 0; tcb->fbfdcn.fenceclip = 0; tcb->fbfdcn.overlap = 0; break; case FENCE_OVERLAP: tcb->ext_locks.fenceVoid = 0; tcb->fbfdcn.fenceclip = 0; tcb->fbfdcn.overlap = 1; break; case FENCE_CLIP: tcb->ext_locks.fenceVoid = 0; tcb->fbfdcn.fenceclip = 1; tcb->fbfdcn.overlap = 1; break; case FENCE_VOID: tcb->ext_locks.fenceVoid = 1; tcb->fbfdcn.fenceclip = 0; tcb->fbfdcn.overlap = 0; break; case FENCE_VOID_OVERLAP: tcb->ext_locks.fenceVoid = 1; tcb->fbfdcn.fenceclip = 0; tcb->fbfdcn.overlap = 1; break; case FENCE_VOID_CLIP: tcb->ext_locks.fenceVoid = 1; tcb->fbfdcn.fenceclip = 1; tcb->fbfdcn.overlap = 1; break; case FENCE_CLEAR: default: tcb->fence = 0; break; } }
Return to MDL articles index.