Making a table from dynamic blocks in a drawing, referencing visibility state and one particular attribute

Making a table from dynamic blocks in a drawing, referencing visibility state and one particular attribute

wsonnek
Contributor Contributor
3,132 Views
58 Replies
Message 1 of 59

Making a table from dynamic blocks in a drawing, referencing visibility state and one particular attribute

wsonnek
Contributor
Contributor

I'm working on yet another lisp (y'all got me hooked, I swear) that's attempting to take all the blocks in a drawing and make a table with them. I started with the two lisps linked below - the first one was almost exactly what I wanted for a table, but didn't handle the dynamic blocks well. The second counted dynamic blocks, but didn't have a way to make a good table. I tried to combine them and kinda wrecked it. Either way, neither of them allowed for counting based on the SIZE attribute, which is kind of important.

 

Basically, I have a ton of different 2D valves in a drawing. The valves are dynamic so I can switch between types (ball, globe, gate, etc) in-place without messing with the size. The size is an attribute (2", 3", 1/2", etc) for the block. There are a few stand-alone valves that I also need to count. I want the table to be "Block Name" "Block Type" (that's the visibility state) "Block Size" (attribute). That way I can quickly tally up what I've got in the drawing  and figure out how many 2" ball valves I need, 3" butterfly valves, etc.

 

Thoughts?

 

https://www.lee-mac.com/dynamicblockcounter.html

https://www.lee-mac.com/blockcounter.html

 

0 Likes
Accepted solutions (1)
3,133 Views
58 Replies
Replies (58)
Message 21 of 59

paullimapa
Mentor
Mentor

What you can try to do is run the dataextraction command once on a sample dwg in a fixed folder location.

This will create a template dxe based on that sample named dwg in that folder location.

Now when you need to create the table count for a specific dwg you're currently in, run lisp function that will first saveas a copy of the dwg into that folder location using the same sample dwg name, then again with lisp run the command line version of dataextraction referencing the dxe template to create the table. After table creation the lisp function does a saveas again back to the original location using the original dwg name. You may want to review this discussion thread on this possibility:

Bypass AutoCAD Data extraction wizzard - Autodesk Community


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
0 Likes
Message 22 of 59

wsonnek
Contributor
Contributor

Let's see if I can't stick a file here...

 

Some dynamic blocks, some regular, all have SIZE attribute and need mapping.

0 Likes
Message 23 of 59

wsonnek
Contributor
Contributor

Hmm. I think I messed something up - I can't get any output now.

0 Likes
Message 24 of 59

wsonnek
Contributor
Contributor

I found that. It is...somewhat similar? Ish?--to what I'm looking to do, but the issue is that it's not practical with 10+ drawings per project, not counting the 3Ds. Tracking what's been saved/finished & what hasn't will turn into a logistical nightmare. Running a table in each drawing is more what I'm looking for.

0 Likes
Message 25 of 59

komondormrex
Mentor
Mentor

should have got, see below, but.... some blocks missing visibility property...skipped. need to tune the code

komondormrex_0-1740423392199.png

 

0 Likes
Message 26 of 59

wsonnek
Contributor
Contributor

Yeah, there's a mix of regular and dynamic blocks. I'd like to make it so the table lists the block name, visibility name (if there is one), SIZE attribute, and count for same. So in the example above, it would look something like this:

wsonnek_0-1740423886900.png

 

 

 

0 Likes
Message 27 of 59

komondormrex
Mentor
Mentor

check updated code below and what it outputs. that list has to finally go to the autocad table.

 

(defun parse_list (_list / unique_list old_member)
	(foreach _member _list (if (not (member _member unique_list)) (setq unique_list (append unique_list (list _member)))))
	(setq unique_list (mapcar '(lambda (_member) (cons _member 0)) unique_list))
	(foreach _member _list
		(if (setq old_member (assoc _member unique_list))
				(setq unique_list (subst (cons (car old_member) (1+ (cdr old_member))) old_member unique_list))
		)
	)
)

;******************************************************************************************************************************************************************************

(defun c:get_the_valves (/ insert_sset valve_list size_attribute vis_property)
  (if (setq insert_sset (ssget "_x" '((0 . "insert") (66 . 1))))  ;selects all attibuted inserts
    (progn
	(setq valve_list (parse_list
			   (vl-remove nil
		       		(mapcar '(lambda (insert) (if (and (vl-some '(lambda (attribute) (= "SIZE" (vla-get-tagstring (setq size_attribute attribute)))) 
			                  			    	     (vlax-invoke insert 'getattributes)
			              			           )
								   ;checks if there is "SIZE" tagged attribute in insert
				                                   (if (vl-some '(lambda (dyn_property) (= "Visibility1" (vla-get-propertyname (setq vis_property dyn_property))))
								    	     	 (vlax-invoke insert 'getdynamicblockproperties)
								       )
								       (setq vis_property_value (vlax-get vis_property 'value))
								       (setq vis_property_value "")
							           )
								   ;checks if there is "Visibility1" dynamic property in insert
		                           	      	      )
						      	      (list (vla-get-effectivename insert) vis_property_value (vla-get-textstring size_attribute)) 
		                  	          	  )
				     	 )
			  	     	 (mapcar 'vlax-ename->vla-object (vl-remove-if 'listp (mapcar 'cadr (ssnamex insert_sset))))
			    	)
	             	   )
		         )
	)
      	(foreach valve valve_list (princ "\n") (princ valve))
    )
  )
  (princ)
)

 

 

komondormrex_1-1740425006139.png

 

 

0 Likes
Message 28 of 59

wsonnek
Contributor
Contributor

DANG that's nice! Thank you! I should be able to port that into a table lisp and add a prompt for selections, right?

wsonnek_0-1740424820873.png

 

0 Likes
Message 29 of 59

komondormrex
Mentor
Mentor

sure thing)

0 Likes
Message 30 of 59

wsonnek
Contributor
Contributor

This may be because I'm mashing two different sections together but I'm clearly screwing something up. The lisp still works, but I can get a selection or a table.

 

(defun parse_list (_list / unique_list old_member)
	(foreach _member _list (if (not (member _member unique_list)) (setq unique_list (append unique_list (list _member)))))
	(setq unique_list (mapcar '(lambda (_member) (cons _member 0)) unique_list))
	(foreach _member _list
		(if (setq old_member (assoc _member unique_list))
				(setq unique_list (subst (cons (car old_member) (1+ (cdr old_member))) old_member unique_list))
		)
	)
)

;******************************************************************************************************************************************************************************

(defun c:LISTBLOCKS (/ insert_sset valve_list size_attribute vis_property)
(prompt "\nSelect Area: ")
  (if (setq insert_sset (ssget "_x" '((0 . "insert") (66 . 1))))  ;selects all attibuted inserts
    (progn
	(setq valve_list (parse_list
			   (vl-remove nil
		       		(mapcar '(lambda (insert) (if (and (vl-some '(lambda (attribute) (= "SIZE" (vla-get-tagstring (setq size_attribute attribute)))) 
			                  			    	     (vlax-invoke insert 'getattributes)
			              			           )
								   ;checks if there is "SIZE" tagged attribute in insert
				                                   (if (vl-some '(lambda (dyn_property) (= "Visibility1" (vla-get-propertyname (setq vis_property dyn_property))))
								    	     	 (vlax-invoke insert 'getdynamicblockproperties)
								       )
								       (setq vis_property_value (vlax-get vis_property 'value))
								       (setq vis_property_value "")
							           )
								   ;checks if there is "Visibility1" dynamic property in insert
		                           	      	      )
						      	      (list (vla-get-effectivename insert) vis_property_value (vla-get-textstring size_attribute)) 
		                  	          	  )
				     	 )
			  	     	 (mapcar 'vlax-ename->vla-object (vl-remove-if 'listp (mapcar 'cadr (ssnamex insert_sset))))
			    	)
	             	   )
		         )
	)
      	(foreach valve valve_list (print valve))
    )
  )
  (princ)
)
;******************************************************************************************************************************************************************************
(defun makeblocktable (lst / aco adoc cls cw hh p1 rn rws spc th tbss tbs ts)
   (vl-load-com)
   (setq aco  (vlax-get-acad-object)
         adoc (vla-get-ActiveDocument aco)
         spc  (if (> (getvar "CVPORT") 1)(vla-get-modelspace adoc)(vla-get-paperspace adoc))
         tbss (vla-item (vla-get-dictionaries adoc) "acad_tablestyle")
         th   (if (= (getvar "measurement") 1) 3.2 0.13);; Alter these values for Data Text Height Preference.
         hh   (if (= (getvar "measurement") 1) 3.2 0.13);; Alter these values for Header Text Height Preference.
         ts   "Standard" ;; Alter this for preferred Text Style
         cw   (if (= (getvar "measurement") 1) 25.0 1.0) ;; Alter for preferred column Width.
   )
   (if
      (vl-catch-all-error-p ;;try to get the existing Style
         (vl-catch-all-apply '(lambda ()(setq tbs (vla-item tbss "MyPipeTable"))))
      )
      (progn
         ;; Create Table Style.
         (setq tbs (vla-addobject tbss "MyPipeTable" "AcDbTableStyle"))
         ;; Set Table Style properties.
         (vla-put-description    tbs "Block Table")
         (vla-put-FlowDirection  tbs acTableTopToBottom)
         (vla-put-HorzCellMargin tbs 0.06)
         (vla-put-VertCellMargin tbs 0.02)
         (vla-settextheight      tbs acDataRow th)
         (vla-settextheight      tbs (+ acHeaderRow acTitleRow) hh)
         (vla-settextstyle       tbs (+ acDataRow acHeaderRow acTitleRow) ts)
         (vla-setalignment       tbs (+ acDataRow acHeaderRow acTitleRow) acMiddleCenter)
      )
   )
   (if (setq p1 (getpoint "\nSelect Top Left corner of Table: "))
      (progn
         (setq rws (+ 1 (length lst)) rn 1 cls 4
               tbl (vla-addtable spc (vlax-3D-point p1) rws cls (* th 1.25) cw)
         )
         (vla-put-RegenerateTableSuppressed tbl :vlax-true)
         (vla-put-stylename tbl "MyBlockTable")
         (vla-put-TitleSuppressed tbl :vlax-true)
         (vla-EnableMergeAll tbl 0 1 :vlax-false)
         (vla-unmergecells tbl 0 0 0 2)
         (vla-settext tbl 0 0 0 0 "Block Name:")
         (vla-settext tbl 0 1 0 0 "Block Varient:")
	 (vla-settext tbl 0 0 1 0 "Size:")
	 (vla-settext tbl 0 0 0 1 "Quantity:")
         (foreach n lst
            (vla-settext tbl rn 0 (rtos (* 2 (car n))))
            (vla-settext tbl rn 1 (rtos (cadr n)))
            (setq rn (1+ rn))
         )
         (vla-put-RegenerateTableSuppressed tbl :vlax-false)
         (vla-regen adoc acAllViewPorts)
      )
   )
)
0 Likes
Message 31 of 59

Sea-Haven
Mentor
Mentor

You may want to set column widths.

 

(vla-setcolumnwidth tbl 0 30) 
(vla-setcolumnwidth tbl 1 100) 
(vla-setcolumnwidth tbl 2 30) 
and so on
0 Likes
Message 32 of 59

komondormrex
Mentor
Mentor

hey there,

check the following

 

;**********************************************************************************************************************************************************************
;
; 	'add_valves_table' custom command for ws
;	komondormrex, feb, 2025
;	totally free of lm
;
;**********************************************************************************************************************************************************************

(defun get_text_length (text_string text_size / dtext_box_list)
	(if (= "" text_string)
		0
		(progn
			(setq dtext_box_list (textbox (list '(0 . "TEXT") (cons 1 text_string) (cons 7 (getvar 'textstyle)) (cons 40 text_size))))
			(+ (* 2 text_size) (- (caadr dtext_box_list) (caar dtext_box_list)))
		)
	)
)

;**********************************************************************************************************************************************************************

(defun add_table_from_list (table_list table_headers / table_text_size table_object row_index column_index columns_widths)
	(if (null table_text_size_saved) (if (zerop (getvar 'measurement)) (setq table_text_size_saved (/ 3.5 25.4)) (setq table_text_size_saved 3.5)))
  	(if (null (setq table_text_size (getreal (strcat "\nEnter table data text size <" (rtos table_text_size_saved) ">: "))))
  		(setq table_text_size table_text_size_saved)
  		(setq table_text_size_saved table_text_size)
  	)
  	(setq table_object (vla-addtable (vla-get-block (vla-get-activelayout (vla-get-activedocument (vlax-get-acad-object))))
  										 (vlax-3d-point (getpoint "\nSet table insertion point (Left Upper Corner): "))
  										 (+ 2 (length table_list)) 																					;	number of rows
  										 (length table_headers) 																					;	number of columns
  										 (* 2.5 table_text_size)             																		;	row height
  										 1

  						  )
  		   row_index -1
  		   column_index -1
  	)
	(vla-deleterows table_object 0 1)
	(vla-put-regeneratetablesuppressed table_object :vlax-true)
	(mapcar '(lambda (list_member) (vl-catch-all-apply 'vla-setcolumnwidth (list table_object (car list_member) (cadr list_member))))
			 (mapcar '(lambda (column_width) (list (setq column_index (1+ column_index)) column_width))
					  (setq columns_widths (mapcar '(lambda (string) (get_text_length string table_text_size)) table_headers))					;	width of column 0 thru last
			 )
	)
	(setq table_list (cons table_headers (mapcar '(lambda (row) (append (car row) (list (itoa (cdr row))))) table_list)))
	(foreach row table_list
		(setq column_index -1
			  row_index (1+ row_index)
			  columns_widths (mapcar 'max columns_widths (mapcar '(lambda (string) (get_text_length string table_text_size)) row))
		)
		(foreach column row
			(vla-settext table_object row_index (setq column_index (1+ column_index)) (nth column_index row))
			(if (and (> row_index 0) (zerop column_index))
				(vla-setcellalignment table_object row_index column_index acmiddleleft)
				(vla-setcellalignment table_object row_index column_index acmiddlecenter)
			)
			(vla-setcelltextheight table_object row_index column_index table_text_size)
			(vla-setrowheight table_object row_index (* 2.5 table_text_size))
		)
	)
	(setq column_index -1)
	(mapcar '(lambda (list_member) (vl-catch-all-apply 'vla-setcolumnwidth (list table_object (car list_member) (cadr list_member))))
			 (mapcar '(lambda (column_width) (list (setq column_index (1+ column_index)) column_width))
					  columns_widths
			 )
	)
	(vla-put-regeneratetablesuppressed table_object :vlax-false)
)

;******************************************************************************************************************************************************************************

(defun parse_list (_list / unique_list old_member)
	(foreach _member _list (if (not (member _member unique_list)) (setq unique_list (append unique_list (list _member)))))
	(setq unique_list (mapcar '(lambda (_member) (cons _member 0)) unique_list))
	(foreach _member _list
		(if (setq old_member (assoc _member unique_list))
				(setq unique_list (subst (cons (car old_member) (1+ (cdr old_member))) old_member unique_list))
		)
	)
)

;******************************************************************************************************************************************************************************

(defun get_the_valves (/ insert_sset valve_list size_attribute vis_property vis_property_value)
	(prompt "\nPick the valves to be listed in a table...")
	(if (setq insert_sset (ssget '((0 . "insert") (66 . 1))))  ;selects all attibuted inserts
		(setq valve_list (parse_list
				   			(vl-remove nil
			       				(mapcar '(lambda (insert) (if (and (vl-some '(lambda (attribute) (= "SIZE" (vla-get-tagstring (setq size_attribute attribute))))
				   				               			    	       	 	 (vlax-invoke insert 'getattributes)
				   				           			           	   )	;checks if there is "SIZE" tagged attribute in insert
				   					                               (if (vl-some '(lambda (dyn_property) (= "Visibility1" (vla-get-propertyname (setq vis_property dyn_property))))
				   									    	     	 			 (vlax-invoke insert 'getdynamicblockproperties)
				   									       			   )	;checks if there is "Visibility1" dynamic property in insert
				   									       			   (setq vis_property_value (vlax-get vis_property 'value))
				   									       			   (setq vis_property_value "")
				   								           		   )
			       				                    	      )
				   							      	      	  (list (vla-get-effectivename insert) vis_property_value (vla-get-textstring size_attribute))
			       				           	           	  )
				   					    )
				   					    (mapcar 'vlax-ename->vla-object (vl-remove-if 'listp (mapcar 'cadr (ssnamex insert_sset))))
				   				)
		           			)
			         	 )
		)
    )
)

;******************************************************************************************************************************************************************************

(defun c:add_valves_table (/ valves_list)
	(if (setq valves_list (get_the_valves))
		(add_table_from_list valves_list '("Block Name" "Block Type" "Size" "Count"))
	)
	(princ)
)

;******************************************************************************************************************************************************************************

 

Message 33 of 59

wsonnek
Contributor
Contributor

That works PHENOMENALLY on my 2D drawing! Can't get it to pick up the 3D blocks for some reason. I thought they'd be the same but there must be a different property that I'm missing. I'll see if there's a tweak I can use, thank you so much!

0 Likes
Message 34 of 59

wsonnek
Contributor
Contributor

Follow-up question - is there a 2D parameter in here somewhere that I am missing? I've been over this quite a few times but I can't figure out how to have it grab 3D blocks.

0 Likes
Message 35 of 59

komondormrex
Mentor
Mentor

you know the drill. post a sample with non-grabbable 3d-block. 

0 Likes
Message 36 of 59

wsonnek
Contributor
Contributor

My apologies, I thought it would be a simple parameter substitution. Here's a sample file.

0 Likes
Message 37 of 59

komondormrex
Mentor
Mentor

well, these have no attribute,

komondormrex_0-1740646456478.png

while

komondormrex_1-1740646575968.png

you are not as dangerous as ought to be)

0 Likes
Message 38 of 59

wsonnek
Contributor
Contributor

I missed that. I thought it was a 2D vs 3D problem. I'll look at it again, but I'm guessing I can't just remove that line without blowing the code up?

0 Likes
Message 39 of 59

komondormrex
Mentor
Mentor

you cannot!

0 Likes
Message 40 of 59

Sea-Haven
Mentor
Mentor

You can change this line removing the (66 . 1)

(if (setq insert_sset (ssget '((0 . "insert") (66 . 1))))

But then the code has to have next "does the Insert have atrributes" if not then dummy up an attribute value for the table visibilty & Size say "-" then count will still work.

@komondormrex  may read this and perhaps consider amending his solution.

0 Likes