TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Woabow on October 09, 2013, 11:35:55 AM

Title: Replace block, also when to be replaced block is nested
Post by: Woabow on October 09, 2013, 11:35:55 AM
There are several methods of replacing a block:

BLOCKREPLACE: does not replace blocks when they are inside another block
-INSERT old=new: works on nested blocks, but does end up with the old blockname. Renaming globally is not possible because there could have been old blocks in the drawing that should not be renamed.
LISP PROGRAMS: As far as I know all lisp programs work with a selection and will not replace nested blocks.

Any suggestions?



Title: Re: Replace block, also when to be replaced block is nested
Post by: kruuger on October 09, 2013, 01:38:22 PM
There are several methods of replacing a block:

BLOCKREPLACE: does not replace blocks when they are inside another block
-INSERT old=new: works on nested blocks, but does end up with the old blockname. Renaming globally is not possible because there could have been old blocks in the drawing that should not be renamed.
LISP PROGRAMS: As far as I know all lisp programs work with a selection and will not replace nested blocks.

Any suggestions?
maybe you can use design center CTRL+2
kruuger
Title: Re: Replace block, also when to be replaced block is nested
Post by: Woabow on October 10, 2013, 02:14:19 AM
Ok, thanks. But Bricscad does not have Designcenter. Maybe it explains why I can't find a lisp.

Title: Re: Replace block, also when to be replaced block is nested
Post by: roy_043 on October 10, 2013, 04:16:45 AM
-INSERT old=new: works on nested blocks, but does end up with the old blockname. Renaming globally is not possible because there could have been old blocks in the drawing that should not be renamed.
Woabow, globally changing all block references from 'old' to 'new' would be equivalent to this. Can you clarify what you want to do?
Title: Re: Replace block, also when to be replaced block is nested
Post by: Woabow on October 10, 2013, 07:06:51 AM
The goal is to replace a block with another block, say "new"replaces "old". But it should also replace all blocks with the name "old" inside other blocks. And in the end all replaced blocks should have the name "new".

With -INSERT old=new all replaced blocks are named "old", not "new".

I cannot rename "old" to "new" because I might rename blocks with the name "new" which existed before the insert. I tried to use a temporarily name before the insert ("old" > "temp"), but this doesn't work also because afterwards I want to rename "temp" to "new" which is not allowed when "new"already existed in the drawing.

Title: Re: Replace block, also when to be replaced block is nested
Post by: Bhull1985 on October 10, 2013, 08:11:27 AM
Please post a sample drawing with examples of the blocks you are dealing with.
I deal with blocks daily but am having a hard time understanding exactly what you are requiring.
Title: Re: Replace block, also when to be replaced block is nested
Post by: Woabow on October 10, 2013, 09:11:09 AM
In attached drawing replace1.dwg are OLD blocks and NEW blocks. There is also a block BLOCKWITHBLOCKS which contains OLD (and NEW).

I just want to replace all OLD blocks with NEW, like in replace2.dwg.

Not by hand, because in real life the OLD blocks are nested in many other blocks, on different levels.

Title: Re: Replace block, also when to be replaced block is nested
Post by: ronjonp on October 10, 2013, 09:50:25 AM
I think this should do what you want. The new block definition has to exist in the drawing though.
Code: [Select]
(defun _updateblocks (old new)
  (if (tblobjname "block" new)
    (vlax-for b (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
      (vlax-for bb b
(if (and (= (vla-get-objectname bb) "AcDbBlockReference")
(wcmatch (strcase (vla-get-name bb)) (strcase old))
(print (vla-get-name bb))
    )
  (vl-catch-all-apply 'vla-put-name (list bb new))
)
      )
    )
  )
)
(_updateblocks "old" "new")
Title: Re: Replace block, also when to be replaced block is nested
Post by: roy_043 on October 10, 2013, 09:52:05 AM
Try this:
Code - Auto/Visual Lisp: [Select]
  1. (defun KGA_Conv_Collection_To_List (coll / ret)
  2.     (vlax-for a coll
  3.       (setq ret (cons a ret))
  4.     )
  5.   )
  6. )
  7.  
  8. (defun BKG_ReplaceBlock_InputName (message / input)
  9.   (setq input (getstring T message))
  10.   (if (= input "")
  11.     (if (setq input (car (entsel)))
  12.       (cdr (assoc 2 (entget input)))
  13.     )
  14.     input
  15.   )
  16. )
  17.  
  18. (defun c:BKG_ReplaceBlock ( / actDocObject blockFile blockNameNew blockNameOld count)
  19.   (if (= (logand (getvar 'undoctl) 8) 8)
  20.     (vla-endundomark actDocObject)
  21.   )
  22.   (vla-startundomark actDocObject)
  23.   (if
  24.     (and
  25.       (setq blockNameOld
  26.         (BKG_ReplaceBlock_InputName "\nBlock to replace (Enter to select): ")
  27.       )
  28.       (tblobjname "block" blockNameOld)
  29.       (setq blockNameNew
  30.         (BKG_ReplaceBlock_InputName
  31.           (strcat "\nReplace '" blockNameOld "' block with (Enter to select): ")
  32.         )
  33.       )
  34.       (or
  35.         (tblobjname "block" blockNameNew)
  36.         (and
  37.           (snvalid blockNameNew)
  38.           (setq blockFile (getfiled "Select a drawing" " " "dwg;dxf" 0))
  39.           (setvar 'cmdecho 0)
  40.           (not (command "_.insert" (strcat blockNameNew "=" blockFile) nil))
  41.           (setvar 'cmdecho 1)
  42.           (tblobjname "block" blockNameNew)
  43.         )
  44.       )
  45.     )
  46.     (progn
  47.       (setq blockNameOld (strcase blockNameOld))
  48.       (setq count
  49.         (length
  50.           (vl-remove
  51.             nil
  52.             (apply
  53.               'append
  54.               (mapcar
  55.                 '(lambda (blockDefObject)
  56.                   (mapcar
  57.                     '(lambda (object)
  58.                       (if
  59.                         (and
  60.                           (= (vla-get-objectname object) "AcDbBlockReference")
  61.                           (= (strcase (vla-get-name object)) blockNameOld)
  62.                         )
  63.                         (progn
  64.                           (vla-put-name object blockNameNew)
  65.                           T
  66.                         )
  67.                       )
  68.                     )
  69.                     (KGA_Conv_Collection_To_List blockDefObject)
  70.                   )
  71.                 )
  72.                 (KGA_Conv_Collection_To_List (vla-get-blocks actDocObject))
  73.               )
  74.             )
  75.           )
  76.         )
  77.       )
  78.       (princ (strcat "\n" (itoa count) " block reference(s) updated "))
  79.     )
  80.   )
  81.   (vla-endundomark actDocObject)
  82.   (princ)
  83. )
  84.  
  85. (defun c:BRBL ()
  86.   (c:BKG_ReplaceBlock)
  87. )
  88.  
  89. (princ "\nUse: BKG_ReplaceBlock or BRBL ")
Title: Re: Replace block, also when to be replaced block is nested
Post by: CAB on October 10, 2013, 09:55:13 AM
An old lisp: (I did not look at your example)
http://www.theswamp.org/index.php?topic=2272.0
Title: Re: Replace block, also when to be replaced block is nested
Post by: Woabow on October 10, 2013, 10:29:00 AM
Thanks! Both programs work great.

The vla-put-name does the trick? I can't find documentation about this function...


Title: Re: Replace block, also when to be replaced block is nested
Post by: CAB on October 10, 2013, 11:21:16 AM
Try highlighting  vla-put-name in VLIDE & press Ctrl+Shift+A
Title: Re: Replace block, also when to be replaced block is nested
Post by: Lee Mac on October 10, 2013, 11:31:07 AM
Here is an online reference for the Name property:
http://entercad.ru/acadauto.en/idh_name.htm (http://entercad.ru/acadauto.en/idh_name.htm)

Here is the full ActiveX & VBA reference:
http://entercad.ru/acadauto.en/ (http://entercad.ru/acadauto.en/)

Here is a short explanation of how to use the reference:
http://bit.ly/1ahKh6g (http://bit.ly/1ahKh6g)
Title: Re: Replace block, also when to be replaced block is nested
Post by: Woabow on October 10, 2013, 11:39:33 AM
Thanks a lot. I have underestimated ActiveX I guess.
Title: Re: Replace block, also when to be replaced block is nested
Post by: CAB on October 10, 2013, 12:54:23 PM
Nice explanation Lee, very helpful.
Title: Re: Replace block, also when to be replaced block is nested
Post by: kruuger on October 10, 2013, 12:54:45 PM
I think this should do what you want. The new block definition has to exist in the drawing though.
Code: [Select]
(defun _updateblocks (old new)
  (if (tblobjname "block" new)
    (vlax-for b   (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
      (vlax-for   bb b
   (if (and (= (vla-get-objectname bb) "AcDbBlockReference")
       (wcmatch (strcase (vla-get-name bb)) (strcase old))
       (print (vla-get-name bb))
       )
     (vl-catch-all-apply 'vla-put-name (list bb new))
   )
      )
    )
  )
)
(_updateblocks "old" "new")
wow . very interesting way to replace block :)
maybe vla-get-EffectiveName to replace dynamic also
kruuger
Title: Re: Replace block, also when to be replaced block is nested
Post by: Lee Mac on October 10, 2013, 12:56:21 PM
Nice explanation Lee, very helpful.

Cheers Alan 8-)
Title: Re: Replace block, also when to be replaced block is nested
Post by: ronjonp on October 10, 2013, 01:58:11 PM
I think this should do what you want. The new block definition has to exist in the drawing though.
Code: [Select]
...
wow . very interesting way to replace block :)
maybe vla-get-EffectiveName to replace dynamic also
kruuger


Code: [Select]
(defun _updateblocks (old new)
  (if (tblobjname "block" new)
    (vlax-for b (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
      (vlax-for bb b
(if (and (= (vla-get-objectname bb) "AcDbBlockReference")
(wcmatch (strcase (vlax-get bb
     (if (vlax-property-available-p bb 'effectivename)
       'effectivename
       'name
     )
   )
  )
  (strcase old)
)
(print (vla-get-name bb))
    )
  (vl-catch-all-apply 'vla-put-name (list bb new))
)
      )
    )
  )
)
;; (_updateblocks "old" "new")
;D
Title: Re: Replace block, also when to be replaced block is nested
Post by: roy_043 on October 10, 2013, 02:15:42 PM
@ronjonp: No need to check if the effectivename property is available.
I will update my code (thank you kruuger).
Title: Re: Replace block, also when to be replaced block is nested
Post by: roy_043 on October 10, 2013, 02:28:29 PM
Updated code:
Code - Auto/Visual Lisp: [Select]
  1. (defun KGA_Conv_Collection_To_List (coll / ret)
  2.     (vlax-for a coll
  3.       (setq ret (cons a ret))
  4.     )
  5.   )
  6. )
  7.  
  8. (defun BKG_ReplaceBlock_InputName (message / input)
  9.   (setq input (getstring T message))
  10.   (if (= input "")
  11.     (if
  12.       (and
  13.         (setq input (car (entsel)))
  14.         (setq input (vlax-ename->vla-object input))
  15.         (= (vla-get-objectname input) "AcDbBlockReference")
  16.       )
  17.       (vla-get-effectivename input)
  18.     )
  19.     input
  20.   )
  21. )
  22.  
  23. (defun c:BKG_ReplaceBlock ( / actDocObject blockFile blockNameNew blockNameOld count)
  24.   (if (= (logand (getvar 'undoctl) 8) 8)
  25.     (vla-endundomark actDocObject)
  26.   )
  27.   (vla-startundomark actDocObject)
  28.   (if
  29.     (and
  30.       (setq blockNameOld
  31.         (BKG_ReplaceBlock_InputName "\nBlock to replace (Enter to select): ")
  32.       )
  33.       (tblobjname "block" blockNameOld)
  34.       (setq blockNameNew
  35.         (BKG_ReplaceBlock_InputName
  36.           (strcat "\nReplace '" blockNameOld "' block with (Enter to select): ")
  37.         )
  38.       )
  39.       (or
  40.         (tblobjname "block" blockNameNew)
  41.         (and
  42.           (snvalid blockNameNew)
  43.           (setq blockFile (getfiled "Select a drawing" " " "dwg;dxf" 0))
  44.           (setvar 'cmdecho 0)
  45.           (not (command "_.insert" (strcat blockNameNew "=" blockFile) nil))
  46.           (setvar 'cmdecho 1)
  47.           (tblobjname "block" blockNameNew)
  48.         )
  49.       )
  50.     )
  51.     (progn
  52.       (setq blockNameOld (strcase blockNameOld))
  53.       (setq count
  54.         (length
  55.           (vl-remove
  56.             nil
  57.             (apply
  58.               'append
  59.               (mapcar
  60.                 '(lambda (blockDefObject)
  61.                   (mapcar
  62.                     '(lambda (object)
  63.                       (if
  64.                         (and
  65.                           (= (vla-get-objectname object) "AcDbBlockReference")
  66.                           (= (strcase (vla-get-effectivename object)) blockNameOld)
  67.                         )
  68.                         (progn
  69.                           (vla-put-name object blockNameNew)
  70.                           T
  71.                         )
  72.                       )
  73.                     )
  74.                     (KGA_Conv_Collection_To_List blockDefObject)
  75.                   )
  76.                 )
  77.                 (KGA_Conv_Collection_To_List (vla-get-blocks actDocObject))
  78.               )
  79.             )
  80.           )
  81.         )
  82.       )
  83.       (princ (strcat "\n" (itoa count) " block reference(s) updated "))
  84.     )
  85.   )
  86.   (vla-endundomark actDocObject)
  87.   (princ)
  88. )
  89.  
  90. (defun c:BRBL ()
  91.   (c:BKG_ReplaceBlock)
  92. )
  93.  
  94. (princ "\nUse: BKG_ReplaceBlock or BRBL ")
Title: Re: Replace block, also when to be replaced block is nested
Post by: roy_043 on October 10, 2013, 02:29:15 PM
And how about AcDbMInsertBlock...
Title: Re: Replace block, also when to be replaced block is nested
Post by: ronjonp on October 10, 2013, 02:38:12 PM
@ronjonp: No need to check if the effectivename property is available.
I will update my code (thank you kruuger).


What about for older versions of CAD ?
Title: Re: Replace block, also when to be replaced block is nested
Post by: roy_043 on October 11, 2013, 04:30:45 AM
What about for older versions of CAD ?
That is a good point. When were dynamic blocks introduced?
Title: Re: Replace block, also when to be replaced block is nested
Post by: roy_043 on October 11, 2013, 06:33:18 AM
Code: [Select]
;;; ======================================================================
;;; BKG_ReplaceBlock: Change the referenced name of inserts.
;;; ======================================================================
;;; Author:       Roy Klein Gebbinck (www.b-k-g.nl)
;;; Made for:     http://www.theswamp.org/index.php?topic=45490.0
;;; Version:      20131011.
;;; History:      20131011: Added xref and recursion check.
;;;               20131011: Added support for AcDbMInsertBlock.
;;;               20131011: Using effective name (thanks kruuger and ronjonp).
;;;               20131010: First version.
;;; ======================================================================
Title: Re: Replace block, also when to be replaced block is nested
Post by: ronjonp on October 11, 2013, 08:31:51 AM
What about for older versions of CAD ?
That is a good point. When were dynamic blocks introduced?


I think it was 2006 .. but don't know for sure.
Title: Re: Replace block, also when to be replaced block is nested
Post by: CAB on October 11, 2013, 08:42:48 AM
I have 2004 & 2006, 2006 has dynamic blocks.

Title: Re: Replace block, also when to be replaced block is nested
Post by: kruuger on October 11, 2013, 12:39:31 PM
Code: [Select]
;;; ======================================================================
;;; BKG_ReplaceBlock: Change the referenced name of inserts.
;;; ======================================================================
;;; Author:       Roy Klein Gebbinck (www.b-k-g.nl)
;;; Made for:     http://www.theswamp.org/index.php?topic=45490.0
;;; Version:      20131011.
;;; History:      20131011: Added xref and recursion check.
;;;               20131011: Added support for AcDbMInsertBlock.
;;;               20131011: Using effective name (thanks kruuger and ronjonp).
;;;               20131010: First version.
;;; ======================================================================
works nicely :) may come in handy someday

puzzle...when we replace attribute block with regular block attributes occurs in all inserts. how to attsync existing/inserted block ?

thanks
kruuger
Title: Re: Replace block, also when to be replaced block is nested
Post by: roy_043 on October 13, 2013, 06:18:44 AM
... how to attsync existing/inserted block ?
Code: [Select]
;;; ======================================================================
;;; BKG_ReplaceBlock: Change the referenced name of inserts.
;;; ======================================================================
;;; Author:       Roy Klein Gebbinck (www.b-k-g.nl)
;;; Made for:     http://www.theswamp.org/index.php?topic=45490.0
;;; Version:      20131013.
;;; History:      20131013: If the new block has no editable attributes,
;;;                         existing attribute references are deleted.
;;;                         Else there is an optional call to the Attsync
;;;                         command.
;;;               20131011: Added xref and recursion check.
;;;               20131011: Added support for AcDbMInsertBlock.
;;;               20131011: Using effective name (thanks kruuger and ronjonp).
;;;               20131010: First version.
;;; ======================================================================