Nate Holt's Blog

July 27, 2009

Project-wide attribute value update’r – AutoCAD Electrical

Filed under: Electrical — nateholt @ 10:23 am

Pushing new attribute values out to block instances on non-opened drawings.

A user wanted to update a target block attribute to a new value, but wanted to do this project-wide. The attribute tag name was IEC_PROJ and it is carried on the invisible”WD_M” block found on every AutoCAD Electrical drawing. There are probably multiple ways to do this in AutoCAD Electrical, but it would be neat to segue off of a past blog posting that illustrates doing this without actually calling each drawing up on the screen.

What will be shown here is a bare-bones tool with crude, minimum command line user interface… but it seems to work when all drawings are accessible (tested on ACE2010). It is very FAST. It might also serve as the foundation for you to create your own custom tools… maybe a title block / revision block update tool. Change the revision level of your complete drawing set with a couple keystrokes. The potential is there!

How the tool works

With your target AutoCAD project “active” and all drawings accessible, APPLOAD the tool and then launch it by typing DBX_DWGPROPS [Enter] at the command line prompt. The tool then prompts you for

  1. the target block name (wild-cards okay)
  2. target attribute name you want to update (wild-cards okay)
  3. new value for the target attribute
  4. then a dialog pops up to select which drawings in the active project you want to process

It takes off and processes the selected drawings. It looks for the target block instances on each drawing and, if found, looks for target attribute. If found, it checks old value against new and, if different, pushes the new attribute value out to that block instance. Finishes in moments.

Example

Here’s an example of running the tool against one of the sample project sets that ships with AutoCAD Electrical. We want to force the IEC_PROJ attribute on the settings “WD_M” block to a new value of “ABC-123” for all drawings in the active project.

Load or APPLOAD the lisp utility (shown below)

 dbx_dwgprops01

Now type dbx_dwgprops [Enter] at the command line and respond to the prompts for target block name, target attribute name, and new attribute value…

dbx_dwgprops02

Then select what drawings of your active project to process…

dbx_dwgprops03

And off it goes… in 10 seconds or so, it was done with all 29 drawings in the project set!

dbx_dwgprops04

The Utility Source Code

Here’s the utility. Cut and paste this into an ASCII text file called dbx_dwgprops.lsp. APPLOAD it and run it as described above. Caution: just to be safe, make a backup of your project set BEFORE launching this utility!

; ** 27-Jul-09 Nate Holt, N8 Consultants LLC, http://n8consultants.com
; ************   D B X _ D W G P R O P S . L S P   *********************
(defun c:dbx_dwgprops ( / x change_cnt blknam target_attrnam newval d2_lst d_lst
                          ss_hdl_list dwg_hdl slen ix hitattr fullfilename
                          ben_hdl oldval atnam ed edd enn_hdl hdl newedd)
  ; Force attribute value of target block to update to new value for selected
  ; drawings in active AutoCAD Electrical project drawing set. Make backup
  ; of dwgs before use.                      
  ; Prompt user for block name and target attribute name and value
  (setq blknam "WD_M") ; default
  (setq change_cnt 0)
  (setq x (getstring (strcat "\nTarget block name (wild-cards OK) [" blknam "]:")))
  (if (AND x (/= x ""))(setq blknam x))
  (if (AND blknam (/= blknam ""))
    (progn ; Now prompt for target ATTRIBUTE tag
      (setq target_attrnam (getstring "\nAttribute tag name (wild-cards OK):"))
      (if (AND target_attrnam (/= target_attrnam ""))
        (progn ; Now prompt for new attribute value
          (setq newval (getstring "\nNew attribute value:" T))
          (if newval
            (progn ; Okay to continue. Prompt for what drawings in 
                   ; active project that need to be processed.
              ; Active project name should be held in global GBL_wd_prj     
              (if (setq x (wd_wdp_get_proj_file_lsts GBL_wd_prj)) 
                (progn
                  (setq d2_lst (nth 5 x)) 
                  (setq d_lst (car (wd_pdwgs_main_withhelp d2_lst
                      (c:wd_msg "GEN018" nil "Select drawings to process")
                      (c:wd_msg "GEN015" nil "Drawings to Process") 
                                   nil "prjwide_pick_dwgs")))
              ) )
              ; Now process each of the selected drawings
              (foreach fullfilename d_lst ; d_lst = list of dwg file names to process
                (setq dwg_hdl (wd_dbx_open fullfilename "w"))
                (if dwg_hdl
                  (progn ; target drawing file is "open". Okay to proceed.
                    ; Get selection set of just target block name instances
                    (setq ss_hdl_list (wd_dbx_ssget dwg_hdl "_X" (list (cons -4 "<AND")
                                                                       (cons 0 "INSERT")
                                                                       (cons 2 blknam)
                                                                       (cons -4 "AND>"))))
                    (if (= ss_hdl_list nil)
                      (progn
                        (princ "\ndwg ")
                        (princ (vl-filename-base fullfilename)) ; display dwg name (no path)
                        (princ ": No target block instance found.")
                      )  
                    ; ELSE  
                      (progn ; found one or more instances of target block on this drawing
                        (setq slen (length ss_hdl_list)) ; number of block entities in selection set
                        (setq ix 0) ; use to index through the selection set list
                        (while (< ix slen)
                          (setq ben_hdl (nth ix ss_hdl_list)) ; get next block insert instance
                                                              ; from the selection set
                          (setq ix (1+ ix)) ; increment index for next time
                          ; Now look for target attribute tag. Can do this in either
                          ; of two way... can use a call to look for the attribute on
                          ; this block insert like this:
                          ; (wd_dbx_entattr ben_hdl dwg_hdl (list target_attrnam))
                          ; or (c:ace_get_pnlval_dbx fullfilename ben_hdl target_attrnam nil)
                          ; ... or can do it the hard way and cycle
                          ; through all stand-alone subentities of this block insert
                          ; instance and look for the target attribute. Let's do it
                          ; the hard way.
        
                          ; Now cycle through its stand-alone subentities like attributes
                          ; (this is not the same as cycling through the entities of the 
                          ; block definition itself)
                          (setq hitattr nil)
                          (if (setq enn_hdl (wd_dbx_entnext ben_hdl dwg_hdl)) 
                            (setq edd (wd_dbx_entget enn_hdl dwg_hdl (list "*"))))
                          (while (AND enn_hdl 
                                      (/= (cdr (assoc 0 edd)) "SEQEND") ; end of this entity
                                      (/= (cdr (assoc 0 edd)) "INSERT") ) ; beginning of next!                                      
                            (if (AND (= (cdr (assoc 0 edd)) "ATTRIB")
                                     (wcmatch (cdr (assoc 2 edd)) target_attrnam))
                              (progn ; yes, found target attribute tag
                                (setq atnam (cdr (assoc 2 edd))) ; actual attrib name (target may
                                                                 ; have been wild-carded)
                                (setq oldval (cdr (assoc 1 edd)))
                                (setq hitattr 1) ; remember that we've found target attribute
                                (if (/= oldval newval)                 
                                  (progn ; Prepare to push new value back out to the attribute
                                    (if (setq newedd (subst (cons 1 newval)(assoc 1 edd) edd))
                                      (progn 
                                        (wd_dbx_entmod newedd dwg_hdl) ; push new attribute value out
                                        (setq change_cnt (1+ change_cnt)) ; track number of changes
                                        ; Display something to the command window
                                        ; Open the block insert instance to get actual block name
                                        (setq ed (wd_dbx_entget ben_hdl dwg_hdl (list "*"))) 
                                        ; Get block name
                                        (setq blknam (cdr (assoc 2 ed)))
                                        ; Get handle of this block instance
                                        (setq hdl (cdr (assoc 5 ed)))
                                        ; Display this stuff to the command window
                                        (princ "\ndwg ")
                                        (princ (vl-filename-base fullfilename))
                                        (princ ": hdl=")(princ hdl)
                                        (princ " blknam=")(princ blknam)
                                        (princ " attr=")(princ atnam) ; actual attribute name (not wild-carded)
                                        (princ " old=")(princ oldval)(princ ", new=")(princ newval)                                            
                                    ) ) 
                                ) )
                            ) )
                            ; Advance to next sub-entity of this block insert instance
                            (if (setq enn_hdl (wd_dbx_entnext enn_hdl dwg_hdl)) 
                            (setq edd (wd_dbx_entget enn_hdl dwg_hdl (list "*")))) 
                          )
                          ; Finished cycling through all subrecords of this one block insert instance
                          (if (not hitattr)
                            (progn ; found target block name instance but attribute not found
                              (princ "\ndwg ")(princ (vl-filename-base fullfilename))
                              ; Open the block insert instance to get actual block name
                              (setq ed (wd_dbx_entget ben_hdl dwg_hdl (list "*"))) 
                              ; Get block name
                              (setq blknam (cdr (assoc 2 ed)))
                              ; Get handle of this block instance
                              (setq hdl (cdr (assoc 5 ed)))
                              ; Display this stuff to the command window
                              (princ ": hdl=")(princ hdl)
                              (princ " blknam=")(princ blknam)
                              (princ " target attribute ")(princ target_attrnam)(princ " not found")
                            )
                          )  
                    ) ) )      
                    (if (> change_cnt 0)
                      (wd_dbx_close dwg_hdl T) ; close and save changes
                    ; ELSE
                      (wd_dbx_close dwg_hdl nil) ; close with no save
                    )                                
          ) ) ) ) )      
        )  
      )
  ) ) 
  (princ)
)
Advertisements

5 Comments »

  1. Hi Nate,

    I’m busy with that also but only I want to change the TAG1F for certain components into normal tags.

    I thought on something like this:
    (while (< ix slen)

    (setq ben_hdl (nth ix ss_hdl_list)) ; get next block insert instance
    ; from the selection set
    (setq ix (1+ ix)) ; increment index for next time
    ; Now look for target attribute tag. Can do this in either
    ; of two way… can use a call to look for the attribute on
    ; this block insert like this:
    ; (wd_dbx_entattr ben_hdl dwg_hdl (list "COLOR"))
    ; or (c:ace_get_pnlval_dbx fullfilename ben_hdl "COLOR" nil)
    ; … or can do it the hard way and cycle
    ; through all stand-alone subentities of this block insert
    ; instance and look for the target attribute. Let's do it
    ; the hard way.

    ; Now cycle through its stand-alone subentities like attributes
    ; (this is not the same as cycling through the entities of the
    ; block definition itself)
    (setq hitattr nil)
    (if (setq enn_hdl (wd_dbx_entnext ben_hdl dwg_hdl)) (setq edd (wd_dbx_entget enn_hdl dwg_hdl (list "*"))))
    (while (AND enn_hdl
    (not hitattr)
    (/= (cdr (assoc 0 edd)) "SEQEND") ; end of this entity
    (/= (cdr (assoc 0 edd)) "INSERT") ) ; beginning of next!
    (if (= (cdr (assoc 2 edd)) "TAG1F")
    (progn ; yes, found target attribute tag
    (setq oldval (cdr (assoc 1 edd)))
    (setq hitattr 1) ; remember that we've found target attribute
    ; so we can exit out of the "while" loop
    ; sooner rather than later.
    (setq change_cnt (1+ change_cnt)) ; track number of changes
    ; Display something to the command window
    (setq ed (wd_dbx_entget ben_hdl dwg_hdl (list "*"))) ; open the block insert instance
    ; Get block name
    (setq blknam (cdr (assoc 2 ed)))
    (if (/= blknam "VW01")
    (progn
    (c:ace_tag_fixed ben_hdl 0 0)
    )
    )
    ; Get handle
    (setq hdl (cdr (assoc 5 ed)))
    ; Display to command window
    (princ "\nHDL=")(princ hdl)
    (princ " BLKNAM=")(princ blknam)
    (princ ", ")(princ target_attrnam)
    (princ " old=")(princ oldval)(princ ", new=")(princ newval)

    ) )
    (if (setq enn_hdl (wd_dbx_entnext enn_hdl dwg_hdl)) ; advance to next sub-entity of this
    (setq edd (wd_dbx_entget enn_hdl dwg_hdl (list "*")))) ; block insert instance
    ) )

    Any idea?

    Comment by Gerald — July 27, 2009 @ 10:46 am

  2. […] posting supplied the basis to solve this missing piece of Gerald’s 3-part utility. It is a blog entry that describes a tool to search for attributes on non-opened drawings and update their values. But […]

    Pingback by Gerald’s reset-fixed-tag tool – AutoCAD Electrical « AutoCAD Electrical Etcetera — July 28, 2009 @ 9:24 pm

  3. Hi Gerald,

    I think you could change the sample program to something like this:

    (if (setq newedd (subst (cons 2 “TAG1”)(assoc 2 edd) edd))
    (progn
    (wd_dbx_entmod newedd dwg_hdl) ; push new attribute name out

    I do not know if this would work… but maybe give it a shot ( ! )

    Nate.

    Comment by nateholt — August 2, 2009 @ 11:34 pm

  4. Hi Nate,

    I found this to be very useful as I needed to update the “P_Item” value in all my blocks (approx. 90) in over 250 drawings. What a time saver!!! The problem I now have is how to update all the associated BOM balloons without manually going into each drawing and updating each one individually.

    I am using AutoCAD Electrical 2010.

    Any help you can give would be much appreciated.

    Miles

    Comment by Miles — September 20, 2010 @ 2:05 pm

  5. Nate:

    This will update the actual drawings, but what about the same values in the Drawing Settings tab of the Drawing Properties. Will the change be reflected there as well?

    Thanks,
    Scott

    Comment by Scott Gensemer — October 20, 2010 @ 12:16 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: