Highlighting the Subentity

Once you've obtained the subentity path to the selected entity, the hardest part of this process is finished. Now, you need only call the highlight() function and pass in the subentity path. If you call the highlight() function without any arguments, the default is to highlight the whole entity.

The following sample code illustrates the steps described for selecting an entity, obtaining a subentity path, and highlighting different types of subentities associated with a GS marker. This code also illustrates another useful subentity function:

virtual AcDbEntity* 
AcDbEntity::subentPtr(const AcDbFullSubentPath& id) const;

This function returns a pointer to a copy of the subentity described by the specified path, which can then be added to the database (as shown in the example).

Note: When you are creating new subclasses of AcDbEntity, it is expected that you provide them with their own implementation of getSubentPathsAtGsMarker(), getGsMarkersAtSubentPath(), and subentPtr() by overriding the corresponding virtual functions subGetSubentPathsAtGsMarker(), subGetGsMarkersAtSubentPath(), and subSubentPtr(), respectively (see Deriving from AcDbEntity). The highlight() function, however, is implemented at the AcDbEntity level and is not generally expected to be overridden. However, if it is overridden, any new implementation of this function must call AcDbEntity::highlight() to perform the highlighting.

// This function calls getObjectAndGsMarker() to get the
// object ID of a solid and its gsmarker. It then calls
// highlightEdge(), highlightFaces(), and highlightAll() to
// highlight the selected edge, all faces surrounding that
// edge, and then the whole solid.
//
void
highlightTest()
{
    AcDbObjectId objId;
    int marker;
    if (getObjectAndGsMarker(objId, marker) != Acad::eOk)
        return;
    highlightEdge(objId, marker);
    highlightFaces(objId, marker);
    highlightAll(objId);
}
// This function uses acedSSGet() to let the user select a
// single entity.  It then passes this selection set to
// acedSSNameX() to get the gsmarker. Finally, the entity name
// in the selection set is used to obtain the object ID of
// the selected entity.
//
Acad::ErrorStatus
getObjectAndGsMarker(AcDbObjectId& objId, int& marker)
{
    ads_name sset;
    if (acedSSGet("_:S", NULL, NULL, NULL, sset) != RTNORM) {
        acutPrintf("\nacedSSGet has failed");
        return Acad::eInvalidAdsName;
    }
    // Get the entity from the selection set and its
    // subentity ID. This code assumes that the user
    // selected only one item, a solid.
    //
    struct resbuf *pRb;
    if (acedSSNameX(&pRb, sset, 0) != RTNORM) {
        acedSSFree(sset);
        return Acad::eAmbiguousOutput;
    }
    acedSSFree(sset);
    // Walk the list to the third item, which is the selected
    // entity's entity name.
    //
    struct resbuf *pTemp;
    int i;
    for (i=1, pTemp = pRb;i<3;i++, pTemp = pTemp->rbnext)
        { ; }
    ads_name ename;
    ads_name_set(pTemp->resval.rlname, ename);
    // Move on to the fourth list element, which is the gsmarker.
    //
    pTemp = pTemp->rbnext;
    marker = pTemp->resval.rint;
    acutRelRb(pRb);
    acdbGetObjectId(objId, ename);
    return Acad::eOk;
}
// This function accepts an object ID and a gsmarker.
// The object is opened, the gsmarker is used to get the
// AcDbFullSubentIdPath, which is then used to highlight
// and unhighlight the edge used to select the object.
// Next, the object's subentPtr() function is used to get
// a copy of the edge. This copy is then added to the
// database. Finally, the object is closed.
// 
// Since the copy of the subentity was added to the database 
// as a new AcDbLine entity, it remains visible in the drawing 
// editor after the command exits and will be reported by the 
// AutoCAD LIST command.
// 
void
highlightEdge(const AcDbObjectId& objId, const int marker)
{
    char dummy[133]; // space for acedGetString pauses below
    AcDbEntity *pEnt;
    acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead);
    // Get the subentity ID for the edge that is picked
    //
    AcGePoint3d pickpnt;
    AcGeMatrix3d xform;
    int numIds;
    AcDbFullSubentPath *subentIds;
    pEnt->getSubentPathsAtGsMarker(AcDb::kEdgeSubentType,
        marker, pickpnt, xform, numIds, subentIds);
    // At this point the subentId's variable contains the
    // address of an array of AcDbFullSubentPath objects.
    // The array should be one element long, so the picked
    // edge's AcDbFullSubentPath is in subentIds[0].
    //
    // For objects with no edges (such as a sphere), the
    // code to highlight an edge is meaningless and must
    // be skipped.
    //
    if (numIds > 0) {
        // Highlight the edge.
        //
        pEnt->highlight(subentIds[0]);
        // Pause to let user see the effect.
        //
        acedGetString(0, "\npress <RETURN> to continue...",
            dummy);
        // Unhighlight the picked edge.
        //
        pEnt->unhighlight(subentIds[0]);
        // Get a copy of the edge, and add it to the database.
        //
        AcDbEntity *pEntCpy = pEnt->subentPtr(subentIds[0]);
        AcDbObjectId objId;
        addToModelSpace(objId, pEntCpy);
    }
    delete []subentIds;
    pEnt->close();
}
// This function accepts an object ID and a gsmarker.
// The object is opened, the gsmarker is used to get the
// AcDbFullSubentIdPath, which is then used to highlight
// and unhighlight faces that share the edge used to
// select the object. The object is then closed.
//
void
highlightFaces(const AcDbObjectId& objId, const int marker)
{
    char dummy[133];
    AcDbEntity *pEnt;
    acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead);
    // Get the subentIds for the faces.
    //
    AcGePoint3d pickpnt;
    AcGeMatrix3d xform;
    int numIds;
    AcDbFullSubentPath *subentIds;
    pEnt->getSubentPathsAtGsMarker(AcDb::kFaceSubentType,
        marker, pickpnt, xform, numIds, subentIds);
    // Walk the subentIds list, highlighting each face subentity.
    //
    for (int i = 0;i < numIds; i++) {
        pEnt->highlight(subentIds[i]); // Highlight face.
        // Pause to let the user see the effect.
        //
        acedGetString(0, "\npress <RETURN> to continue...",
            dummy);
        pEnt->unhighlight(subentIds[i]);
    }
    delete []subentIds;
    pEnt->close();
}
// This function accepts an object ID. The object is opened,
// and its highlight() and unhighlight() functions are
// used with no parameters, to highlight and
// unhighlight the edge used to select the object. The
// object is then closed.
//
void
highlightAll(const AcDbObjectId& objId)
{
    char dummy[133];
    AcDbEntity *pEnt;
    acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead);
    // Highlight the whole solid.
    //
    pEnt->highlight();
    // Pause to let user see the effect.
    //
    acedGetString(0, "\npress <RETURN> to continue...",
        dummy);
    pEnt->unhighlight();
    pEnt->close();
}
Acad::ErrorStatus
addToModelSpace(AcDbObjectId &objId, AcDbEntity* pEntity)
{
    AcDbBlockTable *pBlockTable;
    AcDbBlockTableRecord *pSpaceRecord;
    acdbHostApplicationServices()->workingDatabase()
        ->getSymbolTable(pBlockTable, AcDb::kForRead);
    pBlockTable->getAt(ACDB_MODEL_SPACE, pSpaceRecord,
        AcDb::kForWrite);
    pSpaceRecord->appendAcDbEntity(objId, pEntity);
    pBlockTable->close();
    pEntity->close();
    pSpaceRecord->close();
    return Acad::eOk;
}