LISP to remove only certain attributes from any block in a drawing

LISP to remove only certain attributes from any block in a drawing

Anonymous
Not applicable
7,156 Views
78 Replies
Message 1 of 79

LISP to remove only certain attributes from any block in a drawing

Anonymous
Not applicable

I'm in a unique situation and I've been trying to either create or find a LISP routine solution to my problem.

 

I have a large quantity of dynamic blocks that I extract coordinate information from.  Think a rectangles with 4 corners of data.  I use a predefined attribute called "COORDS_1", "COORDS_2", "COORDS_3", "COORDS_4", etc.... all the way up to "COORDS_12".  The attributes are fields tied to a "point / node" in the block that return coordinate information as an attribute value.

 

Since the attributes are predefined - when I redefine the blocks with new attribute data (each block has up to 50 attributes that are updated) - the predefined attributes try to maintain the old "preset" data instead of accepting the new data.  I can't use "constant" because the coordinate data won't update with the location in the drawing and only stays constant - referencing the location inside the block.

 

I've currently written an update lisp that compiles a list of drawing files from a folder, compares the drawing names in the folder with the block names ina  drawing.  Anything that matches gets redefined and attsync'd to the new values.  For the "Coords_#" attributes that are predefined - I would need the lisp routine to first remove any instance of "COORDS_#s" that matches the file names in the folder.

 

Any pointers or help to point me in the right direction would be great.  Thanks!

0 Likes
7,157 Views
78 Replies
Replies (78)
Message 41 of 79

john.uhden
Mentor
Mentor

There ya go.  The block's name is "*U43" which means it is an anonymous block.  Maybe its "effectivename" is "COMBUSTIBLE WATER." (whatever)

What this means is that either you shift to non-dynamic blocks, or would it work for you to select the blocks on screen?  Or I rewrite my code to iterate through all the blocks to find the effectivename that matches your search criteria.  Or we attack all the blocks, no matter what their name.

John F. Uhden

Message 42 of 79

Anonymous
Not applicable

For my purposes - it would need to find the effective name as I'm not always redefining all of the blocks when I'm running the routine.  I wonder what using the effectivename on the attribute removal will do as far as the "insertion" vs block definition differences I was seeing earlier?

 

We use a block property table with over 50 attribute data points driving the size, shape, and other attributes that wouldn't be easily possible without dynamic blocks.

0 Likes
Message 43 of 79

SeeMSixty7
Advisor
Advisor

I think if you used a lookup table(text file, excel file, or table in a database) for those values instead of storing them all in the block attributes, you would eliminate a lot of size in your file, processing time of your drawing as well as any updates made by a drafter working in the drawing. That is a lot of data that could be stored externally and tied back in for whatever process you are using the data for.

 

Let me know if you want to look at this path.

 

You could also take another path entirely and look at Revit. You could build each of these as a family and then just have parameters, and properties available to you in the family. It would provide all the data directly within the one file, like you seem to want to do here.

 

The easier path in my opinion is simply store the data externally to your AutoCAD file.

 

Good luck,

Message 44 of 79

Anonymous
Not applicable

Haven't had the chance to reply to your e-mail with all of the details yet... Our biggest hurdle we have encountered in trying to use a database / excel file / etc... is each time a dynamic block is manipulated - it changes identifier and breaks the link.  However, I would love to find out more and will e-mail you offline since you have the files to look over with me.  Thanks for the suggestions!

Message 45 of 79

john.uhden
Mentor
Mentor

Hey Clint:  For his immediate needs, would the effectivename property be available with the insertion (reference), or is it available only in the block definition?

John F. Uhden

Message 46 of 79

SeeMSixty7
Advisor
Advisor

John,

 

The Effectivename is available at the insert. using (vla-get-effectivename insertobject)

 

I think that is what you are asking. As quick way to run through the drawing and process all the inserts that match the blockname can be done like this.

There is a block in the code that you would then run your attdel function for that insert entity.

 

Does that help?

 

(defun findblocks(blkname)
	(setq myss (ssget "X" '((0 . "INSERT"))))
	(if myss 
		(progn
			(setq mynum (sslength myss) 
			      mycnt 0 
			)
			(while (< mycnt mynum) 
			    (setq blkent (ssname myss mycnt)
			          blkobj (vlax-ename->vla-object blkent) ; get the entity object
			          blktruename (vla-get-EffectiveName blkobj); get the effective block name (dynamic block store actual name here)
			          mycnt (1+ mycnt); bump the counter
			    ); close the setq
			    (if (= blktruename blkname)
			    	(progn
			    		;;;Do your stuff here
			    		(princ "\nFound one")
			    	)
			    )
		   )
	    )
	    (princ "\nNo BLOCKS Found")
	 )
	 (princ)
)
Message 47 of 79

john.uhden
Mentor
Mentor
That's the answer for which I was looking.
Of course I can't test it here, but it's very straight forward.

John F. Uhden

Message 48 of 79

SeeMSixty7
Advisor
Advisor

Good deal! Yeah I didn't think you had any problem with the process, thought I would just share that for sake if someone just wants that part.

 

Sorry I kind of got you sucked into this thread when I offered up your attdel command/function from a few years back. Then I got hammered at work and didn't have time to dig into it any more. Now it seems you and Kevin have been working pretty diligently on getting a solution.

 

Keep up the great work! Good luck.

Message 49 of 79

Anonymous
Not applicable

Okay - I'll have to process that and see if I can wrap my head around it... I really appreciate the help...,

 

Clint - is there a way to simplify that down to say - find me every block that matches the base filename in this directory (filenames are store current in a selection set titled "FILES") and is found in the drawing (tblsearch block "blkname") and the run the internal attdel against that entire list?  I guess what I'm asking - can you lump the effective names into a list that I can then pass through the attdel before even doing the redefine?

0 Likes
Message 50 of 79

SeeMSixty7
Advisor
Advisor

@Anonymous wrote:

 

Clint - is there a way to simplify that down to say - find me every block that matches the base filename in this directory (filenames are store current in a selection set titled "FILES") and is found in the drawing (tblsearch block "blkname") and the run the internal attdel against that entire list?  I guess what I'm asking - can you lump the effective names into a list that I can then pass through the attdel before even doing the redefine?


Yes you can basically create a list of blocks you want to search for then process all inserts in the drawing. If the effectivename is in th elist then process the attdel function for it.

 

example:

(setq myblocklist (list "BLOCK1" "BLOCK2" "BLOCK3" "JOHNSBLOCK" "JOHNSCAR" "JOHNSOLD")) ; John' appreciates humor!

 

then your if statement would simply check if the effectivename is in the block list

(if (member blktruename myblocklist)
 (progn
  ;;;Do your stuff here
  (princ "\nFound one")
 )
)

 

Hopefully that makes sense,

 

 

0 Likes
Message 51 of 79

john.uhden
Mentor
Mentor
Kudos?! I guess you liked my English grammar ("for which..."). I can
thank Mr. Ranney for that.

John F. Uhden

0 Likes
Message 52 of 79

john.uhden
Mentor
Mentor

I think you are supposed to wait until after work to get hammered.  But maybe you work for Sam Adams, or Jack Daniels, or Johnnie Walker, or Jose Cuervo.

John F. Uhden

0 Likes
Message 53 of 79

john.uhden
Mentor
Mentor

Maybe this one will handle both your dynamic and non-dynamic block insertions...

Plus it can take wildcards in the BlkName (I think).

 

(defun ATTDEL (BlkName Match / dyna err ss i obj atts m n)
  (vl-load-com)
  (and
    (or
      (= (type BlkName) 'STR)
      (prompt "\nBlock name argument id not a string.")
    )
    (or
      (tblsearch "Block" BlkName)
      (prompt (strcat "\n" BlkName " not found.  Will look through dynamic anonymous blocks."))
      (setq dyna 1)
    )
    (or
      (= (type Match) 'STR)
      (prompt "\nAttribute tag match argument is not a string.")
    )
    (setq Match (strcase Match))
    (or
      (if dyna
        (setq ss (ssget "X" (list '(0 . "INSERT")'(66 . 1))))
        (setq ss (ssget "X" (list '(0 . "INSERT")(cons 2 BlkName)'(66 . 1))))
      )
      (prompt (strcat "\nNo insertions with attributes found."))
    )
    (setq n 0 m 0)
    (setq i (sslength ss))
    (while (> i 0)
      (setq obj (vlax-ename->vla-object (ssname ss (setq i (1- i)))))
      (and
        (or
          (not dyna)
          (and
            (vlax-property-available-p Obj 'EffectiveName)
            (setq Name (vlax-get Obj 'EffectiveName))
            (wcmatch (strcase Name)(strcase BlkName))
          )
        )
        (setq atts (vla-getattributes obj))
        (setq atts (vlax-variant-value atts))
        (foreach att (vlax-safearray->list atts)
          (setq m (1+ m))
          (if (wcmatch (strcase (vlax-get att 'TagString)) Match)
            (if (vl-catch-all-error-p (setq err (vl-catch-all-apply 'vla-delete (list att))))
              (princ (strcat "\nERROR: " (vl-catch-all-error-message err)))
              (setq n (1+ n))
            )
          )
        )
      )
    )
  )
  (princ (strcat "\nDeleted " (itoa n) "/" (itoa m) " attributes."))
  (> n 0) ;; to return T if any attributes were deleted.
)

Thanks to both you and Clint for the effectivename clue.

John F. Uhden

0 Likes
Message 54 of 79

SeeMSixty7
Advisor
Advisor

They should add an LOL Reaction next to the Kudos button, just for you John!

 

 

0 Likes
Message 55 of 79

Anonymous
Not applicable

kudos for the major help you've given...funny thing is - I work for a retailer selling all of those as well!  haha

0 Likes
Message 56 of 79

Anonymous
Not applicable

Just tried it...

 

returned...

 

No insertions with attributes found.
** Error: bad argument type: fixnump: nil **

 

Think something is still a little off on translating the effectivename.

0 Likes
Message 57 of 79

SeeMSixty7
Advisor
Advisor

It looks like the dyna value is setting this up to find nothing.

 

John - I think you can just remove that part of the logic, since the block definition either exists in the drawing or it doesn't.

 

The next issue is that you will want to process the selection set as

 

(setq ss (ssget "X" (list '(0 . "INSERT")'(66 . 1))))

 

always because you won't know if their are some that are anonymous or not.

 

Hopefully that helps,

 

 

 

 

 

 

0 Likes
Message 58 of 79

john.uhden
Mentor
Mentor

I just wrote a lengthy response and I think it disappeared.  Anyway, try this version.  The mechanics are slightly different since I think that AutoCAD's selection set filter is failing.  Also, there should be no more fixnump errors.

 

(defun ATTDEL (BlkName Match / dyna err ss i obj atts m n)
  (vl-load-com)
  (and
    (setq n 0 m 0)
    (or
      (= (type BlkName) 'STR)
      (prompt "\nBlock name argument is not a string.")
    )
    (or
      (tblsearch "Block" BlkName)
      (prompt (strcat "\n\"" BlkName "\" not found.  Will look through dynamic anonymous blocks."))
      (setq dyna 1)
    )
    (or
      (= (type Match) 'STR)
      (prompt "\nAttribute tag match argument is not a string.")
    )
    (setq Match (strcase Match))
    (or
      (if dyna
        (setq ss (ssget "X" (list '(0 . "INSERT"))))
        (setq ss (ssget "X" (list '(0 . "INSERT")(cons 2 BlkName))))
      )
      (prompt (strcat "\nNo insertions found."))
    )
    (and (= (type ss) 'PICKSET)(setq i (sslength ss))(= (type i) 'INT))
    (while (> i 0)
      (setq obj (vlax-ename->vla-object (ssname ss (setq i (1- i)))))
      (and
        (or
          (not dyna)
          (and
            (vlax-property-available-p Obj 'EffectiveName)
            (setq Name (vlax-get Obj 'EffectiveName))
            (wcmatch (strcase Name)(strcase BlkName))
          )
        )
        (vlax-property-available-p Obj 'HasAttributes)
        (= (vlax-get Obj 'HasAttributes) -1)
        (setq atts (vla-getattributes obj))
        (setq atts (vlax-variant-value atts))
        (foreach att (vlax-safearray->list atts)
          (setq m (1+ m))
          (if (wcmatch (strcase (vlax-get att 'TagString)) Match)
            (if (vl-catch-all-error-p (setq err (vl-catch-all-apply 'vla-delete (list att))))
              (princ (strcat "\nERROR: " (vl-catch-all-error-message err)))
              (setq n (1+ n))
            )
          )
        )
      )
    )
  )
  (princ (strcat "\nDeleted " (itoa n) "/" (itoa m) " attributes."))
  (> n 0) ;; to return T if any attributes were deleted.
)

John F. Uhden

0 Likes
Message 59 of 79

john.uhden
Mentor
Mentor

I humbly disagree.  The function takes a BlkName argument.  If it's not found by name, then it has to be searched for (one by one) by its EffectiveName.  The Dyna value directs the traffic.  But I do see your point.  The vetting could be done a little differently, but I think it should end up with the same results.

I hate that word "should."  When you are shopping for a used car in the winter, you ask the salesman if the AC works, he invariably replies, "It should."  No kidding.

John F. Uhden

0 Likes
Message 60 of 79

SeeMSixty7
Advisor
Advisor

I bought a loaded  1987 Toyota SR-5 Turbo Pickup with Extra Cab. Did I say Loaded? Yes it had everything. I am originally from Houston, I happened to be living in San Francisco at the time of purchase. I drove it for about a month. A friend hops in says wow LOADED!!! How come it doesn't have AC? "WAIT!!! WHAT??? Yes it does.. It SHOULD. ****... It doesn't" That sucked by the way, because I shortly there after drove it back to Texas, where every car SHOULD have AC.

 

Back on topic.

 

If blocka is a dynamic block with 3 different visibility settings or some sort of dynamic features built in to it. It will be stored in the Drawing as BLOCKA and tblsearch will find it there regardless if it is in the drawing anywhere or not. If there is one that is default in the drawing it will show up as the actual blockname. if there are two others that have used the dynamic states, they will get anonymous block names at the insert level. If you then process all inserts you will be able to find the blocks by effectivename all three inserts in the drawing will have the effective name of BLOCKA. 

 

If you simply do a ssget with BLOCKA as the criteria you will only find the one insert, not the other two. Thsi is why if you use your dyna variable as you have it it will never be set to 1 and will never process the ssget with just the insert and attribute follows flag.

 

Does that make any sense?

 

 

0 Likes