daveacad Posted March 7, 2009 Posted March 7, 2009 hi evrb! i need a big help. i'm working to make quiet easier and faster my activity of measurment for BOM with autocad. i'm not a programmer, so viva all autocad forums! what i'm looking for has two order of problem to solve 1. i'm looking for a lisp or something like, to put values of a block with attributes in a table (acad 2007): if i have in the block 5 attributes, i need to write in a table the values of them. in the first column should be write the first attribute value, in the second, the value of the second attribute, and so on. 2. the second part of the problem is something like "dynamic blocks". if one or more value(s) of attribute(s) in a block(s) are changed, the same value should be automatically updated (in the table). can someone give a help? maybe with the possibility to select more than one block at time (not one by one) and then pick the table where to write in. hope i've been clear with my request. dave. Quote
dave buckberry Posted March 8, 2009 Posted March 8, 2009 Why Dont you Use Data extraction In Autocad this Will Give you both Of Your answers in 1 hit Quote
daveacad Posted March 8, 2009 Author Posted March 8, 2009 Why Dont you Use Data extraction In Autocad this Will Give you both Of Your answers in 1 hit ... becouse Data extraction (both, normal and via express tools) is the last step of the work, when you need to export data to excel or openofiice or anithing like. what i need i a tool easy to use to connect data stored in a block with a table. and also, before someone else suggest to use the table creation wizard, that way is not useful for the work. cheers, dave Quote
Hardeight Posted March 11, 2009 Posted March 11, 2009 Here is some code that I use to do almost the exact same thing. Gathers blocks by name Changes layer of block to an attribute in the block Filters out duplicates Clears out existing schedule if it exists Inserts lines into the schedule with info from the blocks ;THE FUNCTION BELOW SAVES THE USER SETTINGS ;SSETUP (defun ssetup () (setq atdia (getvar "attdia")) (setvar "attdia" 0) (setq scmde (getvar "cmdecho")) (setvar "cmdecho" 0) (setq curlay (getvar "clayer")) (setvar "clayer" "Schedule") (setq snap (getvar "osmode")) (setvar "osmode" 16567) );DEFUN END ;THE FUNCTION BELOW CHANGES THE LAYER NAME TO THE PARTNUMBER OF THE BLOCK. ;LAY2ATT (DEFUN LAY2ATT (/ SSID I THISEN ENTLYST THISLAY ) (SETQ SSID(SSGET "X" (LIST(CONS 0 "INSERT")(CONS 2 "PARTID")(CONS 66 1)))) (IF (/= SSID NIL) (PROGN (SETQ I (SSLENGTH SSID)) (WHILE (NOT(MINUSP(setq I (1- I)))) (PROGN (SETQ THISEN(SSNAME SSID I)) (SETQ ENTLYST (ENTGET THISEN)) (SETQ THISLAY(DXF 8 ENTLYST)) (NAVALUE THISEN "PARTNUMBER" THISLAY) );PROGN END );WHILE END );PROGN END (PROGN (ALERT "THERE ARE NO PART ID'S IN YOUR DRAWING") (PRINC) );PROGN END );IF END );DEFUN END ;THE FUNCTION BELOW COLLECTS THE PART ID'S TO USE IN THE SCHEDULE ;GETPART (defun getpart (/ i2 bEnt ent elist aval attLst) (if (setq ssid (ssget "X" (list (cons 0 "INSERT") (cons 2 "PARTID") (cons 66 1)))) (progn (setq i2 (sslength ssid)) (while (not (minusp (setq i2 (1- i2)))) (setq bEnt (ssname ssid i2)) (setq ent (entnext bEnt)) (while (/= "SEQEND" (cdadr (setq elist (entget ent)))) (if (equal (cdr (assoc 2 elist)) "PARTNUMBER") (setq aval (cdr (assoc 1 elist)));ELSE ) (setq ent (entnext ent)) ) (if (member aval attLst) (ssdel bEnt ssid);ELSE (setq attLst (cons aval attLst)) ) ) ) (alert "No Blocks Found.") ) (princ) );DEFUN END ;THE FUNCTION BELOW DELETES THE CURRENT CONTENTS OF THE SCHEDULE AND SETS THE OFFSET TO 0 ;DELETE SCHEDULE (defun DeleteSchedule (/ SSSCHEDULE SCHDCNT SCHEDULEENTID) ;Delete the truss line blocks (setq ssSchedule (ssget "X" (list (cons 0 "INSERT") (cons 2 "BOMLINE") (CONS 66 1)))) (if (/= ssSchedule nil) (progn (setq Schdcnt (sslength ssSchedule)) (while (not (minusp (setq Schdcnt (1- Schdcnt)))) (entdel (ssname ssSchedule Schdcnt)) );WHILE END );PROGN END );IF END (setq ssSchedule (ssget "X" (list (cons 0 "INSERT") (cons 2 "BOMSCHD") (cons 66 1)))) (if (/= ssSchedule nil) (progn (setq ScheduleEntId (ssname ssSchedule 0)) (navalue ScheduleEntId "OFFSET" "0") );PROGN END (Alert "\nYou must have a Bill of Materials Schedule block inserted to use this application.") );IF END );DEFUN END ;THE FUNCTION BELOW SORTS THE SELECTION SET BY THE PARTNUMBERS TO USE IN THE SCHEDULE ;SORTSSID (defun SortSSid () ; Sorts the selection set according to Part Number ; Copy ssid entity names to SortList (setq SortList (list "")) (setq slong (sslength ssid)) (while (not (minusp (setq SLONG (1- SLONG)))) (setq SortList (cons (cons (avalue (ssname ssid SLONG) "PARTNUMBER") (ssname ssid SLONG)) SortList)) );WHILE END ; Get rid of the space at the end of the list (setq sortlist2 (reverse SortList)) (setq sortlist (cdr sortlist2)) (setq SortList (bsort SortList)) ; Now that we've sorted the list, go through the original ssid and copy the sorted version (setq ssidSorted (ssadd)) (setq mcnt 0) (setq slong (length SortList)) (while ( (setq CurrentEntity (cdr (nth mcnt SortList))) ; For each of the entities in SortList, copy that entity ; in ssid to ssidSorted (ssadd CurrentEntity ssidSorted) (setq mcnt (1+ mcnt)) );WHILE END );DEFUN END ;THE FUNCTION BELOW INSERTS THE LINE INTO THE SCHEDULE WITH COLLECTED INFORMATION ;BOMLINE (defun bomline () (setq idcnt 0);SETS IDCNT COUNTER TO 0 (setq MARK 1);SETS MARK NUMBER TO THE FIRST TO BE USED (1) (setq sidlong (sslength ssidSorted));SETS SIDLONG TO THE LENGTH OF SSIDSORTED (while ( (setq ssmark (ssadd)) (setq pid (ssname ssidSorted 0)) (setq pmark (avalue pid "PARTNUMBER")) ; Copy ssidSorted to tempss (setq tempss (ssadd)) (setq mcnt 0) (setq slong (sslength ssidSorted)) (while ( (ssadd (ssname ssidSorted mcnt) tempss) (setq mcnt (1+ mcnt)) ) (setq mcnt 0) (while ( (setq pid (ssname tempss mcnt)) (setq curmark (avalue pid "PARTNUMBER")) (if (equal curmark pmark) (progn (ssadd pid ssmark) (ssdel pid ssidSorted) (setq idcnt (1+ idcnt)) ) ) (setq mcnt (1+ mcnt)) ) (setq tmp2ss (ssadd)) (setq clong (sslength ssmark)) (setq mcnt2 0) (while ( (ssadd (ssname ssmark mcnt2) tmp2ss) (setq mcnt2 (1+ mcnt2)) );WHILE (setq tcnt (sslength TMP2SS)) (setq rcnt 0) (setq totcnt 0) (while ( (setq pid (ssname ssmark 0)) (setq PNUM (avalue pid "PARTNUMBER")) ;Copy ssmark to tmp3ss (setq tmp3ss (ssadd)) (setq clong (sslength ssmark)) (setq mcnt3 0) (while ( (ssadd (ssname ssmark mcnt3) tmp3ss) (setq mcnt3 (1+ mcnt3)) ) (setq schdss (ssadd)) (setq schdss (ssget "X" (list (cons 0 "INSERT") (cons 2 "BOMSCHD")))) (setq blkid (ssname schdss 0)) (setq ents (entget blkid)) (setq spoint (cdr (assoc 10 ents))) (setq soffset (distof (avalue blkid "OFFSET") 2)) (setq spoint (polar spoint (dtr 270) soffset)) ;in here is where we are going to get the part descripion informaitn from the db (setq ConnectString "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=m:\\CADRef.mdb;Jet OLEDB:System Database=m:\\Workgroups\\MerDBSecure.mdw") (if (not (setq ConnectionObject (ADOLISP_ConnectToDB ConnectString "USER" "PASSWORD")) ) (progn (prompt "\nConnection failed!") (ADOLISP_ErrorPrinter) );progn end (prompt "\nResult: succeeded!") );if end (setq SQLStatement (strcat "SELECT * FROM CADParts WHERE ProductNumber ="" ""'"pnum"'")) (prompt (strcat"\n\nExecuting a SELECT statement to retrieve some data:\n\""SQLStatement"\"") ) (if (setq Result (ADOLISP_DoSQL ConnectionObject SQLStatement)) (progn (setq desclist (cadr result)) (if (= desclist nil) (setq descr "Please enter part description.");else (setq descr (cadr desclist)) );if end );progn end (progn (prompt "\nFailed!") (ADOLISP_ErrorPrinter) );progn end );if end (prompt "\n\nDisconnecting from the database\n") (ADOLISP_DisconnectFromDB ConnectionObject) (setq ConnectionObject nil) (setq Curquan (getstring (strcat "\nEnter quantity for part number " PNUM " : "))) (if (= 0 totcnt) (command "insert" "BOMLINE" spoint "1" "1" "0" descr PNUM curquan mark 0 ) ) (setq totcnt (1+ totcnt)) (navalue blkid "OFFSET" (rtos (+ soffset 0.75) 2)) (setq rcnt (1+ rcnt)) (SETQ CURLAY PNUM) (SETQ CURSS (ssget "X" (list (cons 0 "INSERT")(cons 2 "PARTID")(cons 66 1)(CONS 8 CURLAY)))) (setq CURcnt 0) (setq CURlng (sslength CURSS)) (while ( (setq curid (ssname CURSS CURcnt)) (navalue curid "ID" (ITOA MARK)) (NAVALUE CURID "DESCRIPTION" DESCR) (setq CURcnt (1+ CURcnt)) (ENTUPD CURID)) (SETQ MARK (1+ MARK)) ); THIS ENDS THE SSMARK USE LOOP ); end of main loop ); end of BOMLINE ;THE FUNCTION BELOW RESTORES THE USER SETTINGS ;RSETUP (defun rsetup () (setvar "attdia" atdia) (setvar "cmdecho" scmde) (setvar "clayer" curlay) (SETVAR "OSMODE" SNAP) (princ) );DEFUN END ;MAIN PROGRAM (DEFUN C:BOM () (SSETUP) (LAY2ATT) (GETPART) (DELETESCHEDULE) (SORTSSID) (BOMLINE) (RSETUP) );DEFUN END Quote
Hardeight Posted March 11, 2009 Posted March 11, 2009 I also use some subroutines in this that automatically extract and insert info into the blocks. AVALUE ;THE FUNCTION BELOW - Returns the value of an attribute;SYNTAX (SETQ VARIABLENAME (AVALUE BLOCKNAME "ATTRIBUTENAME")) (defun avalue (bname aname) (setq cnt 0) (setq ent bname) (while (= cnt 0) (setq ent (entnext ent)) (setq entl (entget ent)) (setq entn (cdr (assoc 2 entl))) (if (equal entn aname) (progn (setq cnt 1) (setq aval (cdr (assoc 1 entl))) );progn ); if ); while ); avalue NAVALUE;THE FUNCTION BELOW - Changes value of an attribute to a new value; SYNTAX (NAVALUE BLOCKNAME "ATTRIBUTETAG" NEWVALUE) (defun navalue (bname aname naval) (setq cnt 0) (setq ent bname) (while (= cnt 0) (setq ent (entnext ent)) (setq entl (entget ent)) (setq entn (cdr (assoc 2 entl))) (if (equal entn aname) (progn (setq cnt 1) (setq entl (subst (cons 1 naval) (assoc 1 entl) entl)) (entmod entl) );progn ); if ); while ); navalue And also a sort routineBSORT ;THE FUNCTION BELOW - SORTS LISTS BY THE SLECTED VARIABLE.;Bsort (defun BSORT (data-list / rslt item1 item2 collector) (while ; main loop (progn (setq ; intialize variables item1 nil item2 nil rslt nil ; recursion control: while loop ) ; EXECUTE ONE BUBBLE-SORT CYCLE (repeat (length data-list) (if (= nil item1) ; first cycle - initalize item1 (setq item1 (car data-list) data-list (cdr data-list) ) ) (if (= nil item2) (setq item2 (car data-list) data-list (cdr data-list) ) ) (cond ( (= nil item1)) ; defensive programming ( (= nil item2) ; almost at the end of the list (setq collector (append collector (list item1))) ) ; * the comparison functions are here * ; this could be modified to sort by CADR, etc... ( (cond ( (atom item1) ( ( T ( ) (setq ; if the above returned T collector (append collector (list item1)) item1 item2 ; shuffle item2 over to item1 for simplicity item2 nil ) ) ( T ; otherwise the first item was larger than the second (setq collector (append collector (list item2)) item2 nil ) ; force another recursion - when all item1's are ; then the sort is complete & the initialized nil value in RSLT ; stops the higher-level while loop (setq rslt T) ) ) );repeat (setq data-list collector collector nil ) rslt ) ) data-list ) Also, not sure if you will need it or not but I use ADOLisp Subroutines to access a MSACESS Database and get info from it. You can search for ADOLisp to find all of those codes. As far as the dynamic thing, I'm not even sure if it can be done. You might have to write a separate code to make changes to your table and upon completion it refreshes the data. Maybe Someone else will have some ideas on that one. Hope this helps. Quote
H2Powerman Posted March 13, 2009 Posted March 13, 2009 Here is some code that I use to do almost the exact same thing. Gathers blocks by name Changes layer of block to an attribute in the block Filters out duplicates Clears out existing schedule if it exists Inserts lines into the schedule with info from the blocks This looks fantastic! Just to reinterate a minute. This will build a BOM from the blocks that you add to your drawing, correct? I am a pretty big newb to the AutoCAD world and received a need to have something similar. I have a drawing set with multiple blocks of several PID configurations we for multiple layouts in the same drawing. I had a question on how to change this to ask me what is being shown in the layout tab? Or is there a way to assign a tag to the properties of the items being displayed and have it update a table with the reference tag. So I assign part xyz1 and then in the table I make it into variable text of IF xyz1 exists then TRUE, True = string "xyz1 part #" if FALSE then "". And finally if xyz1 > 2 = "new part #" Thoughts? Thanks in advance, I hope I was somewhat clear. Quote
chavlji Posted March 14, 2009 Posted March 14, 2009 To update table when attribute changes you would probably need to use a reactor. Quote
wizman Posted March 14, 2009 Posted March 14, 2009 here's through field: http://forums.cadalyst.com/showthread.php?t=6430 Quote
Hardeight Posted March 16, 2009 Posted March 16, 2009 This looks fantastic! Just to reinterate a minute. This will build a BOM from the blocks that you add to your drawing, correct? I am a pretty big newb to the AutoCAD world and received a need to have something similar. I have a drawing set with multiple blocks of several PID configurations we for multiple layouts in the same drawing. I had a question on how to change this to ask me what is being shown in the layout tab? Or is there a way to assign a tag to the properties of the items being displayed and have it update a table with the reference tag. So I assign part xyz1 and then in the table I make it into variable text of IF xyz1 exists then TRUE, True = string "xyz1 part #" if FALSE then "". And finally if xyz1 > 2 = "new part #" Thoughts? Thanks in advance, I hope I was somewhat clear. Yes you could change the info being put into the table with an if or cond statement. They might be kinda lenghty But it wouldn't be a problem. Just do search for the values and depending on what was in them insert a different block with different info slots. This is kind of a long routine for a beginner but hey we all started some place right? My best advice is dont be afraid to get in there and get your hands dirty with some data. learn how to fully use your VLIDE and set some breakpoints and keep an eye on what kind of data your code is coming back with. Work on one routine at a time . That was what helped me the most. And the good fellas at the forum. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.