The document discusses how to scan a MicroStation design file based on desired criteria using MDL (MicroStation Development Language). It explains the main scan function, which declares an element address array to store file positions of elements meeting the criteria. It calls a SetScanListMembers function to set the criteria, then uses the mdlScan_file function to perform the scan and return matching elements. It also describes how to set up the scanner by initializing a ScanList structure to specify criteria like element type or level to control what is returned. Examples are provided to scan for elements by type, level, graphic group or other properties.
The document discusses how to scan a MicroStation design file based on desired criteria using MDL (MicroStation Development Language). It explains the main scan function, which declares an element address array to store file positions of elements meeting the criteria. It calls a SetScanListMembers function to set the criteria, then uses the mdlScan_file function to perform the scan and return matching elements. It also describes how to set up the scanner by initializing a ScanList structure to specify criteria like element type or level to control what is returned. Examples are provided to scan for elements by type, level, graphic group or other properties.
The document discusses how to scan a MicroStation design file based on desired criteria using MDL (MicroStation Development Language). It explains the main scan function, which declares an element address array to store file positions of elements meeting the criteria. It calls a SetScanListMembers function to set the criteria, then uses the mdlScan_file function to perform the scan and return matching elements. It also describes how to set up the scanner by initializing a ScanList structure to specify criteria like element type or level to control what is returned. Examples are provided to scan for elements by type, level, graphic group or other properties.
The document discusses how to scan a MicroStation design file based on desired criteria using MDL (MicroStation Development Language). It explains the main scan function, which declares an element address array to store file positions of elements meeting the criteria. It calls a SetScanListMembers function to set the criteria, then uses the mdlScan_file function to perform the scan and return matching elements. It also describes how to set up the scanner by initializing a ScanList structure to specify criteria like element type or level to control what is returned. Examples are provided to scan for elements by type, level, graphic group or other properties.
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