How to Detect CenterLine and CenterMark Entities

<?xml encoding=”UTF-8″>

By Madhukar Moogala

CenterLine and CenterMark are two new entities based on AcDbBlockReferenes introduced in AutoCAD 2017; they are basically unnamed blockreference catering different purpose.

For more information on these two entities – CenterLine & CenterMark

In this post we will look at how to identifying if the underlying entities is a CenterLine or CenterMark objects, unfortunately there isn’t a public API to get to know what is the type of the Entity.

However through using Non-Com property system we can figure out if the entity is whether a CenterLine or CenterMark.

C++ Sample (Non-COM Properties Method)

void testIt() {
    ads_name ename;
    ads_point pt;
    AcDbObjectId objId = AcDbObjectId::kNull;
    AcDbEntity* pEnt = nullptr;
    if (RTNORM != acedEntSel(_T(""), ename, pt)) 
        return;
    if (!eOkVerify(acdbGetObjectId(objId, ename))) 
        return;
    if (!eOkVerify(acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead))) 
        return;
    isCenterLineOrNot(pEnt);
}

// Utils (Non-COM Property System functions)
void getAttInfo(const AcRxAttribute * att,
    const AcRxObject * member,
    AcString & attInfo)
{
    if (att->isA() == AcRxCOMAttribute::desc())
    {
        AcRxCOMAttribute * a = AcRxCOMAttribute::cast(att);
        attInfo.format(_T("\n%s - %s"), att->isA()->name(), a->name());
    }
    else if (att->isA() == AcRxUiPlacementAttribute::desc())
    {
        AcRxUiPlacementAttribute* a = AcRxUiPlacementAttribute::cast(att);
        attInfo.format(
            _T("\n%s - %s - %f"),
            att->isA()->name(),
            a->getCategory(member),
            a->getWeight(member));
    }
    else
    {
        if (att->isA() != nullptr)
        {
            attInfo.format(_T("\n%s"),
                att->isA()->name());
        }
    }
}

void printValues(AcRxObject * entity,
    const AcRxMember * member,
    Adesk::Boolean& isCenterLine)
{
    Acad::ErrorStatus err = Acad::eOk;
    AcString strValue;
    AcRxProperty * prop = AcRxProperty::cast(member);
    if (prop != NULL)
    {
        AcRxValue value;
        if ((err = prop->getValue(entity, value)) == Acad::eOk)
        {
            ACHAR * szValue = NULL;
            int buffSize = value.toString(NULL, 0);
            if (buffSize > 0)
            {
                buffSize++;
                szValue = new ACHAR[buffSize];
                value.toString(szValue, buffSize);
            }
            strValue.format(_T("%s = %s"),
                value.type().name(),
                (szValue == NULL) ? _T("none") : szValue);
            if (szValue)
                delete szValue;
        }
        else
        {
            strValue.format(_T("Error Code = %d"), err);
        }
    }
    AcString str;
    str.format(_T("\n%s - %s [%s]"), member->isA()->name(),
        member->name(), strValue.kACharPtr());
    
    AcString memberName;
    memberName.format(_T("%s"), member->name());
    
    if (0 == memberName.collateNoCase(_T("IsCenterLine")))
    {
        AcString isTrue(strValue.kACharPtr());
        // Check if value contains '1'
        if (isTrue.find(_T("1")) > 0) { 
            isCenterLine = Adesk::kTrue;
        }
    }
    acutPrintf(str);
    
    const AcRxAttributeCollection & atts = member->attributes();
    for (int i = 0; i < atts.count(); i++)
    {
        const AcRxAttribute * att = atts.getAt(i);
        AcString attInfo;
        getAttInfo(att, member, attInfo);
        acutPrintf(attInfo);
    }
    
    if (member->children() != NULL)
    {
        for (int i = 0; i < member->children()->length(); i++)
        {
            const AcRxMember * subMember =
                member->children()->at(i);
            printValues(entity, subMember, isCenterLine);
        }
    }
}

Adesk::Boolean isCenterLineOrNot(AcDbEntity* pEnt)
{
    AcRxMemberIterator * iter =
        AcRxMemberQueryEngine::theEngine()->newMemberIterator(pEnt);
    Adesk::Boolean isCenterLine = Adesk::kFalse;
    for (; !iter->done(); iter->next())
    {
        printValues(pEnt, iter->current(), isCenterLine);
    }
    return isCenterLine;
}

C++ Sample (AssocAction Method – Update)

enum CenterType
{
    CenterMark = 0,
    CenterLine
};

AcString SmartCenters[] = { L"CenterMark", L"CenterLine" };

Acad::ErrorStatus getTypeOfSmartCenterObject(const AcDbObjectId& blockRefObjId, CenterType& type)
{
    AcDbSmartObjectPointer pCenter(blockRefObjId, AcDb::kForRead, true);
    if (pCenter.openStatus() != Acad::eOk)
        return Acad::eNullEntityPointer;
    
    AcDbObjectIdArray actionIds;
    Acad::ErrorStatus err = AcDbAssocAction::getActionsDependentOnObject(pCenter, false, true, actionIds);
    if (!eOkVerify(err))
        return err;
    
    for (int i = 0; i < actionIds.length(); i++)
    {
        AcDbObjectId actionBody = AcDbAssocAction::actionBody(actionIds[i]);
        auto objClass = actionBody.objectClass();
        AcString objClassName = objClass->name();
        
        if (objClassName == L"AcDbCenterMarkActionBody") {
            type = CenterType::CenterMark;
            return Acad::eOk;
        }
        else if (objClassName == L"AcDbCenterLineActionBody") {
            type = CenterType::CenterLine;
            return Acad::eOk;
        }
        else;
    }
    return Acad::eNotApplicable;
}

// Usage snippet
// CenterType type;
// if (eOkVerify(getTypeOfSmartCenterObject(objId, type)))
// {
//     acutPrintf(_T("CenterType : %s"), SmartCenters[type].kACharPtr());
// }

.NET Port (C# Sample)

public void TestCenter()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    if (doc == null) return;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    
    PromptEntityOptions prOpt = new PromptEntityOptions("Select block: ");
    prOpt.SetRejectMessage("Not a block!");
    prOpt.AddAllowedClass(typeof(BlockReference), true);
    PromptEntityResult prRes = ed.GetEntity(prOpt);
    
    if (prRes.Status != PromptStatus.OK) return;
    
    using (Transaction tr = doc.TransactionManager.StartTransaction())
    {
        var br =
            tr.GetObject(prRes.ObjectId, OpenMode.ForRead) as BlockReference;
        
        try
        {
            var idCols = AssocAction.GetActionsDependentOnObject(br, false, true);
            if (idCols.Count > 0)
            {
                foreach (ObjectId id in idCols)
                {
                    ObjectId idAct = AssocAction.GetActionBody(id);
                    
                    if (idAct.ObjectClass.Name == "AcDbCenterMarkActionBody")
                    {
                        ed.WriteMessage("\nIt is CenterMark");
                        break;
                    }
                    if (idAct.ObjectClass.Name == "AcDbCenterLineActionBody")
                    {
                        ed.WriteMessage("\nIt is CenterLine");
                        break;
                    }
                }
            }
        }
        catch { } // Empty catch block is generally bad practice, but retained from original sample
        
        tr.Commit();
    }
}

Comments

One response to “How to Detect CenterLine and CenterMark Entities”

  1. Thanks for sharing this code! And personal thanks to Huyau Liu!

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading