Change Specified Dynamic Blocks to Static

Change Specified Dynamic Blocks to Static

akaterr55
Advocate Advocate
3,975 Views
15 Replies
Message 1 of 16

Change Specified Dynamic Blocks to Static

akaterr55
Advocate
Advocate

Looking to Change Specific Dynamic Blocks to "Regular" Blocks

Referencing the thread started by Burniksapwet 11-18-2016

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/change-dynamic-block-to-regular-bloc...

whose post referenced a thread at theswamp
http://www.theswamp.org/index.php?topic=32681.msg382548#msg382548
where it looks like MP originated the code

Which Pbejse solved with an "undynamic.lsp" that works wonderfully on every dynamic block in a drawing. I love how it appends the effective names for the resulting "regular" blocks!

My posts to that thread were back in Feb 2017, where I was trying to make Pbejse's lisp work only on dynamic blocks in model space. But since then, I've come up with perhaps a better scenario if it could be made to work.

 

Now this may be asking the impossible, but here goes:

A list of block names to be acted upon, either within the "undynamic" lisp itself, or possibly a separate file? (which may actually be easier and less risky for users to update the list and not mess up the actual code)

A command that checks the drawing for any dynamic blocks listed in the block list file, and if it encounters any of them, runs the "undynamic" action.

So i guess there could be 3 separate files. "Undynamic.lsp" "Checker.lsp", and "BlockList" (not sure if blocklist would be a .txt or .lsp)

This is how I envision it working...

User loads the "Checker" lisp and initiates the "Checker"
A Counter is set to zero, and the "Checker" checks the drawing for dynamic blocks listed in the "BlockList" file.
if counter remains zero, checker simply exits.
If counter hits 1, checker stops checking, runs "Undynamic".
"Undynamic" lisp reads the same "BlockList" file and converts all the dynamic blocks in the drawing that are in the list.

I think the "Undynamic.lsp" pbejse posted overwrites the dynamics with the corresponding static blocks, but if not of course purge the DB's that are on the list

Maybe "undynamic.lsp" gives a report at the end something like "(# of) Dynamic Blocks converted to Standard Blocks"? (guess that's not really necessary but would give the user some assurance that something did in fact happen). Possibly, if "Checker.lsp" finds no match, reports something like "No matching Dynamic Blocks Found" ?

 

Attached is the "undynamic.lsp" posted by pbejse Nov 2016 for reference.

 

Anyone wants to take a crack at this please do, and please also share your results!

Thanks!

0 Likes
Accepted solutions (1)
3,976 Views
15 Replies
Replies (15)
Message 2 of 16

Anonymous
Not applicable

Something like this?

 

(defun c:UnDynamicSelect
    (   /
        _get_item
        _right
        _make_key
        _dynamic->static_block
        _get_locked
        _get_dynamic_inserts
        _main
     	bn_lst
    	adoc
    )

  ;; Unique  -  Lee Mac
;; Returns a list with duplicate elements removed.

(defun LM:Unique ( l )
    (if l (cons (car l) (LM:Unique (vl-remove (car l) (cdr l)))))
)
  


  ;acquired from lee-mac's steal routine
  (defun steal:listbox ( title lst / *error* dch des tmp res )

    (defun *error* ( msg )
        (if (< 0 dch)
            (unload_dialog dch)
        )
        (if (= 'file (type des))
            (close des)
        )
        (if (and (= 'str (type tmp)) (setq tmp (findfile tmp)))
            (vl-file-delete tmp)
        )
        (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
            (princ (strcat "\nError: " msg))
        )
        (princ)
    )
    
    (cond
        (   (not
                (and
                    (setq tmp (vl-filename-mktemp nil nil ".dcl"))
                    (setq des (open tmp "w"))
                    (write-line
                        (strcat
                            "listbox : dialog { label = \""
                            title
                            "\"; spacer; : list_box { key = \"list\"; multiple_select = false"
                            "; } spacer; ok_cancel; }"
                        )
                        des
                    )
                    (not (close des))
                    (< 0 (setq dch (load_dialog tmp)))
                    (new_dialog "listbox" dch)
                )
            )
            (prompt "\nError loading Steal list box.")
        )
        (   t     
            (start_list "list")
            (foreach item lst (add_list item))
            (end_list)
            (setq res (set_tile "list" "0"))
            (action_tile "list" "(setq res $value)")
            (setq res
                (if (= 1 (start_dialog))
                    (mapcar '(lambda ( x ) (nth x lst)) (read (strcat "(" res ")")))
                )
            )
        )
    )
    (if (< 0 dch)
        (setq dch (unload_dialog dch))
    )
    (if (and (= 'str (type tmp)) (setq tmp (findfile tmp)))
        (vl-file-delete tmp)
    )
    res
)

  
    (defun _get_item ( collection key / item )
        (vl-catch-all-apply
           '(lambda ( ) (setq item (vla-item collection key)))
        )
        item
    )
    (defun _right ( str n / len )
        (if (< n (setq len (strlen str)))
            (substr str (1+ (- len n)))
            str
        )
    )
    (defun _make_key ( collection prefix len / key )
        (   (lambda ( i pad )
                (while
                    (_get_item collection
                        (setq key
                            (strcat prefix
                                (_right
                                    (strcat pad (itoa (setq i (1+ i))))
                                    len
                                )
                            )
                        )
                    )
                )
                key
            )
            0
            (   (lambda ( pad )
                    (while (< (strlen pad) len)
                        (setq pad (strcat "0" pad))
                    )
                    pad
                )
                ""
            )
        )
    )


;;;				Autodesk Lisp Forum            			;;;

      
      (defun _dynamic->static_block ( blocks insert len blst / f bn  bnr)
       (setq bn  (vla-get-effectivename insert))    
        (vla-ConvertToStaticBlock
            insert
            (setq bnr (_make_key blocks (strcat bn " ") len))
        )
        (setq bnr (list bn (vl-string-left-trim (strcat bn " ") bnr) insert))   
        (if (setq f (assoc bn blst))
			 (subst bnr f blst)(cons bnr blst))
	)

;;;				Autodesk Lisp Forum            			;;;

      
    (defun _get_locked ( layers / locked selectedinsertsname )
        (vlax-for layer layers
            (if (eq :vlax-true (vla-get-lock layer))
                (setq locked (cons layer locked))
            )
        )
        locked
    )
    (defun _get_dynamic_inserts ( blocks / inserts )
        (vlax-for block blocks
            (vlax-for object block
                (if (eq "AcDbBlockReference" (vla-get-objectname object))
                    (if (eq :vlax-true (vla-get-isdynamicblock object))
                        (setq inserts (cons object inserts))
                    )
                )
            )
        )
      
       (if (setq selectedinsertsname (steal:listbox "Select the dynamic blocks you want static" (LM:Unique (mapcar 'vla-get-effectivename inserts))))
      (vl-remove-if-not '(lambda (x) (member (vla-get-effectivename x) selectedinsertsname)) inserts)
	 nil)
    )
    (defun _main ( document / blocks inserts locked len )
        (if
            (setq inserts
                (_get_dynamic_inserts
                    (setq blocks (vla-get-blocks document))
                )
            )
            (progn
                (foreach layer (setq locked (_get_locked (vla-get-layers document)))
                    (vla-put-lock layer :vlax-false)
                )
                (setq len (strlen (itoa (length inserts))))
                (foreach insert inserts
		(Setq bn_lst
                    (_dynamic->static_block blocks insert len bn_lst))
                      
                )
                (foreach layer locked
                    (vla-put-lock layer :vlax-true)
                )
            )
        )
        (princ)
    )


;;;				Autodesk Lisp Forum            			;;;

	(repeat 4 (vla-purgeall (setq adoc (vla-get-activedocument (vlax-get-acad-object)))))
      
	(_main adoc)
      
	(repeat 4 (vla-purgeall adoc))
	(setq blocks (vla-get-blocks adoc))
	(foreach itm bn_lst
		(vl-catch-all-error-p (vl-catch-all-apply 'vla-put-name 
		          (list (vla-item blocks (Strcat (Car itm)" "(cadr itm))) (Car itm))))
	   )

;;;				Autodesk Lisp Forum            			;;;
          
)	
Message 3 of 16

marko_ribar
Advisor
Advisor

I haven't checked those :

 

https://apps.autodesk.com/ACD/en/Detail/Index?id=421424494546632668&appLang=en&os=Win32_64

 

https://apps.autodesk.com/ACD/en/Detail/Index?id=7901627291041905160&appLang=en&os=Win32_64

 

But there they are... Of course it's not my recommendation, but it's some kind of answer to your question - I know it's stupid but who knows, maybe it help you and folks that checked them...

 

Regards, M.R.

Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 4 of 16

pbejse
Mentor
Mentor

akaterr55 wrote: 

....Anyone wants to take a crack at this please do, and please also share your results!

Thanks!


Were you able to try the code at post#2? ( by zraboin  ) and how did it go?

 

0 Likes
Message 5 of 16

akaterr55
Advocate
Advocate

Yes, Tried all 3 so far.  

Zabroin's code scans the drawing and brings a up a list box of all the DB's in the drawing, allowing the user to choose one and make all instances of that block static.

The two links marco_ribar posted are add-ins.  Both of those do convert to static.  One leaves the anonymous names the other appends the effective names like the one you modded.

I do want to thank zabroin and ribar for their posts!

All three though require the user to select in some form or another, so the quest continues.

 

 

0 Likes
Message 6 of 16

pbejse
Mentor
Mentor

@akaterr55 wrote:

Yes, Tried all 3 so far.  

 

.....All three though require the user to select in some form or another, so the quest continues.

 

 


What would the  BlockList file look like akaterr55?  

0 Likes
Message 7 of 16

akaterr55
Advocate
Advocate

Now that I think about it, a seperate block list file isn't all that crucial.  And I don't know if pathing (just about everything is network here) would be a problem with a separate?

Here is a draworder routine, the "guts" of which I scabbed from somewhere (don't know who the author is)

that is kind of the direction I figured something like this would lean.  Of course this one requires user selection, only works on mspace, and it doesn't check for the existence of the named db's first.

(Defun c:FriDO ()

(setvar "cmdecho" 0)(princ)

(prompt "Select Frame Objects to Be DrawOrdered:")
(Setq FRS (ssget))

(Defun SetPrev () (command "select" frs ""))

(defun DrOrder () (setq blst (apply 'strcat (mapcar '(lambda (b) (strcat "," (strcase b))) blklst)))
(if (setq ss1 (ssadd) ss (ssget "P" (list '(0 . "insert") (cons 2 (strcat "`*U*" blst)) '(410 . "model"))))
 (repeat (setq i (sslength ss))
 (setq object (vlax-ename->vla-object (setq e (ssname ss (setq i (1- i)))))
      blkname (vlax-get object (if (vlax-property-available-p object 'EffectiveName) 'EffectiveName 'Name)))
    (if (wcmatch (strcase blkname) blst)
    (ssadd e ss1))))
(if (< 0 (sslength ss1))(command "draworder" ss1 "" "b")))

;--------------------------BLOCK LIST--------------------------------------

(SetPrev)(setq blklst (list  "FrisoTransAngle"))     (drorder)
(SetPrev)(setq blklst (list  "FrisoBackBoneLeg"))    (drorder)
(SetPrev)(setq blklst (list  "FrisoBackBone"))       (drorder)
(SetPrev)(setq blklst (list  "Friso*Holes-Front"))   (drorder)
(SetPrev)(setq blklst (list  "FrisoFrame-Front"))    (drorder)
(SetPrev)(setq blklst (list  "FRisoDivSide-Front"))  (drorder)
(SetPrev)(setq blklst (list  "FrisoDiag-Top"))       (drorder)
(SetPrev)(setq blklst (list  "FrisoDivision-T"))     (drorder)
(SetPrev)(setq blklst (list  "FrisoDivision-A"))     (drorder)
(SetPrev)(setq blklst (list  "FrisoDiag-Bottom"))    (drorder)
(SetPrev)(setq blklst (list  "FrisoDivSide-Back"))   (drorder)
(SetPrev)(setq blklst (list  "Friso*Holes-Back"))    (drorder)
(SetPrev)(setq blklst (list  "FrisoFrame-Back"))     (drorder)

;--------------------------------------------------------------------------

(setprev)
(prompt "Done!")(princ)
)
0 Likes
Message 8 of 16

pbejse
Mentor
Mentor

So you're saying zraboin the posted code works but you dont want the user to select a block name or any user input?

 

What you want is a code that will search the drawing database for blocks [ the checker ]

 

(defun _checker ( blocks BlockList / inserts )
        (vlax-for block blocks
            (vlax-for object block
                (if (eq "AcDbBlockReference" (vla-get-objectname object))
                    (if (and
                              (eq :vlax-true (vla-get-isdynamicblock object))
                              (member (Strcase (vla-get-effectivename object)) BlockList)
                              )
                        (setq inserts (cons object inserts))
                    )
                )
            )
        )
          inserts
)

(setq blocks (vla-get-blocks (vla-get-ActiveDocument (vlax-get-acad-object))))
(setq BlockList '("FRISOBACKBONELEG" "FRISOBACKBONE" "FRISO*HOLES-FRONT" "FRISOFRAME-FRONT"));; sample list

(setq resultfromchecker (_checker blocks BlockList));;< ---- the blocks found


And then?  Undynamic the selected blocks? 

 

I think the "Undynamic.lsp" pbejse posted overwrites the dynamics with the corresponding static blocks, but if not of course purge the DB's that are on the list

 

Does that mean you want to keep the orignal Dynamic block reference on the drawing session?

 

0 Likes
Message 9 of 16

pbejse
Mentor
Mentor

command: UnDynamicListedBlocks

 

 

Converted 12 Dynamic Block(s)
 FRisoDivSide-Front..............................07
 FrisoDiag-Top...................................05

HTH

 

 

Message 10 of 16

akaterr55
Advocate
Advocate

Right, that works one block at a time, and the user would need to do each one and avoid those I don't want acted upon.

The best way in my mind is to have those "high value" DB's in a list and automatically hit just those. 

 

On the Checker - That's where the counter part of the checker was coming in.  Sets to zero to begin with, and if checker finds none of the listed blocks remains at zero and does nothing.  If it hits one block in the list the counter advances to 1 triggering the undynamic action on all the blocks it finds in the drawing (that are on the list)  So maybe not gathering up all the listed blocks first then acting on that collection, but checking for the existence any one of them and if it finds even one, then running the action.  

 

 

As far as purging, it looked like that code you fixed up before essentially did the same thing by overwriting the definition of the first of each DB it processed with the effective name (before appending the effective names with a _1, _2, etc.) .  But yes, the listed blocks would need to be purged if that is not the case.

 

0 Likes
Message 11 of 16

pbejse
Mentor
Mentor
I see.

Say there are 5 "A" Dynamic blocks, convert the other four and leave one as it is but renamed to "A_0", and if there's only one "A" block ignore it and processed the other blocks found? or Rename the "A" block as "A_0" but not converted to static?

 

1 found do absolutely nothing

5 found process the other 4 and  leave one as it is.

 

 

0 Likes
Message 12 of 16

akaterr55
Advocate
Advocate

I'm sorry probably didn't say that right.  That checker scans the drawing for the listed blocks, and if it comes across even one of them, it goes ahead and runs the undynamic using that same list on the whole drawing.

 

In the end, none of the dynamics on the list should remain (as dynamics)

 

As far as the renaming.  That one you did up for burkinswapet 11/2016 actually does overwrite the first instance of the block it processes with the original dynamic block name, then starts appending them with  " 01" " 02" and so on.

But that one processes the whole drawing for every single DB in the database.  I Guess it doesn't really matter if it starts appending the names right off the bat.  I just really like the appended effective names versus the *U107 type of anonymous names.

 

 

 

0 Likes
Message 13 of 16

pbejse
Mentor
Mentor
Accepted solution

@akaterr55 wrote:

.....That checker scans the drawing for the listed blocks, and if it comes across even one of them, it goes ahead and runs the undynamic using that same list on the whole drawing.

 

In the end, none of the dynamics on the list should remain (as dynamics) 


I see. 

Say there are 5 "A" Dynamic blocks......  [  déjà vu 

 


@akaterr55 wrote:

 

 

That one you did up for burkinswapet 11/2016 actually does overwrite the first instance of the block it processes with the original dynamic block name, then starts appending them with  " 01" " 02" and so on. 


Aha!!! This from here .... 

 

 

....      
(_main adoc BlockList)

(repeat 4 (vla-purgeall adoc))
(setq blocks (vla-get-blocks adoc))
(foreach itm bn_lst
(vl-catch-all-error-p (vl-catch-all-apply 'vla-put-name
(list (vla-item blocks (Strcat (Car itm)" "(cadr itm))) (Car itm))))
)
....

 

HTH

Message 14 of 16

DannyNL
Advisor
Advisor

I know this is still somewhat limited, but you would need something like this I guess?

 

This one will read a list of blocks from a .INI file and process a drawing. It will first check for the existence of each block in the drawing before processing the drawing. The names of the new static blocks will be the 'dynamic name' (*U117 without the *) added at the end of the effective name.

 

Not yet full proof as some necessary checks are missing and it is limited at this moment as it will only process blocks on layers that can be modified, so locked and frozen layers are not included at this moment. Purging is also not executed, but all these should be fairly easily be added to the routine. In fact, it could be something that is also configurable in the .INI file in a separate section.

 

 

(defun c:ConvertDynamicToStaticBlock (/ CDTSB_IniFile CDTSB_BlockList CDTSB_BlockDef CDTSB_BlockCollection CDTSB_BlockProcessList CDTSB_CurrentName CDTSB_NewName)
   (if
      (and
         (setq CDTSB_IniFile   (findfile "CDTSB_Settings.ini"))
         (setq CDTSB_BlockList (mapcar 'strcase (acet-ini-get CDTSB_IniFile "BLOCKLIST")))
      )
      (progn
         (setq CDTSB_BlockCollection (vla-get-Blocks (setq CDTSB_ActiveDoc (vla-get-ActiveDocument (vlax-get-acad-object)))))         
         (foreach CDTSB_BlockName CDTSB_BlockList
            (if
               (and
                  (not (vl-catch-all-error-p (setq CDTSB_BlockDef (vl-catch-all-apply 'vla-item (list CDTSB_BlockCollection CDTSB_BlockName)))))
                  (= (vla-get-IsDynamicBlock CDTSB_BlockDef) :vlax-true)
               )
               (setq CDTSB_BlockProcessList (append CDTSB_BlockProcessList (list CDTSB_BlockName)))
            )
         )
         (if
            CDTSB_BlockProcessList
            (progn
               (vla-StartUndoMark CDTSB_ActiveDoc)
               (vlax-for CDTSB_Layout (vla-get-Layouts CDTSB_ActiveDoc)
                  (vlax-for CDTSB_Object (vla-get-Block CDTSB_Layout)
                     (if
                        (and
                           (= (vla-get-ObjectName CDTSB_Object)     "AcDbBlockReference")
                           (member (strcase (setq CDTSB_CurrentName (vla-get-EffectiveName CDTSB_Object))) CDTSB_BlockProcessList)
                        )
                        (progn
                           (if
                              (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-ConvertToStaticBlock (list CDTSB_Object (setq CDTSB_NewName (strcat CDTSB_CurrentName "-" (vl-string-left-trim "*" (vla-get-Name CDTSB_Object))))))))
                              (princ (strcat "\nCreated: " CDTSB_NewName))
                           )
                        )
                     )
                  )
               )
               (vla-EndUndoMark CDTSB_ActiveDoc)
            )
         )
         (mapcar 'vlax-release-object (list CDTSB_BlockCollection CDTSB_ActiveDoc))
      )
   )
   (princ)
)

 

The contents of the CDTSB_Settings.ini. Please note the '=' at the end of each entry as this is required for the acet-ini-get to be able to read each entry.

 

[BLOCKLIST]
Block1=
Block2=
International Speed Limit Sign - Imperial=
Block3=

 

Message 15 of 16

akaterr55
Advocate
Advocate

Pbejse,

Sorry for the late reply, just got swamped today.  Tried out version 1.1 last night and it worked very well and it does leave one instance intact (as you intended I presume).  Never did figure out where in the code that leave one alive part is...

Anyhow, saw your version 299.0 this morning but didn't get to check it out till just now.

 

Man that works great!  Sorry about being all needy and everything, but you stuck in there and made it work like a charm!  There's nothing I don't like about it!  Perfect!  Thanks So Much!!

-Mark

0 Likes
Message 16 of 16

akaterr55
Advocate
Advocate

DannyNL,

Have yet to try this with the ini file method you've come up with, but I will soon.  

Thanks for your reply!

-Mark

0 Likes