Tuesday, October 31, 2023

AutoCAD, Python and Pandas

 

Pandas “pandas is a fast, powerful, flexible and easy to use open source data analysis and manipulation tool, built on top of the Python programming language.”

 You can also use pandas in AutoCAD as a data extraction tool. I’m just learning pandas myself, thankfully there’s good documentation

In this example, I want to search for all block references that begin with ‘SPK’,  to create a takeoff of what sprinkler systems are in this drawing. Then, I’ll use pandas to combine rows and format the output. I’m just printing the output to the command line, but it’s simple enough to create a table or export the data to Excel

 here's the code


import PyRx as Rx
import PyGe as Ge
import PyGi as Gi
import PyDb as Db
import PyAp as Ap
import PyEd as Ed
import traceback

import pandas as pd

#get the attribues and return them as a list
def getAttValues(ref: Db.BlockReference)->list[str]:
    v = [ref.getBlockName()]
    for attrefid in ref.attributeIds():
        attref = Db.AttributeReference(attrefid)
        match attref.tag():
            case 'PART#':
                v.append(attref.textString())
            case 'DESCRIPTION':
                v.append(attref.textString())
            case _:
                pass
    return v

def PyRxCmd_doit():
    try:
        spkIds = []
        db = Db.curDb()

        #define our columns
        data = {'Name': [],
                'PART#': [],
                'DESCRIPTION': [],
                'QTY': []}

        #search for blocks that start with 'SPK'
        bt = Db.BlockTable(db.blockTableId())
        for name, id in bt.toDict().items():
            if name.startswith('SPK'):
                spkIds.append(id)

        for id in spkIds:
            btr = Db.BlockTableRecord(id)
            for refid in btr.getBlockReferenceIds():
                ref = Db.BlockReference(refid)
                values = getAttValues(ref)
               
                #pandas wants equal length lists
                if len(values) != 3:
                    continue
               
                data['Name'].append(values[0].rstrip('.dwg'))
                data['PART#'].append(values[1])
                data['DESCRIPTION'].append(values[2])
                data['QTY'].append(1) #we know we have one

        #create the dataframe, then group by
        df = pd.DataFrame(data)
        dfgr = df.groupby(['Name', 'PART#', 'DESCRIPTION'],
                         sort=False, as_index=False).agg({'QTY': 'sum'})
       
        print(dfgr.to_string())

    except Exception as err:
        traceback.print_exception(err)
 
 


Tuesday, October 17, 2023

Python + AutoCAD, Extract to Excel

 

Here’s a sample extracting attributes from multiple drawings. I use ObjectDBX to open each drawing and collect the attributes from a block named ‘elev’, a block that holds room numbers etc., Openpyxl makes it incredibly easy to write to and excel file. I think the question, “How do I write to excel” is one of the most frequently ask in the CAD forums. In python it’s a breeze  

import PyRx as Rx
import PyGe as Ge
import PyGi as Gi
import PyDb as Db
import PyAp as Ap
import PyEd as Ed
import traceback

import AxApp24 as Ax
import AxAppUtils24 as AxUt

import openpyxl as Ex  # using openpyxl

def PyRxCmd_dbxextract():
    try:
        paths = ["e:\\06457Submittal.dwg",
                 "e:\\06457Submittal2.dwg",
                 "e:\\06457Submittal3.dwg"]

        wb = Ex.Workbook()
        ws = wb.active
       
        nrow = 1
        axDoc = Ax.getDbx()
        for dwg in paths:
            axDoc.Open(dwg, None)
            for ent in axDoc.ModelSpace:
                if ent.EntityName != 'AcDbBlockReference':
                    continue
                #cast
                ref = Ax.IAcadBlockReference(ent)
                if ref.Name != 'elev':
                    continue
                nrow += 1
                for ncol, att in enumerate(ref.GetAttributes()):
                    ws.cell(row=nrow, column=ncol+1, value=att.TextString)

        wb.save('e://ItsAlive2.xlsx')
    except Exception as err:
        traceback.print_exception(err)

 


Monday, October 16, 2023

Python + AutoCAD, create Table and Hittest

 

In this example, I’ll be importing AxApp24, ActiveX wrappers that are a part of PyRx

Using ActiveX is the easy way to create Tables. Table’s in ARX and .NET have gone through some function changes over the years that can sometimes make it a hassle, at least from a scripting language point of view. Also in this example, I show one method of getting access to a Table’s cell without having to manually select the table first. 

 


import PyRx as Rx
import PyGe as Ge
import PyGi as Gi
import PyDb as Db
import PyAp as Ap
import PyEd as Ed
import traceback

import AxApp24 as Ax
import AxAppUtils24 as AxUt


def PyRxCmd_makeTable():
    try:
        axApp = Ax.getApp()
        axDoc = axApp.ActiveDocument

        # pick a point for the table location
        tablePnt = axDoc.Utility.GetPoint("\nTable location: ")

        # point, rows, columns, row Height, row width
        axTable = axDoc.ModelSpace.AddTable(tablePnt, 5, 5, 10, 30)
       
        #:)
        axTable.SetTextString(0, 0, 1, "My Py Table")

    except Exception as err:
        traceback.print_exception(err)


def PyRxCmd_hitTest():
    try:
        axApp = Ax.getApp()
        axDoc = axApp.ActiveDocument

        # view vec, just use a Z vector
        hitVec = (0, 0, 1)
        hitPnt = axDoc.Utility.GetPoint("\nSelect cell: ")

        # combine the hitPnt with vsmax to make a fence
        fence = hitPnt + axDoc.GetVariable("VSMAX")

        axSs = axDoc.SelectionSets.Add("AXTBLSS")
        axSs.SelectByPolygon(Ax.constants.acSelectionSetFence,
                             fence, [0], ["ACAD_TABLE"])

        #do the hit test
        for axEnt in axSs:
            axTable = Ax.IAcadTable(axEnt)
            hit = axTable.HitTest(hitPnt, hitVec)
            if hit[0]:
                cellstr = "Cell={},{}".format(hit[1], hit[2])
                axTable.SetTextString(hit[1], hit[2], 1, cellstr)
                return

    except Exception as err:
        traceback.print_exception(err)

    finally:
        axSs.Delete()



TraceBoundary sample in Python for AutoCAD

    import traceback from pyrx_imp import Rx from pyrx_imp import Ge from pyrx_imp import Gi from pyrx_imp import Db from pyrx_imp...