Replace only selected blocks with a different one LISP

Replace only selected blocks with a different one LISP

Anonymous
Not applicable
5,554 Views
21 Replies
Message 1 of 22

Replace only selected blocks with a different one LISP

Anonymous
Not applicable

Hello world,

 

I found this nice LISP on a CADTutor forum (kudos to Smirnoff) for replacing block and transferring attributes and some properties (layer, rotation, scale). I was wondering if someone was able to upgrade the code to also take note of the dynamic block action parameters like flip state, rotation, scale etc. and transfer it to the new dynamic block that had the same parameters?

 

Br,

 

Robert

 

(defun c:xch(/ iCnt bSet cFlg nBlc cVal pLst
	         bNam aLst aDoc nBlc aSp cAt rLst)

  (vl-load-com)

  (defun Set_Initial_Setenv(varLst)
    (mapcar
      '(lambda(v)(if(not(getenv(car v)))(setenv(car v)(cadr v))))
      varLst)
    ); end of Set_Initial_Setenv

  (defun Unblock_All_Layers(/ aDoc layCol actLay outLst)
     (setq aDoc(vla-get-ActiveDocument
		 (vlax-get-acad-object))
	   layCol(vla-get-Layers aDoc)
	   actLay(vla-get-ActiveLayer aDoc)
	   ); end setq
      (vlax-map-collection layCol
        (function
	  (lambda(x)
	    (setq outLst
	      (cons
		(list x
	       	      (vla-get-Lock x)
	              (vla-get-Freeze x)
	             )outLst)
		  ); end setq
	    (vla-put-Lock x :vlax-false)
	     (if(not(equal x actLay))
              (vla-put-Freeze x :vlax-false)
	    ); end if
	   ); end lambda
	  ); end function
	); end vlax-map-collection
  outLst
  ); end of Unblock_All_Layers

  (defun Restore_All_Layer_States(Lst / actLay)
     (setq actLay(vla-get-ActiveLayer
		   (vla-get-ActiveDocument
		     (vlax-get-acad-object))))
      (mapcar
       (function
	 (lambda(x)
	   (vla-put-Lock(car x)(cadr x))
	    (if(not(equal actLay(car x)))
              (vla-put-Freeze(car x)(last x))
	    ); end if
	   )
	 )
        Lst
       )
  (princ)
  ); end of Restore_All_Layer_States
	   
(Set_Initial_Setenv '(("xchange:layer" "Yes")("xchange:scale" "Yes")
		      ("xchange:rotation" "Yes")("xchange:attributes" "Yes")))
  (princ "\n<<< Select blocks to replace >>> ")
  (if(setq bSet(ssget '((0 . "INSERT"))))
    (progn
      (while(not cFlg)
	(princ
	  (strcat "\nOptions: Layer = "(getenv "xchange:layer")
	          ", Scale = " (getenv "xchange:scale")
	          ", Rotation = " (getenv "xchange:rotation")
	          ", Attributes = " (getenv "xchange:attributes")))
         (initget "Options")
         (setq nBlc(entsel "\nSelect new block or [Options] > "))
	(cond
	  ((and
	     (= 'LIST(type nBlc))
	     (equal '(0 . "INSERT")(assoc 0(entget(car nBlc))))
	     ); end and
	   (setq nBlc(vlax-ename->vla-object(car nBlc))
		 cFlg T); end setq
	   ); end condition #1
	  ((= 'LIST(type nBlc))
	   (princ "\n<!> This isn't block <!> ")
	   ); end condition #2
	  ((= "Options" nBlc)  	   
	    (initget "Yes No")
	    (setq cVal(getkword(strcat "\nInherit old block layer [Yes/No] <"
				       (getenv "xchange:layer")">: ")))
	    (if(member cVal '("Yes" "No"))(setenv "xchange:layer" cVal))
	    (initget "Yes No")
	    (setq cVal(getkword(strcat "\nInherit old block scale [Yes/No] <"
				       (getenv "xchange:scale")">: ")))
	    (if(member cVal '("Yes" "No"))(setenv "xchange:scale" cVal))
	    (initget "Yes No")
	    (setq cVal(getkword(strcat "\nInherit old block rotation [Yes/No] <"
				       (getenv "xchange:rotation")">: ")))
	    (if(member cVal '("Yes" "No"))(setenv "xchange:rotation" cVal))
	    (initget "Yes No")
	    (setq cVal(getkword(strcat "\nInherit attributes with similar tags [Yes/No] <"
				       (getenv "xchange:attributes")">: ")))
	    (if(member cVal '("Yes" "No"))(setenv "xchange:attributes" cVal))
	   ); end condition #3
	  ); end cond
	); end while
      (setq aDoc(vla-get-ActiveDocument(vlax-get-acad-object))
	    bNam(vla-get-Name nBlc)
	    aSp(vla-ObjectIdToObject aDoc(vla-get-OwnerId nBlc))
	    iCnt 0
	    ); end setq
      (vla-StartUndoMark aDoc)
      (setq rLst(Unblock_All_Layers))
      (foreach b(mapcar 'vlax-ename->vla-object
			 (vl-remove-if 'listp
			   (mapcar 'cadr(ssnamex bSet))))
	(if(= :vlax-true(vla-get-HasAttributes b))
	    (setq aLst
		   (mapcar '(lambda (a)
			      (list (vla-get-TagString a)
				    (vla-get-TextString a)))
			   (vlax-safearray->list
			     (vlax-variant-value (vla-GetAttributes b)))))
	  ); end if
	(setq nBlc(vla-InsertBlock aSp (vla-get-InsertionPoint b)bNam 1.0 1.0 1.0 0.0))
	  (if(= "Yes"(getenv "xchange:layer"))
	   (vla-put-Layer nBlc(vla-get-Layer b))
	  ); end if
         (if(= "Yes"(getenv "xchange:scale"))
	   (progn
	     (vla-put-XScaleFactor nBlc(vla-get-XScaleFactor b))
	     (vla-put-YScaleFactor nBlc(vla-get-YScaleFactor b))
	     (vla-put-ZScaleFactor nBlc(vla-get-ZScaleFactor b))
	    ); end progn
	  ); end if
	(if(= "Yes"(getenv "xchange:rotation"))
	   (vla-put-Rotation nBlc(vla-get-Rotation b))
	  ); end if
	(if
	  (and
	     (= "Yes"(getenv "xchange:attributes"))
	     (= :vlax-true(vla-get-HasAttributes nBlc))
	    ); end and
	  (foreach i(mapcar '(lambda (a)(list(vla-get-TagString a)a))
			        (vlax-safearray->list
			          (vlax-variant-value(vla-GetAttributes nBlc))))
	    (if(setq cAt(assoc(car i)aLst))
	      (vla-put-TextString(last i)(last cAt))
	      ); end if
	    ); end foreach
	  ); end if   
	(vla-Delete b)
	(setq iCnt(1+ iCnt))
	); end foreach
      (Restore_All_Layer_States rLst)
      (vla-EndUndoMark aDoc)
      (princ(strcat "\n" (itoa iCnt) " block(s) was replaced. "))
      ); end progn
    (princ "\n<!> Nothing selected <!>" )
    ); end if
  (princ)
 ); end of c:xch
5,555 Views
21 Replies
Replies (21)
Message 2 of 22

john.uhden
Mentor
Mentor

See if this simplistic version works for you...

 

;;; BlockSwap replaces selected blocks.
;;; by John Uhden (updated 03-09-17)
;;;
(defun c:BlockSwap ( / *error* vars ok name1 obj1 name2 obj2 opt ss)
  (vl-load-com)
  (defun *error* (err)
    (mapcar '(lambda (x)(setvar (car x)(cdr x))) vars)
    (vla-endundomark *doc*)
    (cond
      ((not err))
      ((wcmatch (strcase err) "*CANCEL*,*QUIT*"))
      (1  (princ (strcat "\nERROR: " err)))
    )
    (princ)
  )
  (or *acad* (setq *acad* (vlax-get-acad-object)))
  (or *doc* (setq *doc* (vla-get-ActiveDocument *acad*)))
  (vla-endundomark *doc*)
  (vla-startundomark *doc*)
  (setq vars (mapcar '(lambda (x)(cons x (getvar x))) '("cmdecho")))
  (mapcar '(lambda (x)(setvar (car x) 0))  vars)
  (command "_.expert" (getvar "expert")) ;; dummy command
  (while (not ok)
    (setq obj1 (vlax-ename->vla-object (car (entsel "\nPick old block: "))))
    (princ (strcat "  Old block name = \"" (setq name1 (vla-get-name obj1)) "\""))
    (setq  obj2 (vlax-ename->vla-object (car (entsel "\nPick new block: "))))
    (princ (strcat "  New block name = \"" (setq name2 (vla-get-name obj2)) "\""))
    (if (= name1 name2)
      (prompt "\nSame old and new blocks selected.")
      (setq ok 1)
    )
  )
  (initget "Replaceall Select")
  (setq opt (getkword
        "\nEnter an option [Select/Replaceall] <Replaceall> ... "
      )
      opt (if opt opt "Replaceall")
  )
  (cond 
    ((= opt "Select")
      (prompt "\nSelect blocks to be replaced...  ")
      (setq ss (ssget (list (cons 0 "INSERT") (cons 2 name1))))
    )
    ((= opt "Replaceall")
      (setq ss (ssget "X" (list (cons 0 "INSERT") (cons 2 name1))))
    )
  )
  (repeat (setq i (sslength ss))
    (vla-put-name (vlax-ename->vla-object (ssname ss (setq i (1- i)))) name2)
  )
  (vla-regen (vla-get-activedocument (vlax-get-acad-object))
       acActiveViewport
  )
  (*error* nil)
)
(defun c:BS ()(c:BlockSwap))

John F. Uhden

Message 3 of 22

lleeLFG9Q
Community Visitor
Community Visitor

Was looking for this command and found your LISP.

Looked online for information to load a LISP into cad.  Only thing I would add for those that may need this information is that I copied the LISP code and pasted it into notepad on my windows, then saved it and renamed the file with a .lsp extension at the end.  Then I loaded it into cad following the online instructions I found.

0 Likes
Message 4 of 22

john.uhden
Mentor
Mentor

@lleeLFG9Q ,

I am thrilled that you found it.

I don't remember writing or posting it or even where I was at the time.  I must have been unemployed because I am not independently wealthy, and am thankful to be working now because I can't afford to retire.  My wife refuses to understand that this is my hobby, which takes precedence over most of my domestic duties, except doing the garbage and recycling and paying the bills, which score no points at all.

If it works for you, please accept my solution.  A little gratitude is a welcome thing.

John F. Uhden

Message 5 of 22

Sea-Haven
Mentor
Mentor

Re the dynamic block use existing values, if you get a copy of Lee-Mac's dynamic block lisp it has all the necessary code to get the values out then put them into the new block.

0 Likes
Message 6 of 22

Tom2023
Explorer
Explorer

Hi John,

Amazing coding. Now, how do we not copy the scale? So the Destination Block will retain its original Scale?

Thank you

 

0 Likes
Message 7 of 22

john.uhden
Mentor
Mentor

@Tom2023 

Never thought about that.

Maybe I'll have time to look into that this weekend.

John F. Uhden

Message 8 of 22

Tom2023
Explorer
Explorer

Thank you John. You're the greatest 😊

0 Likes
Message 9 of 22

Tom2023
Explorer
Explorer

Hi John, your (updated 03-09-17) block swap lisp is amazing! I use this several times a day!

 

Is it possible to add an error catch when picking? If I accidentally click on empty space, the program stops and I have to run it again.

 

  (setq obj1 (vlax-ename->vla-object (car (entsel "\nPick old block: "))))
    (princ (strcat "  Old block name = \"" (setq name1 (vla-get-name obj1)) "\""))
    (setq  obj2 (vlax-ename->vla-object (car (entsel "\nPick new block: "))))

 

Something like

(princ "\n<!> Nothing selected <!>" )

 Please Pick again?

 

Thank you John. Your lisp is amazing!

0 Likes
Message 10 of 22

john.uhden
Mentor
Mentor

@Tom2023 ,

Luckily I was just holding up dinner when I found your response.

I hope this update improves your usage.

;;; BlockSwap replaces selected blocks.
;;; by John Uhden (updated 03-09-17)
;;; Updated (04-15-23) per request of @Tom2023 to warn but coninue
;;; with erroneous picks.
(defun c:BlockSwap ( / *error* vars vals ok name1 obj1 name2 obj2 opt ss)
  (vl-load-com)
  (defun *error* (err)
    (mapcar 'setvar vars vals)
    (vla-endundomark *doc*)
    (cond
      ((not err))
      ((wcmatch (strcase err) "*CANCEL*,*QUIT*"))
      (1  (princ (strcat "\nERROR: " err)))
    )
    (princ)
  )
  (or *acad* (setq *acad* (vlax-get-acad-object)))
  (or *doc* (setq *doc* (vla-get-ActiveDocument *acad*)))
  (vla-endundomark *doc*)
  (vla-startundomark *doc*)
  (setq vars '("cmdecho"))
  (setq vals (mapcar 'getvar vars))
  (command "_.expert" (getvar "expert")) ;; dummy command
  (while (not ok)
    (and
      (if 
        (and
          (setq obj1 (vlax-ename->vla-object (car (entsel "\nPick old block: "))))
          (= (vlax-get obj1 'ObjectName) "AcDbBlockReference")
        )
        (princ (strcat "  Old block name = \"" (setq name1 (vla-get-name obj1)) "\""))
        (prompt "\nObject not selected or is not a block reference.")
      )
      (if
        (and
          (setq  obj2 (vlax-ename->vla-object (car (entsel "\nPick new block: "))))
          (= (vlax-get obj2 'ObjectName) "AcDbBlockReference")
        )
        (princ (strcat "  New block name = \"" (setq name2 (vla-get-name obj2)) "\""))
        (prompt "\nObject not selected or is not a block reference.")
      )
      (if (= name1 name2)
        (prompt "\nSame old and new blocks selected.")
        (setq ok 1)
      )
    )
  )
  (initget "Replaceall Select")
  (setq opt (getkword
        "\nEnter an option [Select/Replaceall] <Replaceall> ... "
      )
      opt (if opt opt "Replaceall")
  )
  (cond 
    ((= opt "Select")
      (prompt "\nSelect blocks to be replaced...  ")
      (setq ss (ssget (list (cons 0 "INSERT") (cons 2 name1))))
    )
    ((= opt "Replaceall")
      (setq ss (ssget "X" (list (cons 0 "INSERT") (cons 2 name1))))
    )
  )
  (repeat (setq i (sslength ss))
    (vla-put-name (vlax-ename->vla-object (ssname ss (setq i (1- i)))) name2)
  )
  (vla-regen (vla-get-activedocument (vlax-get-acad-object))
       acActiveViewport
  )
  (*error* nil)
)
(defun c:BS ()(c:BlockSwap))

John F. Uhden

Message 11 of 22

Tom2023
Explorer
Explorer

Hi John, I hope your dinner was delicious and memorable. I don't know what I did wrong but the program still stop and exit if I accidentally click on empty space.

 

It's no big deal. There's no rush. Please enjoy your dinner, John. I'm still using your lisp everyday regardless. Thank you John.

Tom2023_0-1681783126596.png

 

0 Likes
Message 12 of 22

john.uhden
Mentor
Mentor

@Tom2023 

I think my hunger and the aroma made me hasty.  I will fix.

John F. Uhden

Message 13 of 22

pdecanio1
Explorer
Explorer

@john.uhden 

 

I came across this and is similar to something I was working on. Are you able to modifiy this to allow for "effective names"? 

 

          (setq obj1 (vlax-ename->vla-object (car (entsel "\nPick old block: "))))
          (= (vlax-get obj1 'ObjectName) "AcDbBlockReference")
        )
        (princ (strcat "  Old block name = \"" (setq name1 (vla-get-effectivename obj1)) "\""))
        (prompt "\nObject not selected or is not a block reference.")
      )
      (if
        (and
          (setq  obj2 (vlax-ename->vla-object (car (entsel "\nPick new block: "))))
          (= (vlax-get obj2 'ObjectName) "AcDbBlockReference")
        )
        (princ (strcat "  New block name = \"" (setq name2 (vla-get-effectivename obj2)) "\""))
        (prompt "\nObject not selected or is not a block reference.")

 

I modified this part and it seemed to work and put the effective names in instead of the *U name autocad gives dynamic blocks...

 

This is what i get when testing it

pdecanio1_0-1690303589825.png

 

Would be very useful. 

 

Thanks in advance 

0 Likes
Message 14 of 22

Kent1Cooper
Consultant
Consultant

Kent1Cooper_0-1690303942085.png

Unfortunately, that's because the <Replaceall> option tries (ssget)-ing with filtering for the Block name.  It's one thing to get the effective name from a dynamic Block insertion, but sadly, (ssget) cannot filter for that, because it doesn't show up anywhere in the insertion's entity data, which is what the filter is looking at.  I suspect it will be necessary, in the case of a source Block being dynamic, to have it select all Blocks, and step through getting the effective name of each to compare to that of the source.

Kent Cooper, AIA
0 Likes
Message 15 of 22

pdecanio1
Explorer
Explorer

@Kent1Cooper 

Thanks for the response. 

 

I am no code guru, I can look and somewhat modify and write some easy stuff.

 

I am not sure how to do what you just mentioned. 

 

Can the name be saved to a variable and just us that variable to be the block names?

 

I am fine with all blocks in the whole drawing with the saved name to changed. 

 

 

0 Likes
Message 16 of 22

Kent1Cooper
Consultant
Consultant

@pdecanio1 wrote:

....

I am not sure how to do what you just mentioned. 

....


Maybe we should let @john.uhden do the modification, but questions arise:

What if the source and the target Blocks are not of the same variety [i.e. either not both "plain" or not both dynamic]?  Would you ever want to replace one of one variety with one of the other variety?  Should it check that they're both the same kind?

And if a dynamic Block can be replaced just by changing its effective Block name, as a plain one can, what happens to whatever dynamic property settings or values it had?  Do the old and new Block definitions need to have the same dynamic ingredients?

Kent Cooper, AIA
0 Likes
Message 17 of 22

pdecanio1
Explorer
Explorer

@Kent1Cooper 

 


@Kent1Cooper wrote:

@pdecanio1 wrote:

....

I am not sure how to do what you just mentioned. 

....


Maybe we should let @john.uhden do the modification, but questions arise:

What if the source and the target Blocks are not of the same variety [i.e. either not both "plain" or not both dynamic]?  Would you ever want to replace one of one variety with one of the other variety?  Should it check that they're both the same kind?

And if a dynamic Block can be replaced just by changing its effective Block name, as a plain one can, what happens to whatever dynamic property settings or values it had?  Do the old and new Block definitions need to have the same dynamic ingredients?


We have alot of old drawings that have old blocks we have to go back to sometimes and we would like to update the drawings to our newer blocks. Yes the old attributes may not come over if they dont have the same attribute tags as the new blocks. Which will be the case on some. We are unworried about that we will just make them right.

 

Alot of our old blocks are not dynamic which we want them to be now, a complete replacement of these is probably what will happen and again if they have or dont have the tag names is something that will have to be dealt with.

0 Likes
Message 18 of 22

pendean
Community Legend
Community Legend

@pdecanio1 wrote:

We have alot of old drawings that have old blocks we have to go back to sometimes and we would like to update the drawings to our newer blocks. Yes the old attributes may not come over if they dont have the same attribute tags as the new blocks. Which will be the case on some. We are unworried about that we will just make them right.

 

Alot of our old blocks are not dynamic which we want them to be now, a complete replacement of these is probably what will happen and again if they have or dont have the tag names is something that will have to be dealt with.


How 'unusable' is the simpler method of INSERTing an old file into a Master template file with your new block definitions already in place for an auto-replacement: old attributes should tag along, same-named blocks and layers get replaced then SAVEAS and tidy-up a smaller list of tasks instead?

0 Likes
Message 19 of 22

Kent1Cooper
Consultant
Consultant

@pendean wrote:
.... the simpler method of INSERTing an old file into a Master template file with your new block definitions already in place ....

.... depends on the new Blocks all having the same names as the old ones.  @pdecanio1, is that always the case for you?

Kent Cooper, AIA
0 Likes
Message 20 of 22

pendean
Community Legend
Community Legend

@Kent1Cooper wrote:

@pendean wrote:
.... the simpler method of INSERTing an old file into a Master template file with your new block definitions already in place ....

.... depends on the new Blocks all having the same names as the old ones.  @pdecanio1, is that always the case for you?


Indeed

pendean_0-1690308755607.png

 

0 Likes