AutoCAD Electrical Etcetera

November 19, 2009

Overview of Simple BOM reporting – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 1:20 am

Brief overview of how two different databases are queried to create various AutoCAD Electrical BOM reports.

This question comes up from time to time, most recently today. Here is a brief summary in the form of screenshots illustrating how a component on an AutoCAD Electrical drawing (a mechanical footprint symbol on a panel layout drawing) finds its way on to a BOM report. This illustrates just a simple, straightforward catalog assignment – without “ASSYCODE” and without “Multi-BOM” catalog assignments (future posting!).

A small portion of one drawing, DEMO08.dwg, which is part of a sample AutoCAD Electrical project drawing set “WDDEMO”, is shown below.

AutoCAD Electrical maintains a “scratch” database file, in Microsoft Access format, that follows what is going on in the project drawing set (it does not drive it, it follows it). The above mechanical footprint component, SS433 on drawing DEMO08.dwg of the project, shows up in the “PNLCOMP” table of the scratch database file for this project.

 The scratch database file name is the same name as the active AutoCAD Electrical project name but with an “.mdb” extension. It is saved in the local AutoCAD Electrical “user” folder. The full name can be displayed by typing this at the AutoCAD “Command:” prompt.

 Command:  (c:wd_mdb_get_proj_scratch_dbnam nil) [Enter]

 Here is a screenshot of the above panel component in the PNLCOMP table of the project scratch database:

And here’s another screenshot of the above record with a few other fields exposed. These fields are used to guide AutoCAD Electrical’s BOM reporting command to the appropriate “table” in the catalog lookup database file DEFAULT_CAT.mdb (shown shortly).

The actual table name that the BOM report queries for this “SS433″ symbol’s catalog description information is influenced by the WDBLKNAM value shown above. See this posting for a description of how auto-table selection works.

Ultimately, the BOM reporting goes to table “SS” in the DEFAULT_CAT.mdb file. It uses the MFG/CAT attribute values carried on the panel footprint symbol (and extracted into the PNLCOMP table shown above) to find the appropriate record in the “SS” table shown here:

And now the BOM reporting command merges the data in the record above with the data from the scratch database file. It is formatted into the report and shows up as an entry here in the BOM Report Generator dialog ( ! ):

Now, at this point, you can write the report out to a file (in various formats) or insert the report as a “smart” table on to your AutoCAD drawing.

November 18, 2009

Feedback – Shaping the future of AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 8:58 am

The Autodesk development team responsible for AutoCAD Electrical wants your feedback. Here’s a note from Autodesk’s Jose Santos:

Are you interested in shaping the future of AutoCAD Electrical?

 The AutoCAD Electrical team is offering two great opportunities if you work with schematics for controls, switchgear, power, process, and instrumentation, and are attending Autodesk University 2009 in Las Vegas:

 Product Usability Evaluation

Various sessions. Nov 30 – Dec 3, 2009

Register here.

 Power, Controls, and Instrumentation Unplugged

November 30, 2009.  2-4pm

Register here.

 If you can’t attend but are interested in keeping in touch with the AutoCAD Electrical team for future events, register here.

November 12, 2009

Enhanced wire number tags based on connected components – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 8:45 pm

Wire number tags based upon connected component tag-ID at each end.

Some time ago we had this posting that dealt with a wire numbering tool utility. It would generate a wire number tag based upon combining the tag-ID and termination pin number of the component connection at each end of the wire. This generated explicit but really “long” wire numbers.

Here’s an example:

wirenox_01

Yes, really long wire numbers ( ! )

Request for a Simplified Version

A user in Australia wanted to do this but make the tags shorter. He just wanted to concatenate the two tag-IDs and then add an alpha suffix to keep each wire number unique. No connection pin numbers embedded in the wire number.

For example, in the above drawing, the upper right-hand wire number would be the two device tags jammed together, “SS406TD406″, and an alpha sufffix, let’s say “A”.

Now there are two more wires that tie the same two devices together: the right-hand wire leaving the two child contacts on the selector switch. Both will be “SS406TD406″. So the utility would need to add a “B” and a “C” to each respectively to keep the wire numbers unique.

Modifying the existing milnum_alldwg.lsp utility

So, let’s start with the previous post’s lsp utility, copy it to a new file name, “milnumx_alldwg.lsp”. Open it up in AutoCAD’s Visual Lisp editor (type vlide [enter] at the “Command:” prompt) or open in any ASCII text editor (like WordPad.exe) and let’s have some fun.

Step 1 – this is the easiest part. We want to bypass the original utility’s task of adding in the connection pin numbers. Here is the before and after code:

BEFORE:

                    (if (= flipit 1)
                      (progn ; reverse the order
                        (setq new_wireno comp2_tag)
                        (if (AND pin2 (/= pin2 ""))(setq new_wireno (strcat new_wireno "-" pin2)))
                        (setq new_wireno (strcat new_wireno "/" comp1_tag))
                        (if (AND pin1 (/= pin1 ""))(setq new_wireno (strcat new_wireno "-" pin1)))
                      )
                    ; ELSE
                      (progn ; normal order of wire number format                  
                        (setq new_wireno comp1_tag)
                        (if (AND pin1 (/= pin1 ""))(setq new_wireno (strcat new_wireno "-" pin1)))
                        (setq new_wireno (strcat new_wireno "/" comp2_tag))
                        (if (AND pin2 (/= pin2 ""))(setq new_wireno (strcat new_wireno "-" pin2)))
                    ) )   
                    (c:wd_putwnf en new_wireno) ; put the wire number on wire
AFTER:
                    (if (= flipit 1)
                      (progn ; reverse the order
                        (setq new_wireno (strcat comp2_tag comp1_tag)) ; just jam two tags together, no delimiter
                      )
                    ; ELSE
                      (progn ; normal order of wire number format                   
                        (setq new_wireno (strcat comp2_tag comp1_tag)) ; just jam two tags together, no delimiter
                    )  )  
                    (c:wd_putwnf en new_wireno) ; put the wire number on wire

Step 2 – the harder part. Okay, we have the base wire number figured out above and pushed into lisp variable “new_wireno”. But we need to check each wire number and make sure it is unique. We add an incrementing alpha suffix to the wire number until it is unique.

This means that we need to first extract a list of all existing wire numbers on the active drawing (could do for all dwgs in project but that will be an upcoming blog posting). Then, when we generate a new wire number, we compare against the existing wire number list and, if a repeat found, keep incrementing the suffix for our new wire number until we find one that isn’t already in the list.

So, here’s a little subroutine we’ll add to our milnumx_alldwg.lsp utility. It runs at the front end of our utility to establish a list of all existing wire number assignments.

Here’s how it works… it creates a “selection set” of all wire number block inserts found on the active drawing. AutoCAD Electrical wire numbers have block names that begin with either “WD_WNH” or WD_WNV”. So the “ssget” line below gets all instances of wire number block inserts on the active drawing.

Then we cycle through this list, one at a time, and get each wire number block insert instance, the “(setq en (ssname sswn ixwn))” line below. Then we get the wire number attribute value, WIRENO or WIRENOF. Add to the running list of wire numbers, loop back to the top of the loop, and process the next wire number block insert instance. When done, all of the drawing’s wire numbers are sitting in AutoLISP variable “lst”. This data is returned from this function.

ALL NEW:

  (defun milnumx_get_all_existing_wirenums ( / sswn ixwn slenwn lst )
    ; Extract a list of all wire numbers found on the active drawing. Create a selection
    ; set of all block insert instances that have block name "WD_WNH*" or "WD_WNV*". There
    ; are AutoCAD Electrical wire number block names.
    (setq lst nil)
    (setq sswn (ssget "_X" '((-4 . "<AND")(0 . "INSERT")(2 . "WD_WNH*,WD_WNV*")(-4 . "AND>"))))
    (if (/= sswn nil)
      (progn ; some wire number block instances found. Process them.
        (setq slenwn (sslength sswn)) ; number of block instances found
        (setq ixwn 0) ; this will be used to index through the blocks
        (while (< ixwn slenwn)
          (setq en (ssname sswn ixwn)) ; get next block instance entity name
          ; Get WIRENO* attribute value off of this wire number block insert
          (setq wn (c:wd_getattrval en "WIRENO*"))
          (if (AND wn (/= wn "") (not (member wn lst)))
            (progn ; add to the running list
              (setq lst (cons wn lst))
          ) )
          (setq ixwn (1+ ixwn))
    ) ) )
    (setq sswn nil) ; release the selection set
    lst ; return the list of existing wire numbers found on active drawing
  )

Step 3 – Putting it all together. Now we add a call to our wire number collection function to capture a list of all wire numbers and dump into AutoLISP variable name “existing_wnum_list”. We do this toward the beginning of the utility as shown here:

  ; -- main routine starts here --                  

  ; Two options here. Uncomment first two lines and uncomment third line to prompt
  ; user to "window" what wires to process. Or, comment out the first two lines and
  ; uncomment the third line to process all wires on active drawing without any
  ; user prompts.

;;;  (princ "\nSelect wire or wires to process for special source/dest wire number format")
;;;  (setq ss (ssget '((0 . "LINE")))) ; user windows what to process
  (setq ss (ssget "_X" '((0 . "LINE")))) ; automatically process all wires on active dwg

  (if (/= ss nil)
    (progn

      ; Get list of all existing wire numbers
      (setq existing_wnum_list (milnumx_get_all_existing_wirenums)) ; ** 12-Nov-09 NEHolt
         
      (setq slen (sslength ss)) ; number of LINE entities selected
      (setq lines_processed_entlist nil) ; used to track what has been processed
      (setq ix 0) ; used to index through the selection set
      (while (< ix slen)

… and we go back to what we did in Step 1. We add a “foreach” loop just below the point where we have generated the raw “component1-component2″ tag. We want to find the next suffix character that keeps this proposed wire number unique.

                    (if (= flipit 1)
                      (progn ; reverse the order
                        (setq new_wireno (strcat comp2_tag comp1_tag)) ; just jam two tags together, no delimiter
                      )
                    ; ELSE
                      (progn ; normal order of wire number format                  
                        (setq new_wireno (strcat comp1_tag comp2_tag)) ; just jam two tags together, no delimiter                       
                    ) )   
                    ; Now add an incrementing alpha suffix to the wire number until
                    ; a unique wire number is found (one that does not appear to have
                    ; already been used elsewhere on this drawing).
                    ; "existing_wnum_list" is the list of existing wire numbers
                    ; collected for the active drawing.

                    (setq alphalst (list "A" "B" "C" "D" "E" "F" "G" "H" "J" "K" "L" "M" "N"
                                         "P" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "A1" "A2"))
                    (setq hit nil)
                    (foreach suffix alphalst
                      (if (not hit)
                        (progn ; don't have a unique number yet. Try this one.
                          (setq x (strcat new_wireno suffix))
                          (if (not (member x existing_wnum_list))
                            (progn ; Yes, found next available suffix that yields a
                                   ; unique wire number!
                              ; Add this new wire number to the running list
                              (setq existing_wnum_list (cons x existing_wnum_list))
                              (setq hit T) ; to bypass the rest of this "foreach" loop
                              (setq new_wireno x)
                          ) )
                    ) ) )                                        
                    (if (not hit)
                      (progn ; didn't find a unique wire number suffix. Add "???"
                        (setq new_wireno (strcat new_wireno "???"))
                    ) )
                    (c:wd_putwnf en new_wireno) ; put the wire number on wire

There it is. Let’s test. Save the above file. APPLOAD it. Then type MILNUM_ALLDWG [Enter] at the Command: prompt.

wirenox_02

Download full file here

UPDATE: found typo in the uploaded file (13-Nov-2009). Fixed and reposted.

November 6, 2009

PLC I/O Drawing Generator – Pre-defining wire numbers – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 11:02 am

Adding a new option to the “Spreadsheet to PLC I/O” drawing generator tool – pre-defining wire numbers right in the spreadsheet.

This AutoCAD Electrical tool is pretty flexible. Using Excel, you lay out your control system’s I/O module requirements and out pops a set of 75-80% complete PLC I/O drawings.

For example, the first three lines of this example spreadsheet drives the AutoCAD Electrical Spreadsheet to PLC I/O utility to generate the circuitry shown below. But wouldn’t it be nice if we could pre-define the existing wire number assignments that tie into the two customer-supplied interlocks?

wdio_wnum_00

wdio_wnum_01

How to add this new feature

This is not too difficult. One thing that makes it possible is that this Spreadsheet to PLC I/O generator tool runs is an AutoLISP function that runs totally bare. It is supplied and runs in full-source mode, file name “wdio.lsp”. This means you are free to modify your copy of this tool.

The second thing that makes adding this new option easy-to-do is that the tool is already set up to support “piggy-backed” attribute assignments.  For example, in the row of your spreadsheet for I/O point “I:003/10″ you’ve entered the block name for a N.O. temperature switch, block name “HTS11″. In the D3DESC column you’ve entered a description for this switch, “SLURRY HEAT READY”. But you’d also like to define the “RATING1″ value for this switch. But your spreadsheet has no column for RATING1 for the 3rd connected component. No problem. Just piggy-back the RATING1 assignment to the D3DESC value:

D3DESC value before:  SLURRY HEAT READY

D3DESC value after: SLURRY HEAT READY;RATING1=95C

We’ll use this same idea to flag pre-defined wire number insertion on each side of a component. Instead of a name of an attribute, we’ll use these names:  $WNL and $WNR for “wire number left side” and “wire number right side”.

So, let’s say that we want to pre-define wire number assignments “TS-100″ and “TS-101″ for this temperature switch in our spreadsheet. We’d enter this:

D3DESC value: SLURRY HEAT READY;RATING1=95C;$WNL=TS-100;$WNR=TS-101

So, that’s how we’ll set up our Excel spreadsheet to define wire number assignments. Now, the key piece is to modify the “wdio.lsp” file to be ready to recognize that a piggy-backed attribute name that is $WNL or $WNR is really a flag for a wire number insert.

Step 1 – find the wdio.lsp utility. A good way to do this is to type this at your AutoCAD Electrical ”Command:” prompt

(c:ace_find_file “wdio.lsp” 3) [Enter]

If it can be found, the full path will display. Ignore the doubled-up back-slashes. It’s a Lisp thing.

Step 2 – MAKE BACK-UP COPY OF wdio.lsp. Important! Safety first.

Step 3 – Open wdio.lsp with any ASCII text editor or use AutoCAD’s Visual Lisp editor (type vlide [enter] at Command: prompt)

Step 4 – find this function within wdio.lsp file

wdio_wnum_03

Step 5 – Carefully cut and paste the code below to replace everything shown in the screenshot above.

  ; --
  (defun wdio_write_out_accum_extra_attr_data ( en lst2 / atnam atval x xx hit_wen lstx)
    ; "lst2" = (list (list attrnam attrval) (list attrnam attrval) ...)
    (foreach x lst2
; ** 06-Nov-09 NEHolt.begin, N8 Consultants LLC     
      (cond
        ((wcmatch (strcase (car x)) "$WNL,$WNT,$WNR,$WNB") ; Look for special wire number flag
          ; masquerading as an attribute tag name. When found, the "attribute value" associated
          ; with it will be the desired fixed wire number value.
          ; The name of the flag indicates which "side" of the inserted component "en" that
          ; the wire number goes with.
          ; Get component's wire connection data
          (setq lstx (c:wd_get_sym_pntlst en 1 nil))
          (setq hit_wen nil)
          (foreach xx lstx
            ; Going through each wire connection returned from the component that was
            ; just inserted (entity name "en"). Each sublist has the X?TERMxx wire connection
            ; direction (the "?" part) held in (nth 4...) element. If any wires tied to
            ; this connection, they are held in a list of entity names in (nth 3...) element.
            (cond
              ((/= hit_wen nil)) ; already processed this wire number, skip
              ((= (nth 3 xx) nil)) ; no wire connected to this component connection, keep looking
              ((AND (= (strcase (car x)) "$WNL")
                    (= (nth 4 xx) 4)) ; connection direction is from the left
                ; Found wire connection on left side (wire connection direction "4")
                ; Push fixed wire number out to this wire connection's attached wire                
                (setq hit_wen (car (nth 3 xx))) ; save wire entity name & exit loop
              ) 
              ((AND (= (strcase (car x)) "$WNR")
                    (= (nth 4 xx) 1)) ; connection direction is from the right
                ; Found wire connection on right side (wire connection direction "1")
                ; Push fixed wire number out to this wire connection's attached wire                 
                (setq hit_wen (car (nth 3 xx))) ; save wire entity name & exit loop
              ) 
              ((AND (= (strcase (car x)) "$WNT")
                    (= (nth 4 xx) 2)) ; connection direction is from above
                ; Found wire connection on top side (wire connection direction "2")
                ; Push fixed wire number out to this wire connection's attached wire                 
                (setq hit_wen (car (nth 3 xx))) ; save wire entity name & exit loop
              ) 
              ((AND (= (strcase (car x)) "$WNB")
                    (= (nth 4 xx) 8)) ; connection direction is from below
                ; Found wire connection on bottom (wire connection direction "8")
                ; Push fixed wire number out to this wire connection's attached wire                 
                (setq hit_wen (car (nth 3 xx))) ; save wire entity name & exit loop               
          ) ) )    
          (if hit_wen
            (progn ; push the defined wire number out to wire entity "hit_wen".
                   ; Insert it as a "fixed" wire number value.
              (c:wd_putwnf hit_wen (cadr x))             
        ) ) )    
        (T
; ** 06-Nov-09 NEHolt.end

          (if (AND (not (c:wd_modattrval en (car x) (cadr x) 1)) (/= (car x) ""))
            (progn ; target attribute name not found
              ; If it is the format of CATxx, MFGxx, CNTxx, ASSYCODExx, or WDBLKNAMxx then write out as XData
              (if (wcmatch (car x) "CAT??,MFG??,CNT??,ASSYCODE??,UM??,WDBLKNAM??")
                (progn ; write as XData
                  (c:wd_upd_pnlval en (car x) (cadr x))             
        ) ) ) ) )
      )
  ) )

Step 6 – save your modified version of wdio.lsp.

Now, let’s test.

Here we’ve opened up the demo PLC spreadsheet demoplc.xls and added some references. We changed the terminal block names from HT0001 to HT1001 so that wire numbers change through them. We’ve added a couple customer symbol references. Finally, we added in our wire number flags to insert wire numbers “W1″, “W2″ on the customer limit switch and “W5″ and “W9″ for the N.C. relay contact.

wdio_wnum_04

Save spreadsheet. Exit out of Excel. Cross fingers and fire up the AutoCAD Electrical Spreadsheet –> PLC I/O utility. Reference the modified spreadhseet, and watch what happens…

wdio_wnum_02

A few things to keep in mind with this modification:

1. Remember that terminals come in two flavors… those that maintain a wire number assignment through the terminal on those that trigger a wire number change through them. You might need to use the latter.

2. If you put the “$WNL=<wire number>” or “$WNR=<wire number>” flag in an empty cell in your spreadsheet, precede it with a semi-colon (ex: empty cell contents becomes ”;$WNL=12345″). This triggers the utility to treat this as a piggy-backed attribute.

3. For wires attaching from above or below, use flags $WNT and $WNB.

4. If these flag names don’t make sense or the “$” character is not one that shows up on your keyboard, adjust to suit your needs by editing the appropriate places in the pasted in Lisp code of step #5 above.

Advertisement – if your company is in need of AutoCAD Electrical customization, please visit http://n8consultants.com

October 26, 2009

Vertical SCOOT work-around – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 9:23 am

Overriding a propensity for AutoCAD Electrical’s cool “Scoot” command to default to “horizontal” mode

This was another “head-scratcher”. The task seemed so simple. Just create a horizontal and vertical version of an electrical symbol to represent a multi-ratio current transformer. Should be easy, piece of cake…

… but, when finished and testing the results, the horizontal version worked great and SCOOTed great, but the vertical version behaved unexpectedly.

Here’s are a couple instances of the new horizontal symbol inserted into a bus wire. The Scoot command works as expected.

CT_scoot_01

Right click on the symbol, select SCOOT command, and slide it over to the right…

ct_scoot_02

… and click. Everything stretches/trims/reconnects nicely.

CT_scoot_03

But not the Vertical version ( ! )

The vertical version wants to scoot horizontally on the horizontal connected wire. What’s going on??

CT_scoot_04

The problem: the SCOOT command appears to have a built-in bias to default to horizontal scooting. If there are the same number of horizontal wire connection points as there are vertical wire connection points on a symbol, and at least one wire connects to each type, the SCOOT command defaults to horizontal scoot mode.

Here’s the exploded vertical version of the custom CT symbol:

CT_scoot_05

There are two vertical wire connection attributes, X2TERM04 and X8TERM03 (where the 2nd character of 2 or 8 flags vertical). There are two horizontal wire connection attributes, X4TERM02 and X4TERM01 (where the 2nd character of 1 or 4 flags horizontal connection). So, equal number of horizontal and vertical… and the SCOOT command defaults to horizontal scooting.

The Work-around

On a tie vote, horizontal wins. So we need to stuff the ballot box with an extra “vote” for vertical. Here’s the work-around. Add a dummy vertical wire connection attribute to the symbol so that the vote will end up being 3 vertical versus 2 horizontal… and scoot will go with the vertical majority.

Add the unused dummy vertical wire connection attribute at a point on the symbol where it will likely not be accidentally used. Here’s the example for the above symbol:

CT_scoot_06

Not necessary, but used an odd suffix value of “99″ to make it “stand out” from the others.

Testing

Now, it scoots vertically, very nicely!

October 15, 2009

‘ZOOM to HANDLE’ utility – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 6:26 pm

Quickly create a tool to find and zoom to a given entity using its handle number.

You know an entity/object’s “handle” number, but where in the world is it in your jumbled drawing?

Complex library creation and testing has been on my plate for a couple weeks. The new code spits out the AutoCAD handle of various entities as processing proceeds. Sometimes there’s a need to go back in and find a problem entity on the drawing. Have the handle reference but that’s it. What is it, where is it?

Manual Method – Crude with  no-frills

Here’s the crude, no-frills way. Open the entity and display its guts in the command window.

Let’s say that you’ve run your program in a “debugging” mode and find that there is some issue with object handle “74F” in the active drawing. What and where is this entity?

Type this AutoLISP expression at the “Command:” prompt

Command: (entget (handent “74F”)) [Enter]

It returns this block of data about this entity.

((-1 . <Entity name: 7ef152f8>) (0 . “LINE”) (330 . <Entity name: 7ef11c10>) (5 . “74F”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”) (8 . “0″) (100 .
“AcDbLine”) (10 6.09375 13.5 0.0) (11 6.12676 13.5 0.0) (210 0.0 0.0 1.0))

The “0″ entry flags the entity type: “LINE” and the “10″ and “11″ parts give the XYZ start and end points of the LINE segment.

Crude, but it does work.

Better Method: auto-ZOOM to the entity

Here’s a little AutoLISP utility thrown together to help in troubleshooting. It zooms in on the target object given the typed-in handle.

The syntax is pretty simple. After the utility is APPLOADed, type ZH at the AutoCAD command prompt and then enter the handle number at the next prompt…

Command: zh [Enter]
Handle  =74F [Enter]

The utility opens up the entity. If it is a simple graphical entity like an arc, text, block insert, line, then it opens it to find “where” it is.

Entity type: LINE XY=(6.11026 13.5 0.0)

… and then it issues a ZOOM “Centered” command to display the object in the middle of the screen. It then tries to highlight it. Now you can zoom in or out with “I” or “O” keystrokes or use your mouse “wheel” to take a better look in context.

Here’s the handle “74F” example… it was an incomplete wire connection on the high side of a control transformer.

zh001

Here’s the utility itself. Cut and paste into an ASCII text file, let’s call it “zh.lsp”.

; ** 13-Oct-09 NEHolt - http://n8consultants.com
(defun c:zh ( / hdl xy enttype ed en xy2)
  ; ZOOM to entity "handle". Does not check model vs layout space.
  (while (/= (setq hdl (getstring (strcat
              "\nHandle " (if en "(or I=Zoom IN, O=Zoom out)" "") " ="))) "")
    (cond
      ((= (strcase hdl) "I")(command "_.ZOOM" "1.5x"))
      ((= (strcase hdl) "O")(command "_.ZOOM" "0.75x"))
      (T
        (if (setq en (handent hdl)) ; convert handle string to its "entity name"
          (progn ; appears to be a valid handle number
            (if (setq ed (entget en)) ; open up the entity
              (progn ; success, okay to continue
                (setq xy nil)
                (setq enttype (cdr (assoc 0 ed))) ; extract the entity type
                (princ "\princ ">nEntity type: ")(princ enttype)
                (if (= enttype "INSERT")
                  (progn ; this is a block INSERT instance
                    (princ " blk nam=")
                    (princ (cdr (assoc 2 ed))) ; display block name
                ) )
                ; Figure where entity is located
                (if (cdr (assoc 10 ed))
                  (progn
                    (setq xy (cdr (assoc 10 ed))) ; 10 subrec often gives a location value
                    (if (= enttype "LINE")
                      (progn ; LINE entity. Reset to zoom to line's midpoint
                        (setq xy2 (cdr (assoc 11 ed))) ; XY of other end
                        ; Calc midpoint coordinate
                        (setq xy (list (+ (car xy) (* 0.5 (- (car xy2) (car xy))))
                                       (+ (cadr cadr ">xy) (* 0.5 (- (cadr xy2) (cadr xy))))
                                       (+ (caddr caddr ">xy) (* 0.5 (- (caddr xy2) (caddr xy))))))
                ) ) ) )
                (if xy
                  (progn ; Non-blank XY extracted from picked entity. Go ahead and
                           ; display the value and ZOOM in to that point on the drawing.
                    (princ " princ ">XY=")(princ xy)
                    (command "_.ZOOM" "_C" xy 1.0) ; use ZOOM CENTER command
                    (redraw en 3) ; trigger entity to "highlight"
                ) )
        ) ) ) )
      )
    )
  )
  (command "_.REGEN") ; brute force - unhighlight everything
  (princ) ; quiet return
)

That should be it. APPLOAD this file and that should expose the utility to use on your active drawing.

September 28, 2009

Nate’s Simple AutoLISP – Lesson 007

Filed under: AutoCAD Electrical — nateholt @ 10:12 pm

Using the selection set function “ssget” to track down and remove instances of an invisible block.

This exercise will be short and [hopefully] sweet. The idea for this one came from personal experience… today.

Let’s say that you create a block instance consisting of just one attribute definition. You define its tag name to be “BY_CUSTOMER” and you leave the value blank, planning to fill in with different values later.

autolisp007a
You go ahead and block this single attribute definition with a block name of “CUSTOMER_FLAG”…

autolisp007b

 

… and you sprinkle a bunch of instances of this block across your drawing. You keep working away. A couple hours later you’re ready to go back and assign values to the BY_CUSTOMER attribute on each inserted instance of your CUSTOMER_FLAG block.

Hey… where are they? Don’t see them. You know you inserted them at multiple places in your drawing. But there’s nothing to pick on!

The block was just a single attribute and, unfortunately, you created it with a blank default value ( ! ).

Okay, let’s erase them and have a “do over”. But hey, how can I erase something I can’t select… something I can’t even see?!

Well, could try the QTEXT trick. Turn QTEXT “ON” and type REGEN. All blank attribute values now should display a tiny dot. But how can I tell which dot is which without picking one at a time and listing what it is?

Quick solution using the AutoLISP function “SSGET” with a filter

The solution uses AutoLISP and is easy… we can do it all right at the “Command:” prompt.

What we’ll do is make a “selection set” of all instances of this invisible / un-selectable block. We’ll do this by scanning ALL entities in our active drawing and filter out everything except blocks that carry the block name “CUSTOMER_FLAG”. A block instance carries the assigned block name in the “2″ entity sub-record. We’ll make a really simple filter by just looking for entities that have “CUSTOMER_FLAG” as the value of their “2″ subrecord.

Type this at the “Command:” prompt:

(setq ss (ssget “_X”  ’((2 . “CUSTOMER_FLAG”))))  [Enter]

If any matches found, the message “<Selection set xx>” will display below the “Command:” prompt. What we’ve done here is defined a dummy variable we’re calling “ss” and it will carry the selection set returned by the call to “(ssget …)”.

Let’s see how many it found. Type this:

(sslength ss) [Enter]

… and it will display the number of instances of CUSTOMER_FLAG that were found in the drawing.

Okay, now let’s blow them away so we can PURGE our drawing. Type this:

(command “_ERASE” ss “”) [Enter]

… and they’re gone! The above just launches the normal AutoCAD ERASE command. We pass the selection set variable we created above, “ss” to this command along with an extra “” at the end to kick out of the “select objects” loop. Finally, launch the PURGE command. You should now see that block CUSTOMER_FLAG is a candidate for purging. Yes! Blow it away.

 

Caution

The above solution will probably work as expected 99.9% of the time. But there are some entities that “share” the “2″ sub-record. For example, an ATTDEF entity uses the “2″ subrecord to carry the attribute tag name. So if we had some orphaned ATTDEFs floating around in our drawing and they happened to have a tag name of “CUSTOMER_FLAG”, then these CUSTOMER_FLAG ATTDEFs would be erased along with the CUSTOMER_FLAG block instances.

To be really, really safe, we could redo our selection set filtering like this to make sure that we’re only dealing with block instances AND the block instance is named “CUSTOMER_FLAG”. The entity type is carried in sub-record type zero. Block insert entity type is “INSERT”. So, a fool-proof, command-prompt-entered query to build the selection set might look like this:

(setq ss (ssget “_X”  ‘((-4 . “<AND”)(0 . “INSERT”)(2 . “CUSTOMER_FLAG”)(-4 . “AND>”))))  [Enter]

September 26, 2009

Nate’s Simple AutoLISP – Lesson 006

Filed under: AutoCAD Electrical — nateholt @ 3:17 pm

Experimenting with attribute definition order, entity sorting, and entmake

This lesson’s issue: Scrambled attribute order on a block insert.

(Note: previous postings: Lesson 001, Lesson 002, Lesson 003Lesson 004, and Lesson 005)

Here is an AutoCAD Electrical transformer symbol popped into a circuit. If I decide to use the generic attribute editor command built into AutoCAD to examine and possibly adjust values for this instance of the transformer block insert, the attribute order listed is pretty scrambled.

autolisp006a

It appears that the order that attributes are listed here are in the same order that the ATTDEF entities were inserted into the block’s source “.dwg” file. (Note: you can use AutoCAD’s BATTMAN command and painfully re-order the attribute listing for the block reference in the active drawing… but that is a one-time fix and not a permanent library “.dwg”-based solution. Read on.)

Call up the block’s original “.dwg” file, VXF1D.dwg. Type this at the command prompt:

Command: (entget (car (entsel))) [Enter]  

Select object:[Pick on the TAG1 attribute definition]

((-1 . <Entity name: 7ffffbbedf0>) (0 . "ATTDEF") (330 . <Entity name: 7ffffbbe820>) (5 . "5F")(100 . "AcDbEntity") (67 . 0) (410 . "Model")
(8 . "0") (100 . "AcDbText") (10 0.166667 0.749995 0.0) (40 . 0.125) (1 . "XF") (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . "WD") (71 . 0) (72 . 1)
(11 0.375 0.749995 0.0) (210 0.0 0.0 1.0) (100 . "AcDbAttributeDefinition") (280 . 0) (3 . "") (2 . "TAG1") (70 . 0) (73 . 0) (74 . 0) (280 . 0))

and then pick on the TAG1 attribute definition. This expression will read the attribute definition entity (the one you select) and return the entity’s data (above). This is pretty cryptic but the part shown in red is the picked entity’s “handle” number, “5F”.

If we repeat for the RATING1 and the DESC1 attributes, the handle numbers are “5E” and “60″ respectively.

autolisp006b

These entity handle numbers (in hexidecimal format) indicate the order that these attribute definitions were created and added to the library symbol drawing. It looks like the RATING1 attribute definition (5E) was created just before the TAG1 (5F) attribute definition. Next, the DESC1 (60) was defined and added to the symbol.

ATTDEF creation order and attribute display order

Does the creation order drive the attribute’s display order when the source library symbol is inserted as a block insert into another drawing?

Let’s take another look at the attribute editor dialog display when the symbol above is inserted as a block reference into a drawing.

autolisp006c

Note that these three attributes are listed together with RATING1 (original handle ”5E”) leading, TAG1 next (original handle “5F”) and DESC1 (original handle “60″) bring up the rear. It looks like that the creation order DOES influence the display order.

Let’s say that we really want the TAG1 attribute to be first in the list. Then we want the three DESC1, DESC2, and DESC3 attributes listed, then all of the “RATING*” attributes, catalog assignment attributes, and then all the rest in alphabetical order. So, if creation order is a controlling factor, we have a couple options…

OPTION 1: We could carefully re-construct our VXF1D.dwg base library symbol (and the many hundreds of others) so that the attribute defintions are each created in this order.

OPTION 2: Write a little AutoLISP utility that takes an existing scrambled library symbol dwg file, deletes all the attribute definitions, and then pushes them back into the symbol’s dwg file in the desired order.

Let’s go with the second option.

Using (entmake…)

Let’s try a little experiment. Let’s save an ATTDEF’s block of data into an AutoLISP variable. Then delete the ATTDEF using AutoCAD ERASE command. Then see if we can re-create a new, carbon-copy of the original ATTDEF with a call to “entmake”.

1. With our VXF1D.dwg drawing open on the screen, type this at the command prompt:

Command: (setq tag1_data (entget(car (entsel)))) [Enter, pick on TAG1 attdef]

Select object: ((-1 . <Entity name: 7ffffbbedf0>) (0 . “ATTDEF”) (330 . <Entity
name: 7ffffbbe820>) (5 . “5F”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”) (8
. “0″) (100 . “AcDbText”) (10 0.166667 0.749995 0.0) (40 . 0.125) (1 . “XF”)
(50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . “WD”) (71 . 0) (72 . 1) (11 0.375
0.749995 0.0) (210 0.0 0.0 1.0) (100 . “AcDbAttributeDefinition”) (280 . 0) (3
. “”) (2 . “TAG1″) (70 . 0) (73 . 0) (74 . 0) (280 . 0))

Command: (setq desc1_data (entget (car (entsel)))) [Enter, pick on DESC1 attdef]

Select object: ((-1 . <Entity name: 7ffffbbee00>) (0 . “ATTDEF”) (330 . <Entity
name: 7ffffbbe820>) (5 . “60″) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”) (8
. “0″) (100 . “AcDbText”) (10 0.234887 -0.89792 0.0) (40 . 0.125) (1 . “”) (50
. 0.0) (41 . 0.7) (51 . 0.0) (7 . “WD”) (71 . 0) (72 . 1) (11 0.424471 -0.89792
0.0) (210 0.0 0.0 1.0) (100 . “AcDbAttributeDefinition”) (280 . 0) (3 . “”) (2
. “DESC1″) (70 . 0) (73 . 0) (74 . 0) (280 . 0))

Command: (setq rating1_data (entget (car (entsel)))) [Enter, pick on RATING1 attdef]

Select object: ((-1 . <Entity name: 7ffffbbede0>) (0 . “ATTDEF”) (330 . <Entity
name: 7ffffbbe820>) (5 . “5E”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”) (8
. “0″) (100 . “AcDbText”) (10 0.136875 0.59375 0.0) (40 . 0.125) (1 . “”) (50 .
0.0) (41 . 0.7) (51 . 0.0) (7 . “WD”) (71 . 0) (72 . 1) (11 0.399375 0.59375
0.0) (210 0.0 0.0 1.0) (100 . “AcDbAttributeDefinition”) (280 . 0) (3 . “”) (2
. “RATING1″) (70 . 0) (73 . 0) (74 . 0) (280 . 0))

2. Now erase these three ATTDEFS ( ! )

3. Now, let’s recreate them, but in a specific order. Type these three commands at the command line:

(entmake tag1_data) [Enter]

(entmake desc1_data) [Enter]

(entmake rating1_data) [Enter]

4. The deleted ATTDEFs are re-created, but they are now in a different order. Confirm that the handles of the three new ATTDEFs now increment in the new order of TAG1, DESC1, and then RATING1.

 

A Re-order ATTDEF AutoLISP utility

With our little utility, we need to more or less duplicate what we just did above:  1. Capture all the ATTDEFs, 2. Erase them, 3. Re-create them with (entmake…) in the desired order.

Here’s what our little AutoLISP utility’s program flow might look like in order to do this:

1. We first define the order for specific attribute definition tagnames. We decide that we’ll support wild-cards in the tag names. This makes it easy to define all of the various AutoCAD Electrical component “tag-ID” attribute tagnames in the first entry of the priority list.

  ; Set up order list of ATTDEFS. Wild-cards are supported.     
  (setq orderlst (list "TAG1*,TAG2,TAGSTRIP,P_TAG1,P_TAGSTRIP"
                       "DESC1"
                       "DESC2"
                       "DESC3"
                       "RATING*"
                       "MFG"
                       "CAT"
                       "ASSYCODE"
                       "INST"
                       "LOC"
                       "FAMILY"
                       "TERM*"))

2. Now, with the source block “.dwg” open in AutoCAD, our utility constructs a selection set of all ATTDEF entities found in the drawing. The call is to “ssget” and we pass the “_X” parameter which processes ALL entities in the active drawing. Our expression has a ‘((0 . “ATTDEF”)) filter included so that only ATTDEFs will end up in our selection set.

  ; Gather up selection set of all ATTDEFs on the active drawing
  (setq ss (ssget "_X" '((0 . "ATTDEF"))))

3. Our utility then opens each of these ATTDEF entities in a “while” loop, indexing through the ATTDEFs in the selction set “ss”, one at a time. It pushes each ATTDEF block of data into an overall big list of data that we’re calling “attdef_lst”.

   (if (AND (/= ss nil)(> (sslength ss) 1))
    (progn ; at least one ATTDEF found. Okay to continue.
      ; Extract all ATTDEF tag names and overall ATTDEF entity data. Save in parallel lists.     
      (setq attdef_lst nil) ; start with blank data list
      (setq slen (sslength ss)) ; number of ATTDEFs in selection set
      (setq ix 0) ; used to index through the selection list
      (while (< ix slen)        
        (setq en (ssname ss ix)) ; get next ATTDEF entity name from selection set
        (setq ed (entget en)) ; open up this ATTDEF entity
        (setq attdef_lst (cons ed attdef_lst)) ; add its data to the big list
        (princ " ")(princ (cdr (assoc 2 ed))) ; display existing order in command window
        (setq ix (1+ ix)) ; increment index to get next ATTDEF entity from selection set
      )

4. Next we sort this long list of chunks of ATTDEF data alphabetically - by the tagname part of each chunk of ATTDEF data. Setting up this sort function is a bit cryptic. See the normal AutoCAD help for a few more examples. For our time here, just go with it as shown. Basically it doing a sort on the “2″ part of each ATTDEF block of data. This is the part that carries the ATTDEF “tag name”. To get at it in each list, our function uses the “(assoc 2…)” to dig it out and then a “(cdr …” to strip off the leading “2″ identifier. This leaves just the tag name to be used in the sort compare.

      ; Initially sort the list alphabetically by tagname. The tagname is in the "2"
      ; part of the entity's data. Access the value by extracting with the
      ; (assoc 2 ...) function.
      (setq attdef_lst (vl-sort attdef_lst
            '(lambda (X Y) (< (cdr (assoc 2 X)) (cdr (assoc 2 Y))))))

5. Now we’re ready to create a new version of this data list with certain ATTDEF tagnamed chunks pushed to the front part of the list. The utility cycles through the tagname priority list that we’ve set up in “orderlst” (step #1 above). For each tagname or wild-carded tagname, the utility cycles through the alphabetized list, looking for a match on the (cdr (assoc 2 …)) tagname extracted from each ATTDEF block of data. On a match, that block of data is pushed into the new list.

      ; Okay. So far, so good. We now have all ATTDEFs alphabetically sorted and held
      ; in a big data list called "attdef_lst".
           
      ; Now prepare to create a brand new ATTDEF list by pulling entries from the
      ; "attdef_lst" and pushing them into this new list in the desired order.
      (setq new_attdef_lst nil) ; Start with empty new list
      (setq processed_ix_lst nil) ; To be used for tracking what items have been
                                  ; pulled from alphabetized list into the new list.
     
      ; Process the ATTDEF tagnames against the desired order given in the "orderlst"
      (foreach sortorder_name orderlst
        (setq ix 0)
        (foreach rec attdef_lst
          (setq attdef_tag (cdr (assoc 2 rec))) ; extract ATTDEF tagname for this entry
          (if (AND (not (member ix processed_ix_lst)) ; check if already processed
                   (wcmatch attdef_tag sortorder_name)) ; check if tagname wild-card
                                      ; matches with the target sortordername string.
            (progn ; This ATTDEF name matches what we're looking for. Pull its data out
                   ; of the attdef_lst and push the entity's block of data into the
                   ; new "new_attdef_lst" ordered list.
              (setq new_attdef_lst (cons rec new_attdef_lst))
              ; Remember this entry's index number so won't try to add it in again
              (setq processed_ix_lst (cons ix processed_ix_lst))
          ) )
          (setq ix (1+ ix))
        )
      )   

6. When no more of the priority list to process, we need to push any un-referenced attribute definition chunks of data on to the new list (they are still alphabetized).

      ; The new_attdef_lst should contain the ordered attributes that were specifically
      ; defined. Now add in any left-overs. These will go in alphabetically.
      (setq ix 0)
      (foreach rec attdef_lst
        (if (not (member ix processed_ix_lst))
          ; This entry not processed above. Go ahead and push it into the new list.
          (setq new_attdef_lst (cons rec new_attdef_lst))
        )
        (setq ix (1+ ix))
      )

7.  That’s it. Our new ATTDEF blocks of data list is complete. But it’s in reverse order because we used the more efficient “cons…” function to build the new version of the list (instead of using the slower “append…” function). Reverse the list.

      ; Now put the new_attdef_lst into the correct order (it is reversed due to
      ; using "(cons ...) to add elements to the beginning of the list instead of
      ; the end of the list)
      (setq new_attdef_lst (reverse new_attdef_lst))

8. Now we cross our fingers. The utility erases ALL of the existing ATTDEF entities in the drawing…

      ; Erase all existing ATTDEFS (!)
      (command "_.ERASE" ss "")

9. … and we then cycle through our new, re-ordered list of ATTDEF data and re-create each ATTDEF using calls to (entmake …) .

      ; Now rewrite the ATTDEFs but using the new ordered list of ATTDEF blocks of
      ; data. Each ATTDEF should pop back in exactly as before, but the handle assignment
      ; given to each re-written ATTDEF will now be the next sequential for the
      ; drawing (!)
      (foreach rec new_attdef_lst
        (princ "\n")(princ (cdr (assoc 2 rec))) ; display attdef name to command window
        (entmake rec)
      )

 

Full Utility

Here’s the full utility. Cut and paste it into a file called reorder_attdef.lsp.

; ----------  R E O R D E R _ A T T D E F . L S P  ---------------------
(defun c:reorder_attdef ( / attdef_lst ix slen ss en ed attdef_tag new_attdef_lst
                            processed_ix_lst rec orderlst sortorder_name x y)
                           
  ; Set up order list of ATTDEFS. Wild-cards are supported.     
  (setq orderlst (list "TAG1*,TAG2,TAGSTRIP,P_TAG1,P_TAGSTRIP"
                       "DESC1"
                       "DESC2"
                       "DESC3"
                       "RATING*"
                       "MFG"
                       "CAT"
                       "ASSYCODE"
                       "INST"
                       "LOC"
                       "FAMILY"
                       "TERM*"))
  ; Gather up selection set of all ATTDEFs on the active drawing
  (setq ss (ssget "_X" '((0 . "ATTDEF"))))
 
  (if (AND (/= ss nil)(> (sslength ss) 1))
    (progn ; at least one ATTDEF found. Okay to continue.
      ; Extract all ATTDEF tag names and overall ATTDEF entity data. Save in parallel lists.     
      (setq attdef_lst nil) ; start with blank data list
      (setq slen (sslength ss)) ; number of ATTDEFs in selection set
      (setq ix 0) ; used to index through the selection list
      (while (< ix slen)        
        (setq en (ssname ss ix)) ; get next ATTDEF entity name from selection set
        (setq ed (entget en)) ; open up this ATTDEF entity
        (setq attdef_lst (cons ed attdef_lst)) ; add its data to the big list
        (princ " ")(princ (cdr (assoc 2 ed))) ; display existing order in command window
        (setq ix (1+ ix)) ; increment index to get next ATTDEF entity from selection set
      )
     
      ; Initially sort the list alphabetically by tagname. The tagname is in the "2"
      ; part of the entity's data. Access the value by extracting with the
      ; (assoc 2 ...) function.
      (setq attdef_lst (vl-sort attdef_lst
            '(lambda (X Y) (< (cdr (assoc 2 X)) (cdr (assoc 2 Y))))))
      ; Okay. So far, so good. We now have all ATTDEFs alphabetically sorted and held
      ; in a big data list called "attdef_lst".
           
      ; Now prepare to create a brand new ATTDEF list by pulling entries from the
      ; "attdef_lst" and pushing them into this new list in the desired order.
      (setq new_attdef_lst nil) ; Start with empty new list
      (setq processed_ix_lst nil) ; To be used for tracking what items have been
                                  ; pulled from alphabetized list into the new list.
     
      ; Process the ATTDEF tagnames against the desired order given in the "orderlst"
      (foreach sortorder_name orderlst
        (setq ix 0)
        (foreach rec attdef_lst
          (setq attdef_tag (cdr (assoc 2 rec))) ; extract ATTDEF tagname for this entry
          (if (AND (not (member ix processed_ix_lst)) ; check if already processed
                   (wcmatch attdef_tag sortorder_name)) ; check if tagname wild-card
                                      ; matches with the target sortordername string.
            (progn ; This ATTDEF name matches what we're looking for. Pull its data out
                   ; of the attdef_lst and push the entity's block of data into the
                   ; new "new_attdef_lst" ordered list.
              (setq new_attdef_lst (cons rec new_attdef_lst))
              ; Remember this entry's index number so won't try to add it in again
              (setq processed_ix_lst (cons ix processed_ix_lst))
          ) )
          (setq ix (1+ ix))
        )
      )   
     
      ; The new_attdef_lst should contain the ordered attributes that were specifically
      ; defined. Now add in any left-overs. These will go in alphabetically.
      (setq ix 0)
      (foreach rec attdef_lst
        (if (not (member ix processed_ix_lst))
          ; This entry not processed above. Go ahead and push it into the new list.
          (setq new_attdef_lst (cons rec new_attdef_lst))
        )
        (setq ix (1+ ix))
      )
      ; Now put the new_attdef_lst into the correct order (it is reversed due to
      ; using "(cons ...) to add elements to the beginning of the list instead of
      ; the end of the list)
      (setq new_attdef_lst (reverse new_attdef_lst))
     
      ; Erase all existing ATTDEFS (!)
      (command "_.ERASE" ss "")
     
      ; Now rewrite the ATTDEFs but using the new ordered list of ATTDEF blocks of
      ; data. Each ATTDEF should pop back in exactly as before, but the handle assignment
      ; given to each re-written ATTDEF will now be the next sequential for the
      ; drawing (!)
      (foreach rec new_attdef_lst
        (princ "\n")(princ (cdr (assoc 2 rec))) ; display attdef name to command window
        (entmake rec)
      )
  ) )
  (setq ss nil) ; release the selection set
  (princ)
)        
       

Let’s try it.

With drawing VXF1D.dwg open on screen, APPLOAD the above utility file reorder_attdef.lsp.

Then type REORDER_ATTDEF [Enter] at the command prompt. In the blink of an eye, the utility should delete all ATTDEFs, sort, and re-write them. Save the symbol “.dwg”.

Now, in a fresh or purged drawing, insert this revised symbol. Cross fingers. Launch the attribute edit command, pick on the newly inserted transformer symbol…

autolisp006d

Good work! Now batch this tool against a bunch of symbols (make a backup first, just in case!). In short order your library should be modified.

Advertisement

Could some custom applications make your company more productive? Find out. http://n8consultants.com

U P D A T E :  I just noticed that the original program with “RATING*” would put RATING10, 11, and 12 right after RATING1 and before RATING2. Looks like my original attribute definition order list example should explicitly list all 12 “RATING*” tag names like this to avoid this problem:

(setq orderlst (list "TAG1*,TAG2,TAGSTRIP,P_TAG1,P_TAGSTRIP"
                       "DESC1"
                       "DESC2"
                       "DESC3"
                       "RATING1"
                       "RATING2"
                       "RATING3"
                       "RATING4"
                       "RATING5"
                       "RATING6"
                       "RATING7"
                       "RATING8"
                       "RATING9"
                       "RATING10"
                       "RATING11"
                       "RATING12"
                       "MFG"
                       "CAT"
                       "ASSYCODE"
                       "INST"
                       "LOC"
                       "FAMILY"
                       "TERM*"))

September 21, 2009

“Super” Project Manager utility – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 1:34 am

Tool to create and manage sub-projects within an overall “super” project set of AutoCAD Electrical drawings

Performance takes a hit when an AutoCAD Electrical project gets very large. Also, on large projects, a user sometimes needs the ability to divide the overall drawing set into separate document numbers.  They require that each different type of document (i.e. schematic, panel layout, wire list, parts list) have a separate document number and title block information.  They want all drawings to be intelligently linked for design and editing but separated for title block update and page numbering.

There is a nifty way to manually split a project into more manageable or logically grouped sub-projects while still allowing ability to do overall project cross-referencing and reporting functions. This is described in detail in a posting made last month, link here.

This idea has resonated with some users including Nick Hall who has indicated that he has put together a VB program that can combine multiple subprojects into one “super” project (see note 2 at the end of the above link).

Super Project Manager tool

Here is another approach, an automated way to split out sub-projects. This is a manager tool that will take one big project and break it down into multiple, related sub-projects where each sub-project is a stand-alone AutoCAD Electrical project. This tool gives a listing of all drawings in the overall “super” project and lets you pick groups of drawings to move into sub-projects. Each new sub-project inherits the settings of the main super project. NOTE: the overall “super” project never changes - drawings in this overall project stay… the sub-projects just reference subsets of the drawings permanently held in the overall super project.

It seems to work pretty well.

Example

We’ll use the small, simple example give in the previous posting. Our overall project, PROJ-07, has just 29 drawings. But we want to create three sub-projects that each contain a sub-set of these 29 drawing references. This will give us the ability to either work on a small subset of the main project drawing set (a sub-project is marked as the “active” project) or instantly flip over to take the whole project drawing set into account (main project is flipped to be the “active” project).

We appload the new tool and then launch it by typing SPM at the “Command:” prompt. It checks for the current active project and pops this active project’s drawing list into the dialog shown below. If it detected any existing sub-projects tied to this main project, these would be listed in the lower display list.

All subprojects are identified by this tool by their file name…. “<main_projectname>[subproj_name].wdp“. None are found for this sample project – there is project file PROJ-07.wdp but there are no PROJ-07[xxx].wdp projects found in the same folder.

spm01

Our first sub-project

We want to reference six of these drawings in a small sub-project called “CELL01″. Highlight the drawings that you want to reference in this new sub-project. Hit the “Create a new sub-project” button. Enter ”CELL01″ as shown in the sub-dialog that pops up.

spm02

Hit OK to dismiss this “suffix code” sub-dialog.

The new sub-project reference goes into the first position of the sub-project listing. A “1″ marks each drawing that is referenced in this first sub-project.

spm03

Adding a 2nd sub-project

Repeat the process. Let’s say we want drawings 001 through 006 to be referenced in a second sub-project. Repeat the above but type “CELL02″ as a name for this new sub-project.

spm04

A third sub-project

And we repeat the above for the third sub-project, picking drawings 001, 002 and 010-014, and 019.

Here’s what our main dialog display now looks like (below). Note that each of the three sub-projects that we’ve defined show up in the bottom list box along with an “index” number. The upper dialog records which drawings have been referenced in each of the three sub-projects. Up to 9 sub-projects in one main project are supported by this tool.

spm05a

Tools are there to add and remove drawing references from selected sub-project(s).

When all looks good, hit the “Save changes” button. The three new sub-projects are created. The main AutoCAD Electrical Project Manager window now displays the original, main “super” project and now three more sub-projects. Each sub-project is the same name as the main project but with a unique suffix shown in square brackets.

spm06

This Super Project Manager tool keys off of the square bracketed suffixes at the end of the project files names to automatically group all sub-projects together with a main “super” project. Seems to work well.

Touch base with Doug McAlexander ECADConsultant@aol.com if any interest in this cool tool.

U P D A T E:  short video demo of this tool is here.

September 10, 2009

Circuit Builder – leveraging AutoCAD’s “Group” concept – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 9:12 am

AutoCAD’s ”Group” concept for entity selection can be leveraged by Circuit Builder.

This was a cool idea. John Zwerlein, a long-time AutoCAD Electrical guru guy, asked me if Circuit Builder could somehow interact with existing entities on a drawing that carry specific AutoCAD “Group” name assignments. For example, when running Circuit Builder in its “Configure” circuit mode, could certain existing things be removed from the drawing is a given circuit option was selected? Hmm…

Tried it. Worked. Pretty cool.

Here’s a simple example.

Let’s say your drawing has a list of engineering notes in a column along the side of the drawing. Two of them are appropriate if the user selects a “full voltage” option, a different one is appropriate for the “with transformer” option, and none of the three are appropriate if the user selects a “None” option.

What we do is make sure each note carries a unique AutoCAD “GROUP” name. Let’s use names “NOTE1″, “NOTE2″, and “NOTE3″. You assign a group name to one or more entities by launching the AutoCAD “GROUP” command (type GROUP or _GROUP at the “Command:” prompt). Dialog pops up and you make it happen.

Now, your drawing engineering notes are set up with unique “group” names. Next step is to adjust the Circuit Builder spreadsheet “ace_circuit_builder.xls”. Open in Excel. If you have trouble finding this file, type this at the AutoCAD command prompt:  (c:ace_find_file “ace_circuit_builder.xls” 3) [Enter]. Go to the appropriate sheet. Here’s the “horizontal insertion” sheet showing the control transformer entries:

cb_group01

What we want to do is carefully add in the stuff shown in red and yellow. For the red part, be very cautions. You need to enter the number zero but it needs to be interpreted by Excel as text, not as numeric. This means you should type in with a preceeding single quote, ‘0, instead of just the number zero. The value will appear left justfied in the cell. If it does not, fix it! This is important.

Here’s a close up.

cb_group02

In operation… when the “None” option is selected, the string “(Command “_ERASE” “_GROUP” “NOTE*” “”)” is sent by Circuit Builder to AutoCAD’s command processor. All entities with wild-card group name “NOTE*” are selected and erased. If the “Control transformer” option is selected, then entities with group names “NOTE1″ and “NOTE2″ are erased. For full voltage option, only “Note3″ is erased.

Pretty cool.

Invoking the old, “classic” version of Symbol Builder

Filed under: AutoCAD Electrical — nateholt @ 9:11 am

I’ve spent the last week or so creating library symbols and circuits from a set of existing, dumb AutoCAD schematic drawings. It’s just a matter of picking some existing geometry out of a drawing, wblocking it out to a new name, and then making it “AutoCAD Electrical smart”.

There is a tool in AutoCAD Electrical to help streamline this “make symbol smart” process – i.e. converting text to the attributes AutoCAD Electrical wants to see and adding in new, invisible attributes for wire connection points. It is the “Symbol Builder” tool and is selectable from the ribbon or toolbar UI. The current implementation of Symbol Builder is based upon AutoCAD’s “Block Editor” feature.

But, under some conditions, I yearn for the clunky old version that was in AutoCAD Electrical long ago. The one with the minimal interface and features. For certain repetitive tasks, once mastered, I could really churn out converted symbols.

This last week was one of those times. This “classic” version of Symbol Builder is still in the code, it’s just been replaced in the UI by a call to the newer “Block Editor-based” version. I was able to launch the older version by typing this at the “Command:” prompt – wd_sym_build [Enter].

September 1, 2009

Nate’s Simple Autolisp – Lesson 005

Filed under: AutoCAD Electrical, Tutorials — nateholt @ 12:20 am

Using (nentsel…) and changing an existing block insert instance

Here’s the real-world example (happened  yesterday) that triggers quick Lisp lesson number “005″.  The issue revolves around the color yellow.

The challenge

lisp005_01I reviewed some drawings from a client. Everything looked fine with dark background. But a light background, some of the attributed blocks were difficult to read - yellow ones. Very uncomfortable at best, bordering on impossible at worst.

Normally, I would just figure out what “layer” the attributed text was on and force that layer’s color from yellow to a better color.

 

But there was a problem. This block’s single yellow text attribute definition was not set up to have its COLOR display “ByLayer”. It was “hard-coded” to be yellow ALL the time.

How can we tell?… Here is the result of the AutoCAD “LIST” command on the upper “52″ bubble. Note that the single attribute, tag name BUBNUM, has been defined to always display as ”YELLOW”.

autolisp005a

A Solution

Let’s fix this. What we’ll do now is build up a little AutoLISP tool to force a picked attribute to display in a different color. If you’d like to follow along “hands on”, download the above sample dwg file here. What we want our little AutoLISP tool to do is this: we pick on a yellow attribute. Our tool reads the attribute and, if the attribute’s color was NOT set up “BYLAYER”, changes its color to color “red”. This should show up nicely whether a dark or light background is selected.

Step-by-Step: Difference between (entsel) and (nentsel)

In each of the previous lessons here, here, here, and here we have looked at the AutoLisp (entsel) entity selection function.

With the example dwg file open/active on your screen, type this at the “Command:” prompt:

Command: (entsel) [Enter]
Select object: [pick on text in upper bubble] (<Entity name: 7ffffb04930> (-0.0405614 0.0279495 0.0))

The (entsel) function returns a two-element list: the first element is the entity name of the picked entity (i.e. the block insert instance) and the second element is the XY coordinate of the mouse pick point. We just want the entity name, the first element of this returned list. Use the AutoLISP “car” function to extract the first element. So, let’s do it again. Type this at the “Command:” prompt and pick on the upper bubble:

Command: (car (entsel)) [Enter]
Select object: [pick on text in upper bubble] <Entity name: 7ffffb04930>

Remember, just like in the previous lessons, we need to keep those “(” and “)” balanced out. For each “(” you add, you need to balance it with a “)”. Okay, good so far. Now let’s modify our “program” to open up the returned entity name with a call to “entget”:
 
Command: (entget (car (entsel))) [Enter]
Select object: [pick on text in upper bubble] ((-1 . <Entity name: 7ffffb04930>) (0 . “INSERT”) (330 . <Entity
name: 7ffffb039f0>) (5 . “18B”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”)
(8 . “0″) (100 . “AcDbBlockReference”) (66 . 1) (2 . “bubble”) (10 0.0 0.0 0.0)
(41 . 1.0) (42 . 1.0) (43 . 1.0) (50 . 0.0) (70 . 0) (71 . 0) (44 . 0.0) (45 .
0.0) (210 0.0 0.0 1.0))
 
Okay, so this is the available information returned when we picked on the block insert instance with (entsel). If you compare this cryptic list of data (the very top part below) with the upper part of the LIST command’s display when pick the same item (shown below beginning at the “list” command entry), you can see some of the potential data match-ups. Each piece of data is represented by a “dotted pair”. There is a lead number, referred to as the “DXF code”, identifies what the data on the right-hand side of the dot is associated with. We can guess at the ones shown here… they seem to match up:
 
autolisp005b
 
Here is a partial list of DXF codes (i.e. the left-hand number in each dotted pair). This is pulled from the Visual Lisp on-line HELP (topic = “DXF group codes in numerical order”).
 
autolisp005d
 
 
The problem
 
No problem getting information on the overall block insert instance itself. The problem is that we cannot get access to the attribute text embedded inside of the block insert instance… we cannot specifically “pick” on it.  No matter what we pick on the block insert, whether it is the circle part or the attribute part of the block, (entsel) always returns the entity name of the overall block insert. What we really need is a pick function that digs deeper into these complex entities and pulls out the “nested” sub-entity name of what we pick.
 
 
Selection of nested sub-entities with (nentsel)
 
This is where the AutoLISP function (nentsel) comes into play. It works like (entsel) but, if you pick on an entity that is part of an overall complex entity like a block insert instance or a multi-segment polyline, (nentsel) returns the picked sub-entity name, not the main overall entity name that (entsel) always returns.
 
So, let’s try it on the top bubble. Type this at the “Command:” prompt and pick on the text attribute inside of the top bubble block insert:
 
Command: (entget (car (nentsel))) [Enter]
Select object: [pick on text in upper bubble] ((-1 . <Entity name: 7ffffb04940>) (0 . “ATTRIB”) (330 . <Entity
name: 7ffffb04930>) (5 . “18C”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”)
(8 . “0″) (62 . 2) (100 . “AcDbText”) (10 -0.0606988 -0.0385562 0.0) (40 .
0.078125) (1 . “52″) (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . “Standard”) (71 . 0)
(72 . 4) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . “AcDbAttribute”) (280 . 0)
(2 . “BUBNUM”) (70 . 0) (73 . 0) (74 . 0) (280 . 0))
 
Okay, now compare the above data return from (entget (car (nentsel))) with the original “LIST” display on the whole bubble block insert. Note that the data returned due to the (nentsel) pick now points at the attribute itself, NOT the overall block insert instance as we saw with (entsel).
 
 
autolisp005c 
 
How do we know that the “62″ type identifies the entity “Color” assignment? Look at the bottom of the “DXF codes” listing. DXF code “62″ is associated with a fixed color assignment (i.e. not “ByBlock” or “ByLayer”). The value that is the right-hand part of the 62 dotted pair is the color number.
 
Our yellow attribute text is forced to remain yellow at all times because the BUBNUM attribute carries a (62 . 2) subrecord. Color yellow is color number 2!
 
Experiment – rewrite the attribute to color 1 – RED.
 
If we could only force this attribute’s (62 . 2) subrecord to be (62 . 1), then maybe it would turn “red”. Let’s try.
First step, we repeat the last command but we save the entity’s data in a variable we’ll call “old_data”. Type this at the Command: prompt.
 
Command:(setq old_data (entget (car (nentsel)))) [Enter]
Select object: [pick right on the attribute]((-1 . <Entity name: 7ffffb26940>) (0 . “ATTRIB”) (330 . <Entity
name: 7ffffb26930>) (5 . “18C”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”)
(8 . “0″) (62 . 2)(100 . “AcDbText”) (10 -0.0606988 -0.0385562 0.0) (40 .
0.078125) (1 . “52″) (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . “Standard”) (71 . 0)
(72 . 4) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . “AcDbAttribute”) (280 . 0)
(2 . “BUBNUM”) (70 . 0) (73 . 0) (74 . 0) (280 . 0))
 
Now we’re going to use a “substitution” AutoLISP function called “subst” along with a couple other cryptic fuctions “cons” and “assoc”. Type this at the Command: prompt.
 
Command: (setq new_data (subst (cons 62 1) (assoc 62 old_data) old_data)) [Enter]
((-1 . <Entity name: 7ffffb26940>) (0 . “ATTRIB”) (330 . <Entity name:
7ffffb26930>) (5 . “18C”) (100 . “AcDbEntity”) (67 . 0) (410 . “Model”) (8 .
“0″) (62 . 1)(100 . “AcDbText”) (10 -0.0606988 -0.0385562 0.0) (40 . 0.078125)
(1 . “52″) (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . “Standard”) (71 . 0) (72 . 4)
(11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . “AcDbAttribute”) (280 . 0) (2 .
“BUBNUM”) (70 . 0) (73 . 0) (74 . 0) (280 . 0))
 
Okay, now we have our new version of the entity’s data held in a variable called “new_data”.
 
One more step. We push this new version of the data back out to the entity. Type this at the Command: prompt.
 
Command: (entmod new_data) [Enter]

… and the attribute instantly changes from yellow (color 2) to red (color 1) !

autolisp005e

Wrapping all this into a little utility

That was instructive, but very painful. Let’s put all of these steps into a little ASCII text file, give it a “.lsp” extension, and APPLOAD it to use when needed.

Here it is using the Visual Lisp editor (any ASCII text editor can be used).

autolisp005g

APPLOAD the file and, when you need it, type ATTR2COLOR [Enter] at the Command: prompt. Change the color of as many “non-BYLAYER” colored attributes as you can pick!

August 27, 2009

Using the Multi-Connection Sequence Terminal Symbol – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 8:50 am

Single in-line symbol that can represent a series of up to six daisy-chained terminals

Sometimes there is just not enough room to squeeze in all of the terminal connections that a wire must pass through to get from a connection on Component A to Component B.

Here’s a field-mounted limit switch tied back to a terminal related to a PLC I/O module. It looks simple enough. But in reality, that wire passing from the “Field” to the terminal just ahead of the PLC I/O point may actually pass through a couple field junction boxes and control enclosure’s roof-mounted terminal strips.

phantomterm01

It may not be necessary or convenient to show on the controls schematic each and every one of these interm, field terminals that the wire passes through. BUT… each connection needs to show up in the various wire from/to reports. So, for AutoCAD Electrical to properly report the limit switch wiring back to the terminals ahead of the PLC module, each of these daisy-chained connections needs to be somehow defined in the schematics.

Let’s say that for wire number 503 to get from pin 14 on PRS503 to MCAB5 terminal strip TB1 terminal 45, it has to pass through these additional terminal connections:

  1. Junction box JB23, terminal strip TS1, terminal 3
  2. Marshalling panel MP1, terminal strip IN05, terminal 32
  3. Jumper out via marshalling panel MP1, terminal strip OUT02, terminal 15
  4. MCAB5 roof-top terminal strip TOP2 terminal 10
  5. MCAB5 unit 3A interface terminal strip 3A terminal 1

What if it’s just not convenient to show these five series-connected terminals on the schematic? Is there a way to add this intelligence to the wire network.

Multi-Connection “Phantom Terminals” Symbol

This is one way to do it. It is a bit tedious but does enable intelligence to be added in the form of a single multi-terminal symbol. All information for the five daisy-chained terminals (and even part numbers for the BOM) can be assigned to this one symbol (series of six daisy-chained terminals is the maximum supported).

The multi-connection sequence terminal symbol is not represented as an icon pick on the Insert Component icon menu. You’ll have to “Browse…” to it. Here are the various versions of the multi-connection sequence terminal symbol:

  • H--1_MULTI_CONN.dwg  - horizontal wire insertion, wire number changes from terminal to terminal
  • H--1_MULTI_CONN_NOCHG.dwg - horizontal wire insertion, wire number does not change
  • V--1_MULTI_CONN.dwg - vertical wire insertion, wire number changes from terminal to terminal
  • V--1_MULTI_CONN_NOCHG.dwg - vertical wire insertion, wire number does not change

Let’s select a horizontal version of the symbol that does not change the wire number through it, H–1_MULTI_CONN_NOCHG.dwg:

phantomterm02

… and pop it in at the interface point where the wire crosses the location box boundary. Doing this displays this rarely seen dialog:

phantomterm03

Now we pick on the first group of “WD_1_*” entries and hit the “Edit” button. A sub-dialog appears. We start to enter in the daisy-chained, multi-terminal connection sequence.

Here’s the first terminal’s entry:

phantomterm04

We continue through the other four terminals in the sequence, entering in the minimum connection information for each terminal in the sequence. When all five are entered, our main summary dialog looks like this:

phantomterm05

And that’s it. The five terminal sequence is all embedded into this single squiggley symbol that breaks wire 503 at the field/location box boundary. Now let’s try the AutoCAD Electrical “Wire From/To Report”.

Wire From/To Report

Here is the result of the wire from/to report that includes the single in-line multi-sequence terminal symbol in wire number “503″:

phantomterm06

This Multi-Connection Sequence Terminal support is in the recent versions of AutoCAD Electrical and probably goes back three or four releases, not sure.

Customizing the symbol

The default symbols are set up to show the list of terminal strip tag-IDs as visible attribute text. You can hide this text after-the-fact or you can modify the symbol to hide these attributes by default. Just like any other AutoCAD Electrical schematic symbol, you can call up the library symbol’s “.dwg” file in AutoCAD and change the way the symbol looks.

Results

It’s a manual data entry, but seems to give expected results. If this concept appeals to you, a set of custom application tools might be wrapped around it to fit your specific requirements. Call me.

August 25, 2009

Multi-item number balloon positioning utility – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 2:37 pm

Simple tool to re-configure a cluster of item number balloons

This seems so trivial, but if you have to do it often, a tool is much appreciated. Here we have a pushbutton that consists of three different item numbered parts. When the item bubble balloons pop in, the string of bubbles extends in a straight line. If in a crowded space, the string of bubbles can bleed across and bump into the next-door neighbor.

bal00

We need a tool! AutoCAD Electrical “groups” these three bubbles and leader together, so to reposition one or two bubbles, you first have to turn the GROUP mode off (CTRL+SHIFT+A). Then reposition each bubble and try to keep them touching at nice, clean tangent points. Tedious.

Let’s quickly review how we got to this point.

Multi-item number support

Recent versions of AutoCAD Electrical support multiple item numbers assigned to a single component. This mode is set up as a project-wide property as shown here.

bal01

In this mode AutoCAD Electrical can assign and track a unique item number assigned for each catalog part number. If a component consists of multiple pieces  (ex: operator, N.O. contact block, N.C. contact block), an item number can be assigned and tracked, drawing-wide or project-wide, for each catalog part number piece.

In our example shown above, here is what the part number assignments might look like:

bal02

The Tool

So, that is the issue and how it manifests itself. Now for the tool…

…type this at the “Command:” prompt:  

 AEBALLOONREPOSITION [Enter]

Then pick on the bubble to move. Just get it close to where you want it to go. It should sense the nearby balloon(s) of the cluster and auto-position to remain tangent. You do NOT have to turn “grouping” off.

This seems to work in both ACE2009 and ACE2010 for clustered, multi-item number balloons.

bal03

August 24, 2009

Circuit Builder configure mode – adding a “pick from icon menu” selection

Filed under: AutoCAD Electrical — nateholt @ 5:01 pm

How to encode a ”pick from icon menu” option into Circuit Builder’s Excel spreadsheet

This posting builds upon the previous one. In fact, we’ll start with the same 3-phase motor control circuit template and “stop” component marker block “PB01″.

cbicon01

As we insert this circuit using Circuit Builder’s “Configure” mode, it processes the various marker blocks that come in with the circuit’s skeleton template drawing. The various options for each marker block are hard-coded in the ace_circuit_builder.xls spreadsheet.

For example, when Circuit Builder processes the “PB01″ marker block shown here, it finds five options and “none” defined in the Excel spreadsheet. These options then show up in the user interface. The user can select from this list of six options to insert at the “PB01″ position as the circuit inserts.

cbicon02

But what if none of these hard-coded options is really what is needed for this particular circuit? Maybe a N.C. pressure switch contact is the appropriate “stop” contact to interrupt power to the motor circuit. Wouldn’t it be nice to have a 7th option, one that calls up the normal “Insert Component” icon menu and let’s the user browse to the pressure switch page and then pick an appropriate component for the circuit?

This is do-able. Not super easy, but do-able. Here’s how…

How to enable Icon Menu picks from within Circuit Builder

The key is to create a small AutoLISP utility that can substitute for the normal Insert Component API call. We then add a new row to the spreadsheet for our “PB01″ options and reference this new AutoLISP function. That should do it. 

Step 1

Here is the AutoLISP utility. It wraps a call to “wd_wdmenu” around the normal circuit builder API call “(c:ace_cb_insym…)”. What this does is call the icon menu function, user picks, and function returns the block name of the picked component. This block name is saved in variable “symnam” and then this variable is passed to the normal Circuit Builder insert component command. The very last line “auto-starts” this function as soon as it’s loaded. Should work!

(defun c:cb_use_iconmenu ( / )
  ; Make sure that an icon menu resides in memory
  (if (not GBL_wd_wdmenu2use)(c:wd_menu_load_schem))
  ; Display icon menu and return user's selection
  (setq symnam (wd_wdmenu GBL_wd_wdmenu2use))
  (if symnam
    (progn ; User picked something. Go ahead and call
           ; the normal Circuit Builder insert component
           ; API call. Pass the symbol name picked from
           ; the icon menu in "symnam".
      (c:ace_cb_insym #xyz nil symnam #scl 8 nil)
  ) )
)
(c:cb_use_iconmenu) ; auto-start when this program loads

Save this AutoLISP program in an ASCII text file named “cb_user_iconmenu.lsp”. Save it to a folder that is somewhere in the AutoCAD Electrical or AutoCAD support file search path list.

Step 2

Reference the above (c:cb_use_iconmenu) function in a new line for marker block PB01 in the Excel spreadsheet ace_circuit_builder.xls. If you have a hard time finding where this support file is located, type this at your “Command:” prompt:

(c:ace_find_file "ace_circuit_builder.xls" 3) [Enter]

Here is the edited “PB01″ marker block section of the 3PH_H sheet of the spreadsheet. Note that it has to use the “c:ace_cb_eval” function that was introduced in the last posting. Carefully enter the call as shown, (c:ace_cb_eval “(load (c:ace_find_file ‘cb_use_iconmenu.lsp’ 3))” ).

cbicon03

Testing

Save the edited Excel spreadsheet and exit. Now run Circuit Builder in “Configure” mode. When you get to the “Stop” selection in the control circuit, you now see a new option ( ! ). Pick it.

cbicon04

The standard “Insert Component” dialog appears. Now browse to the “pressure switch” page and make your selection. The picked block name is passed back to Circuit Builder and it inserts at the appropriate spot in the circuit.

Alternate solution

The first solution uses an auto-starting AutoLISP function that is searched for and “apploaded” with each use. The advantage of this first approach is that no AutoLISP function has to be pre-loaded and in memory. The disadvantage is that encoding it in the Excel spreadsheet is a bit mysterious… the use of the (c:ace_cb_eval…) function and the goofy syntax. Another disadvantage for ACE2009 users is that this (c:ace_cb_eval…) function needs to be pre-APPLOADED (in ACE2010 it is pre-defined).

Here is an alternate solution. The AutoLISP file is laid out just a bit differently… it has no auto-run line at the end of the code.

(defun c:cb_use_iconmenu2 ( / )
  ; Make sure that an icon menu resides in memory
  (if (not GBL_wd_wdmenu2use)(c:wd_menu_load_schem))
  ; Display icon menu and return user's selection
  (setq symnam (wd_wdmenu GBL_wd_wdmenu2use))
  (if symnam
    (progn ; User picked something. Go ahead and call
           ; the normal Circuit Builder insert component
           ; API call. Pass the symbol name picked from
           ; the icon menu in "symnam".
      (c:ace_cb_insym #xyz nil symnam #scl 8 nil)
  ) )
  (princ) ; quiet return
)

… and here is how it would look in the Excel file for the PB01 marker block section:

cbicon05

It’s a lot cleaner in the Excel entry but the downside is that the function has to be in memory before Circuit Builder is launched (in other words, it needs to be loaded or APPLOADed).

Going Deeper

If you feel a custom Circuit Builder-based app might make a significant difference at your company, please contact me at n8consultants.com.

August 23, 2009

Circuit Builder – embedding custom calls in the spreadsheet – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 5:41 pm

A simple way to customize the behavior of the Circuit Builder tool

The Circuit Builder utility first appeared in AutoCAD Electrical 2009. It enables electrical circuits to be generated and interactively modified as they insert into your electrical schematic drawings. The key pieces of this process are a set of “template” drawings with “marker blocks” and an Excel spreadsheet that lists the selectable options.

How Circuit Builder works

Here it is in a nut-shell. The Excel spreadsheet comes into play two times. The first time, it maps a skeleton template drawing to the user’s selected circuit type. The inserted template is populated with ”marker blocks” inserted at strategic points in the skeleton circuit. These carry attribute codes that maps back into the spreadsheet. As the Circuit Builder program runs, it processes each marker block that comes in with a skeleton circuit template. It looks in the spreadsheet for a match on the marker block code and presents the user with the defined options that can be inserted at that marker block’s location in the template. User picks option and the spreadsheet defines what Circuit Builder needs to do to insert that option into the circuit.

For example, part of the template for a full-voltage, non-reversing 3-phase motor circuit is shown here. One of the marker blocks carries an attribute value of “PB01″. The position of this in the control part of the 3-phase motor circuit corresponds to where a “stop” contact could be inserted. This might be a pushbutton, a relay contact, a limit switch, or something else.

cbalert00

 Here is what the portion of the Excel spreadsheet ace_circuit_builder.xls looks like that corresponds with this template’s marker block marked with code “PB01″…

 cbalert00a

… and then here’s how it drives the Circuit Builder’s user interface, allowing the user to interactively modify the circuit as it inserts…

 cbalert00b

OK, That’s how it works… now we have a need to customize…

Let’s say that your users need to be reminded of something when a specific option is selected. For example, let’s say that if a “stop” mushroom head pushbutton is specified for marker block “PB01″ shown above, you want to remind the user to consider specifying a “jumbo” size part number. Popping up an alert dialog at this point would do the job.

How to do this? Let’s look at the ace_circuit_builder.xls spreadsheet. First task is finding this support file ( ! ). You can use the “Support file finder” idea in this posting… just type this at the AutoCAD command prompt: 

(c:ace_find_file "ace_circuit_builder.xls" 3) [Enter]

…and it searches for the file and returns the full path to it. Now open in Excel and go to the 3PH_H sheet (for three-phase, horizontal circuits). Scroll down to the section for the PB01 marker block shown below. Row 100 is what we’re interested in… the row that, if selected from the UI, inserts a mushroom head pushbutton symbol into the circuit at marker block “PB01″.

cbalert01

First Attempt – FAILURE!

Well, maybe we can just add a standard AutoLISP “(alert <msg>)” call as shown in red below.

cbalert02

Make the change to row 100, save the Excel file. Fire up Circuit Builder. Get down to the pushbutton selection and pick “Mushroom head”.

Ouch. Didn’t work. Got this goofy dialog…

cbalert03

Here is the problem. Circuit Builder does not recognize lisp functions embedded into the Excel spreadsheet unless they are defined as “c:” type functions. If our alert function had been defined as (c:alert “some message”), then Circuit Builder would recoginze it as it is pulled from the Excel spreadsheet. But not (alert “some message”).

Second Attempt – a Work-around

 ACE2010 has a predefined “wrapper” function we can use in our Excel spreadsheet. It provides a “c:” wrapper around the normal AutoLISP expression we want to evaluate / execute.

We go back into our Excel spreadsheet and adjust the call to that shown here. The wrapper function is “(c:ace_cb_eval …)” and provides the “c:” part so that Circuit Builder will be able to read it from the Excel entry. It is documented in the AutoCAD “Electrical Help” –> “API Help”.

Important… note that we have to replace the embedded double quotes with single quotes. So the evaluated expression becomes “(alert ‘Specify jumbo head if possible’)”. This is needed to avoid ending up with two nested sets of double-quotes.

cbalert03a

Save the Excel file. Fire up Circuit Builder. Get down to the pushbutton selection and pick “Mushroom head”…

Second Attempt – It Worked!

cbalert04

There it is. An example of embedding a generic AutoLISP call into the Circuit Builder spreadsheet. This concept should open up a wide range of customization possibilities. Go for it! (If you would like help, please contact me at n8consultants.com.)

Work-around for ACE2009

ACE2009 does not have this predefined (c:ace_cb_eval…) wrapper function. But we can add in a look-alike function and, as long as it get’s APPLOADED, it should work. Cut and paste below into an ASCII text file. Call it something like cb_eval.lsp. Make sure it gets APPLOADED.

(defun c:ace_cb_eval ( str / )
  (if (AND str (/= str ""))
    (progn
      ; Replace any ' character found in string with double quote " character
      (setq str (wd_fr_txt_replace str "'" "\"" nil))
      (eval (read str)) ; evaluate the lisp expression
  ) )
  (princ)   
)

August 20, 2009

Dual Range Component Tagging: Power Vs. Control – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 8:06 am

Setting up different component tagging sequentials for power schematics versus control schematics

This posting is a flip-side of the last one… now dealing with component tags instead of wire number tags.

Let’s say that the customer wants his schematics to use sequential component tagging (instead of line reference or X-Y grid reference tagging). He wants all 240/480VAC power components (ex: motor circuits) to be tagging starting at sequential “1″. But he wants the control schematic components to be sequentially tagged starting at sequential “500″. And, he has a small amount of pneumatic circuitry and these components to be tagged with sequentials starting at number “1000″.

Initially you might think that this is not going to be too much fun. You fear that you’re going to be manually typing in a lot of “fixed” component tag values and having to track the next sequential for each component type and each component voltage (power, control, or “pneumatic”).

But, using a little trick, it ends up that it is very easy to set up AutoCAD Electrical to automatically assign and track multiple sets of next available component tag-IDs.

Here’s how

Let’s say that the customer’s project is probably going to be 10 power schematics, 25 controls schematics, and two pneumatic logic drawings.

Power Schematics

This is how you’d set up the Drawing Properties for each of the 10 power schematic drawings.

dualseqcomp01

Controls Schematics

Here’s what you would set up for EVERY controls schematic:

dualseqcomp02 

Pneumatic Schematics

… and here is the setup for pneumatic schematic drawings in the customer’s project:

dualseqcomp03

Yes, It Works!

So, as you insert components into your design, AutoCAD Electrical checks the active drawing’s starting sequential (will be either “1″, “500″, or “1000″ depending upon what type of drawing you’re working on). As the new component goes in, AutoCAD Electrical starts at this sequential. It formats a candidate component tag using the tag format value for the drawing (ex: %F%N meaning the tag is family code plus sequential). Then it scans the project to see if this tag is unique. If not, it increments to the next sequential and checks again. Keeps going until it finds a unique tag.

This will fail to give desired results under extreme conditions. For example, if AutoCAD Electrical finds more than 499 power fuses on your project’s 10 power schematics, then power fuses will start to bleed into the control fuse tag range. In this case, power fuses would start to compete with controls fuses for the next available fuse tag number 500 or greater. AutoCAD Electrical would still maintain unique component tag-IDs for all the fuses… you’d just have a mixture of power and control fuse tags in the 500 range and higher.

August 17, 2009

Dual range wire number tagging: Power vs. Control – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 11:36 pm

Setting up different wire tagging sequentials for power wiring versus control wiring

This is a follow-up to the last posting that dealt with wire tagging format based upon wire type. 

Let’s say that the customer specifies wire number tagging beginning at “1″ for wiring that begins or is contained on “power” schematics. For all controls schematics, the customer wants wire number assignments to begin at number “1000″.

Initially you might scratch your head on this one. But using a little trick, it ends up that it is very easy to set up AutoCAD Electrical to automatically assign and track multiple sets of next available wire numbers.

Here’s how

Your project set has 10 power schematics and 30 controls schematics. On all of the power schematic drawings you go to “Drawing Properties” and set up for “Sequential” wire numbering with a starting number of “1″.

Power Schematics

This is how you’d set the Drawing Properties on all 10 of the power schematic drawings.

dualseqwnum01

Controls Schematics

Here is how you’d set up the Drawing Properties for each of the 30 controls schematics:

dualseqwnum02

 

Ready for Project-Wide Wire Numbering…

You need to make sure that this option is selected… the option to begin sequential wire number calculation based upon the drawing properties starting sequential stored on each drawing:

dualseqwnum03

It Works

So, as AutoCAD Electrical processes wiring project-wide, it looks at the starting sequential on each drawing. For each power schematic, the starting number is “1″. So it starts at “1″ and works its way up, checking all drawings, until it finds the next unused wire number 1 or greater. When it hits a controls schematic, it does the same thing but starts at number “1000″.

This will fail to give desired results if AutoCAD Electrical finds more than 999 power wires. In that case, power wiring would start to compete with controls wiring for the next available wire number 1000 or greater. AutoCAD Electrical would still maintain unique wire numbers… you’d just have a mixture of power and control wiring in the 1000 range and higher.

August 16, 2009

Wire number tagging based upon “wire type” – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 10:39 pm

Auto-track / auto-assign wire numbers based upon wire type

Let’s say that your company standards for wire number assignment includes the following wire numbering requirements:

  1. 24volt DC wiring to use blue wire and tagged with a “DC-” prefix and sequential starting in the “5000″ range.
  2. Ground wires to use green wire and have a “GND-” prefix plus a three digit sequential starting at “001″
  3. White neutral wires to have a “N-” prefix and start at sequential “1″
  4. Black power wiring to have a “-PWR” suffix.
  5. All other wiring to default to sequential starting at number “1″

At first blush you might think that your wire number assignments are going to be all manual and tedious. But that’s not the case. AutoCAD Electrical can be quickly set up to automatically conform to the above standard!

Here’s how

This mode is set up for the active project, project-wide, under AutoCAD Electrical’s ”Project Properties”. This means that you can have one or more projects that behave this way (i.e. wire numbering based upon wire type) and other projects that behave in a more traditional manner. The wire numbering behavior is carried in the project itself.

Here is what the project properties dialog and wire number formats by wire layer sub-dialog look like in order to accommodate the above special conditions. The wire number format override is set up on a per wire layer basis (i.e. per “wire type” basis). Wild cards can be used.

 

wnum_wiretype03

For example, look at the “BLU*” entry. This line instructs AutoCAD Electrical to process all wiring found on layers (i.e. wire types) that begins with layer name “BLU” will be tagged with a wire number format “DC-%N”. This means that wires on layers BLU-16AWG, BLU-18AWG, BLU_1.0mm, and so on… in any drawing in the active project… will be tagged with unique wire numbers starting at “5000″ and having a “DC-” prefix.

Yellow, green, and white wiring has its own format override defined above, one gauge of black wiring has a special format. All other wire color (i.e. wire types) will default to the drawing’s default wire tag format.

Test run

Here’s a simple example of a nonsense circuit with blue, green, white, red, black, and yellow wiring.

wnum_wiretype01

 To get the full effect, we need to make sure that the above drawing’s “Drawing Properties” is set up to default to “Sequential” wire numbering as shown here:

wnum_wiretype04

Now we run the normal AutoCAD Electrical “Wire Numbers” command (from ribbon or type AEWIRENO at command prompt), and… here is the result:

wnum_wiretype02

It works great. Note how the blue DC wiring, the green “ground” wiring, white, yellow, and black wiring all follow the project-wide wire number format overrides. The red wiring, not overridden, follows the normal drawing’s wire number format.

August 13, 2009

How to execute a Lisp function, all dwgs / project-wide – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 5:23 pm

AutoCAD Electrical’s “project-wide utilities” command has an option to process a script file against each drawing in the active AutoCAD Electrical project. You set up the script file and then enter its name in the box as shown in the utility’s dialog:

script01

But, little known… instead of entering a script file name, you can enter a one-line AutoLISP function in this edit box (cannot browse to it!). Instead of launching a script file against each drawing in the project, the utility will apply this Lisp function against each drawing in the project set ( ! ). Neat and clean. No need to create a separate script file with the Lisp function embedded in it… just enter the single-line lisp function and off you go.

Example – Lisp utility to work-around Model/Paper space Mtext cross-reference issue

A user noticed a strange issue with his Paper space schematics created with AutoCAD Electrical. Whenever he would scoot a child component on a drawing that had its parent on some other drawing, the Mtext-based cross-reference annotation for the parent would disappear. He enlisted some help from N8 Consultants and discovered that AutoCAD Electrical was mistakenly pushing the new cross-reference Mtext out to Model space instead of the active Paper space tab.

Autodesk support was notified. But, in the meantime, the temporary work-around was to create a little AutoLISP utility that checks all cross-reference Mtext annotation on the active drawing and makes sure that it matches up with the “space” of the parent.

The complication is that this AutoLISP function needed to be run periodically against a lot of drawings (i.e. all schematic drawings in the active project). Launching it, one drawing at a time, was not something to look forward to.

The solution was to use AutoCAD Electrical’s “Project Wide Utilities” command as described above. But to keep it really simple, N8 set it up so that the user could enter in a one-line lisp function in the edit box normally reserved for a script file’s name. Launching the Project-Wide Utilities command then ran this lisp function against each selected dwg in the project set.

Setting up the Lisp function to auto-run as soon as it loads

This made it really simple. Here is the full ”Paper space Cross-reference checker” utility. Note the two lines tacked on to the very end of the function…

; 13-Aug-2009 Nate Holt, http://n8consultants.com
; -------   P A P E R S P A C E _ X R E F . L S P  -----
; Process block inserts. Look for cross-ref Mtext tied via Xdata pointer. Make sure Mtext is in
; same space as the parent block insert. Work-around for problem with ACE2009, ACE2010 (and
; perhaps others) when parent is on a layout tab and insert/move related child on some other
; drawing. Cross-ref Mtext back on the parent sometimes ending up incorrectly pushed out to
; Model space even through the parent is in Paper space.
(defun c:paperspace_xref ( / ss ix slen parent_ed en mtext_ed newed hdl
              parent_410 mtext_410)
  ; Process all block inserts
  (setq ss (ssget "_X" '((0 . "INSERT"))))
  (if (/= ss nil)
    (progn
      (setq slen (sslength ss))
      (setq ix 0)
      (while (< ix slen)
        (setq en (ssname ss ix)) ; get next block insert instance
        ; Look for pointer to graphical cross-reference Mtext. This is carried as Xdata on
        ; the parent component and points to the "handle" of the cross-ref Mtext entity.
        (if (setq hdl (c:wd_get_1005_xdata en "VIA_WD_XREF_G"))
          (progn ; okay, found block insert instance that points at Mtext
            (if (handent hdl) ; valid handle, Mtext not deleted
              (progn
                ; Open the Mtext entity
                (setq mtext_ed (entget (handent hdl)))
                ; Open the block insert entity
                (setq parent_ed (entget en))
                ; Get the "space" each is in
                (setq mtext_410 (cdr (assoc 410 mtext_ed)))
                (setq parent_410 (cdr (assoc 410 parent_ed)))
                (if (/= mtext_410 parent_410)
                  (progn ; Problem. Try to force
                         ; the Mtext entity into the same space as
                         ; the parent. Adjust the 410 and 67 subrecords.
                    (setq newed (subst (assoc 410 parent_ed)(assoc 410 mtext_ed) mtext_ed))
                    ; 67 carries a value of 1 if paper space, 0 or missing if in model space
                    (if (AND (assoc 67 parent_ed) (assoc 67 mtext_ed))                   
                      (progn ; 67 subrecords different
                        (setq newed (subst (assoc 67 parent_ed)(assoc 67 mtext_ed) newed))
                        (entmod newed) ; update the Mtext entity
                        (princ "\nMoved Mtext hdl ")
                        (princ hdl)
                        (princ " from ")
                        (princ (cdr (assoc 410 mtext_ed)))
                        (princ " to ")
                        (princ (cdr (assoc 410 parent_ed)))
                ) ) ) )
            ) )
        ) )
        (setq ix (1+ ix))
      )
  ) )
  (setq ss nil) ; release the selection set
  (princ) ; quiet return
)    
; Set up to auto-run this function as soon as it is loaded
(c:paperspace_xref)
(princ)
 
 
script03
 
   Referencing the auto-start Lisp function in Project-Wide Utilities command

We don’t have to APPLOAD this lisp utility to make it run. We can do the same thing on the command line with a “(load …)” lisp function (tested on ACE2009 and ACE2010)

 

Let’s say that our above utility’s full file name is “c:/temp/paperspace_xref.lsp”. Here is how we reference it in the Project-Wide Utilities edit box (shown in yellow in the screen-shot).

We enter (load “c:/temp/paperspace_xref.lsp”) in the edit box. But we need to use forward slashes (or double backslashes) in the file’s name.

Hit OK. Select drawings to process… and that’s it. We don’t have to APPLOAD the function or embed it into a script file or add it to a Startup Suite of functions. We just reference it here in the “(load <filename>)” line and we’re good to go.

August 12, 2009

User enhancement to Spreadsheet-to-PLC I/O drawing tool – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 2:16 pm

Modifiable Source Code

The spreadsheet to PLC I/O drawing generator is impressive. Lay out your PLC I/O and connected devices in an Excel spreadsheet, launch the utility, get a cup of coffee, come back, and what awaits you is an initial set of PLC I/O drawings generated from your spreadsheet data. 

This utility is powerful out-of-the-box, but it begs to be customized. So much so that Autodesk ships this utility un-compiled format… it loads and runs from it native Lisp source ASCII text file “wdio.lsp” and its dialog definition file “wdio.dcl”!

A simple user customization

honda2009-01From time to time, a seasoned AutoCAD Electrical user needed to generate sets of PLC I/O drawings without a “ladder” hot/neutral bus. He would set the “Suppression” toggle as shown here in the utility’s “Setup” sub-dialog.

Without the vertical bus in the way, he set up his library symbols such that the wire connection for each I/O point would wrap around and tie to a second connection terminal of the I/O point pair.

 

Everything worked great except for…

honda2009-02

The user’s issue with the AutoCAD Electrical Spreadsheet to PLC I/O generator tool is that under these conditions (suppressed ladder vertical bus wires), unused I/O points could end up with unconnected

… dangling wires…

tied to the “return” connection terminals. These dangling wires would have to be manually removed after the drawings were auto-generated.

The reason why the wdio.lsp utility was not removing them was because they actually made a connection to the module, but not at an I/O address point so there was no in-line device check.

The solution seemed to be this… if an inserted wire ends up unconnected at one end (i.e. a “dangling” wire) ANYWHERE on the module, then the utility should go ahead and trim it out of the circuit.

Customizing the wdio.lsp utility

The user enlisted the help of N8 Consultants. The first task was to actually find the wdio.lsp file. A recent posting on this blog gave a software utility tool to quickly locate it.

Next, open the file with either the Visual Lisp IDE or any ASCII text editor. Looking through the lisp code, there is a function that is called to “clean up” the ladders (i.e. remove unused “rungs”). This seemed like a good place to also check and remove “dangling” wire connections.

After making sure that a backup copy of wdio.lsp was saved, a bit of experimentation began. Soon, we had a working prototype customization, the key part shown in red below. What this new “erase_if_dangling_wire” function does is process the passed line segment entity wire_en. It throws a crossing window around each end of the line segment to see if it captures any block insert instances. If so, and if only captures one at one end of the wire segment, then it goes ahead and trims out this “dangling” wire ( ! ).

(defun ladder_cleanup ( ldr_cnt / ben wire_en)
    ; Check if unused rungs can be removed from this ladder
    ; Figure out center point of upper ladder rung
; ** 04-Aug-09 NEHolt - customer issue with dangling wire
    ; -- internal function --                    
    (defun erase_if_dangling_wire ( wire_en pt3 / dangling_wire ssf ed plcblock_connection)
      (setq ed (entget wire_en))                           
      (setq dangling_wire nil)
      (setq ssf (ssget "_C"
                  (list (- (car (cdr (assoc 10 ed))) GBL_wd_trp) (- (cadr (cdr (assoc 10 ed))) GBL_wd_trp) 0.0)
                  (list (+ (car (cdr (assoc 10 ed))) GBL_wd_trp) (+ (cadr (cdr (assoc 10 ed))) GBL_wd_trp) 0.0) ))
      (if (AND ssf (= (sslength ssf) 1)) ; check if capture something other than itself (crossing
                                         ; window captures more than the line entity itself
        (progn ; the 10 end of the wire segment has nothing connected to it
          (setq dangling_wire T)
        )
      ) 
      (if (not dangling_wire)
        (progn ; check other end
          (setq ssf nil)
          (setq ssf (ssget "_C"
                       (list (- (car (cdr (assoc 11 ed))) GBL_wd_trp) (- (cadr (cdr (assoc 11 ed))) GBL_wd_trp) 0.0)
                       (list (+ (car (cdr (assoc 11 ed))) GBL_wd_trp) (+ (cadr (cdr (assoc 11 ed))) GBL_wd_trp) 0.0) ))
          (if (AND ssf (= (sslength ssf) 1))
            (progn
              (setq dangling_wire T)
            ) 
        ) )
      )
      (setq ssf nil) ; release the selection set
      (if dangling_wire
        (progn ; one end of this wire segment is unconnected
          (c:wd_trimwire wire_en pt3) ; get rid of dangling wire
    ) ) ) 
; ** 04-Aug-09 NEHolt.end 
    ; -- main subfunction begins here --
    (if Aw_debug (princ "\nIN:ladder_cleanup"))
    (cond
      ((= h_or_v_rungs "V")
        ; Erase unused rungs
        (setq xcoor (car first_ladder_XY_org))
        (setq pt3 (list xcoor
                (- (- (cadr first_ladder_XY_org) (* ldr_cnt ladder_2_ladder_dist))
                        (* ladder_width 0.5))
                0.0))            
        (setq ix ladder_rung_cnt)
        (while (> ix 0)
          (if (setq x (wd_get_nearby_line pt3))
            (progn ; hit LINE
              (setq ed (entget x))
              ; check length of LINE
              (if (equal (distance (cdr (assoc 10 ed)) (cdr (assoc 11 ed)))
                  ladder_width 0.1)
                (progn ; this LINE is same width as ladder. Erase LINE.
                  (c:wd_trimwire x pt3)
                )
; ** 04-Aug-09 NEHolt - customer issue with dangling wire
              ; ELSE
                (progn
                  (if (/= plc_keep_shorted_wire 1)
                    (progn ; flag to erase unused wires. Check this wire to see if
                           ; it is not connected at one end. If so, then go ahead and
                           ; consider erasing this dangling wire segment.
                      (erase_if_dangling_wire x pt3)
                ) ) )
; ** 04-Aug-09 NEHolt.end               
          ) ) )
          (setq ix (1- ix))
          (setq xcoor (+ xcoor rung_spacing))
          (setq pt3 (list xcoor (cadr pt3) 0.0))      
        )
       

Conclusion

 The user reports that this specific customization to his local copy of the out-of-the-box wdio.lsp utility works great!

Multiple projects within a “Super” project – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 9:55 am

This has been published before. Back then it was floated as a possible work-around for dealing with large drawing sets. But the idea seems to have resonated with some users and probably deserves a fresh, second look.

The original posting is re-published here with some additional comments.

===

Performance takes a hit when an AutoCAD Electrical project gets very large. Here’s a way to split a project into more manageable sub-projects while still allowing ability to do overall project cross-referencing and reporting functions.

Let’s say you have an electrical design project consisting of three manufacturing cells. Each cell could pretty much be its own “project”. But there is a small amount of interconnection between the cells. And there is a need for overall cross-referencing and full BOM reporting over the whole project. For the most part, each manufacturing cell will be worked on by its own team using AutoCAD Electrical.

Instead of having a single project of a thousand drawings, it would be nice to split this into three smaller sub-projects that can be worked on independently. Then, when necessary, be able to process all three sub-projects as a single project.

There is a work-around to accomplish this. Here’s how.

1. Create all three sub-project files (the “.wdp” ascii text files) in a common folder.

2. Create a new fourth project in this common folder. This extra project will be the overall “super” project and will list ALL of the drawings that are listed in the three sub-projects.

3. Work in a sub-project. But when need to do an overall ”super-project-wide” operation, temporarily make the “super” project the active project. Do the project-wide operation(s). Then flip your original sub-project to be the “active” project again.

  

Simple Example

We’ll just use three small sub-projects containing 10 or fewer drawings each to illustrate how this might work.

Setup

superproj01

We create an overall folder for our project, “PROJ-07″. In this folder we create three sub-projects, “PROJ-07-CELL01″ through “PROJ-07-CELL03″. Each sub-project’s drawings are stored in a separate subfolder (not required but necessary if drawing names are going to be repeated!). 

We create an overall “super” project, “PROJ-07-ALL” as well. It does not have any unique drawings in it. It just references all of the drawings already referenced in all three of the sub-projects.

 

 

 

Here are the drawings in PROJ-07-CELL01:

superproj02

 

 

 

 

 

 

 

 

 

 

superproj03

 

 

 

… and here are the drawings in the sub-projects for CELL02 and CELL03:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 Fired up and Ready to Go

superproj05

Now, with all four projects set up (three sub-projects and the one “super” project), we list all four in the AutoCAD Electrical Project Manager window (at the right), here is what it looks like with all four projects “expanded” to show the individual drawings (below):

 

 

 

 

 superproj06

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

In Operation

superproj07

Let’s say you’ve been assigned to work on CELL02 and you’re currently working on drawing 004.dwg in the CELL02 project. You suddenly have the need to insert an interlock relay contact and cross-reference it… but it is tied to a relay coil that is somewhere in one of the other two sub-projects.

Just temporarily flip the active project to the overall “super” project (moves to the top of the Project Manager list as shown at the right)…

… and do your project-wide operations. Then flip back to the CELL02 project as the “active” project.

That’s it.

Creating the overall “super” project is probably the most tedious part of this whole work-around. You need to include each sub-project’s drawing list. But there is a quick way to do it…

 

  1. Set up your sub-projects with their drawings listed.
  2. Create an empty overall super project.
  3. Open this overall project’s “.wdp” file with an ASCII text editor like wordpad.exe. Scroll to the end of the file.
  4. Open each of the sub-project “.wdp” files with an ASCII text editor. Cut and paste the list of drawings found in the bottom section of each of these “.wdp” files into the bottom of the overall project wdp file.
  5. Save the modified overall project “.wdp” file.

That’s it. It should work.

UPDATE: this idea might also be a good work-around for title block updating. Let’s say that you want to process subgroups of drawings “sheet x of n” within your “super” project. This might be a way to do it… run title block update on each sub-project.

August 9, 2009

User creates custom “Add New Drawing” tool – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 9:11 pm

debbie03

Debbie Guenthner wanted to improve the automation department’s efficiency. It was taking a bit too long for the automation drafters at Kice Industries to correctly set up and add a new, blank drawing to an existing AutoCAD Electrical project.

Kice Industries, located in Wichita, Kansas, has a long history of designing and building a wide range of industrial air systems. A key part of these systems is the electrical controls and AutoCAD Electrical has been the tool of choice for this task for the last four years.

Out-of-the-box

Setting up a new drawing and adding it to the current project is fully supported in out-of-the-box AutoCAD Electrical and shown below in the ACE project manager.

debbie02

This would bring up the generic AutoCAD Electrial “Add drawing” dialog where the user would need to browse to an appropriately-sized template drawing, select a “save to” folder, etc.

Debbie wanted to create a Kice-specific “Add drawing” tool that would have Kice drawing-size option selectable by just a button pick. All of the other stuff would take care of itself. Goal: one button pick and off and running!

A VBA Utility

debbie01Debbie decided to write a small Visual Basic utility to provide a simple pick dialog.

The pick on the dialog would launch a small AutoLISP function which would then create the new drawing from the appropriate template. It would then make a call into the AutoCAD Electrical API to add the new drawing to the project drawing list.

But there was one missing piece to making this work seamlessly…

 

 

 

 

A missing piece

Adding a drawing using the built-in “Add Drawing” tool prompts the user for permission to adjust the new drawing’s “Drawing Properties” to match a set of defaults carried in the overall project “.wdp” file (the “?[n]” entries). But there is no equivalent API call to do this. So, her VB utility would do everything very nicely but the user would then need to manually check the new drawing’s Drawing Properties to make sure that they matched up with the project defaults.

Solution – create a small AutoLISP function to “fill in the missing piece”

The solution was pretty straightforward. Read the project defaults from the “.wdp” project file and save to a list. Next read the new drawing’s invisible “WD_M” block attribute values – this block with its attributes is used to store the “Drawing Properties”. Go through these two lists and compare. For each mismatch, update the corresponding WD_M block attribute with the value pulled from the project defaults carried in the “.wdp” file. There it is.

N8 Consultants put together this small AutoLISP function to deal with the missing piece above:

; ** 06-Aug-09 NEHolt  N8 Consultants LLC  http://n8consultants.com
(defun c:match_proj_properties ( / rtrn proj_default_lst wd_m_entname ix
                x oldval newval change_cnt attrname wd_m_attribute_name_lst)
  ; Make active drawing's WD_M block settings match the defaults
  ; carried in the active project's ".wdp" file - the "?[n]" values.
  ; Skip update of drawing "WD_M" block's "SHEET" attribute value.
 
  ; The attributes carried on the WD_M block are extracted into a 77+ element global list
  ; called "GBL_wd_m". The values in this list correspond to the following list of attribute names
  ; in the order they are shown here.
  (setq WD_M_attribute_name_lst
    (list "RUNGHORV" "REFNUMS" "TAGMODE" "TAG-START" "TAG-RSUF" "TAGFMT"
            "WIREMODE" "WIRE-START" "WIRE-RSUF" "WIREFMT" "WINC"
            "RUNGDIST" "DLADW" "SHEET" "XREFFMT" "RUNGINC" "DRWRUNG" "PH3SPACE"
            "DATUMX" "DATUMY" "DISTH" "DISTV" "CHAR_H" "CHAR_V" "HORIZ_FIRST"
            "XY_DELIM" "WIRELAYS" "WIRENO_LAY" "WIRECOPY_LAY" "WIREFIXED_LAY"
            "UNIT_SCL" "FEATURE_SCL"
            "TAG_LAY" "XREF_LAY" "DESC_LAY" "TERM_LAY" "CXREF_LAY"
            "CDESC_LAY" "LOC_LAY" "POS_LAY" "MISC_LAY"
            "WLEADERS" "PLC_STYLE" "ARROW_STYLE"
            "LINK_LAY" "COMP_LAY" "SHEETDWGNAME" "ALT_XREFFMT" "TAGFIXED_LAY"
            "GAP_STYLE" "MISC_FLAGS" "IEC_PROJ" "IEC_INST" "IEC_LOC"
            "WIREREF_LAY" "MISC_DATA" "FAN_INOUT_LAYS" "FAN_INOUT_STYLE"
            "LOCBOX_LAY" "SORTMODE" "XREF_STYLE" "XREF_FLAGS" "XREF_UNUSEDSTYLE"
            "XREF_FILLWITH" "XREF_SORT" "XREF_TXTBTWN" "XREF_GRAPHIC"
            "XREF_GRAPHICSTYLE" "XREF_CONTACTMAP" "XREF_TBLSTYLE"
            "XREF_TBLTITLE" "XREF_TBLINDEX"
            "XREF_TBLFLDNAMS" "XREF_TBLCOLJUST" "WNUM_OFFSET" "WNUM_FLAGS"
            "WNUM_GAP")
  )
  ; -- program begins here -- 
  (setq change_cnt 0)
  (if (setq rtrn (c:wd_proj_wdp_data))
    (progn ; some data returned from active project's ".wdp" file
      (if (setq proj_default_lst (nth 3 rtrn))
        (progn ; have project defaults, now get active dwg's WD_M values
               ; and push into GBL_wd_m global. Return the entity name
               ; of the WD_M block insert in "wd_m_entname".
          (if (AND (setq wd_m_entname (c:wd_reread_dwg_params))
                   GBL_wd_m) ; valid data pulled from WD_M block insert
            (progn ; now cycle through and look for differences between
                   ; the project settings and the active drawing's
                   ; settings. Skip over the SHEET attribute value.
              (setq ix 0) ; index number    
              (foreach newval proj_default_lst
                (setq oldval (nth ix GBL_wd_m))
                (if (AND oldval (listp oldval))
                  (progn ; old value is a Lisp "list". Convert it to comma-delimited string value
                    (setq oldval (wd_1_lst_to_delim_str oldval ","))
                ) )   
                (if (AND newval oldval (/= newval oldval))
                  (progn
                    (setq attrname (nth ix WD_M_attribute_name_lst))
                    (cond
                      ((= ix 13)) ; skip the SHEET number assignment
                      ((not attrname)) ; no target attribute name, skip
                      ((listp oldval) ; old value is a "list", avoid the complication for now
                        (princ "\nList difference skipped old=")(princ oldval)(princ " new=")(princ newval)
                      )
                      (T ; project default is different from active dwg's
                         ; wd_m block setting. Update.
                        (princ "\n")(princ attrname)
                        (princ " old=")(princ oldval)(princ " new=")(princ newval)
                        (c:wd_modattrval wd_m_entname attrname newval nil)
                        (setq change_cnt (1+ change_cnt))
                    ) )
                ) )
                (setq ix (1+ ix))
              )
          ) )
      ) )
  ) )
  (if (> change_cnt 0)(c:wd_reread_dwg_params)) ; make sure to reread the WD_M block's values
  (princ)
) 

 

Debbie added a call to the above utility in her overall Lisp function “(c:project)” … 

(defun c:project()
  (setq name (getvar "DWGPREFIX"))
  (setq dwg (getvar "DWGNAME"))
  (setq filename (strcat name dwg))
  (c:ace_add_dwg_to_project filename nil)
  (c:wd_tb_process_one 0 (list (list 0 0 0 0 0 0 1 1 0 0 1 1 1) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))
  (c:match_proj_properties)
  (princ)
)

… that is then called from within her VB program…

'Update ladder numbers to match filename
    If frmSheetValues.txtDwgSeries.Text = "C" Then
        ThisDrawing.SendCommand ("wd_ladr_reref ")
    ElseIf frmSheetValues.txtDwgSeries.Text = "IO" Then
        ThisDrawing.SendCommand ("wd_ladr_reref ")
    End If           
        'If true then the new drawing is added to the active project.
    If chkProject.Enabled = True Then
        ThisDrawing.SendCommand "(c:project) "
 

Conclusion

Debbie added these utilities to the Startup Suite. Everything now works perfectly!

August 7, 2009

Quick-fix for blank line issue in PnlPurchBOM “User Post”

Filed under: AutoCAD Electrical — nateholt @ 2:02 pm

Doug McAlexander called about a customer issue with listing a repeating ITEM number in a purchase-list format panel bill of materials.

Here’s an example of the original issue… showing the BOM entry lists every occurrence of the tallied component as its own line in the BOM report.

purbom01

purbom02

 

 

The original fix was to select the “User Post” button and run the little utility to suppress the repeated ITEM numbers.

 

 

 

 

purbom03

 

 

 

But, when the ITEM number column is shown but there is no ”TAGS” or “HDL” or other parallel column shown, the report ends up with empty, blank lines for those suppress entries.

Doug needed the “User Post” utitility for this report type to be a bit more clever and somehow suppress these blank lines from the customer’s reports.

 

 

 

 

A simple work-around

purbom04N8 Consultants took a look and here’s a one-line fix that seemed to address the problem.

The first step was to find the AutoLISP utility that runs when the “User Post” button is selected from the Panel Purchase-list format BOM report. Just look at the Command window after picking the User Post button. The full file-name is shown…

 

 Next, make a backup copy of this file.

 

Modify the pur_pbom.lsp file – add one line

Now… open it with the AutoCAD Visual Lisp editor or any ASCII text editor. Down, near the bottom… add this line of code shown highlighted in red:

(if (= user_3 "1")
        (progn ; Suppress repeated numbers in ITEM column
          (setq newdatalst nil)
          (foreach lst combined_data
            ; Process the "ITEM" numbers list. Blank out adjacent repeats
            (setq itemlst (nth 22 lst))
            (setq new_itemlst nil) ; start with empty list
            (setq lastitem nil)
            (foreach x itemlst
              (if (= x lastitem) ; repeat of previous
                (progn
                  (setq x "") ; blank it out
                  (setq blanked T)
                )
              ; ELSE
                (setq lastitem x) ; save last non-blank item 
              )
              (setq new_itemlst (cons x new_itemlst))
            )
           
            (while (= (car new_itemlst) "")(setq new_itemlst (cdr new_itemlst))) ; ** 06-Aug-09 NEHolt
            ; Put back into original order
            (setq new_itemlst (reverse new_itemlst))
            (setq lst (wd_nth_subst 22 new_itemlst lst))
            (setq newdatalst (cons lst newdatalst))
          ) 
          (setq combined_data (reverse newdatalst))
      ) )

Save the file. That’s it.

Test

   Now Doug tries the report again…

  purbom05

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 …and confirms that the fix “works perfectly” for this reporting scenario.

Customer happy.

Doug McAlexander happy.

purbom06

August 4, 2009

Support file finder – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 10:31 pm

Recently moved from XP to Vista. It had been a pain to learn/remember where AutoCAD Electrical support files were located. Now, the deck is re-shuffled. Who knows where the AutoCAD Electrical support files are now!?!

Here are a couple little tricks to help you find your way around.

Standard: ”(findfile <filename>)” function

This is one of the base AutoLISP functions, not AutoCAD Electrical-specific. It will search all standard AutoCAD support paths for the target file you pass to it as its single argument. If it can find the file after searching the list of AutoCAD support paths in the order they’re defined, it will return the full path plus file name. If not found, it will return “nil”.

For example, I wanted to find the Spreadsheet –> PLC I/O generator source file wdio.lsp. But where is it on my new Vista installation?

This file happens to be installed in one of the AutoCAD support paths (under OPTIONS –> Files). So, I should be able to type this at the command prompt:

Command:(findfile “wdio.lsp”) [Enter]

findfile01

The “findfile” function finds my file! Its full path returned!

Note: the double backslashes is a Lisp display thing. Each double backslash display really represents a single backslash character in the file name string.

Better: AcadE-specific file search function: “(c:ace_find_file <filename> options)”

But AutoCAD Electrical has some paths to support files that are not part of the normal AutoCAD support path list. For example, I needed to open the catalog look-up database file “default_cat.mdb” with a copy of Microsoft Access. Where is that file on my Vista install?!? Typing in (findfile “default_cat.mdb”) returned nil. No good. The file is in one of the support paths specific to AutoCAD Electrical and not defined as a normal AutoCAD support path.

The solution is this function listed in the AutoCAD Electrical API help (below). It is a generic file finder function that checks for a target file in the various AutoCAD Electrical paths AND, if not found, it checks for it in the normal AutoCAD support paths (i.e. does the above ”findfile” !).

findfile04

Looks like this function can be used for AutoCAD Electric path searches AND the regular “findfile” basic AutoCAD path searches.

Typing this function at the “Command:” prompt revealed the file’s location:

Command: (c:ace_find_file “default_cat.mdb” 3) [Enter]

findfile02

Using a 3 for the options argument above triggers the function to look in all of the extra support folders for PLC and for catalog lookup files.

Getting Fancier

Here’s a little program that does the above but also supports a search for electrical “.dwg” library symbols. For example, I want to open and edit my active project’s parent push button symbol for horizontal wire insert, normally-open contact. From experience, I can guess that the library symbol’s name is probably HPB11.dwg. But where is it installed on my Vista-based system??? Combining the (c:ace_find_file…) function above with this schematic libary search function (c:wd_does_block_exist…) shown in bold below, this little utility should do it all.

(defun c:acefindfile ( / str fnam )
  (setq fnam nil)
  (setq str (getstring " File name with extension: " T))
  (if (AND str (/= str ""))
    (progn
      ; First check all normal AutoCAD Electrical paths plus
      ; the normal AutoCAD support paths
      (if (not (setq fnam (c:ace_find_file str 3)))
        ; No luck yet. Check active project's library paths for
        ; match on ".dwg" file name.
        (if (not (setq fnam (c:wd_does_block_exist str) ))
          ; Still no good. Try panel layout libs.
          (setq fnam (wd_fio_does_pnlblock_exist str))
  ) ) ) )
  (if fnam
    (princ fnam) ; display nil if not found, otherwise return full file name
                 ; unless file is a block instance on active drawing. In that case
                 ; just return the block name.    
  ; ELSE
    (princ " File not found")
  )
  (princ)              
)

Let’s try it. Copy and paste the above into a little ASCII text file and call it acefindfile.lsp. APPLOAD or “(load…)” it. Then type this at the command line:

findfile03

… and there it is!

Note: if this HPB11 block had been in the active drawing, this tool would have returned that block name and would not have done a search for the file on disk.

July 28, 2009

Gerald’s reset-fixed-tag tool – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 9:24 pm

fixed2unfixed02A reader looked a recent posting on this blog and had an idea.

He downloaded the posting’s code, modified it, and created a cool, brand-new AutoCAD Electrical productivity tool. Awesome!

Here is what Aceri Nederland’s Gerald te Wierik did with the recent blog posting (Gerald is shown here, at the left, with a big AutoCAD Electrical smile).

 

 

Project Re-tag, Cross-reference, and “Fixed tag” reset tool

Here is what Gerald says about the need for this new tool.

“The goal for this routine was that after generating the drawings with Typical Manager we have to retag the components, except the cables because we can have star/delta motor circuits for example. In that case the same cablename is used multiple times on the parent cable markers. If we reset and retag the complete project we lose the link between those cables.”

The re-tag and the re-cross-reference parts of Gerald’s tool were pretty straightforward. But the missing piece was a need for a way to go through the drawing set and selectively turn any “fixed” component tag attributes back to “normal” EXCEPT FOR cable markers! This basically meant renaming each block instance’s TAG1F attribute back to TAG1 UNLESS the component was a cable marker… in which case the utilty would leave it alone.

A recent 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 Gerald was not interested in changing the TAG1F attribute value, he wanted to change the TAG1F attribute name. So he took this utility and modified it to rename a target attribute instead of changing a target attribute’s value. He only had to modify a small number of lines of code in the original utility to accomplish this new behavior – i.e. flip “fixed” component tags back to nomal tags UNLESS the component is a cable marker symbol.

The small code change to change the utility’s function

Here is the key part of the original blog entry utility:

(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 oldval (cdr (assoc 1 edd)))      
      (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

… and here are the key changes Gerald made to alter what the utility would do (i.e. change attribute tag name instead of changing attribute value):

(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")                       
           (= (cdr (assoc 2 edd)) "TAG1F"))
    (progn ; yes, found target attribute tag
      (setq ed (wd_dbx_entget ben_hdl dwg_hdl (list "*"))) ; open the block insert instance
      ; Get block name. Check if it is a parent cable marker (block name = "HW01" or "VW01") 
      (setq blknam (cdr (assoc 2 ed)))     
      (if (not (wcmatch blknam "VW01,HW01"))       
        (progn ; not a parent cable marker, go ahead and flip the "fixed"              
          ; TAG1F attribute tag name to the normal TAG1 attribute name         
          (setq newedd (subst (cons 2 "TAG1")(assoc 2 edd) edd)) ; Change TAG1F into TAG1        
          (wd_dbx_entmod newedd dwg_hdl) ; push new TAG name out

DCL file to create a front-end dialog

Gerald created a small ASCII text file to define a simple dialog for his 3-part tool. Here’s what it looks like when the command is launched with the “fixed” tag reset option highlighted.

fixed2unfixed01

Gerald’s tool - try it

Gerald invites you to give it a try. Download the AutoLisp file here and the supporting dialog DCL file here. Put both files into some folder that is in the AutoCAD support path. APPLOAD the AutoLisp file, then type TNEC [Enter] at your “Command:” prompt. The above dialog should appear (if it does not, then confirm that the DCL file tag_normal_except_cables.dcl is in an AutoCAD support file path).

Here’s is a short Gerald te Wierik bio:  I’m working as support/application engineer at Aceri Nederland BV. Providing demonstrations, consulting, implementation, training and project management for AutoCAD Electrical, Electrical Designer  and Typical Manager. Prior to Aceri I worked for 6 years at an Autodesk Reseller as trainer and support engineer for AutoCAD, AutoCAD Mechanical, Electrical Designer, Engineering and Data management applications.

July 27, 2009

Overview of AutoCAD Electrical’s WDATA table – intermediate wire network data table

Filed under: AutoCAD Electrical, Tutorials — nateholt @ 4:48 pm

Lines and blocks/attributes are used to construct “smart” schematic diagrams in AutoCAD Electrical. This raw information automatically finds its way into the WDATA table in the active project’s scratch database file. Further processing and formatting (i.e. time consuming) eventually pushes this data into the finished WFRM2ALL and WNETLST tables. But, with care, this intermediate WDATA table data can be parsed to obtain complete wire network data without the overhead of the additional processing. The format of the WDATA table’s data is briefly outlined here with examples. It may provide benefit in creating custom AutoCAD Electrical applications that have a need for speed.

WDATA table in the overall scheme of things

The project’s wire connection information is pulled into various tables in the project scratch database, processed, and then presented in several forms as separate tables in the project scratch database.

Wire network processing takes place with the scratch database serving as temp storage for raw wire and component connection data (includes WIREFRM2, WIRESEG, WIRENET tables). This is processed into an intermediate wire network result (the WDATA table). Finally, a full from/to version of the data is formatted in a separate operation (table WFRM2ALL and an alternate format WNETLST tables).

 The first two levels of processing (pulling in the raw wire and component connection data and then creating the intermediate wire network results) are done automatically by the “running in the background” project database service (i.e. “PDS”). When a drawing in a project is changed, even without QSAVING the drawing, PDS will eventually recalculate all wire networks and update through to the WDATA table.

 The “final”, full form of the wire from/to data in tables WFRM2ALL and WNETLST is derived from this WDATA table’s data. These two new tables only update if user does a full rebuild with wire connection option checked or invokes some ACADE command that requires full from/to wire data (ex: panel footprint annotation with schematic wire connection data or a project-wide wire from/to report).

 This WFRM2ALL/WNETLST table update can be a bit time consuming whereas the data in WDATA is always being updated, behind the scenes, by PDS. With care, complete or nearly comple wire network information can be derived directly from this WDATA table.

WDATA table format

The WDATA table’s data is in a format that is a bit confusing. Some examples will illustrate how to decode it.

 Example 1 – simple, single wire connection between two components, all on same drawing, no source/destination arrows involved, no gap/loop involved.

wdata01

The handle numbers for the entities are hand-drawn in RED.

The entry in the project scratch database file’s WDATA table for this wire network, is reproduced below:

wdata02

 

 

Example 2 – more complex network with two source arrows going to three split-off continuation pieces of the network.

wdata03

The handle numbers for the entities are hand-drawn in RED and the source/destination arrow SIGCODE values are shown in BLUE.

The entry in the project scratch database file’s WDATA table for this wire network, a bit more complex, is reproduced below. Since there are four distinct pieces of the network tied together with source/destination arrows, there are four records in the database for this overall network.

One record shows two “Source arrow” SIGCODE values. There are three other records in the WDATA table that have matching “Destination arrow” SIGCODE values. This means that these three records tie into the first record, forming one big wire network.

The breakdown of each of these four records for wire number “1” is the same as described in the first example.

wdata04

So, to build up this split-up network stored in four separate records, here is what needs to happen. 

Program processes all networks that have neither Source nor Destination codes. What is left will be networks that are split.

Begin with first split network record. Gather up list of Source/Destination codes. Scan all remaining records for others that reference either one of these Source or Destination codes. For each found, add to the list of records that are to be combined into one big network. If other Source/Destination codes are found in these added records, add to the running list and make a second pass to collect any additional network pieces. When no more to add to the list, process the multi-piece list as one big network ( ! )

Project-wide attribute value update’r – AutoCAD Electrical

Filed under: AutoCAD 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)
)

July 23, 2009

Text to Attribute conversion tool – AutoCAD Electrical

Filed under: AutoCAD Electrical — nateholt @ 9:28 am

AutoCAD Electrical has a set of tools for converting “dumb” schematic drawings into semi-smart AutoCAD Electrical schematics. One of these tools, the Convert Text to Attribute Definition conversion tool, can come in handy for some other tasks.

Last night I was looking over a new user’s drawing set. He had constructed a complex servo drive schematic symbol. It inserted fine into his schematics and he could wire it up using AutoCAD Electrical’s INSERT WIRE command. The servo’s wiring reported in the various from/to reports but was lacking some useful information.

There was no reporting of the servo’s terminal pin number in the wire from/to report. A small portion of the wired servo symbol is shown below, servo symbol on the right and wiring coming in from the left. The various wire from/to reports would report wire number “07023″ coming from some device and tying to servo such-and-such, but the report would NOT say that wire 07023 tied to terminal pin connection number “27″.

text2attdef01

Exploding the servo symbol revealed the problem. The wire connection attributes were there and correct (ex: X4TERM12, X4TERM13,…), but the terminal pin number and its description text were both fixed text entities! AutoCAD Electrical had no way to link a wire connection on the symbol to its terminal pin text value.

text2attdef02

These terminal pin numbers needed to really be attribute definitions with appropriate tag names (TERM12, TERM13, … to match up with their wire connection attribute names) and with pre-defined default values (27, 28,…). As a bonus, the extra description text to the right of each terminal pin text could be converted to tag-names TERMDESC12, TERMDESC13, … (again, to match up with their wire connection attribute names) and with default values of “I/O COMMON” and so on. This would provide ability for terminal pin description text to also be included in the various from/to reports.

If both terminal pin and terminal description text entities were converted to appropriately tagged attribute definitions, then the from/to wire connection reporting would be much more complete. Fixing this very large/complex library symbol… the prospect was to go back, open up this servo library symbol “.dwg” in AutoCAD, and then manually/painfully replace each one of the several dozen text entities with equivalent attribute definitions. Not a happy thought.

Rescue

But using the “Convert Text to Attribute Definition” tool hidden on the Conversion Tools ribbon made this task almost painless.

text2attdef03

 

Start the conversion command. Pick on the “27″ text entity (if it is MTEXT, need to explode it first). The dialog below pops up. Enter in the attribute definition name “TERM12″ to match with the wire connection attribute X4TERM12 and hit OK. The existing text is flipped to an attribute definition “TERM12″ with a default value of “27″.

text2attdef04

The command loops around and prompts you to keep going. Pick on the next text entity to convert and the dialog pops up with the previous TERM12 default. Hit the “>” arrow to increment the tag name to the next value, TERM13. Hit OK. Keep going till done!

text2attdef05

A cool thing about this technique is that the attribute definition carries the same text font and justification and size as the original text AND the original text’s value becomes the attribute defintion’s default value.

July 16, 2009

Propagating AutoLISP variables drawing to drawing – the ( vl-propagate…) function

Filed under: AutoCAD Electrical, Tutorials — nateholt @ 12:52 pm

The last posting gave an example utility to do a find/replace on substrings with MText entities. When going from one drawing to another in AutoCAD, this function could “remember” the previous find and replace substrings, even when AutoCAD was running in its normal “multiple drawing interface” mode.

This was made possible by using the VisualLisp “Blackboard”. The first time the utility was executed, the user’s “find” and “replace” substrings were pushed out to the blackboard. Then, on subsequent runs of the utility, possibly on other drawings later opened in the session, the utility would check the blackboard and retrieve any saved values. These then presented as defaults to the user.

There’s another way to do this, it works well and is a tiny bit simpler. It is to use the (vl-propagate…) function to preset a given AutoLISP variable to a preset value for all open drawings.  It eliminates the “check the blackboard” step. And, even cooler, it presets this variable for any future drawings opened during the AutoCAD session (see highlighted VisualLisp help shown below)!

mtext03

Both the blackboard and propagate methods are detailed here using the last posting’s AutoLISP utility as an example.

Drawing to drawing values – the “Blackboard” method

Here is a snippet from the original version of the utility. It deals with checking for a previous “find” substring value, previously saved on the blackboard as “save_find”. This check for “save_find” on the blackboard happens on the third line down - the call to the function ”vl-bb-ref”.

; Look for previous find/replace substrings stored on the
  ; "black board". If found, present these as defaults.
  (setq default_find (vl-bb-ref 'save_find))
  (if (AND default_find (/= default_find ""))
    (progn ; default "find" string found from previous run
      (setq find default_find) ; default from previous run
      (setq find (getstring (strcat "\nFind [" default_find "]=") T))
      (if (= find "")(setq find default_find)) ; use previous
    )
  ; ELSE
    (setq find (getstring "\nFind=" T))
  )
  (if (AND find (/= find ""))
    ; Save the "find" string on the "black-board" for
    ; reference next time command is invoked.
    (vl-bb-set 'save_find find) 
  ) 

And, in the last line above, the current value of the “find” AutoLISP variable is pushed out to the blackboard with the call to “vl-bb-set”. This enables the “find” substring value to be retrieved on subsequents runs of the utility (using the vl-bb-ref function above!).

Drawing to drawing values – the “Propagate” method

 Here is the same snippet but using the “vl-propagate” function. It is a bit cleaner / simpler. The key thing to remember here is to NOT list the propagated AutoLISP variables as “local” variables in the utility’s definition.

; Look for previous find/replace substrings that have been
  ; "propagated" to Lisp variables "default_find" and "default_replace"
  ; in all dwgs of current session, whether open or yet to be opened.
  (if (AND default_find (/= default_find ""))
    (progn ; default "find" string propagated from previous run
      (setq find default_find) ; default from previous run
      (setq find (getstring (strcat "\nFind [" default_find "]=") T))
      (if (= find "")(setq find default_find)) ; use previous
    )
  ; ELSE
    (setq find (getstring "\nFind=" T))
  )
  (if (AND find (/= find ""))
    (progn ; Save the "find" string out to variable "default_find" for all
           ; other open drawings or those that will be opened during this
           ; AutoCAD session.
      (setq default_find find) ; set the value into "default_find"
      (vl-propagate 'default_find) ; preset variable "default_find" everywhere 
  ) )

What happens with this one call to (vl-propagate ‘default_find) is that this AutoLISP variable and its value at the moment the vl-propagate function is executed is suddenly visible within any other drawings open on the screen… AND this variable will magically appear preset to the initial value in any future drawings you open during your AutoCAD session!

Conclusion

There it is. I wish I had stumbled across vl-propagate a bit sooner. It would have simplified setting up an AutoLISP utility’s processing of multiple-drawing in a batching operation.

Older Posts »

Blog at WordPress.com.