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.

Fences & Scan Ranges

With the above in mind, there are two answers to the question about fences and scan ranges …

Process the Fence Contents

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.

Fence Processing trace messages

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*.

Type Definition in Header File

typedef struct my_fence_params
{
  int     intValue;
  double  doubleValue;
  char    text [12];

} MY_FENCE_PARAMS, *LP_MY_FENCE_PARAMS;

Fence Callback Function

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;
}

Start Fence Processing

MY_FENCE_PARAMS param;

//  Set up parameter values for our fence process callback function
memset (¶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 function
mdlState_startFenceCommand (fenceFunction, NULL, NULL, NULL,
	0, 0, FENCE_NO_CLIP);

//  Set locate criteria to allow or prevent the processing
//  of elements in referenced models
mdlLocate_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 function
mdlFence_process (¶m);
Fence Processing complete

Download Example Project

Download Project Example

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

Scan the model using the Fence Range

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 …

Extract a ScanRange from the Fence Outline

BoolInt extractScanRangeFromFence (ScanRange* scanRange)
{
  BoolInt  valid  = (0 < tcb->fence);
  if (valid)
  {
    *scanRange = tcb->fenceRange;
  }
  return valid;
}

Apply the ScanRange to Scan Criteria

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);
}

Fence Modes

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.

MicroStation V8

    //  Turn Fence overlap on	
    mdlParams_setLock (1, ACTIVELOCK_FENCEOVERLAP);

    //  Turn Fence overlap off	
    mdlParams_setLock (0, ACTIVELOCK_FENCEOVERLAP);

MicroStation/J

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.