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,165 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,166 Views
78 Replies
Replies (78)
Message 61 of 79

john.uhden
Mentor
Mentor

I didn't know all that, but, yes, it makes sense even though it is rather indirect.  Looks like I'll post another version, probably tomorrow, where the vetting is done farther down.  As you have probably noticed, I love ands and ors anyway, as influenced by Stephan Koster.  I'm sure glad I was around back then.  Wait, I'm sure glad that he was around back then!  And I'm sure glad that folks like you are around here today.

 

BTW, I got invited for a position in Whacko, TX.  Um, no thanks.  I'll take a good hurricane over a twister anytime.  We go down to the beach in our shorts to get sand-blasted and watch as the pier we were just walking on just got washed away.  It's great fun.  In 1960 we were in the eye of Hurricane Donna.  It was beautiful except that we got hit a second time from the opposite direction.

 

Most of those Frisco people don't have a clue anyway, right?  I mean like why would you leave your heart behind anywhere?

"I left my spleen in Atlantic City." la-di-da-di-da.

John F. Uhden

0 Likes
Message 62 of 79

Anonymous
Not applicable

I've been "banned" till they work out whatever issue they are having...lol


0 Likes
Message 63 of 79

Anonymous
Not applicable

Ran your latest version...

 

The update routine finished without error - however, the "COORDS*" weren't removed from the block prior to the redefine so they error'd out.

 

I checked your routine by running the following:

 

(setq Blkname "DG_HIGHLY CONSUMABLES_BEVERAGES_WATER")

 

followed by

 

(attdel Blkname "COORDS_*")

 

returned:

 

No insertions found.
Deleted 0/0 attributes.nil

 

 

0 Likes
Message 64 of 79

john.uhden
Mentor
Mentor

Here.  Try one more based on Clint's advice.  I tried it in my drawing using (attdel "*" "*") and it removed all attributes from everything.

Did you still maybe want it to remove the attdefs from the block definition too?  We can do that.

 

(defun ATTDEL (BlkName Match / err ss i obj Name 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
      (= (type Match) 'STR)
      (prompt "\nAttribute tag match argument is not a string.")
    )
    (setq Match (strcase Match))
    (or
      (setq ss (ssget "X" '((0 . "INSERT")(66 . 1))))
      (prompt (strcat "\nNo insertions with attributes 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
          (and
            (vlax-property-available-p Obj 'Name)
            (setq Name (vlax-get Obj 'Name))
            (wcmatch (strcase Name)(strcase BlkName))
          )
          (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 65 of 79

Anonymous
Not applicable

IT WORKSSSSSSSSSSSS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 

I would love to see the iteration of removing the attribute from the block definition vs the block insertion to see what kind of impacts it may have on the speed.

 

The only issue I still see in the full routine is that it doesn't work on "Non-Dynamic" blocks fully.  Since the old non-dynamic block only has the Coord* attributes removed from the insertion - Attsync doesn't bring them back nor does the redefine process.  The only way to bring them back is to reinsert the block again.  By removing them from the block definition instead of the insertion may solve the issue.

 

Thanks again John and Clint!  You two have been an amazing help and Kudo's all the way around!!!

0 Likes
Message 66 of 79

SeeMSixty7
Advisor
Advisor

I thought the Block redefine was how you were deleting the attributes from the block definition. If so there is no benefit to removing the attributes from the bock definition. Am I missing something here? The Block definition is a single process that takes place once in the drawing, versus the attributes are attached to the insert of each block. You won't be able to bypass that step of touching every insert that has the attributes.

 

John - The comparing for name and effectivename is not really needed. The effective name will return the true block name if it is dynamic or non-dynamic, so you really don't need that section in the code. (at least that is how it works for 2014 and up as far as I've seen) 

 

I'm not sure why it is not working on the non-dynamic blocks. "ITSHOULD!" GRIN (sorry that was for John, but it really should be working. 

 

John, yes, I have noticed you like the AND OR blocks. Sheesh!!! not as much as Ranjit like Mapcar though, just saying...

 

One of my son's is attending school up in Whacko, Texas. LOL  What kind of job were you offered over there?

0 Likes
Message 67 of 79

john.uhden
Mentor
Mentor

Okay.  This one takes a third argument called DefsToo.  If it is non-nil it will delete the specified attribute definition.

 

(defun ATTDEL (BlkName Match DefsToo / Doc Item err ss i obj Name atts m n k)
  (vl-load-com)
  (and
    (setq Doc (vlax-get (vlax-get-acad-object) 'ActiveDocument))
    (setq n 0 m 0 k 0)
    (or
      (= (type BlkName) 'STR)
      (prompt "\nBlock name argument is not a string.")
    )
    (or
      (= (type Match) 'STR)
      (prompt "\nAttribute tag match argument is not a string.")
    )
    (setq Match (strcase Match))
    (or
      (setq ss (ssget "X" '((0 . "INSERT")(66 . 1))))
      (prompt (strcat "\nNo insertions with attributes 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
          (and
            (vlax-property-available-p Obj 'Name)
            (setq Name (vlax-get Obj 'Name))
            (wcmatch (strcase Name)(strcase BlkName))
          )
          (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))
            )
          )
        )
        DefsToo
        (setq Name (vlax-get Obj 'Name))
        (setq Obj (vla-item (vlax-get Doc 'blocks) Name))
        (vlax-for item Obj
          (and
            (= (vlax-get item 'ObjectName) "AcDbAttributeDefinition")
            (wcmatch (vlax-get item 'Tagstring) Match)
            (not (vla-delete item))
            (setq k (1+ k))
          )
        )
      )
    )
  )
  (princ (strcat "\nDeleted " (itoa n) "/" (itoa m) " attributes and " (itoa k) " attribute definition(s).\n"))
  (> n 0) ;; to return T if any attributes were deleted.
)

John F. Uhden

0 Likes
Message 68 of 79

Anonymous
Not applicable

Sorry - I fat fingered an insert!

 

Routine still works after the rewrite...still doesn't work on the non-dynamic blocks

0 Likes
Message 69 of 79

SeeMSixty7
Advisor
Advisor

John added a third argument deftstoo . If it is non-nil it will delete the attribute definitions.

 

So I believe  you are looking for T as the third argument. This means it will open the blocks and delete the attribute definitions from the block definition too.

 

so your call should be

(attdel BlkName "COORD*" T)

 

hope that helps,

 

0 Likes
Message 70 of 79

Anonymous
Not applicable

I apologize - I added the ":T" to the wrong lisp routine iteration....

 

I added the T and it worked!

 

 

This is what happens when you look at code right after a big meeting!

Message 71 of 79

Anonymous
Not applicable

okay - ran this new code - added the (attdel Blkname "COORDS*" T) and it works fine...

 

Then ran again with my redefine removed (basically just running the Attdel routin and that's it) and then looked inside the parent block definition.  The Coords* attributes are still in the block itself - just not in the specific insertion.

 

That said - for me - all of our blocks are 100% dynamic so it's not an issue.  However, leaving those attributes inside of a non-dynamic block - creates an issue where they cannot be removed or added back to the inserted block - unless you reinsert each instance of that block.

 

For giggles - I edited thenon-dynamic block manually, removing the Coords* attributes, attsync'd the block afterwards (fully removing the coords*), and then redefining with the insert command it worked just like the others.

 

Wondering if you would have to do an attsync to fully remove them before redefining with non-dynamic blocks - I ran through the steps manually... Still the same issues with non-dynamic blocks.

 

 

0 Likes
Message 72 of 79

Anonymous
Not applicable

Just attempted to run on an entire store....Got the following error:

 

** Error: ActiveX Server returned an error: Invalid index **

0 Likes
Message 73 of 79

john.uhden
Mentor
Mentor

I think the position had a rating of GO4.

John F. Uhden

0 Likes
Message 74 of 79

SeeMSixty7
Advisor
Advisor

I would say start checking the variables, but they are defined as local variables. You might try commenting out the local variable declaration part of the defun statement then check the values of some of the variables to get an idea of where it bombed.

 

You could use VLIDE to debug as well, I've just always done it the hard way. LOL

 

 

 


@Anonymous wrote:

Just attempted to run on an entire store....Got the following error:

 

** Error: ActiveX Server returned an error: Invalid index **


 

0 Likes
Message 75 of 79

john.uhden
Mentor
Mentor

I hate leaving things unfinished, but I feel like my hands are tied (behind my back even).  I don't know what the ATTSYNCH command does or how it works.

Clint:  Maybe you can finish this thing.  I have to prepare for the deluge of kids and grandkids  and nephews and neiees etc. showing up this weekend and my son in the hospital.  I'm maybe gonna need some of that Johnnie Walker.

John F. Uhden

Message 76 of 79

SeeMSixty7
Advisor
Advisor

John,

 

enjoy the grand kids and have a great break. I'm out after today for a four day break too. I'll see if I can help get Kevin the rest of the way. The problem is the size of his drawings, LOL.

 

Happy Fourth of JULY!!!

 

Clint

0 Likes
Message 77 of 79

SeeMSixty7
Advisor
Advisor

@Anonymous just opened up a drawing the one you sent me, I made about 9000 copies of the sample block. I also created a plain jane non-dynamic block with all the attributes in it.

 

Ran the routine (Last one posted by John) - Came out great took about 2-3 seconds  for each run. The second run I only had a a few blocks.

Command: (attdel "DG_HIGHLY CONSUMABLES_PAPER PRODUCTS_BATH TISSUE" "COORDS_*" nil)
Deleted 112320/430560 attributes and 0 attribute definition(s).
T
Command: (attdel "test" "COORDS_*" nil)
Deleted 124/589 attributes and 0 attribute definition(s).

T

 

I don't seem to have any issue with dynamic or non-dynamic blocks.

 

I didn't use the flag to redefine the blocks.

 

Also Those fields are killing your performance in that drawing. Are you utilizing the FIELDEVAL variable and setting it to 0 before working with these? I would imagine if you are not setting it to ZERO it is taking forever to do anything. I made the mistake of not setting it to 0 and did a zoom extents and it took about 10 minutes to regenerate and update all those fields. Turn it off using 0 and it regens immediately. something else to consider is when working on these drawings is to disable or set AutoSAVE time to be  a long enough time for processing.  I noticed that autosave will kill you if it stops in the middle of processing and then decides to do a significant write disk operation.

 

good luck and let me know if I there is another snag. I can't get your active x error, but that may be fixed with one of the settings I mentioned here.

 

If it does creep up again, then we may want to pass a selection set to the routine to process a select group at a time.

 

Good luck,

 

 

 

 

0 Likes
Message 78 of 79

Anonymous
Not applicable

Really not having an issue on the performance of our machines and the fields that we use.  However, we are all running Xeon Processors, 32 Gig Ram, and K/M4000/M5000 graphics cards...so fairly robust systems.

 

Our external e-mail is down right now so I can't send you any files at the moment but I've narrowed the issue down and will send that over in an e-mail including my update routine so you can see how it all pulls together but with a simple two block drawing (which is still producing the error).  In the smaller drawing I'll email - you can see where the single "COORDS_1" attribute doesn't come back in the one block (not dynamic) but it does in the other... Not for sure of the differences and why one is running one way and not the other.

 

Thanks again everyone and John have a great time with the family and thank you again for all of the help!  I'm closer now than ever before.

0 Likes
Message 79 of 79

john.uhden
Mentor
Mentor

That's very kind of you (and Clint).  The gang may not be showing up until Sunday (oldest is coming from Maine), but my wife is creating her list of to-dos in advance.  OMG, the pool, blowing, weeding, recycling, etc. etc.

John F. Uhden

0 Likes