Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

blockreplace or block replace multiple blocks at one time

36 REPLIES 36
Reply
Message 1 of 37
raulvaldemar
6491 Views, 36 Replies

blockreplace or block replace multiple blocks at one time

The following is a lisp that I wrote that replaces all the blocks within your drawing to the block you choose.  The lisp is different than the express command blockreplace because  one can replace multiple different blocks at one time with a particular block of your chosing.  In addition, the replaced blocks will have the same layer of the block you wanted to replace the others with.   Since I couldn't find a lisp like this in the forums, here's my small contribution:

 

(defun C:CHANGEBLOCKS(/ printDebug ssAll ssAllTotal ss ssTotal ssCount ssCount2 ssTotal ssMainBlock ssMainBlock entListMainBlock ssBlocks entListBlock entListBlock2 entElementNewBlock entElementOldBlock entElementOldBlock2 oldBlockName)
  ;PROGRAM CHANGES MULTIPLE BLOCKS
  ;WRITTEN BY --- RAUL BENITEZ

  ;Command reference
  ;subst - returns a list with a new item substituted for every occurrence of an old item
  ;quote (or ') - easy way to make the string into a list.
  ;cdr - returns a list containing all but the first element of the specified list
  ;assoc - searches an association list for an element and returns that association list entry
  ;entmod - modifies the definition data of an object (entity)
  ;cons - adds an element to the beginning of a list, or constructs a dotted list
  
  (vl-load-com)
  (setvar "CMDECHO" 0)
  (setq printDebug 0)

  (setq ss nil) ;set ss variable to nil
  (princ "\n(1). Pick the blocks you want to replace: ")
  (setq ss (ssget))               ;Gets selection set
  (setq ssTotal (sslength ss))    ;Gets the total number of entities within the selection
  
  (command "PICKADD" "0")         ;Changes the pickadd variable so the user can only select one object at a time
  
  ;Obtain the block you want to replace the others with
  (princ "\n(2). Pick the block you want to replace the others with: ") 
  (setq ssMainBlock (ssget))      ;Create selection set for the main block you want to replace the others with  
  (setq entListMainBlock (entget (ssname ssMainBlock 0)))    ;Obtain entity list (group codes) containing definition data of the block
  (setq entElementNewBlock (assoc 2 entListMainBlock))       ;Searches the block entity list and returns the element associate with 2 (the block name)
  
  (if (= printDebug 1)
  	  (progn
	  (princ "\nEntity list of the block you want to replace others with")
	  (princ "\n-----------------------------------------------------------\n")
	  (princ entListMainBlock)
	  )
  )
  
  ;Cycle thru all the blocks replacing each block one at a time
  (setq ssCount 0) 
  (while (< ssCount ssTotal)
              
	  (setq entListBlock (entget (ssname ss ssCount)))   ;Obtain entity list (group codes) from each of the entities (blocks) in the selection set
	  (setq entElementOldBlock (assoc 2 entListBlock))   ;Searches the block entity list and returns the element associate with 2 (the block name)
          (setq oldBlockName (cdr entElementOldBlock))       ;Returns a list containing all but the first element of the specified list, therefore only the block name

          (setq ssAll nil)				                          ;Set the variable to nil
	  (setq ssAll (ssget "X" (list '(0 . "INSERT") (cons 2 oldBlockName))))   ;Obtain the entire selection of all the blocks throughout the drawing
    	  (setq ssAllTotal (sslength ssAll))                                      ;Gets the total number of entities within the selection
	  (if (= printDebug 1)
		  (progn
	    	  (princ "\n\n\nCount of all the old blocks in the drawing: ")
		  (princ ssAllTotal)
	          )
 	  )
    
          (setq ssCount2 0) 
  	  (while (< ssCount2 ssAllTotal)
		  (setq entListBlock2 (entget (ssname ssAll ssCount2)))   ;Obtain entity list (group codes) from each of the entities (blocks) in the selection set
		  (setq entElementOldBlock2 (assoc 2 entListBlock2))      ;Searches the block entity list and returns the element associate with 2 (the block name)
	          
	          (entmod (subst entElementNewBlock entElementOldBlock2 entListBlock2))   ;Substitute the new block entity name for the old block entity name within the old block entity list
	          (command "MATCHPROP" (ssname ssMainBlock 0) (ssname ssAll ssCount2) "" )  ;Match the properties of the old block(s) to the new block
	          (setq ssCount2 (+ ssCount2 1))  ;Loop counter
	  )
        
          ;Print out information
          (if (= printDebug 1)
		  (progn
		  (princ "\n\n\nssCount: ")
		  (princ ssCount)
		  (princ "\nEntity list of the block that is going to be replaced")
	  	  (princ "\n-----------------------------------------------------------\n")
	          (princ entListBlock)
		  (princ "\n\nName entity of the block that is going to replaced: ")
	          (princ entElementOldBlock)
		  (princ "\nName entity of the new block: ")
	          (princ entElementNewBlock)
		  (princ "\n\n")
		  )
	  )
    
    	  (setq ssCount (+ ssCount 1))  ;Loop counter
  )  

  (command "PICKADD" "2")         ;Changes the pickadd variable so the user select multiple objects at a time
  
  (setvar "CMDECHO" 1)

  (print "Changed multiple blocks.") 
  (princ)  

)

 

36 REPLIES 36
Message 2 of 37
fran9YSUT
in reply to: raulvaldemar


@raulvaldemar wrote:

The following is a lisp that I wrote that replaces all the blocks within your drawing to the block you choose.  The lisp is different than the express command blockreplace because  one can replace multiple different blocks at one time with a particular block of your chosing.  In addition, the replaced blocks will have the same layer of the block you wanted to replace the others with.   Since I couldn't find a lisp like this in the forums, here's my small contribution:

 

(defun C:CHANGEBLOCKS(/ printDebug ssAll ssAllTotal ss ssTotal ssCount ssCount2 ssTotal ssMainBlock ssMainBlock entListMainBlock ssBlocks entListBlock entListBlock2 entElementNewBlock entElementOldBlock entElementOldBlock2 oldBlockName)
  ;PROGRAM CHANGES MULTIPLE BLOCKS
  ;WRITTEN BY --- RAUL BENITEZ

  ;Command reference
  ;subst - returns a list with a new item substituted for every occurrence of an old item
  ;quote (or ') - easy way to make the string into a list.
  ;cdr - returns a list containing all but the first element of the specified list
  ;assoc - searches an association list for an element and returns that association list entry
  ;entmod - modifies the definition data of an object (entity)
  ;cons - adds an element to the beginning of a list, or constructs a dotted list
  
  (vl-load-com)
  (setvar "CMDECHO" 0)
  (setq printDebug 0)

  (setq ss nil) ;set ss variable to nil
  (princ "\n(1). Pick the blocks you want to replace: ")
  (setq ss (ssget))               ;Gets selection set
  (setq ssTotal (sslength ss))    ;Gets the total number of entities within the selection
  
  (command "PICKADD" "0")         ;Changes the pickadd variable so the user can only select one object at a time
  
  ;Obtain the block you want to replace the others with
  (princ "\n(2). Pick the block you want to replace the others with: ") 
  (setq ssMainBlock (ssget))      ;Create selection set for the main block you want to replace the others with  
  (setq entListMainBlock (entget (ssname ssMainBlock 0)))    ;Obtain entity list (group codes) containing definition data of the block
  (setq entElementNewBlock (assoc 2 entListMainBlock))       ;Searches the block entity list and returns the element associate with 2 (the block name)
  
  (if (= printDebug 1)
  	  (progn
	  (princ "\nEntity list of the block you want to replace others with")
	  (princ "\n-----------------------------------------------------------\n")
	  (princ entListMainBlock)
	  )
  )
  
  ;Cycle thru all the blocks replacing each block one at a time
  (setq ssCount 0) 
  (while (< ssCount ssTotal)
              
	  (setq entListBlock (entget (ssname ss ssCount)))   ;Obtain entity list (group codes) from each of the entities (blocks) in the selection set
	  (setq entElementOldBlock (assoc 2 entListBlock))   ;Searches the block entity list and returns the element associate with 2 (the block name)
          (setq oldBlockName (cdr entElementOldBlock))       ;Returns a list containing all but the first element of the specified list, therefore only the block name

          (setq ssAll nil)				                          ;Set the variable to nil
	  (setq ssAll (ssget "X" (list '(0 . "INSERT") (cons 2 oldBlockName))))   ;Obtain the entire selection of all the blocks throughout the drawing
    	  (setq ssAllTotal (sslength ssAll))                                      ;Gets the total number of entities within the selection
	  (if (= printDebug 1)
		  (progn
	    	  (princ "\n\n\nCount of all the old blocks in the drawing: ")
		  (princ ssAllTotal)
	          )
 	  )
    
          (setq ssCount2 0) 
  	  (while (< ssCount2 ssAllTotal)
		  (setq entListBlock2 (entget (ssname ssAll ssCount2)))   ;Obtain entity list (group codes) from each of the entities (blocks) in the selection set
		  (setq entElementOldBlock2 (assoc 2 entListBlock2))      ;Searches the block entity list and returns the element associate with 2 (the block name)
	          
	          (entmod (subst entElementNewBlock entElementOldBlock2 entListBlock2))   ;Substitute the new block entity name for the old block entity name within the old block entity list
	          (command "MATCHPROP" (ssname ssMainBlock 0) (ssname ssAll ssCount2) "" )  ;Match the properties of the old block(s) to the new block
	          (setq ssCount2 (+ ssCount2 1))  ;Loop counter
	  )
        
          ;Print out information
          (if (= printDebug 1)
		  (progn
		  (princ "\n\n\nssCount: ")
		  (princ ssCount)
		  (princ "\nEntity list of the block that is going to be replaced")
	  	  (princ "\n-----------------------------------------------------------\n")
	          (princ entListBlock)
		  (princ "\n\nName entity of the block that is going to replaced: ")
	          (princ entElementOldBlock)
		  (princ "\nName entity of the new block: ")
	          (princ entElementNewBlock)
		  (princ "\n\n")
		  )
	  )
    
    	  (setq ssCount (+ ssCount 1))  ;Loop counter
  )  

  (command "PICKADD" "2")         ;Changes the pickadd variable so the user select multiple objects at a time
  
  (setvar "CMDECHO" 1)

  (print "Changed multiple blocks.") 
  (princ)  

)

 


totally works ^_^ thank you 😄

Message 3 of 37
weeddesign
in reply to: fran9YSUT

Beautiful!  Works perfectly. Thanks.

MWeed
Message 4 of 37

how do I load the lisp and which command do i use to invoke it

Message 5 of 37
justin
in reply to: fran9YSUT

What about a way to replace multiple blocks with multiple blocks, such that i have a client that wants us to change our blocks to their blocks.

Message 6 of 37
pbejse
in reply to: justin


@justin wrote:

What about a way to replace multiple blocks with multiple blocks, such that i have a client that wants us to change our blocks to their blocks.


Are you offering a solution for multiple block replacement? considering the fact that you are replying to a post from a year ago or so. 

 

Or are you looking for a solution?  Have you considered redefining the block? What kind of changes are you looking at?

One option is Tool palette / Right click / Redefine... easy peasy, Yes?

Another is Design Center / Right click / Redefine..

 

Or we can do it with lisp if that will make you happy 😊.

 

 

 

Message 7 of 37
justin
in reply to: pbejse

I am looking for a solution. I tried to use this LISP routine as advertised, "multiple" block replacement. But then i ran it and it is the same a the regular blockreplace command in autoCAD in that it only replaces multiple blocks with 1 block. What i need is a command to replace multiple blocks with multiple. Like i said i have a client who wants us to convert to their blocks. So our manhole symbol turns into their manhole symbol x 100 other objects.

Message 8 of 37
pbejse
in reply to: justin


@justin wrote:

What i need is a command to replace multiple blocks with multiple. Like i said i have a client who wants us to convert to their blocks. So our manhole symbol turns into their manhole symbol x 100 other objects.


How do you determine which block to replace what block?   How would you want it ? by a harcoded list? or via selection? 

The reason why i'm asking, its too easy to do it with desingn center? The list is already there.  You jsut need to direct it to one file that show all the blocks you needed to redefine.

 

redefine.png

 

If not, please post a sample drawing. Will code the heck out of that drawing.

 

 

 

Message 9 of 37
justin
in reply to: pbejse

So i tried that, but for whatever reason the option to redefine is greyed out. Also this is a pain to do to 100 objects, i might as well just do the blockreplace. I am looking for a way to redifine ALL of them at once. I could be a hard coded list, as it is for a specific client.

 

I downloaded and attempted to use this LISP routine, but it doesn't seem to do anything, not even an error. The thread was a couple years old.

 

(defun c:CHMB  (/ lst ss i sn en bn nw od o n)
 (setq lst '(("SS-MH" . "H:\CLSI Cad standards\Carlson-Settings\Layer Translator\Individual Blocks\SAN SEWER MH.dwg")
	     ("ST-MH" . "H:\CLSI Cad standards\Carlson-Settings\Layer Translator\Individual Blocks\STORM MH.dwg")
             )
       )
 (if (setq ss (ssget "_X" (list '(0 . "INSERT") (cons 2 (apply 'strcat (mapcar '(lambda (x)
                                                                                  (strcat (car x) "," (cdr x) ","))
                                                                               lst)))
                                )
                     )
           )
   (repeat (setq i (sslength ss))
     (setq sn (ssname ss (setq i (1- i)))
           en (entget sn)
           bn (cdr (assoc 2 en))
           )
     (if (assoc bn lst)
       (setq od (cons (list bn en sn) od))
       (if (not (member bn nw))
         (setq nw (cons (list bn en) nw))
         )
       )
     )
   )
 (if (and nw od)
   (foreach x  od
     (and (setq o (assoc (car x) lst))
          (setq n (assoc (cdr o) nw))
          (entmake
            (append
              (list '(0 . "INSERT") (cons 2 (car n)))
              (vl-remove-if-not
                '(lambda (j) (member (car j) '(10 41 42 43 50)))
                (cadr x))
              (vl-remove-if-not
                '(lambda (k) (member (car k) '(6 8 62)))
                (cadr n))))
          (entdel (caddr x))
          )
     )
   )
 (princ)
 )(vl-load-com)

 

Message 10 of 37
Kent1Cooper
in reply to: justin

The Design Center's Redefine option is good if  all their Blocks have the same names  as your Blocks that they are to replace.  Is that the case?  And they would need to be Blocks inside a drawing file  [or files -- much easier if all in one], not separate drawings.  Is that the case?

 

If they're separate drawings, a routine could be written pretty easily to go through and change definitions, pulling them from those drawings, and also change to their names if that's part of the task, given a list pairing your-names with their-names.

 

But there are potential complications.  If they want your "horse" Block to become defined as their "donkey" Block instead, and they want you to use their names, but you also have a "donkey" name in use for another Block, there will be trouble....

Kent Cooper, AIA
Message 11 of 37
pbejse
in reply to: Kent1Cooper


@Kent1Cooper wrote:

The Design Center's Redefine option is good if  all their Blocks have the same names  as your Blocks that they are to replace. 


Ahh, I see your point there Kent. good call,

 

 

Message 12 of 37
justin
in reply to: Kent1Cooper

They are not named the same, and i need to keep them with their original names, that's the whole point is that when the client gets a drawing from us it acts like it came from them.

 

As far as separate files, i could do this either way. I have all the blocks in one drawing at the moment, but i could pull them out into separate files if needed. I could keep it clean so none of their names are in there, as it should be by default anyway.

 

This is going to be a process that is the same every time, so the blocks to be translated could be hard coded, whatever that may look like.

 

I cant believe they haven't built this into AutoCAD yet. This has been a problem in Survey world forever.

Message 13 of 37
pendean
in reply to: justin

>>>...I cant believe they haven't built this into AutoCAD yet....<<<
Why would Autodesk build in a command that swaps a DWG's entire set of blocks with an external set of blocks? I'm curious more than anything since in 30+ years of using AutoCAD I have yet to ever have a need to do that, when a client has strict standards as you state we draft with their content from their start and never "swap them out" later before submission/return of files.

>>>...They are not named the same...<<<
Q: How is the swap list to be determined? Is that something you will write for both source and destination file(s)? You know, external block AA is to go where block A is in the file, but for the 100s or 1000s of blocks list at the source and destination file.

Can you share DWG files of each (source and destination) so we can see the extent of the scope?
Message 14 of 37
pbejse
in reply to: justin

Where is your sample drawing @justin ? You want this done YES?

 

Message 15 of 37
justin
in reply to: pendean

Well in Survey world, you get field data from fancy data collectors, and that data is coded such that an automated "field to finish" process draws the line work and symbols based on our company standards. We would have to completely re code our field standards in order to draft in company B's standards, such we have to translate it to the other companies standards. I have been in survey world a very long time, and it has always been this way.

 

I don't see how sending the drawings helps, they are just symbols/blocks, i have about 50 of them that need to be translated, and that could be hard coded into a lisp routine for example as it will always be the same set of blocks that need to be translated.

Message 16 of 37
pbejse
in reply to: justin


@justin wrote:

I don't see how sending the drawings helps, they are just symbols/blocks, i have about 50 of them that need to be translated, and that could be hard coded into a lisp routine for example as it will always be the same set of blocks that need to be translated.


We just wanted to see what we're dealing with. Like is it annotative? , blocks that are uniformly scaled, are they dynamic blocks.? etc.. to avoid going back to you and asking the questions back and forth.

Jeez., You ask for our help. We're trying to give it to you.

 

Anyway I'm out.

 

Message 17 of 37
justin
in reply to: pbejse

Okay i get your point, i hadn't thought of all that. I attached my legend, but i will have to get you a drawing of there symbols tomorrow.

 

I greatly appreciate all of your help, sorry if i came off wrong, not intentional.

Message 18 of 37
roland.r71
in reply to: justin


@justin wrote:

Okay i get your point, i hadn't thought of all that. I attached my legend, but i will have to get you a drawing of there symbols tomorrow.

 

I greatly appreciate all of your help, sorry if i came off wrong, not intentional.



We can all see for ourselves if you do, but I'm currious:

Do these blocks share the same content, size & insertion points? Besides attributes. (do they have similar attributes if any) ?

 

I would be surprised if thats the case, which could make this a tedious job.

Message 19 of 37
pendean
in reply to: justin

Thanks for the info about your workflow needs: are you using CIvil3D or MAP3D versions of AutoCD in your "survey world" or is this all just plain AutoCAD?

>>>...I don't see how sending the drawings helps,...<<<
See responses from others.

You did not answer my question about who gets to determine which client block replaces your own block in each and every drawing from different clients, we need to understand how that works or any LISP will only be good enough for one sample DWG file you provide and not much else.

TIA
Message 20 of 37
justin
in reply to: pendean

We are using the map version of AutoCAD, with an add on survey software, Carlson Survey 2018. I don't know if this helps being it is an AutoCAD forum, but we do have a license of Microstation Open Roads as well, so if that tool might help in this regard. My familiarity with Microstation is basically none.

 

In this case i have one client who needs this process, so a table or spreadsheet or whatever that defines a 1 to 1 block translation is what i am looking for, it could be hard coded because it will always be the same set of blocks being replaced.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost