Author Topic: redefining dynamic blocks  (Read 4207 times)

0 Members and 1 Guest are viewing this topic.

Birdy

  • Guest
redefining dynamic blocks
« on: July 26, 2006, 07:32:50 AM »
I love the functionality of dblocks, but here's an issue I have:

A number of our standard dblocks have been updated with additional functionality.  We pull them off our server from a "dblocks.dwg" file using tool palettes.

When I open an older drawing, it has the older dblocks.  The only way I've found to get the newer blocks in the old drawing is through design center (ugh).  I can plow in DC to the server drawing "dblocks" find the new and improved dblock, and right click, insert and redefine, into the old drawing.  This works fine but is kind of a drag plowing through the Design Center.

Anyone know of an easier way?

Sdoman

  • Guest
Re: redefining dynamic blocks
« Reply #1 on: July 26, 2006, 08:29:16 AM »
What happens when you use the Insert command to redefine the dynamic blocks?  I've had mixed results.  The old blocks do get redefined.  But sometimes the db's also auto-dynamically change size or move in position ever so slightly.

My work around is to use AutoLISP to collect all dynamic block properties from the old blocks in the drawing before redefining -- parameter values, insertion point, and attribute data.  Then I use the InsertBlock method to redefine the block.  And finally, I push the saved properties to each old block.  I can provide code if you're interested, but I have to find it and untangle it from the pile of spaghetti it is in.


Draftek

  • Guest
Re: redefining dynamic blocks
« Reply #2 on: July 26, 2006, 08:36:08 AM »
Your dealing with the nature of a block. When it gets inserted into the drawing the first time the definition gets stored into the block definition table. The inserts merely reference this (with some additional stuff for the dynamic ones).

The easiest way to redefine is to insert from a file and force the update. With your setup of blocks nested inside a drawing it would be more difficult. This is one reason why I use a library of individual blocks and not a drawing container.


Birdy

  • Guest
Re: redefining dynamic blocks
« Reply #3 on: July 26, 2006, 08:46:37 AM »
I'd prefer to just drag them in from my tool palette.  Problem is, if I do that with a block called "door" and that block is already defined in the old drawing, the new and improved block assumes the "old" block properties.

A lisp that could be run in an old (or any) drawing that would check for new dblock parameter sets and add them might work, but I wouldnt want it to change values of existing parameters.  Not sure that made sense to me, so sorry if it dont make sense to you :)

I guess it should work the same way the "redefine" option in DC works, cause that seems to do the trick.  (I've never liked that design center... maybe I should  just get over it :) )

Thanks Draftek, I see your point, but for our purposes I kinda like one drawing file (on server) with a bunch of dblocks in it.... I will rethink that method though.

'steved, go ahead and post the code when you get time.  I'll take a look at it.  No rush though, whenever you get a chance.  I just got a pile dropped on my desk, so it may be a few days till I get back to this.

Sdoman

  • Guest
Re: redefining dynamic blocks
« Reply #4 on: July 26, 2006, 08:49:04 AM »

With your setup of blocks nested inside a drawing it would be more difficult. This is one reason why I use a library of individual blocks and not a drawing container.


I agree.  I've been keeping all my dblocks in a single file for ease of editing.  Then wblock them out for inserting into other drawings.


Birdy, you posted as I was about to send this message.  I've got to go to work but will post code later today around noon pacific time, if not sooner.

Draftek

  • Guest
Re: redefining dynamic blocks
« Reply #5 on: July 26, 2006, 08:52:53 AM »
oh, I'm not saying there is a right or wrong way of storing blocks. It all depends on the use I think.

I have about 60,000 to keep up with, it would be difficult to contain them in one drawing....

Birdy

  • Guest
Re: redefining dynamic blocks
« Reply #6 on: July 26, 2006, 12:23:24 PM »
I agree.  I've been keeping all my dblocks in a single file for ease of editing.  Then wblock them out for inserting into other drawings.


Birdy, you posted as I was about to send this message.  I've got to go to work but will post code later today around noon pacific time, if not sooner.
Yeah, ease of editing is where I'm at... and now rethinking the ease of use side :)


Thanks.  (and then I found this thread...)

Sdoman

  • Guest
Re: redefining dynamic blocks
« Reply #7 on: July 26, 2006, 03:32:59 PM »
Ok as promised here is some code I cobbled together.  I hope it works cause I did this fast and dirty.

The goal is to redefine dynamic blocks in the current drawing with a dwg file on disk, usually located on your server.  Before redefining, the routine saves data from the existing blocks to be redefine: custom parameter values, insertioin point, and attribute values.  Then it use vla-insert from disk to redefine the db's in the dwg. 

You'll need to change the path to your dblock folder before running.  [See the (setq db-path ...) below right after the first defun.]  I keep all my DB's in one folder.  You will have to modify this code if you use more then one folder.

Anyhow, there isn't a lot of code comments, sorry.  And beware that this code was written on the fly, while having to do my real job of making drawings.  Did some real world testing, seems to work.  Not meant to be the best method or even a good method.  If you find a better way, let me know.

Code: [Select]

(defun c:dbupdate (/        attlst   blkname  blknames db-path  dprops
               layer    n        nobj     obj      ss       sslen
              )
  ;;
  (setq db-path "k:\\cfg\\acad\\objects\\blocks\\dbi\\")  ;; <-- change this to your path
  ;;
  (if (setq ss (sd:ssGetDblock "*")) ;_ change filter to suit
    (progn
      (setq n     0
            sslen (sslength ss)
      )
      (repeat sslen
        (setq obj     (vlax-ename->vla-object (ssname ss n))
              dprops  (sd:GetDBProps obj)
              layer   (vla-get-layer obj)
              attlst  (sd:getatts obj "*")
              blkname (sd:GetBlockName obj)
              n       (1+ n)
        )
        (if (not (vl-position blkname blknames))
          (progn (setq blknames (cons blkname blknames))
                 (setq blkname (strcat db-path blkname ".dwg"))
          )
        )
        (setq nobj (vla-insertblock
                     (vla-get-modelspace
                       (vla-get-activedocument (vlax-get-acad-object))
                     )
                     (vla-get-insertionpoint obj)
                     blkname
                     1
                     1
                     1
                     0
                   )
        )
        (vla-put-layer nobj (vla-get-layer obj))
        (mapcar '(lambda (a) (sd:putattributeVal nobj (car a) (cdr a)))
                (car attlst)
        )
        (sd:PutDBProps nobj dprops)
        (vla-put-insertionpoint nobj (vla-get-insertionpoint obj))
        (vla-delete obj)
      ) ;_ repeat
    ) ;_ progn
  ) ;_ if
  (princ)
)


Here are the subs I ripped from my library.  I hope I didn't miss any:
Code: [Select]

(defun sd:ssGetDblock (EffectiveName / filter n ssUser rslt)
  ;;
  ;; Function prompts the user to select blocks which
  ;; match the specified EffectiveName argument.
  ;;
  ;; Returns a selections set or nil
  ;;
  ;; Argument:
  ;;  EffectiveName = name of dblock.
  ;;  Can use wildcards accepted by ssget
  ;;
  ;; Example:
  ;; (setq ss (sd:ssGetDblock "ffc-cab-elev-*"))
  ;;  ->  <Selection set: 6f>
  ;;
  (setq EffectiveName
         (strcase EffectiveName)
        filter (list '(0 . "INSERT")
                     (cons 2 (strcat EffectiveName ",`*U#*"))
               )
        n 0
  )
  (prompt (strcat "\nBlocks with names not matching \""
                  EffectiveName
                  "\" will be discarded "
          )
  )
  (if (setq ssUser (ssget ":L" filter))
    (progn (setq rslt (ssadd))
           (repeat (sslength ssUser)
             (if (wcmatch
                   (strcase
                     (vla-get-effectivename
                       (vlax-ename->vla-object (ssname ssUser n))
                     )
                   )
                   EffectiveName
                 )
               (ssadd (ssname ssUser n) rslt)
             )
             (setq n (1+ n))
           )
           (princ (strcat "\n"
                          (itoa (sslength ssUser))
                          " selected, "
                          (itoa (- (sslength ssUser) (sslength rslt)))
                          " discarded, "
                          (itoa (sslength rslt))
                          " total"
                  )
           )
    )
  )
  rslt
)

(defun sd:GetBlockName (objent)
  ;; Returns Name of block given the block ename or vla-object
  ;; (sd:getblockname (car (entsel)))
  (if (= 'ENAME (type objent))
    (setq objent (vlax-ename->vla-object objent))
  )
  (cond ((not (vl-position
                (vla-get-objectname objent)
                '("AcDbMInsertBlock" "AcDbBlockReference")
              )
         )
         nil
        )
        ((and (vlax-property-available-p objent 'isdynamicblock)
              (eq (vla-get-isdynamicblock objent) :vlax-true)
         )
         (vlax-get-property objent "effectivename")
        )
        (t (vla-get-name objent))
  )
)

(defun sd:getatts
       (blkobj tagname / nattobjs cattobjs ListTagstrings GetTagstring)
;;;
;;; A multipurpose attribute extractor toolbox function
;;; By Steve Doman 4/26/06
;;;
;;; Given a block object or ename, and an attribute tag name,
;;; this function returns the value of the first matching tag name.
;;; If no match is found, the function returns nil.
;;;
;;; Example:
;;; (sd:getatts (car (entsel "\nSelect block: ")) "Eq-factor")
;;;  -> "SomeValue" or nil
;;;
;;; If the tag argument is "*", this function returns a list
;;; containing two lists as described below:
;;;
;;; The first list contains tagnames and values of all normal attibutes.
;;; If no normal attributes are found then the first list will be nil.
;;;
;;; The second list contains tagnames and values of all constant attributes.
;;; If no constant attriutes are found, then the second list will be nil.
;;;
;;; Example:
;;;   (setq rslt (getatts (car (entsel "\nSelect block: ") "*")))
;;;    -> '(((ntag1 . "nval1") (ntag2 . "nval2") (ntagNth . "nvalNth"))
;;;         ((ctag1 . "cval1") (ctag2 . "cval2") (ctagNth . "cvalNth"))
;;;        )
;;;
;;; From the result of the previous example, you can...
;;;
;;; Example: Get a list of only the normal attributes
;;;   (setq natts (car rslt))
;;;
;;; Example: Get a list of only the constant attributes
;;;   (setq catts (cadr rslt))
;;;
;;; Example: Combine both list into one
;;;  (setq both (append (car rslt)(cdr rslt)))
;;;
  (defun ListTagstrings (attobjlst)
    (mapcar
      '(lambda (o) (cons (vla-get-tagstring o) (vla-get-textstring o)))
      attobjlst
    )
  )
  ;;
  (defun GetTagstring (attobjlst tag / string)
    (setq tag (strcase tag))
    (vl-some
      '(lambda (o)
         (if (= (strcase (vla-get-tagstring o)) tag)
           (setq string (vla-get-textstring o))
         )
       )
      attobjlst
    )
    string
  )
  ;;
  (if (= (type blkobj) 'ename)
    (setq blkobj (vlax-ename->vla-object blkobj))
  )
  (if (and (= (vla-get-objectname blkobj) "AcDbBlockReference")
           (= (vla-get-hasattributes blkobj) :vlax-true)
      )
    (progn (setq nattobjs
                  (vl-catch-all-apply
                    'vlax-safearray->list
                    (list (vlax-variant-value (vla-getattributes blkobj))
                    )
                  )
           )
           (setq cattobjs
                  (vl-catch-all-apply
                    'vlax-safearray->list
                    (list (vlax-variant-value
                            (vla-getconstantattributes blkobj)
                          )
                    )
                  )
           )
           (if (vl-catch-all-error-p nattobjs)
             (setq nattobjs nil)
           )
           (if (vl-catch-all-error-p cattobjs)
             (setq cattobjs nil)
           )
           (if (= "*" tagname) ;_ ok, do it
             (list (ListTagstrings nattobjs) (ListTagstrings cattobjs))
             (cond ((GetTagstring nattobjs tagname))
                   ((GetTagstring cattobjs tagname))
             )
           )
    )
  )
)

(defun sd:GetDBProps (objent)
;;;
;;; Returns: a list containing a dynamic blocks custom properties
;;;
;;; Syntax : (GetDBProps ename|object)
;;;          where objent is an ename or vla-object of dynamic block
;;;
;;; Example: (GetDBProps (car (entsel "\nSelect dynamic block: ")))
;;;
;;; Based from code by Tony Tanzillo and Herman Mayfarth
;;;
  (if (= 'ENAME (type objent))
    (setq objent (vlax-ename->vla-object objent))
  )
  (vl-remove-if
    '(lambda (y) (= (car y) "Origin"))
    (mapcar '(lambda (x)
               (cons (vlax-get-property x "PropertyName")
                     (vlax-variant-value (vlax-get-property x "Value"))
               )
             )
            (vlax-safearray->list
              (vlax-variant-value (vla-getdynamicblockproperties objent))
            )
    )
  )
)

(defun sd:PutDBProps (objent lst / blkprops len propname propvalue n)
;;;
;;; Modifies the custom properties of a dynamic block
;;;
;;; Syntax  : (PutDBProps ename|object list)
;;;           where objent is an ename or vla-object of dynamic block
;;;           and list is a list of dotted pairs of property names and values
;;;
;;; Example1: (PutDBProps
;;;             (car (entsel "\nSelect dynamic block: "))
;;;             '(("Visibility" . "No Shelves")("Width" . 36.0))
;;;           )
;;;
;;; Example2: (PutDBProps
;;;             (car (entsel "\nSelect dynamic block: "))
;;;             (list
;;;               (cons
;;;                 "Flip state"
;;;                 (vlax-make-variant 1 vlax-vbinteger)
;;;               )
;;;              '("Width" . 36.0)
;;;             )
;;;           )
;;;
;;; Based from code by Tony Tanzillo and Herman Mayfarth
;;;
  (if (= 'ENAME (type objent))
    (setq objent (vlax-ename->vla-object objent))
  )
  (setq blkprops
         (vlax-safearray->list
           (vlax-variant-value
             (vla-getdynamicblockproperties objent)
           )
         )
  )
  (setq len (length blkprops))
  (foreach
         prop lst
    (setq n 0)
    (setq propname (car prop))
    (setq propvalue (cdr prop))
    (while (< n len)
      (if
        (= propname (vlax-get-property (nth n blkprops) "PropertyName"))
         (progn (vl-catch-all-apply
                  'vlax-put-property
                  (list (nth n blkprops) "Value" propvalue)
                )
                (setq n len)
         )
         (setq n (1+ n))
      )
    ) ;_while
  ) ;_foreach
)


{fixed code formating}
« Last Edit: July 26, 2006, 07:47:35 PM by 'steved »

Birdy

  • Guest
Re: redefining dynamic blocks
« Reply #8 on: July 26, 2006, 05:28:14 PM »
Thanks.
May be a while before I can test drive it though.  :-(