Appendix -- Creating an Entity


The first thing to learn is that drawing the line is the easy part and is done only after you have defined the line.

Consider the definition of a line. First, you have all the data that is common to all entities such as line type, color, layer, etc. Then for every type of entity that DataCAD understands there is specific data that enables its creation. For our example of a line, all that is required are the two points at either end.

The DCAL manual can elaborate on the fields that make up an entity definition. You do not need to set them all but some must be set or you cannot create your desired entity. For example, if you do not specify a specific color, DataCAD will use the current color. On the other hand, if you try to create a line without defining the endpoints you will have problems.

All of the entity types have specific fields that must be accounted for. A line is one of the simple ones with only the two end points required. Dimensions are an example of a rather complex entity type with many fields required.

So back to the question how do we draw a line?

Here is an outline:

  1. Tell DCAL our intention to create an entity and initialize a 'blank' entity
  2. Describe the entity by assigning values to it's fields
  3. Add the entity to the database
  4. Optionally set other fields
  5. Update the entity to reflect the optional fields
  6. Draw the entity to the screen

Here is a simple routine from one of my files that I use to create entities.

PROCEDURE add_line ( pnt1, pnt2 : point; line : line_attribs); PUBLIC;
{* Draws a single line on the screen given two points and the attributes for the line. *}

VAR
  ent : entity;

BEGIN
  ent_init (ent, entlin);
  ent.linpt1 := pnt1;
  ent.linpt2 := pnt2;
  ent.linpt1.z := zbase; ! this line will have no height
  ent.linpt2.z := zbase;
  ent_add (ent);
  ent.ltype := line.ltype;
  ent.width := line.width;
  ent.spacing := line.spacing;
  ent.ovrshut := line.ovrshut;
  ent.color := line.color;
  ent_update (ent);
  ent_draw (ent, drmode_white);
END add_line;

OK, what do we have here? This is a procedure that is called with 3 parameters. These parameters are two points (end points for the line) and something described as LINE_ATTRIBS. You will not find line_attribs .html anywhere in the DCAL manual. It is a record structure that I have defined as follows:

TYPE
  line_attribs = RECORD
    ltype   : integer;
    width   : integer;
    spacing : real;
    ovrshut : real;
    color   : integer;
  END;

If you recall you can define your own types in DCAL. Then you are free to use your type as if it was one of the predefined types such as string or real. To access the values within this record we use 'dot' notation. So if we go back to the procedure declaration above where the parameter named LINE is of type line_attribs, we can access the individual components of the record as follows:

line.ltype
line.width

etc....

Why would you set up such a thing? The main reason is to simplify passing data back and forth. Without the line_attribs type definition our procedure declaration would look something like the following:

PROCEDURE add_line ( pnt1, pnt2 : point;
                     ltype      : integer;
                     width      : integer;
                     spacing    : real;
                     ovrshut    : real;
                     color      : integer); PUBLIC;

See the difference? By using the type definition we are able to pass one data structure rather than 5 separate parameters.

You do not have to use record structures at all but you should understand them since the entire entity definition is based on one big record structure.

returning to our outline...

1. Tell DCAL our intention to create an entity and initialize a 'blank' entity

ent_init (ent, entlin);

this tells DCAL we want to initialize all the required fields of an entlin. We are using our variable ent of entity type to define our new line entity. All of the possible entities are described in the DCAL manual. Entlin is a constant defined within DCAL. More on this later.

2. Describe the entity by assigning values to it's fields

ent.linpt1   := pnt1;
ent.linpt2   := pnt2;
ent.linpt1.z := zbase; ! this line will have no height
ent.linpt2.z := zbase;

Here we define the required properties of an entity of type entlin. Notice the use of the zbase constant. zbase is the current z base setting. By using this we assure that the line is drawn with no height. A line will be created with its base set to the current z base. By setting it's height to match this we have defined a 'flat' line. If you wanted a line of a specific height simply plug in the desired height. Use care with your units. You may be tempted to describe an 8'-0" height as 8.0 but in DCAL all units are based on 1/32 of an inch. Some math is required to get what you want.

1 unit =1/32, 1 inch = 32 units (1x32), 1 foot = 384 units (12x32)

It is sometimes helpful to define some constants such as:

CONST
  inch = 32.0;
  feet = 384.0;

Then you are free to do the following:

ent.linpt2.z := (3.0 * feet) + (6.0 * inch); ! this will evaluate to 3'-6"

and it may be easier for you to understand.

back to our example...

3. Add the entity to the database

  ent_add (ent);

Does exactly what it says. Adds entity 'ent' to the database. So we are done, right? Nope. We have added the definition of our entity to the database BUT this does not draw it to the screen. So, just do ent_draw then, right? Nope. Not yet.

One quirk of creating entities is you cannot set the color, line type, etc. in the first pass. If you were to draw this entity it would have all the current settings for line type, color, etc. Even if you were to assign values to these fields, as our next few lines of code will do, THEN call ent_add you would not get the desired results. This is simply the way DCAL works. What I like to do is set all the required fields of the entity. By required, I refer to those that are specific to the entity type. Then add the entity. Finally set the common fields such as color, line type, etc and update the entity.

This is what the next few lines of our example do.

4. Optionally set other fields

  ent.ltype   := line.ltype;
  ent.width   := line.width;
  ent.spacing := line.spacing;
  ent.ovrshut := line.ovrshut;
  ent.color   := line.color;

Here we set these values to those that were passed in the line parameter. Remember the line_attrib record structure we discussed above? This is where it is used. Notice that the names that sounded a little strange when we discussed line_attrib now match up exactly with the DCAL field names for entities. It is a good idea to not mix terms or typos will occur.

5. Update the entity to reflect the optional fields

  ent_update (ent);

Now we can update the entity definition to have the color, line type, etc changes stick.

6. Finally, draw the entity to the screen

  ent_draw (ent, drmode_white);

Again, an appropriately named procedure. But what is drmode_white? drmode_white is a constant that is available within DCAL. There are three constants to describe how to draw an entity. They are as follows:

  • drmode_black - draw the entity in the screen background color, effectively erasing it.
  • drmode_white - draw the entity in the defined color (ent.color)
  • drmode_flip - draw the entity in the opposite mode than what it is currently drawn as.
    huh? if the entity is currently drawn as drmode_white then it will be drawn as drmode_black. If you want to flash an entity call drmode_flip several times. Be sure to leave the entity drawn in the state you want.

Here is a routine that might call the add_line procedure:

var
  line : line_attribs
  pnt1,
  pnt2 : point

begin
  pnt1.x := 0.0;
  pnt1.y := 0.0;

  pnt2.x := 384.0;
  pnt2.y := 384.0;

  line.ltype := ltype_solid;
  line.width := 1;
  line.spacing := 1.0;
  line.ovrshut := 0.0;
  line.color := clr_blue;

  add_line (pnt1, pnt2, line);
end;

This will draw a one foot long line at an angle of 45 degrees. It's color will be blue and line type will be solid. It will have a width of 1 and no overshoot.

If you look at the definition of the point type you will see that it too is a record of 3 reals. A point is defined as follows:

point = record
  x : real;
  y : real;
  z : real;
end;

The x, y and z values correspond to the x, y and z coordinates of this point. You can define a point as we do above by setting the values or you can use a function such as getpoint that will return a point. We have already covered the line_attribs definition but you may notice some terms used in conjunction with the fields of this record. For convenience, DCAL defines certain constant values for often-used things like line types or colors. The manual will list them all but some examples are the built-in line types which are defined as:

  • ltype_solid
  • ltype_dotted
  • ltype_dashed
  • ltype_dotdash

User line types begin with the number 4 and will go up to the maximum defined user line type.

Colors are similarly defined as:

  • clrblue
  • clrbrown
  • clrcyan
  • etc...

Entity types such as entlin, entarc, etc are also defined as convenient constants. Again, the manual lists all these values.

That should explain why the record fields are defined as 'integer' but you see some text used as the value. The text corresponds to the predefined constant. Remember from the basic tutorial that you can define your own constants. So I could also have written...

  ent.linpt2.x := 1.0 * feet;

assuming I have defined a constant called 'feet' somewhere in my project. You can use any expression in such an assignment as long as it evaluates to the correct data type. What? You could say 2.0 + 2.0 or any complex calculation as long as it evaluates to a real type. If you were to say ABSI(-489) this would fail since it would return the absolute value of the integer expression (489) which is an integer value.

Grab the entity utilities module from DDN. There are plenty of routines in it to make different types of entities.

The code below may be cut and pasted into a text file. Save it as addline.dcs. This example illustrates the use of what we have covered here.

PROGRAM addline; {addline.dcs}

TYPE
  line_attribs = RECORD
    ltype : integer;
    width : integer;
    spacing : real;
    ovrshut : real;
    color : integer;
  END;
PROCEDURE add_line ( pnt1, pnt2 : point;
                   line : line_attribs);
PUBLIC;
{* Draws a single line on the screen given two points and the attributes
 * for the line.
 *}

VAR
  ent : entity;

BEGIN
  ent_init (ent, entlin);
  ent.linpt1 := pnt1;
  ent.linpt2 := pnt2;
  ent.linpt1.z := zbase; ! this line will have no height
  ent.linpt2.z := zbase;
  ent_add (ent);
  ent.ltype := line.ltype;
  ent.width := line.width;
  ent.spacing := line.spacing;
  ent.ovrshut := line.ovrshut;
  ent.color := line.color;
  ent_update (ent);
  ent_draw (ent, drmode_white);
END add_line;


PROCEDURE main;

var
  line : line_attribs;
  pnt1,
  pnt2 : point;

begin
  pnt1.x := 0.0;
  pnt1.y := 0.0;

  pnt2.x := 384.0;
  pnt2.y := 384.0;

  line.ltype := ltype_solid;
  line.width := 1;
  line.spacing := 1.0;
  line.ovrshut := 0.0;
  line.color := clrblue;

  add_line (pnt1, pnt2, line);
end main;

begin
  main;

end addline.

Notes:

This article was originally posted to the DDN mailing list. At the time it was posted, a few questions were asked and points raised. Here is some additional information related to this article:

Always initialize your data. If you look at the addline.dcs sample code above you will notice that pnt1 and pnt2 are given values for their x and y components. What you do not see is a z component. In this case it is not critical since the add_line routine will insert zbase for the z component of any points passed to it. However, it is important to remember that unless you are certain all values will contain valid data, you should initialize them yourself. Never assume that DCAL will handle this or that it is not needed.

Some useful constant values for our metric friends

CONST
  mm = 1.25984252; {1.0 / .79375}
  cm = 12.5984252;
  metre = 1259.84252;

Finally, note that all point locations are based on the drawing origin. The point (0.0, 0.0, 0.0) is equivalent to the drawing origin and a z height of zero. (384.0, 384.0, 384.0) would be a point one foot from the origin in the x, y, and z directions.

< Previous Lesson



SITE SEARCH