Entity Data Functions

Some functions operate on entity data and can be used to modify the current drawing database. The acdbEntDel() function deletes a specified entity. The entity is not purged from the database until you leave the current drawing. So if the application calls acdbEntDel() a second time during that session and specifies the same entity, the entity is undeleted. (You can use acdbHandEnt() to retrieve the names of deleted entities.)

Note: Using acdbEntDel(), attributes and polyline vertices cannot be deleted independently from their parent entities; acdbEntDel() operates only on main entities. To delete an attribute or vertex, use acedCommandS() or acedCmdS() to invoke the AutoCAD ATTEDIT or PEDIT commands, use acdbEntMod() to redefine the entity without the unwanted subentities, or open the vertex or attribute and use its erase() method to erase it.

The acdbEntGet() function returns the definition data of a specified entity. The data is returned as a linked list of result buffers. The type of each item (buffer) in the list is specified by a DXF group code. The first item in the list contains the entity's current name (restype == -1).

An ObjectARX application could retrieve and print the definition data for an entity by using the following two functions. (The printdxf() function does not handle extended data.)

void getlast() 
{ 
    struct resbuf *ebuf, *eb; 
    ads_name ent1; 
    acdbEntLast(ent1); 
    ebuf = acdbEntGet(ent1); 
    eb = ebuf; 
    acutPrintf("\nResults of entgetting last entity\n"); 
    // Print items in the list.
    for (eb = ebuf; eb != NULL; eb = eb->rbnext) 
        printdxf(eb); 
    // Release the acdbEntGet() list.
    acutRelRb(ebuf); 
} 
int printdxf(eb) 
struct resbuf *eb; 
{ 
    int rt; 
    if (eb == NULL) 
        return RTNONE; 
    if ((eb->restype >= 0) && (eb->restype <= 9)) 
        rt = RTSTR ; 
    else if ((eb->restype >= 10) && (eb->restype <= 19)) 
        rt = RT3DPOINT; 
    else if ((eb->restype >= 38) && (eb->restype <= 59)) 
        rt = RTREAL ; 
    else if ((eb->restype >= 60) && (eb->restype <= 79)) 
        rt = RTSHORT ; 
    else if ((eb->restype >= 210) && (eb->restype <= 239)) 
        rt = RT3DPOINT ; 
    else if (eb->restype < 0) 
        // Entity name (or other sentinel)
        rt = eb->restype; 
    else 
        rt = RTNONE; 
    switch (rt) { 
    case RTSHORT: 
        acutPrintf("(%d . %d)\n", eb->restype, 
            eb->resval.rint); 
        break; 
    case RTREAL: 
        acutPrintf("(%d . %0.3f)\n", eb->restype, 
            eb->resval.rreal); 
        break; 
    case RTSTR: 
        acutPrintf("(%d . \"%s\")\n", eb->restype, 
            eb->resval.rstring); 
        break; 
    case RT3DPOINT: 
        acutPrintf("(%d . %0.3f %0.3f %0.3f)\n", 
            eb->restype, 
            eb->resval.rpoint[X], eb->resval.rpoint[Y], 
            eb->resval.rpoint[Z]); 
        break; 
    case RTNONE: 
        acutPrintf("(%d . Unknown type)\n", eb->restype); 
        break; 
    case -1: 
    case -2:  
        // First block entity
        acutPrintf("(%d . <Entity name: %8lx>)\n", 
            eb->restype, eb->resval.rlname[0]); 
    } 
    return eb->restype; 
} 

In the next example, the following (default) conditions apply to the current drawing.

Also, the user has drawn a line with the following sequence of commands:

Command: line

Specify first point: 1,2

Specify next point or [Undo]: 6,6

Specify next point or [Undo]: ENTER

Then a call to getlast() would print the following (the name value will vary).

Results from acdbEntGet() of last entity:

(-1 . <Entity name: 60000014>)

(0 . "LINE")

(8 . "0")

(10 1.0 2.0 0.0)

(11 6.0 6.0 0.0)

(210 0.0 0.0 1.0)

Note: The printdxf() function prints the output in the format of an AutoLISP association list, but the items are stored in a linked list of result buffers.

The result buffer at the start of the list (with a -1 sentinel code) contains the name of the entity that this list represents. The acdbEntMod() function uses it to identify the entity to be modified.

The codes for the components of the entity (stored in the restype field) are those used by DXF. As with DXF, the entity header items are returned only if they have values other than the default. Unlike DXF, optional entity definition fields are returned regardless of whether they equal their defaults. This simplifies processing; an application can always assume that these fields are present. Also unlike DXF, associated X, Y, and Z coordinates are returned as a single point variable (resval.rpoint), not as separate X (10), Y (20), and Z (30) groups. The restype value contains the group number of the X coordinate (in the range 10–19).

To find a group with a specific code, an application can traverse the list. The entitem() function shown here searches a result buffer list for a group of a specified type.

static struct resbuf *entitem(rchain, gcode) 
struct resbuf *rchain; 
int gcode; 
{ 
    while ((rchain != NULL) && (rchain->restype != gcode)) 
        rchain = rchain->rbnext; 
    return rchain; 
} 

If the DXF group code specified by the gcode argument is not present in the list (or if gcode is not a valid DXF group), entitem() “falls off the end” and returns NULL. Note that entitem() is equivalent to the AutoLISP function (assoc).

The acdbEntMod() function modifies an entity. It passes a list that has the same format as a list returned by acdbEntGet(), but with some of the entity group values (presumably) modified by the application. This function complements acdbEntGet(); the primary means by which an ObjectARX application updates the database is by retrieving an entity with acdbEntGet(), modifying its entity list, and then passing the list back to the database with acdbEntMod().

Note: To restore the default value of an entity's color or linetype, use acdbEntMod() to set the color to 256, which is BYLAYER, or the linetype to BYLAYER.

The following code fragment retrieves the definition data of the first entity in the drawing, and changes its layer property to MYLAYER.

ads_name en; 
struct resbuf *ed, *cb; 
char *nl = "MYLAYER"; 
if (acdbEntNext(NULL, en) != RTNORM) 
    return BAD; // Error status  
ed = acdbEntGet(en); // Retrieve entity data.
for (cb = ed; cb != NULL; cb = cb->rbnext) 
    if (cb->restype == 8) {											// DXF code for Layer
        // Check to make sure string buffer is long enough.
        if (strlen(cb->resval.rstring) < (strlen(nl))) 
            // Allocate a new string buffer.
            cb->resval.rstring = realloc(cb->resval.rstring, 
                strlen(nl) + 1); 
        strcpy(cb->resval.rstring, nl); 
        if (acdbEntMod(ed) != RTNORM) { 
            acutRelRb(ed); 
            return BAD; // Error
        } 
        break; // From the for loop
    } 
acutRelRb(ed); // Release result buffer.

Memory management is the responsibility of an ObjectARX application. Code in the example ensures that the string buffer is the correct size, and it releases the result buffer returned by acdbEntGet() (and passed to acdbEntMod()) once the operation is completed, whether or not the call to acdbEntMod() succeeds.

Note: If you use acdbEntMod() to modify an entity in a block definition, this affects all INSERT or XREF references to that block; also, entities in block definitions cannot be deleted by acdbEntDel().

An application can also add an entity to the drawing database by calling the acdbEntMake() function. Like acdbEntMod(), the argument to acdbEntMake() is a result-buffer list whose format is similar to that of a list returned by acdbEntGet(). (The acdbEntMake() call ignores the entity name field [-1] if that is present.) The new entity is appended to the drawing database (it becomes the last entity in the drawing). If the entity is a complex entity (a polyline or block), it is not appended to the database until it is complete.

The following sample code fragment creates a circle on the layer MYLAYER.

int status; 
struct resbuf *entlist; 
ads_point center = {5.0, 7.0, 0.0}; 
char *layer = "MYLAYER"; 
entlist = acutBuildList(RTDXF0, "CIRCLE",// Entity type
    8, layer, // Layer name 
    10, center, // Center point 
    40, 1.0, // Radius 
    0 ); 
if (entlist == NULL) { 
    acdbFail("Unable to create result buffer list\n"); 
    return BAD; 
} 
status = acdbEntMake(entlist); 
acutRelRb(entlist); // Release acdbEntMake buffer.
if (status == RTERROR) { 
    acdbFail("Unable to make circle entity\n"); 
    return BAD; 
} 

Both acdbEntMod() and acdbEntMake() perform the same consistency checks on the entity data passed to them as the AutoCAD DXFIN command performs when reading DXF files. They fail if they cannot create valid drawing entities.