Jump to content

Recommended Posts

Posted (edited)

When you call a method against an entity in Lisp or ActiveX, AutoCAD manages the state of the entity for you. The sequence is:

- Lock the document

- Open the Object kForRead/kForWrite

- Perform the operation

- Close the Object

- Unlock the document

 

The overhead starts to build up if you’re setting lots of dbobject Properties

 

Unlike Lisp or ActiveX, Db.DbObject, in Python, .NET, and ObjectARX you have to manage the object’s lifetime. .NET mainly uses the transaction manager for this, I won’t be getting into that

 

Writing in Python(PyRx) is almost identical to modern C++ in that both systems use smart pointers to help manage the state for you.

 

Consider C++

static void AcRxPyApp_idoit(void)
{
    auto [ps, id, pnt] = entsel(L"\nSelect Entity: ");
    AcDbEntityPointer pEnt(id, AcDb::OpenMode::kForWrite);
    pEnt->setLayer(L"0");
}

 

vs Python

def doit():
    try:
        ps, id, pnt = Ed.Editor.entSel("\nSelect Entity: ")
        ent = Db.Entity(id,Db.OpenMode.kForWrite)
        ent.setLayer("0")
    except Exception as err:
        traceback.print_exception(err)

 

 

In Both C++ and Python, ent (pEnt) is closed at the end of the function scope

Edited by Danielm103
Posted

The Pros:

You can leave the entities open for longer, set multiple properties without the overhead of multiple open/close.

 

Consider adding a large number of entities to modelspace, with PyRx, you can leave modelspace opened for write for the entire operation

 

@Ap.Command()
def doit():
    try:
        db = Db.curDb()
        space = Db.BlockTableRecord(db.currentSpaceId(), Db.OpenMode.kForWrite)
        for idx in range(20):
            nidx = idx + 100
            space.appendAcDbEntity(
                Db.Line(Ge.Point3d(idx, idx, idx), Ge.Point3d(nidx, nidx, nidx)))
    except Exception as err:
        traceback.print_exception(err)

 

Posted

The Cons:

 

You have to consider the states of the objects when writing your code, for example function dobad throws an exception

Db.ErrorStatusException: Exception!(eWasOpenForRead) because space and model are the same object, to be opened in different states

 

@Ap.Command()
def dobad():
    try:
        db = Db.curDb()
        space = Db.BlockTableRecord(db.modelSpaceId())
        for id in space.objectIds(Db.Line.desc()):
           line = Db.Line(id)
        # ......
        model = Db.BlockTableRecord(db.modelSpaceId(), Db.OpenMode.kForWrite)
        model.appendAcDbEntity(  Db.Line(Ge.Point3d(0, 0, 0), Ge.Point3d(100, 100, 0)))
        #Db.ErrorStatusException: Exception!(eWasOpenForRead)
    except Exception as err:
        traceback.print_exception(err)


@Ap.Command()
def dogood():
    try:
        db = Db.curDb()
        space = Db.BlockTableRecord(db.modelSpaceId())
        for id in space.objectIds(Db.Line.desc()):
           line = Db.Line(id)
        # ......
        space.upgradeOpen() # change to write
        space.appendAcDbEntity(  Db.Line(Ge.Point3d(0, 0, 0), Ge.Point3d(100, 100, 0)))
    except Exception as err:
        traceback.print_exception(err)


@Ap.Command()
def dobest():
    try:
        db = Db.curDb()
        readlines(db)
        #...
        writelines(db)

    except Exception as err:
        traceback.print_exception(err)

def readlines(db):
    space = Db.BlockTableRecord(db.modelSpaceId())
    for id in space.objectIds(Db.Line.desc()):
        line = Db.Line(id)
        
def writelines(db):
    model = Db.BlockTableRecord(db.modelSpaceId(), Db.OpenMode.kForWrite)
    model.appendAcDbEntity(  Db.Line(Ge.Point3d(0, 0, 0), Ge.Point3d(100, 100, 0)))    

 

best practice is to separate out operations if you run into conflicts  

Posted

Checking Db.Object types and casting

 

Every database object has a static description Db.Line.desc()

https://help.autodesk.com/view/OARX/2025/ENU/?guid=OARX-RefGuide-AcRxObject__desc

 

Every database object has an instance method to verify the type

https://help.autodesk.com/view/OARX/2025/ENU/?guid=OARX-RefGuide-AcRxObject__isA

 

examples:

 

@Ap.Command()
def doit():
    try:
        # check types
        line = Db.Line()
        print(line.isA() == Db.Line.desc())
        print(line.isA().isDerivedFrom(Db.Line.desc()))
        print(line.isKindOf(Db.Line.desc()))
        
        #check types
        print(line.isA().isDerivedFrom(Db.Curve.desc()))
        print(line.isKindOf(Db.Curve.desc()))
        
        
        ps, id, pnt = Ed.Editor.entSel("\nSelect Entity: ")
        curve = Db.Curve(id)
        if curve.isKindOf(Db.Line.desc()):
            #PyRx does not check in the cast
            cline = Db.Line.cast(curve)
            print(line.isA() == Db.Line.desc())
            print(line.isA().isDerivedFrom(Db.Line.desc()))
            print(line.isKindOf(Db.Line.desc()))
            print(line.isA().isDerivedFrom(Db.Curve.desc()))
            print(line.isKindOf(Db.Curve.desc()))
        
        
    except Exception as err:
        traceback.print_exception(err)

 

Command: DOIT
True
True
True
True
True
Select Entity:

True
True
True
True
True

Posted

Note with casting, the cast internally increases the reference count to the same C++ pointer. If you close one, the other will be closed.

Like entangled particles, if Alice changes something, Bob will observe the change

 

        
        line = Db.Line()
        curve = Db.Curve.cast(line)
        print(line,curve)
        #<PyDb.Line object at 0x000001FB834B5940> <PyDb.Curve object at 0x000001FB83577240>

 

Posted (edited)

Best practice for checking types is to use the ObjectId as the AcRxClass is cached when the drawing is opened in CAD. it’s much faster than opening the object

 

        db = Db.curDb()
        for id in db.modelSpace():
            if id.isDerivedFrom(Db.Line.desc()): # check the id
                line = Db.Line(id)

 

Edited by Danielm103

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...