The Main Scan Function

Download as pdf or txt
Download as pdf or txt
You are on page 1of 7

November 1992 MicroStation Manager

Article by Keith Bertram


When writing a utility or application for a CAD package, the programmer may need to search the
design file for all elements that meet specific criteria. The criteria may be all drawn elements, all elements
of a certain type, all elements on a certain level or all elements pertaining to certain graphic groups. MDL
has the ability to perform such an operation. This article will explain how to scan a MicroStation design file
based on a desired criteria using MDL.
THE MAIN SCAN FUNCTION
Let's start out by looking at the following function. This function scans a design file and gathers the
file positions of any elements meeting the desired criteria. The algorithm can be found in the example
programs delivered with MicroStation.
In line 6 of the following function, the elemAddr array is declared. This array is used to store the
element file positions returned by the scanner, and it is not dependent on the size of the design file. The
following algorithm will work even if the number of file positions returned is greater than 50.
The SetScanListMembers function, called at line 8, is created by the programmer to set the desired
criteria. This function is all that needs to be modified to create different criteria. Several examples of this
function will be discussed later.
Line 9 gets the end-of-file position. This is needed so you don't process a file position that is beyond
the end of the file.
The f ilePos variable is set to 0L (zero Long) at line 10, ensuring that the scan starts at the beginning of
the file.
Line 13 determines the maximum number of words that can be returned by the mdlScan_file function.
Line 15 determines the number of file positions returned by the mdlScan_file function. In the
scanWords variable, the scanner returns two words for every element meeting the criteria. The number of
elements returned by the scanner can be determined by dividing the scanWords variable by the size of a
"short." The size of a short is 2.
The if statement at line 18 ensures that a file position past the end of file will not be processed.
The mdlModily_elementSingle function, called at line 19, is used to modify the element located at the
file position given by elemAdd[i]. Consult the MDL manual for more information on this function. Other
operations can be executed with the file position, for example, obtaining a MSElementUnion using the
function indlElement_read.
The mdlScan_file function does most of the work for this algorithm, The first parameter is returned as
an array of file positions for elements meeting the scan criteria. The second parameter is both an input and
output parameter; on the input side, the maximum number of words that can be returned is specified,
whereas on the output side, the actual amount of words returned is given. The third parameter is the size of
the elemAddr array in bytes. The fourth parameter is also an input and output parameter; on the input side
the file position to start scanning should be paused. On the output side, the next element's file position is
returned after the scan is complete. The next element's file position will then become the start position for
the next time through the loop.
The return value for this function is used to determine if more calls to mdlScan_file are needed. This
is done by the test in the "do-while" loop.
November 1992 MicroStation Manager
Article by Keith Bertram
MAIN SCAN FUNCTION:
1 Private void scanFile
2 (
3 void
4 )
5 Ulong elemAddr[50], eofPos, filePos;
6 int scanWords, status, i, numAddr;
7 setScanListMembers( );
8 eofPos = mdlElement_getFilePos (FILEPOS_EOF, NULL);
9 filePos = 0L;
10 do
11 {
12 scanWords = sizeof(elemAddr)/sizeof(short);
13 status = mdlScan_file (elemAddr, &scanWords, sizeof(elemAddr), &filePos);
14 numAddr = scanWords/sizeof(short);
15 for (i=0; l.<numAddr; i++)
16 {
17 if (elemAddr[i] >= eofPos)
18 break;
19 mdlModify_elementSingle (0, elemAddr[i], MODIFY_REQUEST_NOHEADERS,
MODIFY_ORIG, modifyfunction, NULL, 0L);
20 }
21 } while (status = BUFF_FULL);
22 }
TWO IMPORTANT SCANLIST MEMBERS
To understand the setup of the MicroStation scanner, two ScanList members should be talked about.
The first of these members is "extendedType" which tells the scanner what type of information the
programmer expects to be returned. These types of information include file positions, elements, memory
pointers and 3D elements from a 2D file. The constants used to specify these return types can be found in
the scanner.h file.
The second member is "scantype," This member's main purpose is to tell the scanner what type of
comparisons to make when scanning the design file. The following table describes a few of the more
popular comparisons:
TABLE 1
Pickcell compare on a cell name
Propclas compare on elements properties and class
Grphgrp compare on elements graphic group
Attrent compare on attribute linkage entity
Attrocc compare on attribute occurrence
Levels compare on levels
Elemtype compare on element types
Multiple values can be specified by separating them with the | character. For example, having multiple
values would allow you to search the design file and find all lines located on level 10.
This member accepts a few more constants that tell the scanner how to perform the scan. For instance,
multiple scan range blocks are performed by using the constant Multi. Cells and all their elements are
treated as one element by using the constant Nestcell, The scanner returns only one element if the constant
Oneelem is used.
The scanner can return a MSElementUnion variable filled with data by using the constant Elemdata.
This tells the scanner to return only the data and not the location in the design file where the element
resides. To get the location, set scantype to Both, placing the block and offset of the element in el.buf[0]
and el.buf[1]. The file position can be found by using the DGN_FILEPOS macro. An example of this
November 1992 MicroStation Manager
Article by Keith Bertram
macro follows:
ULong filePos;
filePos = DGN_FILEPOS(el. buf [1], el.buf [0]);
Two other constants available for scantype are Skew and Stopsect. Skew tells the scanner to do a skew
scan to create an imaginary tunnel through the design file, checking for any elements that intersect this
tunnel.
Stopsect tells the scanner to check the value in the stopsector member and use it as a mark for the end of
the scan.
SETTING UP THE SCANNER:
Now let's look at the function that sets the scan criteria. Remember, this function was called by the
previously described function.
Line 6 declares the scanList variable of type ScanList. The ScanList structure (found in the Scanner.h
file) is used by the MicroStation scanner to create the scan criteria. Members of this structure will be
described later.
The mdlScan_initScanlist function, called at line 7, zeros out all the members of the ScanList variable
and sets the sllen member to its correct size.
The MicroStation scanner always checks the range of the element against the xlowlim, ylowlim,
ziowlim, xhighlim, yhighRm, and the zhighlim members of the ScanList structure. The
mdlScan_noRangeCheck function, in effect, disables this check.
Line 8 tells the scanner to return the file position of elements meeting the criteria.
Lines 10 and 11 set a few members of scanList to the criteria desired. This particular scan criteria looks
only for lines.
The mdlScan_initialize function, called at line 12, makes the scanList variable available to the
MicroStation scanner. The first parameter is the file to scan. In this case we will scan the master design file.
The scanner can also be used to search reference files or the attached cell library. The second parameter is
the scanList variable describing the scan criteria.
SETTING UP THE SCANNER:
1 Private -void setScanListMembers
2 (
3 void
4 )
5 {
6 Scanlist scanList;
7 mdlScan_initScanlist (&scanList);
8 scanList.extendedType = FILEPOS;
9 mdlScan_noRangeCheck (&scanList);
10 scanList.scantype= ELEMTYPE;
11 scanList.typmask [0] = TMSKO_LINE;
12 mdlScan_initialize (0, &scanList);
13 }
VARIOUS SCAN CRITERIA
There are several different scan criteria. Let's look at how to set these up by modifying the
setScanListMembers function to fit our needs.
BY ELEMENT TYPE
The first criteria searches for particular elements types. The two ScanList members used in this case are
"scantype" and "typmask."
When checking for element types, use the value Elemtype for the scantype member.
The typmask member is used to specify the types of elements for which to search and is an array of 8 bit
masked words. The first index of the array (typmask[0]) is used for element types 1-16; the second
(typmask[1]) is used for element types 17-32. This method is also used for indexes 2 through 8. To specify
an element type, use the macros defined for elements in the mselems.h file.
As an example, use the values Tmsk0_Line for a line and Tmskl_Arc for an arc. Notice the 0 and 1 in the
November 1992 MicroStation Manager
Article by Keith Bertram
fifth character of the macro. This number specifies in which index of the typmask array it should be used,
so the Tmsk0_Line should be used in the typmask[0] variable. Multiple types of elements can be scanned
for by separating the macros with the "|" sign. The first setScanListMembers function (see "Setting Up
The Scanner") is a good example of how to scan a design file for all lines.
BY LEVELS
The second criteria searches for elements on particular levels. The two ScanList members in this case are
"scantype" and "levmask." The scantype member should be set to Levels. The levmask member works in a
similar manner as the typmask member and is an array of four words. Each bit in the words represents a
level. Levels 1-16 can be scanned for by setting the appropriate bit in levmask[0], levels 17-32 by setting
the appropriate bit in levmask[1], levels 33-48 by setting the appropriate bit in levmask[2] and levels 49-
64 (64 actually being 0) by setting the appropriate bit in levmask[3]. Combinations of levels can be
selected by separating the bit mask with the "|" symbol. The following code demonstrates how to set up the
scanner and return only those elements residing on levels 1, 20 and 21.
SCAN BY LEVELS:
Private void modifyScanList
(
void
)
{
Scanlist scanList;
mdlScan_initScanlist (&scanList);
mdlScan_noRangeCheck (&scanList);
scanList.scantype= LEVELS;
scanList.levmask [0] = 0x1; /* level 1 */
scanList.levmask [1] = 0x8 | 0x10; /* levels 20 and 21 */
scanList.extendedType = FILEPOS;
mdlScan_initialize (0, &scanList);
}
BY GRAPHIC GROUP
The third criteria scans for elements that are a member of a particular graphic group. To enable this
search, set the scantype member to Grphgrp. Then, set the "grgroup" member to the graphic group number
to be searched for. For example:
ScanList.scantype = GRPHGRP;
ScanList.grgroup = 1;
The two lines above allow the scanner to search only for elements that have a graphic group of one.
BY CELL NAMES
The fourth criteria searches for cell names. The first step is to set the scantype member to Pickcell. The
cell name is stored in rad50 format in the element which allows for three characters to be stored in a 16-bit
word. With this in mind, let's look at the two members that are compared with the two words (6 characters)
containing the cell name. The first of these is the pcl.cell0 member. This member should contain (in rad50
format) the first three characters of the cell name. The second member is pch.cell1 which should contain
(also in rad50 format) the 4th, 5th and 6th characters of the cell name. The flunction mdlCnv__fromAsci-
iToR5O is used to convert a character string to the rad50 format. The following function sets up the
ScanList members for searching by cell name.
SCAN BY CELL NAME:
Private void setScanListMembers
(
void
)
November 1992 MicroStation Manager
Article by Keith Bertram
{
Scanlist scanList;
Ushort cell0, cell1;
mdlScan_initScanlist (&scanList);
mdlScan_noRangeCheck (&scanList);
scanList.scantype= LEVELS;
scanList.extendedType = FILEPOS;
if (strlen(cellName > 3)
{
mdlCnv_fromAsciiToR50 (3, cellName, &cell0);
mdlCnv_fromAsciiToR50 (strlen(cellName+3), cellName+3, &cell1);
}
If the string containing the cell name has more than three characters, convert the first three characters to
rad50 format and store it in the cell0 variable.
else
{
mdlCnv_fromAsciiToR50 (strlen(cellName), cellName, &cell0);
mdlCnv_fromAsciiToR50 (3, %%%, &cell1);
}
If the string has less than three characters, convert just those characters and store them in variable cell0,
The three percent signs are converted to spaces by the mdlCnv__fromAsciiToR5O function because the
rad50 format can only store the characters [A-Z] [0-9], the "$" sign, the space character, the period and the
underbar character. The three spaces for the celll variable are necessary because the second word of the cell
name is equivalent to three spaces if the cell name is less than three characters long.
scanList.scantype =ELEMTYPE | PICKCELL;
scanList.typmask[0] = TMSKO_CELL_HEADER;
The scantype member is set to Elemtype and Pickcell to tell the scanner to search for cells of a certain
cell name. Since you used Elemtype for scantype, set a typmask member to look for cells. Use the value
Tmsk0_Cell_Header for typmask[0] to tell the scanner you are looking for cells.
scanList. pcl.cell0 = cell0;
scanList. pch.cell1 = cell1;
mdlScan_intialize (0, &scanList);
}
The last step entails setting the pcl.cell0 and pch.cell1 members to the value of the cell0 and cell1
variables.
BY LOCATION
The fifth type of criteria searches by physical location on the design plane (cube). This type of search
does not require that the scantype member be set because range is always checked. The members include
xlowlim, ylowlim, zlowlim, xhighlim, yhighlim and zhighlim and define an area in the design plane (cube).
The zlowlim and zhighlim members are not needed for a 2D design file, and they need to be in scan format.
If an element's range is located inside this defined area then the element is returned. The
mdlCnv_ScanFormat and mdlCnv_toScanFormat functions can be used to convert from/to the scan
format. The following function tells the scanner to look only for elements whose own range intersects a 1
MU range cube centered around 0,0,0.
SCAN BY PHYSICAL LOCATION:
Private void setScanListMembers
(
void
)
November 1992 MicroStation Manager
Article by Keith Bertram
{
Scanlist scanList;
mdlScan_initScanlist (&scanList);
scanList.xlowlim = mdlCnv_toScanFormat (
-.5 * tcb->subpermast * tcb->uorpersub);
scanList.ylowlim = mdlCnv_toScanFormat (
-.5 * tcb->subpermast * tcb->uorpersub);
scanList.zlowlim = mdlCnv_toScanFormat (
-.5 * tcb->subpermast * tcb->uorpersub);
scanList.xhighlim = mdlCnv_toScanFormat (
.5 * tcb->subpermast * tcb->uorpersub);
scanList.yhighlim = mdlCnv_toScanFormat (
.5 * tcb->subpermast * tcb->uorpersub);
scanList.zhighlim = mdlCnv_toScanFormat (
.5 * tcb->subpermast * tcb->uorpersub);
scanList.extendedType = FILEPOS;
mdlScan_intialize (0, &scanList);
}
BY ATTRIBUTE ATTACHMENT
The last type of search is by attribute data. This checks the "a" bit of the element's properties word. The
"a" bit is set if attribute data is attached to the element. To check the "a" bit, first set the scantype member
to Propclas. This tells the scanner we are searching by properties and class. Next set the pch.propmsk and
pcl.propval members. These members are one word bit masks. Since the "a" bit is located in bit 11 of the
word, we will set pch.propmsk to the value of 0x0800 (equal to 100 000 000 000 in binary). This value is
masked with the element's properties word using the And operator, giving us just the value located in bit
11. Now this value is compared to the value stored in pcl.propval; if the two values are equal then the
element is accepted. The following code demonstrates how to set up a search for all elements that do not
have attribute data attached.
SCAN BY ATTRIBUTE DATA:
Private void setScanListMembers
(
void
)
{
Scanlist scanList;
mdlScan_intialize (0, &scanList);
scanList. scantype = PROPCLAS;
scanList. clasmsk = 0xffff;
scanList.pcl.propval = 0x0000;
scanList.pch.propmsk = 0x0800;
scanList.extendedType = FILEPOS;
mdlScan_intialize (0, &scanList);
}
Note that the propmsk member gives the value of the eleventh bit. If no attributes are attached to this
element, then the value in the eleventh is zero. Since you have set the propval member to zero, all elements
that do not contain attribute data will be returned. The above example searched for all types of classes. If
you had not set a value for clasmsk, the scanner would not return any elements because no element's class
is equal to zero.
SOME BUILT IN FUNCTIONS
MDL offers a few functions that help in setting some of the scanList members.
One of these is mdlScan_setDrawnElements that sets the typmask member to look for only displayable
November 1992 MicroStation Manager
Article by Keith Bertram
elements. Another is mdlScan_noRangeCheck that sets the xhighlim, yhighlim, and zhighlim members to
be less than the xlowlim, ylowlim, and zlowlim members. This ensures that the elements range is not
checked during a scan of the design file.
The mdlScan_singleViewClass function sets the clasmsk member to be equal to only the classes that are
currently displayable in the specified view. For the function to work, the scantype member should be set to
Propclas.
The last function, mdlScan_viewRange, sets the scanner's range cube to be equal to the extents of the
specified view. This means that if an element's range intersects the range of the view, then the element is
returned.
For more information read Mach N. Dinh-Vu's book Programming with MDL, or look at the programs in
Bill Steinbeck's 101 MDL Commands.
Keith Bertram is a customer engineer with Intergraph Corporation in Southfield, Mich

You might also like