Chapter 6 -- Data Routines


Character and String Routines

The routines in this section allow you to convert between several data types and strings, manipulate strings, and perform useful operations on characters.

cvangst

PROCEDURE cvangst (ang : real; str : OUT string);

cvangst converts its first argument (an angle measured in radians) to a string and which it returns in its second argument.

The returned string depends upon the current angle type. An error occurs when the string is not long enough to hold the result.

cvdisst

PROCEDURE cvdisst (dis : real; str : OUT string);

cvdisst converts a distance to a string. The distance is in DataCAD units as described earlier.

The returned string depends upon the current scale type (metric, architectural, etc.). An error occurs when the string is not long enough to hold the result.

cvintst

PROCEDURE cvintst (i : integer; str : OUT string);

cvintst converts an integer to a string. An error occurs when the string is not long enough to hold the result.

For example, in the statements:

i := 45;

cvintst (-1 * i, str);

str is equal to '-45'.

cvlntst

PROCEDURE cvlntst (li : longint; str : OUT string);

cvlntst converts a long integer to a string.

cvrllst

PROCEDURE cvrllst (rl : real; str : OUT string);

cvrllst converts a real number to a string.

An error occurs when the string is not long enough to hold the result.

The statement:

cvrllst (45.56, str);

results in str being equal to '45.56'.

cvstint

FUNCTION cvstint (str : string; i : OUT integer) : boolean;

cvstint converts the string str to an integer and returns the result in i.

When cvstint is able to convert the string, it returns true. When there is an error in conversion, (for instance, str = '45x3') false returns.

cvstlnt

FUNCTION cvstlnt (str : IN string; li : OUT longint) : boolean;

cvstlnt converts a string to a long integer (longint).

cvstrll

FUNCTION cvstrll (str : string; rl : OUT real) : boolean;

cvstrll converts the string to a real.

true returns when there is no error in conversion; false returns when there is a conversion error.

islower

FUNCTION islower (ch : char) : boolean;

islower returns true when ch is a lowercase letter. When ch is an uppercase letter or not a letter islower returns false.

islower (a) returns true

islower (B) returns false

islower ($) returns false

isupper

FUNCTION isupper (ch : char) : boolean;

isupper returns true when its argument is an uppercase character. When its argument is a lowercase character or not a character isupper returns false.

isupper (a) returns false

isupper (B) returns true

isupper ($) returns false

strassign

PROCEDURE strassign (dest : IN OUT string; source : string);

strassign copies source into dest.

This procedure is needed because you can't assign two string variables of different maximum or dynamic lengths to one another using ':='. A string literal, however, can be assigned to a string variable with ':=' or strassign.

strcat

PROCEDURE strcat (str1 : IN OUT string; str2 : string);

strcat returns in its first argument the first argument concatenated with the second argument.

An error occurs when the maximum length of the first argument cannot hold the result.

If str1 = 'Good ' and str2 = 'Morning', then:

strcat (str1, str2);

results in str1 = 'Good Morning'. str2 will be unchanged. Similarly:

strcat (str2, str1);

results in str2 = 'MorningGood ' and str1 is unchanged.

strcomp

FUNCTION strcomp (str1, str2 : string; len : integer) : boolean;

strcomp compares two strings to see if they are equal.

When len is -1, the entire strings are compared, that is, their dynamic lengths must be the same for them to be equal. When len is a positive number, only the first len characters are compared.

strcomp ('Hello', 'Hello', -1) = true

strcomp ('Hello', 'Hello1', 5) = true

strcomp ('Hello', 'Hello1', -1) = false

strdel

PROCEDURE strdel (str : IN OUT string; start, len : integer);

strdel deletes len characters from str starting at position start.

When there are not len characters in the string after position start, a run-time error occurs.

For example if str = 'abcdefghij', then results in str = 'abcghij'.

strinc

PROCEDURE strinc (str : IN OUT string);

strinc increments a string.

The characters on the right end of a string that form a number are incremented to the next number. The string can have any number of digits on the right end of the string.

For example if str = 'abc123', then after

calling strinc four times, str = 'abc127'.

strins

PROCEDURE strins (dest: IN OUT string; source: string; pos: integer);

strins inserts source into dest before position pos.

For example if dest = '12345', then

strins (dest, 'hi', 3)

results in dest = '12hi345'.

strlen

FUNCTION strlen (str : string) : integer;

strlen returns the current dynamic length of its argument.

For example, if str = 'hello, world', then:

strlen (str)

returns 12. Also,

strlen (test)

returns 4.

strpad

PROCEDURE strpad (str : IN OUT string; len : integer; ch : char);

strpad pads the string str on the right with character ch until its length (as returned by strlen) is equal to len.

When str is longer than len, it is truncated to be len characters long.

For example if str = '123', then

strpad (str, 6, "*")

leaves str = '123***'.

strpos

FUNCTION strpos (pat, str : string; start : integer) : integer;

strpos searches for pat in str, starting at position start.

* It returns the position in str where pat first occurs, or 0 if pat does not occur in str after start characters. For example:

strpos ('12', '123123', 2)

returns 4, the position of the first occurrence of '12' after position 2.

strsub

PROCEDURE strsub (source : string; start, len : integer; dest : IN OUT string);

strsub extracts a piece of a string.

On exit, dest contains len characters from source starting at start.

For example:

strsub ('12345678', 2, 4, dest)

results in dest = '2345'.

strupcase

PROCEDURE strupcase (str : IN OUT string; toupper : boolean);

strupcase converts a string to either all uppercase or all lowercase.

* When the parameter toupper is true, the string is converted to uppercase. When toupper is false, the string is converted to lowercase. strupcase uses the same rules as the functions toupper and tolower.

tolower

FUNCTION tolower (ch : char) : char;

tolower returns its argument converted to lowercase if it is an uppercase character; otherwise, tolower returns its argument unchanged.

tolower (a) returns 'a'

tolower (A) returns 'a'

tolower ($) returns '$'

toupper

FUNCTION toupper (ch : char) : char;

toupper returns its argument converted to uppercase if it is a lowercase character, otherwise, toupper returns its argument unchanged.

toupper (a) returns 'A'

toupper (A) returns 'A'

toupper ($) returns '$'

Working with Entities

Use the routines in this section to perform operations on entities that have been read from the database. See the following section on ways to read entities from the database.

ent_add

PROCEDURE ent_add (ent : IN OUT entity);

ent_add adds the entity ent to the database on the current layer. All fields of an entity specific to the particular entity type (line, slab, dome) must be set prior to calling ent_add. The macro stops executing when there is not enough room to add the entity to the database.

During this procedure, the currently-set values of the variables that define line type, entity color, etc., are used for the added entity. When the entity is added to the database, it is not automatically drawn on the graphics screen. This must be done separately by the macro.

See the "Variables" chapter for more information. See ent_draw.

ent_copy

PROCEDURE ent_copy (oldent, newent : IN OUT entity; toCurr, doAttr : boolean);

ent_copy duplicates an entity in the database. Use this procedure instead of assigning entities and then adding the new one to the database.

For example:

ent_copy (oldent, newent, false, true);

* The parameter toCurr controls whether newent is copied to the current layer or to the layer that oldent is on. When toCurr is true, newent is copied to the current layer. When toCurr is false, newent is copied to the same layer as oldent.

* When doAttr is true, the attributes of oldent are copied to newent. When doAttr is false, the attributes are not copied. It is recommended that doAttr always be true, unless you have a specific reason not to copy attributes. There is no need to call ent_init (newent,...); prior to ent_copy or to call ent_update (newent); after a call to ent_copy.

ent_del

PROCEDURE ent_del (ent : IN OUT entity);

ent_del deletes ent from the database.

* ent must have been read from the database using one of the database routines. If it was not, a fatal internal error occurs.

ent_draw

PROCEDURE ent_draw (ent : IN OUT entity; drmode : integer);

ent_draw draws ent on the screen using the specified drawing mode.

* drmode can be either drmode_white, drmode_black, or drmode_flip.

* ent does not have to have been read from the database with ent_get, as long as all the information needed to draw the entity has been specified (color, end points, radius, etc). This is useful for creating temporary images on the screen.

ent_draw_2d

PROCEDURE ent_draw_2d (ent : IN entity; drmode : IN integer);

ent_draw_2d is similar to procedure ent_draw except that in any viewing projection other than orthographic, ent_draw_2d draws an entity disregarding the 3D to 2D viewing projection.

ent_draw_2d is typically used during input and editing operations which are performed in parallel projections to allow for the drawing of entity geometry without accounting for the current viewing matrix, but correctly handling the current window-to-viewport transformation.

ent_draw_dl

PROCEDURE ent_draw_dl (ent : IN entity; drmode : IN integer; todl : boolean);

ent_draw_dl draws ent on the screen using the specified drawing mode.

* drmode can be either drmode_white, drmode_black, or drmode_flip.

* ent does not have to have been read from the database with ent_get, as long as all the information needed to draw the entity has been specified (color, end points, radius, etc).

* When todl is true, the entity is added to the display list. When todl is false, the entity is not added to the display list. todl should be false for temporary screen data. This is useful for creating temporary images on the screen.

ent_drawmode

FUNCTION ent_drawmode (mode : IN mode_type; drmode : IN integer; todl, clearscr : IN integer) : integer;

ent_drawmode is similar to ent_draw_dl, except that instead of drawing only one entity, every entity returned by mode is drawn.

* drmode can be either drmode_white, drmode_black, or drmode_flip.

* ent does not have to have been read from the database with ent_get, as long as all the information needed to draw the entity has been specified (color, end points, radius, etc).

* When todl is true, the entity is added to the display list. When todl is false, the entity is not added to the display list. todl should be false for temporary screen data.

* When clearscr is true, the screen is cleared before the entities are drawn.

See "mode".

ent_enlarge

PROCEDURE ent_enlarge (ent : IN OUT entity; cent : point; Xsc, Ysc, Zsc : real);

ent_enlarge enlarges entity ent by the factors Xsc, Ysc, and Zsc about the point cent.

Perform an ent_update after the entity is enlarged to update the database.

ent_extent

PROCEDURE ent_extent (ent : IN OUT entity; lowleft, upright : OUT point);

ent_extent finds the minimum and maximum extents of ent. This is the smallest box that completely encloses the entity.

ent_init

PROCEDURE ent_init (ent : IN OUT entity; enttype : integer);

Whenever an entity is declared, ent_init should be called to initialize the entity. This call initializes all fields of an entity so that it may be drawn and otherwise operated on. Failure to call this procedure before using an entity can result in an entire range of errors.

* enttype is the constant for the type of entity, such as entlin or entply.

ent_move

PROCEDURE ent_move (ent : IN OUT entity; dx, dy, dz : real);

ent_move moves entity ent by dx, dy, and dz.

Perform an ent_update after moving an entity to replace the entity in the database.

ent_relink

PROCEDURE ent_relink (ent1, ent2 : IN OUT entity);

ent_relink moves the logical location of an entity in the database.

* ent1 is not relocated in the database.

* The relinking operation is performed upon ent2. The logical location in the database of ent2 is altered so that ent2 resides on the same layer as ent1 and so that ent2 immediately follows ent1 in the chain of entities on that layer. ent1 and ent2 must both be valid entities that currently exist in the drawing database. Both entities must have been read from the database using the function ent_get, or just added to the database using ent_add with no intervening operations.

The following example demonstrates how to use ent_relink to effectively insert an entity into a drawing after another entity by first adding the entity and then relinking it using ent_relink:

VAR

oldent : entity;

newent : entity;

...

ent_add (newent);

ent_relink (oldent, newent);

ent_rotate

PROCEDURE ent_rotate (ent : IN OUT entity; cent : point; ang : real);

ent_rotate rotates entity ent by ang radians about the point cent.

The rotation is around the Z axis, that is, in the XY plane. This is the normal DataCAD 2D rotation. Perform ent_update to update the database.

ent_tran

PROCEDURE ent_tran (ent : IN OUT entity; mat : IN modmat; doatr, update : IN boolean);

ent_tran transforms an entity by the transformation described in a modeling matrix. ent_tran may not be used on all of DataCAD's entities, but only those which may be arbitrarily translated, scaled, mirrored, and rotated in space.

The function ent_tranok determines if the entity will respond to the procedure ent_tran. Entities which can be described by the following constants can be used with ent_tran and cause the function ent_tranok to return true:

entLn3

entAr3

entDom

entMrk

entCon

entTor

entSym

entCyl

entSrf

entPly

entTrn

entBlk

entSlb

entCnt

* ent is the entity to transform.

* mat is the modeling matrix to apply to ent. Set mat using one or more of DCAL's matrix calculation routines.

* When the flag doatr is true, any visible attributes attached to the entity ent are transformed as well.

* When the flag update is true, an ent_update is performed automatically by ent_tran. When the flag update is false, an ent_update is not performed automatically.

Entities of type polygon or slab which contain voids, have their voids transformed and updated in the database regardless of the value of the flag update.

ent_tranok

FUNCTION ent_tranok (ent : IN OUT entity) : boolean;

ent_tranok determines when an entity responds to a transformation applied directly via a modeling matrix.

ent_tranok is typically used with the procedure ent_tran to determine if ent_tran can be applied to an entity of a particular type. When the entity passed to ent_tranok can be transformed using ent_tran, ent_tranok returns true. When the entity cannot be transformed ent_tranok returns false.

* ent is the entity to check.

ent_update

PROCEDURE ent_update (ent : IN OUT entity);

ent_update updates the database with the current description of ent.

For example, you can read entities from the database, undraw them, change their colors, put them back into the database, and then redraw them using the following code:

mode_init (mode);

mode_lyr (mode, lyr_curr);

adr := ent_first (mode);

WHILE ent_get (ent, adr) DO

ent_draw (ent, drmode_black);

ent.color := clrred;

ent_update (ent);

ent_draw (ent, drmode_white);

adr := ent_next (ent, mode);

END;

stopgroup

PROCEDURE stopgroup;

As entities are added to the database, they are considered part of the same group. stopgroup sets the last entity entered as the last entity belonging to a group. stopgroup works only on the current layer. When the current layer is changed, an implicit stopgroup is performed since a group can not span layers.

Selection Set Routines

Use the routines in this section to add to, delete from, and scan selection sets. DataCAD provides eight selection sets for the macro writer.

Every entity 'knows' which selection set(s) it belongs to. Therefore, when an entity is deleted, its selection set is automatically corrected to reflect that the entity is no longer present. This ensures that selection sets never contain invalid data by pointing to entities that no longer exist.

Every selection set routine takes a selection set number as a parameter. This number must be in the range of 0 to 7, specifying one of the eight selection sets available. There are other selection sets within DataCAD, but they are used internally and should not be used by the macro programmer. Use of a selection set other than those numbered zero through seven can cause unpredictable results in both the execution of the macro and the subsequent use of DataCAD.

ssAdd

PROCEDURE ssAdd (ssNum : integer; ent : IN OUT entity);

ssAdd adds its second argument, ent, to the selection set number ssNum.

* When ent is already a member of ssNum, no operation is performed.

ssClear

PROCEDURE ssClear (ssNum : integer);

ssClear clears out selection set number ssNum. All entities that were in the selection set are deleted from the selection set. These entities are removed from this selection set only. They remain in the database and are still members of other selection sets.

ssDel

FUNCTION ssDel (ssNum : integer; ent : IN OUT entity) : boolean;

ssDel deletes ent from selection set number ssNum.

* When ent is a member of ssNum, true is returned. When ent is not a member of ssNum, false is returned and no other operation is performed.

ssGetName

PROCEDURE ssGetName (ssNum : IN integer; ssname : OUT string);

ssGetName reads the name of one of the first eight selections sets (0 through 7).

ssLength

FUNCTION ssLength (ssNum : integer) : integer;

ssLength returns the number of entities that are in selection set number ssNum.

ssMember

FUNCTION ssMember (ssNum : integer; ent : IN OUT entity) : boolean;

ssMember determines when an entity is a member of a particular selection set.

When ent is a member of selection set ssNum, ssMember returns true, otherwise false returns

ssSetName

PROCEDURE ssSetName (ssNum : IN integer; ssname : IN string);

ssSetName sets the name of one of the first eight selection sets.

Layers

Every entity in a drawing is on a layer. The routines in this section manipulate layers. Notice that some of the built-in variables described in the "Variables" chapter also affect the current layer.

getlyrcurr

FUNCTION getlyrcurr : layer;

getlyrcurr returns the current (or active) layer.

getlyrname

PROCEDURE getlyrname (lyr : layer; name : OUT string);

getlyrname returns the name of the layer lyr in name.

* When lyr is not a valid layer, an error occurs.

lyr_clear

PROCEDURE lyr_clear (lyr : layer);

lyr_clear erases every entity from layer lyr and deletes them from the database.

lyr_create

FUNCTION lyr_create (lname : string; lyr : OUT layer) : boolean;

lyr_create adds a new layer to the current drawing.

* The layer is created with the name lname.

* The layer variable that describes the new layer is returned in lyr. lyr_clear returns true when DataCAD creates the layer, and false when DataCAD is unable to create the layer (too many layers or out of disk space).

lyr_del

PROCEDURE lyr_del (lyr : IN layer);

lyr_del deletes a layer from a drawing database.

* lyr must be a valid layer in the drawing database and must be a part of the standard layer/entity data structure. All entities on the layer, as well as the layer itself, are deleted and completely removed from the database. Unless the drawing is cancelled, the layer and its entities are completely deleted and may not be undone or recovered in any way. Do not attempt to use lyr_del on a layer which was added to the drawing database using the function lyr_init. lyr_init adds a layer to the database which is not a part of the standard layer/entity structure. In this case, use the procedure lyr_term. lyr_term is specifically designed to terminate and delete layers which are not part of the standard layer/entity database structure.

lyr_find

FUNCTION lyr_find (lname : string; lyr : OUT layer) : boolean;

lyr_find looks for a layer with the name lname in the database.

* When successful, true returns and lyr is set to be the layer that was found. When there is no layer named lname, false returns.

lyr_first

FUNCTION lyr_first : layer;

lyr_first returns the first layer that is in the database.

lyr_ison

FUNCTION lyr_ison (lyr : layer) : boolean;

lyr_ison returns true when the layer lyr is on (displayed). When lyr is off (not displayed), lyr_ison returns false.

lyr_next

FUNCTION lyr_next (lyr : layer) : layer;

lyr_next returns the next layer in the database after lyr. When lyr is the last layer in the drawing, lyr_next returns a layer that is nil. Test this with lyr_nil.

lyr_nil

FUNCTION lyr_nil (lyr : layer) : boolean;

lyr_nil returns true when the layer lyr does not point to anything.

The following code writes the name of every layer in the database that is on:

lyr := lyr_first;

WHILE NOT lyr_nil (lyr) DO

IF lyr_ison (lyr) THEN

getlyrname (lyr, str);

wrterr (str);

pause (0.5);

END;

lyr := lyr_next (lyr);

END;

lyr_read

FUNCTION lyr_read (lyr : IN layer; filename : IN string; clearlyr, drawlyr : IN boolean) : integer;

lyr_read reads a layer from a layer file into the drawing database.

lyr_read returns fl_ok when the layer file successfully loads or returns one of the other file operation constants. See the "Constants" chapter for more information .

* lyr is the layer to which the contents of the layer file are added. lyr must exist in the drawing database, and must have been added to the drawing using lyr_create, lyr_init, or DataCAD's standard layer user interface. lyr is renamed to match the name of the file which was read in. This could result in two different layers in a drawing with the same name.

* filename is the name of the layer file to read. filename must be a correct layer filename including a complete or relative pathname of the file but without the .lyr extension. This function only looks for files with .lyr extensions.

* clearlyr is a flag that is true when the layer lyr is to be cleared of all entities prior to appending the contents of the layer file. When clearlyr is false, the contents of the layer file are appended to the layer and any existing entities on the layer are not deleted.

* drawlyr is a flag which is true when the layer is to be drawn immediately after it is loaded. When drawlyr is false, the layer is loaded into the drawing database, but is not drawn. If lyr is on when new entities are concatenated to it by lyr_read and drawlyr is false, although the new layer file information is not visible, that information is scanned during the next editing or snapping operation. The next operation which causes the screen to refresh redraws the new data as well.

lyr_set

PROCEDURE lyr_set (lyr : layer);

lyr_set sets the current layer to the parameter lyr.

When lyr is not a valid layer, an error occurs.

lyr_seton

PROCEDURE lyr_seton (lyr : layer; onoff : boolean; redraw : boolean);

lyr_seton toggles layers on or off.

lyr is the layer to act upon.

* onoff is true when the layer is to be turned on and false when it is to be turned off.

* The parameter redraw is true when the layer is to be drawn, and false when the layer is not to be redrawn. To remove entities (which reside on a particular layer) from the screen, set onoff to false and redraw to true. The current layer cannot be turned off.

lyr_viewfile

PROCEDURE lyr_viewfile (filename : IN string; refresh, extents : IN boolean; imagesize : IN real);

NOTE:

The declaration for the procedure lyr_viewfile is not built into the DCAL compiler but may be found in the system include file _views.inc. lyr_viewfile duplicates the functionality of Layer/ViewFile in DataCAD allowing the user to quickly view images or pictures as though they were slides. The layer file appears on the screen only; the file is not loaded into the drawing database.

* filename is the name of the layer file to view. filename must be a complete pathname to the file, or a valid pathname relative to the current directory. filename must contain the .lyr filename extension, when applicable.

* When the flag refresh is true, the screen is cleared prior to drawing the contents of the layer file. When refresh is false, the screen is not refreshed prior to displaying the contents of the layer file.

* When the flag extents is true, a WindowIn based on the extents of the layer file is performed prior to the display of the contents of the layer file. When extents is false, the layer file appears at the current scale and window-to-viewport mapping.

* imagesize controls the size of the image relative to the current viewport. imagesize has an effect when extents is true. When extents is false, imagesize is ignored. imagesize must be a real number between 1.0 and 100.0 and indicates the percentage of the screen area which the image should fill. For example, if imagesize is set to 80.0, the actual size of the image is reduced by 20 percent of the screen width or height (as appropriate) so that the image does not bleed to the edges of the screen.

lyr_write

FUNCTION lyr_write (lyr : IN layer; filename : IN string) : integer;

lyr_write writes a layer out to a layer file.

* lyr is the layer to be written. lyr must exist in the database.

* filename is the name of the file to which the layer is written. filename should contain either the full pathname of the file, or a valid pathname relative to the current directory. The filename should not contain the .lyr extension. This is added by the routine. When a layer file of the same name exists, the layer file is overwritten and no warning is generated. To first check for the existence of a layer file with the same name prior to writing the layer using lyr_write, use the function file_exist.

numlayer

FUNCTION numlayer : integer;

numlayer returns the number of existing layers in the drawing. This number is always at least one.

setlyrname

PROCEDURE setlyrname (lyr : layer; name : string);

setlyrname sets the name of lyr to name.

* When lyr is not a valid layer, an error occurs. The layer name on the screen is not updated when lyr is the current layer. You must call wrtlyr to force the layer name to be updated.

Symbol Routines

A symbol is often a name given to a variable like pt1. With the routines in this section you can add and manipulate symbols in the current drawing. Symbol instances are treated just like any entity. Use these routines to manipulate the definition of a symbol.

sym_clearref

PROCEDURE sym_clearref;

Every symbol has a Boolean field in its header, .refflag, that determines if the symbol has been referenced by the procedure sym_ref. sym_clearref clears (sets to false) all .refflag fields for all symbols in the database.

sym_count

PROCEDURE sym_count (mode : IN OUT mode_type);

sym_count looks through the entities returned by mode which are instances of symbols (entsym) and counts the number of instances of each symbol. This count can then be examined by looking at the num field of each symbol.

A macro should never write a value to num.

For example, to count the number of times each symbol has an instance on the current layer, use:

mode_init (mode); {look on this layer}

sym_count (mode);

saddr := sym_first;

WHILE sym_get (sym, saddr) DO

writeCount (sym.num);

saddr := sym_next (sym);

END;

sym_create

PROCEDURE sym_create (sym : OUT symbol; mode : IN OUT mode_type; ref : point; sname : string; delEnts, undraw : boolean);

sym_create creates or redefines a symbol.

* When a symbol of name sname already exists, it is redefined; when it does not exist, it is created.

* The entities that make up the symbol are read by mode.

* The reference point of the symbol is ref.

* When delEnts is true, the entities read from mode are deleted.

* When undraw is true, the entities are undrawn as the symbol is created.

* On exit, sym refers to the new (or updated) symbol. As an example, the following code converts everything in selection set 0 to a symbol:

mode_init (mode);

mode_ss (mode, 0);

setpoint (pt, 0.0);

sym_create (sym, mode, pt, 'newSym',

true, true);

sym_find

FUNCTION sym_find (sname : string; sym : OUT symbol) : boolean;

sym_find looks in the database for a symbol named sname.

* When sname is found, sym is set to the symbol and true is returned. If the symbol is not found, then sym_find returns false.

sym_first

FUNCTION sym_first : symaddr;

sym_first returns the address of the first symbol in the database. This, along with sym_next and sym_get, are used to scan through the symbols defined in the drawing.

sym_get

FUNCTION sym_get (sym : OUT symbol; saddr : symaddr) : boolean;

sym_get reads a symbol sym given its address.

If the address is nil, sym_get returns false, otherwise it returns true.

For example, to write the name of every symbol in the database, use:

saddr := sym_first;

WHILE sym_get (sym, saddr) DO

wrterr (sym.name);

pause (0.5);

saddr := sym_next (sym);

END;

sym_get_atr

FUNCTION sym_get_atr (sym : OUT symbol; saddr : symaddr; atrName : string; atr : OUT attrib);

sym_get_atr is similar to sym_get, but returns the next symbol that has an attribute with the given name. If no more such symbols exist in the database, false is returned.

This example shows how to use sym_get_atr. This piece of code reads every symbol that has an attribute named '*mtec'.

saddr := sym_first;

WHILE sym_get_atr (sym, saddr, '*mtec', atr) DO

wrtAtr (atr);

saddr := sym_next (sym);

END

sym_next

FUNCTION sym_next (sym : symbol) : symaddr;

sym_next returns the address of the next symbol in the database. When there is no next symbol, sym_next returns nil.

See the example under sym_get.

sym_read

FUNCTION sym_read (fName, symName : string; sym : OUT symbol) : integer;

sym_read reads a symbol from a symbol file.

* The filename fName may not contain the file extension; .sm3 is automatically added.

* symName is the internal name to use for the symbol. On exit, the function returns the file i/o constant from reading the symbol file. fl_ok indicates success.

* On exit, sym refers to the symbol that was read.

sym_ref

PROCEDURE sym_ref (mode : IN OUT mode_type);

sym_ref sets the .refflag fields to true for all symbols that have instances returned by mode, including nested symbols. The main use of this routine is internal to DataCAD to determine when a redefinition of a symbol is self-referencing. It is also used when saving a symbol to a file.

sym_write

FUNCTION sym_write (sym : symbol; fName : string) : integer;

sym_write writes an existing symbol sym to a file. As with sym_read, the filename must not contain the file extension.

The return constant of fl_ok indicates success.

The symbol and all of the nested symbols that it references as well as all of its attributes are written to the file.

Attribute Routines

Use the routines in this section to handle attributes. Attributes consist of two parts, the name and the value. The name is a string of maximum length atr_name_len characters. The value can be a real, integer, distance, angle, point, string, or logical address.

Attributes can be attached to symbols,

entities, symbol instances, layers, and the drawing (referred to as system attributes). Most of the routines in this section deal with attributes attached to any of these, but some are specific as to what the attribute is attached to. These have ent, sym, lyr, or sys in their name.

atr_2str

PROCEDURE atr_2str (atr : IN OUT attrib; str : OUT string);

atr_2str converts the value of atr to a string str, for any type of attribute. This procedure correctly converts any attribute of type integer, real, distance, angle, point, or string to a string.

atr_add2ent

PROCEDURE atr_add2ent (ent : IN OUT entity; atr : IN OUT attrib);

atr_add2ent adds an attribute to an entity.

* The attribute atr must be initialized with atr_init and the name and value of the attribute should be assigned. The entity atr is added to ent. When the attribute field visible is true, the value of atr appears when the entity is drawn. The remaining fields of the attribute type describe how the attribute is displayed.

For example, to add an integer attribute to an entity:

atr_init (atr, atr_int);

atr.name := '*EVS';

atr.int := 3;

atr_add2ent (ent, atr);

atr_add2lyr

PROCEDURE atr_add2lyr (lyr : IN OUT layer; atr : IN OUT attrib);

atr_add2lyr adds an attribute to the chain of attributes attached to a layer in the drawing database.

* lyr is the layer to which the attribute is added. lyr must exist in the drawing database before calling atr_add2lyr. l atr is the attribute to add to the layer. atr should be initialized using the procedure atr_init, and should contain a valid name and data.

* The attribute field visible may be set to true, but the layer attribute does not appear. Visible attributes appear only for entities.

atr_add2sym

PROCEDURE atr_add2sym (sym : IN OUT symbol; atr : IN OUT attrib);

This procedure is virtually identical to atr_add2ent, except it adds an attribute to a symbol.

* The attribute atr must be initialized with atr_init and the name and value of the attribute should be assigned.

* The entity atr is added to ent.

* The attribute field visible may be set true, but the symbol attribute will not appear. Visible attributes are displayed only for entities. The remaining fields of the attribute type describe how the attribute appears.

atr_add2sys

PROCEDURE atr_add2sys (atr : IN OUT attrib);

atr_add2sys adds an attribute to the chain of attributes attached to a drawing at the system level.

* atr is the attribute to add. atr should be initialized using the procedure atr_init, and should contain a valid name and data.

* The attribute field visible may be set to true, but the system attribute does not appear. Visible attributes appear only for entities.

atr_delent

PROCEDURE atr_delent (ent : IN OUT entity; atr : attrib);

atr_delent deletes an attribute from an entity.

* The parameters are the entity to delete from, ent, and the attribute to delete, attrib.

atr_dellyr

PROCEDURE atr_dellyr (lyr : IN OUT layer; atr : IN OUT attrib);

atr_dellyr deletes an attribute from the chain of attributes attached to a layer.

* lyr is the layer from which to delete the attribute.

* atr is the attribute to delete. atr must be read from the chain of attributes attached to the layer using the function atr_get.

atr_delsym

PROCEDURE atr_delsym (sym : IN OUT symbol; atr : attrib);

This procedure deletes an attribute from a

symbol definition.

* The parameters are the entity to delete from,

ent, and the attribute to delete, attrib.

atr_delsys

PROCEDURE atr_delsys (atr : IN OUT attrib);

atr_delsys deletes an attribute from the chain of system attributes. Space in the drawing file taken up by the attribute is freed up for later use.

* atr is the attribute to delete. atr must have been read from the chain of system attributes using the function atr_get. The attribute is deleted from the drawing database.

atr_entfind

FUNCTION atr_entfind (ent : IN OUT entity; aName : string; atr : OUT attrib) : boolean;

atr_entfind finds an attribute atr of name aName belonging to entity ent.

When an attribute with the given name exists, atr_entfind returns true and sets atr equal to the attribute. If the attribute does not exist, false is returned.

atr_entfirst

FUNCTION atr_entfirst (ent : IN OUT entity) : atraddr;

This function returns the address of the first attribute associated with an entity.

See the example under atr_get.

atr_get

FUNCTION atr_get (atr : OUT attrib; addr : atraddr) : boolean;

atr_get reads an attribute atr given its address addr.

* When addr is nil, false returns; otherwise true is returned. This function is similar to ent_get and sym_get.

To read all of the attributes belonging to an entity, use:

aAddr := atr_entfirst (ent);

WHILE atr_get (atr, aAddr) DO

processAtr (atr);

aAddr := atr_next (atr);

END;

To read all of the attributes belonging to a symbol, use:

aAddr := atr_symfirst (sym);

WHILE atr_get (atr, aAddr) DO

processAtr (atr);

aAddr := atr_next (atr);

END;

Notice these two pieces of code are identical except for the function used to find the address of the first attribute. This code shows how all attributes are the same, regardless of what they are attached to.

See also atr_lyrfirst and atr_sysfirst.

atr_init

PROCEDURE atr_init (atr : IN OUT attrib; atrtype : IN integer);

atr_init initializes a variable of type attrib so the attribute can then be added to the database.

Always call atr_init before adding an attribute to any data object.

* atr is the attribute to initialize.

* atrtype is an integer constant indicating the type which the attribute assumes (integer, distance, real, angle, string, or address).

atr_lyrfind

FUNCTION atr_lyrfind (lyr : IN layer; aname : IN string; atr : OUT attrib) : boolean;

atr_lyrfind searches for an attribute of name aname belonging to layer lyr.

When an attribute with the given name exists, atr_lyrfind returns true and sets atr equal to the attribute. If the attribute does not exist, false returns.

* lyr must exist as a valid layer in the drawing database.

atr_lyrfirst

FUNCTION atr_lyrfirst (lyr : IN layer) : atraddr;

atr_lyrfirst returns the address of the first attribute attached to a given layer.

atr_lyrfirst is usually used with the routines atr_get, and atr_next to linearly scan the chain of attributes attached to a layer.

* lyr is the layer to examine for attributes.

The following example scans the list of attributes attached to a layer and counts those which are a distance:

VAR

atr : attrib;

addr : atraddr;

count : integer;

lyr : layer;

...

count := 0;

addr := atr_lyrfirst (lyr);

WHILE atr_get (atr, addr) DO

addr := atr_next (atr);

IF atr.atrtype = atr_dis THEN

count := count + 1;

END;

END;

atr_next

FUNCTION atr_next (atr : IN OUT attrib) : atraddr;

atr_next returns the address of the next attribute after atr. This procedure is used regardless of whether the attributes are coming from entities, symbols, layers, or the system.

* When there are no more attributes after atr, nil is returned.

atr_symfind

FUNCTION atr_symfind (sym : IN OUT symbol; aName : string; atr : OUT attrib) : boolean;

atr_symfind finds an attribute atr of name aName belonging to symbol sym.

When an attribute with the given name exists, atr_symfind returns true and sets atr equal to the attribute. If the attribute does not exist, false returns.

atr_symfirst

FUNCTION atr_symfirst (sym : IN OUT symbol) : atraddr;

atr_symfirst returns the address of the first attribute belonging to a symbol.

atr_symfirst is usually used with the routines

atr_get, and atr_next to linearly scan the chain of attributes attached to a symbol.

* sym is the symbol to examine for attributes.

atr_sysfind

FUNCTION atr_sysfind (aName : IN string; atr : OUT attrib) : boolean;

atr_sysfind searches for an attribute atr of name aname belonging to symbol sym.

When an attribute with the given name exists, atr_sysfind returns true and sets atr equal to the attribute. If the attribute does not exist, false returns.

atr_sysfirst

FUNCTION atr_sysfirst : atraddr;

atr_sysfirst returns the address of the first system attribute.

atr_sysfirst is usually used with the routines atr_get and atr_next to linearly scan the chain of system attributes.

The following example scans the list of system attributes and counts those which are a distance.

VAR

atr : attrib;

addr : atraddr;

count : integer;

...

count := 0;

addr := atr_sysfirst;

WHILE atr_get (atr, addr) DO

addr := atr_next (atr);

IF atr.atrtype = atr_dis THEN

count := count + 1;

END;

END;

atr_update

PROCEDURE atr_update (atr : IN OUT attrib);

atr_update updates an attribute in the database after it is changed. The type of an attribute may change, as well as whether or not the attribute is visible.

Polyline and Polyvert Routines

The declarations for the routines in this section require the inclusion of the file _pline.inc because they are not built-into the DCAL compiler.

The following types, constants, and routines manipulate the geometric data associated with entities of type polyline and surface of revolution. These two entities, unlike most other entities, contain what is referred to as copious data. In a typical entity such as an arc, all of the data describing the arc can be contained completely within a variable of type entity; attributes are stored in a separate list attached to each entity. With polylines and surfaces of revolution, not all the data for the entity is contained within the entity record structure.

An entity of type polyline or surface of revolution consists of header information (like color, linetype, etc.) which is exactly like that for any other entity. These entities also contain additional information in the entity record structure like z-base and z-height, with polylines, or a modeling matrix, with surfaces of revolution. The data describing the vertices, lines, and arcs of a polyline or surface of revolution profile is contained in a list of objects attached to the entity. This list, comprised of objects called polyverts, is accessed through the address of the first and last polyvert in the list.

The basic entity also contains the addresses of the first and last polyverts in the list associated with each entity. The remaining polyverts are accessed by linearly scanning the list. With the exception of where these two addresses are stored, access to and manipulation of polyverts is identical for both polylines and surfaces of revolution.

Additional steps must be taken to access the geometry of this copious data. Therefore, DataCAD and DCAL have a variety of built-in types, constants, routines, and functions for managing and manipulating copious data.

Each vertex of the polyline requires that a polyvert be attached to the entity. A polyvert contains the (x,y,z) coordinates of a single point (the vertex) and a real number which describes the type of arc between the vertex and the following vertex. This real number is usually referred to as the bulge.

arc_to_bulge

PROCEDURE arc_to_bulge (center : IN point; radius, begang, endang : IN real; ccw : IN boolean; pnt1, pnt2 : OUT point; bulge : OUT real);

arc_to_bulge converts an arc which is defined by the same method as entities of type entarc to the form used by polylines and surfaces of revolution.

* The arc is defined using five parameters:

center is the center point of the arc

radius is the arc's radius

begang and endang are the arc's beginning and ending angles

ccw is a Boolean flag which is true when the arc goes counterclockwise from begang to endang; and false when the arc goes clockwise from begang to endang.

* The results of the computation are stored in pnt1, pnt2, and bulge:

pnt1 contains the coordinates of the polyvert vertex

pnt2 contains the coordinates of the next polyvert in the list

bulge contains the value of the bulge parameter for the polyvert.

When the value of bulge is zero the polyvert is a line and should be assigned a shape of pv_vert; otherwise it is an arc segment and should be assigned a shape of pv_bulge. For example, to convert an ordinary entity of type entarc to a polyvert, use the following code:

arc_to_bulge (ent.arccent, ent.arcradius, ent.arcbang, ent.arceang, true, pv.pnt, pv.nextpnt, pv.bulge);

In actual use, ccw must first be calculated, but its computation is typically dependent on the application. true is used here for simplicity.

bulge_to_arc

PROCEDURE bulge_to_arc (pnt1, pnt2 : IN point; bulge : IN real; center : OUT point; radius, begang, endang : OUT real; ccw : OUT boolean);

bulge_to_arc performs the complement function of arc_to_bulge. It takes a polyline vertex of shape pv_bulge and converts it into the standard description of an arc segment.

* The input to this routine consists of three parameters:

pnt1, the coordinates of the polyvert vertex

pnt2, the coordinates of the next polyvert vertex in the list

bulge, the value of the bulge parameter for the polyvert.

* The output of bulge_to_arc consists of five parameters:

center is the center point of the arc

radius is the arc's radius

begang is the beginning angle of the arc

segment endang is the ending angle of the arc segment

ccw is a Boolean flag which is true when the arc goes counterclockwise from begang to endang, and false when the arc goes clockwise from begang to endang.

NOTE: When working with arc segments as related to polyverts, maintain sufficient information indicating the direction of the arc segments because a polyline or surface of revolution maintains the connectivity of polyverts. A polyvert maintains this information by maintaining the order of the vertices in a polyline and, implicitly, via the bulge parameter. For the standard description of an arc, an additional flag, ccw, indicates the direction of the arc relative to the center and beginning of arc.

disfrompolyvert

FUNCTION disfrompolyvert (pv : IN OUT polyvert; tstpnt : IN point) : real;

disfrompolyvert returns the square of the distance (note that this is not the actual distance) from a point to a polyvert. Use this function to determine exactly which polyvert in a polyline a user is pointing to.

In the following example, the variable ent has already been read using ent_near or a similar operation and is a valid entity of type entpln. The following code finds the nearest polyvert to a point:

VAR

pv : polyvert;

addr: pvtaddr;

ent : entity;

pnt : point;

nearest : pvtaddr

dis : real

neardis : real

first : boolean

...

first := true;

addr := ent.plnfrst;

WHILE polyvert_get (pv, addr) DO

addr := pv.next

dis := disfrompolyvert (pv, pnt);

IF first THEN

first := false;

closedis := dis;

nearest := pv.addr;

ELSE

IF dis < closedis THEN

closedis := dis;

nearest := pv.addr;

END;

END;

END;

IF NOT first THEN

{ At least one polyvert was scanned and nearest now

contains the address of the polyvert which is nearest

to the point pnt. }

END;

ent2polyvert

PROCEDURE ent2polyvert (ent : IN entity; pv : OUT polyvert);

ent2polyvert performs the complement function of polyvert2ent.

* An entity of type entlin or entarc converts to a polyvert of the appropriate type. When the entity is of type entarc and has a valid geometry, a polyvert of shape pv_bulge returns. When the entity is of type entlin a polyvert of shape pv_vert returns.

getpolyline

FUNCTION getpolyline (msg : IN str80; viewmode : IN integer; dodraw, doclosed : IN boolean; init, isclosed : IN OUT boolean; frst, last : IN OUT pvtaddr; key : OUT integer) : integer;

getpolyline allows user input of a complete polyline by a call to a single DCAL routine. This routine takes most of the work out of designing a user interface for entering a series of polyverts which make up a polyline or surface of revolution.

The many parameters of getpolyline allow as much control over its operation as possible. With getpolyline you can use some function keys (those not used by getpolyline itself). getpolyline automatically allows the user to enter chains of polyverts which contain bulges using two-point arc, three-point arc, and tangent arc inputs, with all dragging handled automatically.

* msg is a string constant or variable containing the message you want to appear on the message line during the entering of normal vertices.

* viewmode takes a value of one of the viewing projection constants.

* Set dodraw to true when you want getpolyline to draw the polyline as the user enters each polyvert. When dodraw is false, the chain of polyverts are not drawn as they are entered.

* Set doclosed to true when you want getpolyline to automatically present the *Closed label key to the user and handle the toggling of this flag; then the variable isclosed reflects the status of this toggle. When doclosed is false, getpolyline does not handle the toggling of the closed field. In this case, whether or not the chain of polyverts is closed is determined by the current value of the variable isclosed.

* init is a Boolean variable which indicates to getpolyline that you are starting a new input sequence. When init is true, the variables frst and last are automatically set to nil. After the first call to getpolyline, init is set to false. In this way, getpolyline is reentrant. You can trap the function keys, process them accordingly, call getpolyline again, and you are at the same place as before. Simply reset init to true when you want to initiate a new input sequence.

* getpolyline returns an integer value which should be interpreted in the same way as a call to getpoint. The return value of getpolyline is either of the constants res_normal or res_escape. When the return value is res_normal, a valid chain of polyverts has been captured and entered into the database. This chain may be processed accordingly. The parameters frst and last contain the addresses of the first and last polyverts in the chain. The parameter isclosed is true when the chain of polyverts is closed (as indicated by the user), or false when the chain of polyverts is open.

* When one of the function keys not used by getpolyline is pressed, the return value from getpolyline is res_escape. getpolyline uses keys (F1), (F2), (F3), (F5), (S7), (S8) and (S0). Don't assign labels to these keys because they will be overwritten.

* The variable key contains the keycode of the pressed function key. You can test this variable and process it accordingly. As is the case with the function getpoly, you need only execute lblsinit; lblson is performed automatically by getpolyline.

The following portion of DCAL code provides a skeleton for the use of getpolyline. In this example, the viewing projection may only be orthographic as indicated by the vmode_orth parameter. In this example getpolyline controls the drawing of the polyline during its operation, and allows the user to toggle the closed option on or off.

When the polyline is closed, the variable isclosed is returned with a value of true, otherwise it is false. frst and last return the address of the first and last polyverts created during the call to getpolyline.

VAR

done,

init,

isclosed : boolean;

key,

result: integer;

frst,

last : pvtaddr;

...

done := false;

init := true;

closed := true;

REPEAT

lblsinit;

{ lblson done by getpolyline }

result := getpolyline ('Enter the next point of polyline.',

vmode_orth, true, true, init, isclosed, frst,

last, key);

IF result = res_normal THEN

{ A valid chain of polyverts was entered. Process

the chain of polyverts. }

ELSIF result = res_escape THEN

{ A function key was pressed. }

IF key = s0 THEN

done := true;

END;

END;

UNTIL done;

pline_area

FUNCTION pline_area (frst, last : IN pvtaddr) : real;

pline_area calculates and returns the area enclosed by a polyline. The area returned may be positive or negative depending upon the sense of the polyline. Usually you want the absolute value of the resulting area so an appropriate call to absr is included in the expression. pline_area assumes that the polyline is closed regardless of the status of the entity to which the chain of polyverts is attached.

* frst and last are the addresses of the first and last polyverts defining the polyline.

pline_centroid

PROCEDURE pline_centroid (frst, last : IN pvtaddr; totarea : IN OUT real; frstmoment, centroid : IN OUT point; first, add : IN boolean);

pline_centroid calculates the first moment and centroid of an area described by a polyline. This procedure calculates centroids of areas made of multiple subareas, each described by a polyline, and allows for both positive and negative areas.

* frst and last are the addresses of the first and last polyverts in the chain making up each loop.

* When the flag first is true, pline_centroid automatically assumes that this is the first or only call of a sequence, and initializes the parameters totarea, frstmoment, and centroid prior to initiating calculations. first should be set to false when pline_centroid is called the second or later time in a sequence of calls in order to accumulate calculations for multiple areas.

* totarea is the cumulative total area of the polyline and used for calculating the centroid of areas containing multiple subareas and/or voids.

* frstmoment is the cumulative first moment of the area of the polyline and used for calculating the centroid of areas containing multiple subareas and/or voids. l centroid is the centroid of the polyline or composite polyline when multiple subareas and/or voids are considered.

* When the flag add is true, the area of the polyline passed to pline_centroid is assumed to be a positive area in the calculations. When the flag add is false, the area of the polyline passed to pline_centroid is assumed to be negative or a void in the calculations. The following example assumes that mode is a mode_type variable containing a selection set of entities of type polyline. The first entity in the selection set is assumed to be a positive area encompassing a series of voids. The remaining polylines are assumed to be voids within this area. This example computes the centroid of the resulting area:

VAR

ent : entity;

addr : entaddr;

mode : mode_type;

first : boolean;

addit : boolean;

area : real;

frstmom : point;

centroid : point;

...

first := true;

addit := true;

{ First time through, initialize

and add result--subsequent times

subtract the result. }

addr := ent_first (mode);

WHILE ent_get (ent, addr) DO

addr := ent_next (ent, mode);

pline_centroid (ent.plnfrst,

ent.plnlast, totarea,

frstmom, centroid,

first, addit);

first := false;

addit := false;

END;

{ centroid now contains the centroid

of the polyline with voids. }

pline_perim

FUNCTION pline_perim (frst, last : IN pvtaddr) : real;

pline_perim calculates the perimeter of a polyline.

pline_perim returns the perimeter of the polyline. pline_perim assumes that the polyline is closed regardless of the status of the entity to which the chain of polyverts is attached.

* frst and last are the addresses of the first and last polyverts describing the polyline.

polyvert_add

PROCEDURE polyvert_add (pv : IN OUT polyvert; frst, last : IN OUT pvtaddr);

polyvert_add takes the polyvert contained in pv and adds it to the end of the chain of polyverts for which frst and last are the addresses of the first and last polyvert in the chain.

* When frst and last are part of an entity you must perform ent_update to ensure that the entity itself is properly updated in the database.

For example:

polyvert_init (pv);

pv.shape := pv_vert;

pv.bulge := 0.0;

pv.pnt.x := 10.0;

pv.pnt.y := 50.0;

pv.pnt.z := 0.0;

polyvert_add (pv, ent.plnfrst,

ent.plnlast);

ent_update (ent);

polyvert_copy

PROCEDURE polyvert_copy (oldfrst, oldlast, newfrst, newlast : IN OUT pvtaddr);

polyvert_copy makes a complete copy of a chain of polyverts.

Because polyvert_copy needs only the addresses of the first and last polyverts in both the existing (old) and new chains, polyvert_copy works correctly regardless of what the chains are attached to.

* Initialize newfrst and newlast before calling polyvert_copy. Typically, newfrst and newlast are initialized to nil. Alternatively, newfrst and newlast may represent an existing chain of polyverts, in which case the old chain is appended to the new chain. To copy an entire entity which may contain a chain of polyverts, use ent_copy rather than polyvert_copy. ent_copy properly copies the chains of polyverts which make up entities of type polyline or surfaces of revolution. For complete control over which polyverts are copied, use polyvert_copy.

For example, the following code copies an entity of type polyline without using ent_copy. Note that any attributes associated with the old entity are not copied to the new entity.

VAR

oldent: entity;

newent: entity;

...

ent_init (newent);

setnil (entaddr (newent.plnfrst));

setnil (entaddr (newent.plnlast));

newent.plnbase := oldent.plnbase

newent.plnhite := oldent.plnhite

newent.plnclose := oldent.plnclose

polyvert_copy (oldent.plnfrst,

oldent.plnlast, newent.plnfrst,

newent.plnlast);

ent_update (newent);

polyvert_count

FUNCTION polyvert_count (frst : IN pvtaddr) : integer;

polyvert_count returns the number of polyverts in a chain beginning with the polyvert pointed to by frst.

For example, to know how many polyverts are attached to a surface of revolution, use the following code:

numverts := polyvert_count (ent.revfrst);

polyvert_del

PROCEDURE polyvert_del (pv : IN OUT polyvert; frst, last : IN OUT pvtaddr);

polyvert_del deletes a polyvert from the chain of polyverts indicated by the fields frst and last. The polyvert is deleted from the database.

* When frst and last are part of an entity the entity itself must be updated after the delete operation. For example, if pv had previously been read out of the database and belongs to an entity of type surface of revolution, then the following two calls must be made to delete the polyvert from the database and update the entity appropriately:

VAR

ent : entity;

pv: polyvert

...

polyvert_del (pv, ent.revfrst, ent.revlast);

ent_update (ent)

polyvert_get

FUNCTION polyvert_get (pv : OUT polyvert; addr, frst, last : IN pvtaddr) : boolean;

polyvert_get reads a polyvert out of the database and places its contents into the variable pv.

* addr is the address of the polyvert to read.

* frst and last are the addresses of the first and last polyverts in the chain. frst and last must be valid addresses of polyverts in the database or an error occurs. To read the entire list of polyverts associated with an entity of type polyline, use the following code:

VAR

pv: polyvert;

addr : pvtaddr;

ent : entity;

frst, last : pvtaddr

...

addr := ent.plnfrst;

WHILE polyvert_get (pv, addr) DO

addr := pv.next

{ Operate upon the polyvert here. }

END;

polyvert_init

PROCEDURE polyvert_init (pv : IN OUT polyvert);

polyvert_init initializes a polyvert variable before using it for a subsequent polyvert_add or polyvert_ins call.

Similar to ent_init and atr_init, polyvert_init initializes all the fields of the polyvert, in particular those which might affect the way the polyvert is added to or read from the database.

polyvert_ins

PROCEDURE polyvert_ins (pv : IN OUT polyvert; locaddr : IN pvtaddr; frst, last : IN OUT pvtaddr);

polyvert_ins is similar to polyvert_add but with polyvert_ins you can add a polyvert at a particular location in the list of polyverts for a particular entity, not just at the end of the list.

* locaddr is the address of the polyvert after which to insert the new polyvert. Typically, locaddr is determined from an editing operation which immediately precedes the adding of a polyvert to the chain.

* frst and last are the addresses of the first and last polyverts in the chain of polyverts for this particular entity.

polyvert_update

PROCEDURE polyvert_update (pv : IN OUT polyvert);

polyvert_update updates a polyvert in the database after it is changed.

This is only a valid operation when the polyvert was read from the database via polyvert_get or added to the database via polyvert_add or polyvert_ins.

NOTE: As is the case with most database operations, simply changing the values of a variable does not update the database; an appropriate update call must be performed.

polyvert2ent

PROCEDURE polyvert2ent (pv : IN polyvert; ent : OUT entity);

polyvert2ent converts a polyvert into an entity of the appropriate type. polyvert2ent automatically accounts for the directionality of the arc.

When the polyvert has a shape of pv_vert, or the value of the bulge parameter for the polyvert is zero, the entity is of type entlin. When the polyvert has a shape of pv_bulge and the value of bulge is non-zero, the entity is of type entarc. When the distance between the vertex of the polyvert and the vertex of the next polyvert is zero, the entity is of type entmrk.

NOTE: The nextpnt field is used by polyvert2ent, and therefore must contain valid information. Void Database Routine The following routines manage voids in entities of type polygon or slab (entply or entslb). Voids are handled much like the polyverts which are attached to entities of type polyline and surface of revolution in that voids constitute copious data. Copious data is information which is required to completely describe an entity's geometry, but which is not fully contained in the record structure of a variable of type entity. Unlike polyverts, voids do not have their own record type, but instead use the type entity for their description. Voids do, however, have their own set of database routines. You must take care when using voids not to use any of the standard entity database management routines even though a void uses the same variable type as a standard entity.

A polygon or slab may have zero or more voids attached to it. There is no limitation (except for drawing file size) on the number of voids which may be attached to an entity of type polygon or slab. The routines described here are used only for the database management of voids attached to entities of type polygon and slab. The geometric calculation, manipulation, and integrity of voids is the responsibility of the programmer, and may be managed using DCAL's standard library of arithmetic and geometric routines.

For more information, see "Voids" in the DataCAD Reference Manual which contains a discussion of voids and the operations which may be performed upon them. Of particular importance are the concepts regarding geometric integrity, the geometric relationship of the master polygon or slab to the void, the relationship of the reference and offset face when working with slabs, and the rules regarding convex and degenerate polygons, slabs, and voids.

void_add

FUNCTION void_add (ent, void : IN OUT entity); boolean;

void_add adds a void to an entity of type polygon or slab. void_add returns true when a void is added.

* ent is the entity to which the void is added.

* void is an entity variable which is initialized using void_init, and contains the valid geometric description of a void corresponding to that particular entity. The geometric integrity of the void relative to the entity is the responsibility of the programmer. No geometric checking is performed by void_add.

void_del

PROCEDURE void_del (ent, void : IN OUT entity);

void_del deletes a void from an entity of type polygon or slab.

* ent must be previously read from the database using the function ent_get and must contain a valid description of an entity of type polygon or slab.

* void must be previously read from the database using the function void_get or procedure void_get_di and be a void belonging to ent. The void is deleted from the entity and removed from the database.

void_del_all

PROCEDURE void_del_all (ent : IN OUT entity);

void_del_all deletes all voids from an entity of type polygon or slab when any voids currently belong to the entity. When the entity does not have any voids associated with it, no action is taken.

void_del_all is functionally identical to the following code, but is more efficient:

VAR

ent : entity;

void : entity;

addr : entaddr;

...

addr := ent.plyfrstvoid;

WHILE void_get (void, addr) DO

addr := void.next;

void_del (ent, void);

END;

ent_update (ent);

void_get

FUNCTION void_get (void : OUT entity; addr : IN entaddr) : boolean;

void_get reads a void from the drawing database.

void_get is usually used in a WHILE loop to read the chain of voids attached to an entity of type polygon or slab. After each void is read, the data for that void may be interrogated or updated. void_get returns true when the void is successfully read out of the database. void_get returns false when there are no voids attached to the entity, or when the end of the chain of voids is reached (addr is equal to nil).

* void is an entity variable containing the contents of the void which is read from the database.

* addr is the address of the void. The following code demonstrates this principle. In this example, ent is known to be an entity of type polygon (entply):

VAR

void: entity;

ent : entity;

addr: entaddr

...

addr := ent.plyfrstvoid;

WHILE void_get (void, vaddr) DO

addr := void.next;

{ Operate on the void here. }

END;

void_get_di

PROCEDURE void_get_di (void : OUT entity; addr : IN entaddr);

void_get_di works similarly to the function void_get except void_get_di is used when addr is not equal to nil, but points to a valid void.

void_init

PROCEDURE void_init (ent, void : IN OUT entity);

void_init initializes a variable of type entity for use as a void.

void_init should always be called prior to adding a void to an entity. It is good practice to call void_init before using an entity for any void database management operation.

* ent must be an entity of type polygon or slab, and should be the entity to which the void is added.

void_update

PROCEDURE void_update (void : IN OUT entity);

void_update updates a void in a drawing database.

void_update is usually called after a void is read from the database using void_get and its geometry is altered. As is the case for entities, simply altering the contents of the void variable do not update the description of the void in the drawing database. void_update makes the drawing database reflect the changes made to the variable void.



SITE SEARCH