Looking for an easy way to extract attributes
I am looking for an easy way to extract attributes from a drawing. I am vague on the details of the attribute exraction template that the ATTEXT command. But, it seems like you have to know in advance the names of any possible attribute tags. In my case, this is not practical. So, I was hoping there was a utility to just extract all attributes from all blocks. Ideally, in a form such as a text file that can be easily put into Excel, where they can be organized.
I recall trying to do this years ago, and there was a utility to put text in the drawing after extracting all the data. Rather than do this, I think it is better to just generate the text file directly. Note that it has been many years since I have done any programming, so I am trying to avoid having to do any programming or even tweaking on my own.
Any suggestion?
Joe Dunfee
Comments
-
Of course, I have continued to try to find a solution. Some years ago, I had found some LISP that I customized, but it no longer works. I did just find a version that writes text to the drawing with all the attributes in a arrangement like a table (but not a table entity). However, this is just not anything I can take out and do anything with. Each field and record is an individual text object. I can't paste these in any other program. I think I was expecting Bricscad to have the EATTEXT command or something comparable.
I have found other AutoCAD programs, but they all want to create a table object, which Bricscad doesn't allow.
It CAN'T be this hard to get all that attribute data out of Bricscad. . My search in the help files only show the attext command, nothing more advanced. I think the attext command is from AutoCAD version 10 DOS, without any changes over two decade..
What am I overlooking?
Joe Dunfee
0 -
Hello Hoe,
Don't sweat it out! If you want to consider using a third-party application, here is the solution (see link below)
http://www.4d-technologies.com/geotools/manual/block_tools.htm#ATTEXT
GeoTools offers 'easy Attrtibute Extraction' and over 270 more tools to help improve your Bricscad (and AutoCAD) productivity by leaps and bounds.
Let me know if you have any questions.
Regards
Rakesh Rao
http://rakeshrao.typepad.com0 -
Since the 4D attribute extractor does not do a global extraction of all blocks, I continued to look for another source. I found a shareware LISP program that seems to be very nicely done.
http://lee-mac.com/macatt.html
However, that I get an error when it comes time to actually extract the info and create the file;
** Error: Automation Error 80020009; Error accessing [GETINTERFACEOBJECT] method. ErrIndex=0
I am certainly not a skilled LISP programmer (thought I dabbled a bit in it a few years back). Would there be an easy way to fix the problem above?
Joe Dunfee
0 -
The GT_ATTEXT command works one block at a time, but once the block name is defined, it can extract all (or selected) block attributes in the current drawing. In that sense, it is global. I am not sure what you mean by "cannot extract globally". Normally, people would not like to extract all block attributes from multiple named blocks into one single file. That would be messy and confusing.
In the meantime, I received another request from an existing client to be able to make a list of all unique attributes to each block and spit out a report into a text file. I am currently working on this tool as an enhancement to our GT_COMPAREBLKATTS tool that already spits out a list of unique block attribute tags and the names of the blocks having these tags. I am mentioning just in case this interests you.
Regards
Rakesh Rao
www.coordsys.com0 -
Mr Rao, thank you for your attention to this. I was not expecting so much attention from a commercial programming company. I especially like the way you make your tools available as low-cost individual purchases, instead of a higher cost for the entire package.
To be more detailed about my own needs, by Globally, I meant that it would extract all attributes for all blocks. In my case, there are a number of blocks, and I am afraid I might miss selecting one of the blocks I need to account for. True, the results would be messy, since the blocks each have their own set of tags. But, hopefully the output would be clear enought to read if it were organized appropriately.
Here is the example I sent to your company [view in a monospace font like courier].
===============================================
Block name|Quantity |Tag:Size |Tag:Price
Window 10 24x36 $120
Window 3 36x36 $150
Block name|Quantity |Tag:Style |Tag:Size |Tag:Cost
Door 4 Wood#232 30x82 $120
Door 2 Steel#2431 32x82 $-
Door 1 Closet#22 24x72 $34
Block name |Quantity
FuseBox2 1
=============================================I had used an old program years ago that did a similar thing, but it would only insert the results as text. Each individual tag being its own text object. When there were a lot of objects, it became unmanagable.
Joe Dunfee
0 -
I use one which inserts the results as text. I use a second lisp called Count which totals all like instances of text from any selection, again adding the results as text if that's any use.
PASTE CODE HERE(DEFUN C:COUNT (/ oldl oldp act1 b num act2 upd lst a n ss exp)
(SETQ OS (GETVAR "OSMODE"))
(SETVAR "OSMODE" 0)
(if (/= 0 (cdr (assoc 40 (tblsearch "style" (getvar "textstyle")))))
(progn
(princ "\nTextsize must be 0 ")(terpri))
(progn
(setq oldl (getvar "clayer"))
(COMMAND "LAYER" "M" "DEFPOINTS" "")
(SETQ OLDP (GETVAR "LUPREC"))
(SETVAR "LUPREC" 0)
(Defun act1 ()
(while (/= num (sslength ss))
(setq b (ssname ss num))
(if (= (cdr (assoc 1 (entget a)))
(cdr (assoc 1 (entget b))))
(progn (setq n (+ 1 n))
(ssdel b ss)(setq num (- num 1))))
(setq num (1+ num)))
)
(defun act2 ()
(setq upd (STRCAT (cdr (assoc 1 (entget a))) " " (rtos n)))
(SETQ LST (APPEND LST (LIST UPD)))
(ssdel a ss)(setq a (ssname ss 0))
(setq num 1)(setq n 1)
)
(SETQ LST NIL)
(setq ss (ssget))
(setq a (ssname ss 0))
(setq num 1)
(setq n 1)
(while (/= 0 (sslength ss))(act1)(act2))
(SETQ LST (ACAD_STRLSORT LST))
(SETQ P1 (GETPOINT "\nStart Point For Text: "))
(setq n 0)
(while (/= n (length lst))
(setq exp (nth n lst))
(command "text" p1 "" "" exp)
(setq n (1+ n) p1 (polar p1 (* 1.5 pi)(* 0.4 (getvar "LTSCALE"))))
)
(SETVAR "LUPREC" OLDP)
(command "layer" "m" oldl "")
))
(SETVAR "OSMODE" OS)
)0 -
I can coax Excel to count totals of unique items. It is just getting all the information out seems to be the difficutly. What program are you using to get the attributes as text? Does it create a separate text entity for each attribute like the one I have does? If it would just put everything in one mtext item, then perhaps I could copy-past the text into Excel
Joe Dunfee.
0 -
Joe, I was going to recommend Lee Macs program to you but Bricscad does not have the ObjectDBX functionality required to make it work. Having said that, someone with a little lisp knowledge should definately be able to accomplish the same thing on a single (open) drawing.
0 -
This gets up to 3 attributes from each block and lists each att separately as Text, in a line for each block.
You can increase the possibilities and Strcat each line, but it suits me this way.
I think originally I had to redo some blocks I typically use, so their att's would appear in the right order. That is, the order in which they were created dictates the order in which they are read?
I can't cut/paste the result for export, I think you would have to modify it to send them off to a file then cut/paste from there. That's how I came to do it within Bcad.
(DEFUN c:CAT ()
(SETVAR "CMDECHO" 0)
(if (/= 0 (cdr (assoc 40 (tblsearch "style" (getvar "textstyle")))))
(progn
(princ "\nTextsize must be 0 ")(terpri))
(progn
(setq oldl (getvar "clayer"))
(COMMAND "LAYER" "M" "DEFPOINTS" "")
(SETQ OLDP (GETVAR "LUPREC"))
(SETVAR "LUPREC" 0)
(setq ss (ssget "x" (list (cons 0 "ATTRIB"))) n 0 p1 nil p1 (getpoint "\nStart Point: "))
(while (/= n (sslength ss))
(setq a (ssname ss n) b (entnext a) c (entnext (entnext a))
d (entnext (entnext (entnext a)))
p (cdr (assoc 2 (entget b)))
q (cdr (assoc 1 (entget b)))
p2 (polar p1 0 (* (getvar "textsize") 12))
p3 (polar p1 0 (* (getvar "textsize") 24))
p4 (polar p1 0 (* (getvar "textsize") 36)))
(command "text" p1 "" "" p)
(command "text" p2 "" "" q)
(if (= "ATTRIB" (cdr (assoc 0 (entget c))))
(progn
(setq r (cdr (assoc 1 (entget c))))
(command "text" p3 "" "" r)))
(if (= "ATTRIB" (cdr (assoc 0 (entget d))))
(progn
(setq s (cdr (assoc 1 (entget d))))
(command "text" p4 "" "" s)))
(setq n (1+ n) p1 (polar p1 (* 1.5 pi)(* (getvar "LTSCALE") 0.4)))
)
(SETVAR "LUPREC" OLDP)
(command "layer" "S" oldl "")
)))0 -
John, thank you for that code. I think it is similar to the one I am already having difficulty with. But, this one is shorter, so it may be easier for me to decode.
I just tried the CAT.LSP routine as you uploaded it. The test drawing was a simple one with only blocks in it. I initiate the "cat" command and it generates the following error immediately after I select a point;
: cat
Start Point:
; ----- LISP Error : Call Stack -----
; [0]...C:CAT <<--
;
; ----- Error around expression -----
(SSLENGTH SS)
;
; error : bad argument type <NIL> ; expected SELECTIONSET at [SSLENGTH]I tried it both without having anything selected, and pre-selecting the blocks.
0 -
Here is the code I created a few years ago. It didn't work properly because the text was getting some other stuff inserted somehow. I ended up abandoning the attempt, and now that I want it again, I don't recall enough of LISP to follow it again.
; Program to create a list of all blocks with attributes
; It then creates a mtext object with the list.
; VERSION DATE APRIL 11, 2011.
; NOTE THAT THIS VERSION IS NOT WORKING CORRECTLY.
;
; Then, the contents of the mtext list can be copied
; and then pasted into a word processor to be modified
; so it can be pasted into something like Excel.
;
; Since tabs can't be used to separate attributes, they
; are each on a new line. To delineate when a new block
; is started, the phrase "---RECORD SEPARATOR---" is
; inserted.
; Later, by pasting the text into a word processor and
; performing a search-and-replace to replace all returns
; [i.e. ^p] with a tab [i.e. ^t]. Then, the phrase
; "---RECORD SEPARATOR---" can be replaced with a carriage
; return [^p]. The results of all this can be copied and
; then pasted into a spread sheet.
;
; Variables used
; oldl - store current layer (clayer) to restore later.
; oldp -the old precision (luprec) to restore later.
;
;********************************
(DEFUN c:CATALOG ()
(SETVAR "CMDECHO" 0) ;Turn off echo of prompts
;Test if text style is set to a height of zero
(if (/= 0 (cdr (assoc 40 (tblsearch "style" (getvar "textstyle")))))
;Beginning of Then statement
(progn
(princ "\nTextsize must be 0 ")(terpri))
;Beginning of Else statement, which is the main program
(progn
(setq oldl (getvar "clayer"))
(COMMAND "LAYER" "M" "DEFPOINTS" "")
(SETQ OLDP (GETVAR "LUPREC")) ;Store lunits precision to restore it later
(SETVAR "LUPREC" 0) ;Set decimal places for lunits variable to zero
(setq ss (ssget "x" '((0 . "INSERT")(66 . 1))) n 0 p1 nil p1 (getpoint "\nStart Point: "))
(while (/= n (sslength ss))
(setq a (ssname ss n) b (entnext a) c (entnext (entnext a))
d (entnext (entnext (entnext a)))
p (cdr (assoc 2 (entget b)))
q (cdr (assoc 1 (entget b)))
p2 (polar p1 0 (* (getvar "textsize") 12))
p3 (polar p1 0 (* (getvar "textsize") 24))
p4 (polar p1 0 (* (getvar "textsize") 36)))
(if (= "ATTRIB" (cdr (assoc 0 (entget b))))
(progn
(setq p (cdr (assoc 2 (entget a))))
(command "mtext" p1 p2 p)))
(if (= "ATTRIB" (cdr (assoc 0 (entget b))))
(progn
(setq q (cdr (assoc 1 (entget b))))
(command q)))
(if (= "ATTRIB" (cdr (assoc 0 (entget c))))
(progn
(setq r (cdr (assoc 1 (entget c))))
(command r)))
(if (= "ATTRIB" (cdr (assoc 0 (entget d))))
(progn
(setq s (cdr (assoc 1 (entget d))))
(command s "---RECORD SEPARATOR---")))
(setq n (1+ n) p1 (polar p1 (* 1.5 pi)(* (getvar "LTSCALE") 0.4)))
)
(SETVAR "LUPREC" OLDP)
(command "layer" "S" oldl "")
)))Joe Dunfee
0 -
@ Joe, daniel AT cadext.com, I have one you can try
0 -
@ Joe, oops.... email me @ daniel AT cadext.com, I haveone you can try
0 -
Joe, are there attributes in the blocks? If Cat finds none it gives that message.
Also, it extracts without you selecting, just pick a place for the text to start. The blocks don't even need to be on a thawed layer.
One of the reasons it is fairly short is it doesn't have luxuries like error trapping or helpful descriptions.
I wrote it for Acad originally and have used it on files/blocks other than mine, so it is reasonably 'transportable'.
0 -
Hey Joe, these are remarkably similar. Lucky there are no issues of copyright here though it's not polished enough to be commercial.
I doubt anyone but I would have chosen those variables, the text positioning of 12, 24 & 36 times Textsize or the limit of 4 Att's per block.
This is my single most useful routine, it was the first lisp which had to work in Intellicad when I originally tried it out.
0 -
Yes, John, I am sure I had modified existing code which probably came from you.
Also, thank you to Rakesh Rao, and his company, which has been very responsive to my queries.
There are a lot of first-class people on this list. It has been invaluable in my ability to use Bricscad.
Joe Dunfee
0