Author Topic: Update block definition from block inside external DWG  (Read 4399 times)

0 Members and 1 Guest are viewing this topic.

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1192
  • Marco
Re: Update block definition from block inside external DWG
« Reply #30 on: April 07, 2018, 05:09:09 AM »
Everything seems ok even in AutoCAD.  :) :) :)
Good to hear that. :-D
From the number of visits I think your work has been much appreciated, thanks again.  :-)

MrSmith

  • Mosquito
  • Posts: 10
Re: Update block definition from block inside external DWG
« Reply #31 on: March 17, 2021, 10:46:51 PM »
Just a heads up, you are using global variables not defined in the code which may cause people confusion.

*AcadApp* = (vlax-get-acad-object)
*AcAcDwg* = (vla-get-ActiveDocument (vlax-get-acad-object))

Otherwise, my initial tests looked very promising. Going to use it to create a DCL for some mass block redefining.  :-D
Thanks everyone who contributed!

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1192
  • Marco
Re: Update block definition from block inside external DWG
« Reply #32 on: March 18, 2021, 05:12:24 AM »
Just a heads up, you are using global variables not defined in the code which may cause people confusion.

*AcadApp* = (vlax-get-acad-object)
*AcAcDwg* = (vla-get-ActiveDocument (vlax-get-acad-object))

Otherwise, my initial tests looked very promising. Going to use it to create a DCL for some mass block redefining.  ;D
Thanks everyone who contributed!
>>> you are using global variables not defined in the code which may cause people confusion  Where?

MrSmith

  • Mosquito
  • Posts: 10
Re: Update block definition from block inside external DWG
« Reply #33 on: March 18, 2021, 12:17:06 PM »
Post #15, "Function: ALE_Block_UpdByBlkInFile, Version 1.02 - 2018/04/04..." used the variables I mentioned above.

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1192
  • Marco
Re: Update block definition from block inside external DWG
« Reply #34 on: March 19, 2021, 10:14:27 AM »
Post #15, "Function: ALE_Block_UpdByBlkInFile, Version 1.02 - 2018/04/04..." used the variables I mentioned above.
Yes  :yes: you are correct, code updated:

(or *AcadApp* (setq *AcadApp* (vlax-get-Acad-Object)            ))           ; edit 20210321
(or *AcAcDwg* (setq *AcAcDwg* (vla-get-ActiveDocument *AcadApp*)))          ; edit 20210321
;
; (ALE_Block_UpdByBlkInFile BlkNam FilNam (vla-get-Blocks *AcAcDwg*) nil)    ; edit 20210321

MrSmith

  • Mosquito
  • Posts: 10
Re: Update block definition from block inside external DWG
« Reply #35 on: March 19, 2021, 04:00:40 PM »
Awesome! On a different note, do you know how to handle attribute blocks? It looks like they don't get sync properly without an ATTSYNC command.

I've looked through various threads like:
https://www.theswamp.org/index.php?topic=52255.msg572293#msg572293
https://www.theswamp.org/index.php?topic=52209.0

Seems like it is a bug on AutoCAD's side? Vla-update on either the block object or the attribute object didn't work.

MrSmith

  • Mosquito
  • Posts: 10
Re: Update block definition from block inside external DWG
« Reply #36 on: March 19, 2021, 08:58:45 PM »
For what is worth, I played around with it to allow for processing a list of blocks. It also allows you to have the documents open.

I still couldn't figure out how to sync attributes. Also noticed it doesn't work well with dynamic blocks either. The Design Center "Redefine" also doesn't seem to work well with them either, though it does a slightly better job with dynamic blocks that have the same anonymous name. I am guessing it looks at both when it redefines them.

I plan on writing a DCL later on which I may post.

Code - Auto/Visual Lisp: [Select]
  1. ;RedefineBlocks => By MrSmith 3/19/2021
  2. ;Support functions mostly by Lee Mac
  3. ;Redefine Block functionality mostly from https://www.theswamp.org/index.php?topic=54041.msg586836#msg586836
  4.  
  5. ;NOTE: Function does not work well with Attribute Blocks or Dynamic Blocks.
  6.  
  7. ;############EXAMPLE FUNCTION############
  8. ;Change blockNameList, newBlockLocation, and oldBlockLocation
  9. (defun c:RedefineBlocks ( / blockNameList newBlockLocation oldBlockLocation DbxDocNew DbxDocOld blocksInfo)
  10.    (setq blockNameList (list "TestBlock1" "TestBlock2")) ;List of block names to be updated
  11.    (setq newBlockLocation "C:\\Test Land\\Redefine Blocks\\0.dwg") ;Set this to the drawing path of most updated blocks
  12.    (setq oldBlockLocation "C:\\Test Land\\Redefine Blocks\\1.dwg") ;Set this to the drawing to update blocks inside
  13.    (setq DbxDocNew (setDBXDocument newBlockLocation))
  14.    (setq DbxDocOld (setDBXDocument oldBlockLocation))
  15.    (setq blocksInfo (setSourceBlocks blockNameList DbxDocNew)) ;Get all the blocks information
  16.    (updateOldBlocks blocksInfo DbxDocOld DbxDocNew) ;Update all the blocks with the information
  17.    (vla-regen DbxDocOld acActiveViewport)
  18.    (mapcar 'release (list DbxDocNew DbxDocOld *dbx*))
  19.    (princ "\nUpdate Complete!")
  20.    (princ)
  21. )
  22.  
  23. ;#############MAIN FUNCTIONS#############
  24. ;blockList - list of block names to be redefined
  25. ;sourceDWG - DBX document object containing the location of the updated blocks
  26. (defun setSourceBlocks (blockList sourceDWG / getBlockObjects  BlkLst  sourceBlockLst sourceBlockCol blkData)
  27.    (defun getBlockObjects (blkData / subBlock ObjLst) ;Used to get each entity in a block
  28.       (vlax-for obj blkData ;obj is vla entity of block
  29.          (and
  30.             (= "AcDbBlockReference" (vla-get-ObjectName obj)) ;The object is a Block
  31.             (not (vl-position (setq subBlock (vla-get-EffectiveName obj)) BlkLst)) ;The object does not currently show up in our block list
  32.             (setq BlkLst (cons subBlock BlkLst)) ;Add object to block list, this is to prevent duplicant blocks from being gathered
  33.             (getBlockObjects (_getitem sourceBlockCol subBlock)) ;Get the sub block entities
  34.          )
  35.          (setq ObjLst (cons obj ObjLst)) ;Save the vla object
  36.       )
  37.       (setq sourceBlockLst (cons (cons (vla-get-name blkData) (list ObjLst)) sourceBlockLst))
  38.       ;sourceBlockLst => (list (list "BlockName1" (list vlaObjs...)) (list "BlkName2" (list vlaObjs2...)...))      
  39.    )
  40.    
  41.    (setq sourceBlockCol (vla-get-blocks sourceDWG))
  42.    (foreach block blockList ;Cycle through our list of block names
  43.       (if (setq blkData (_getitem sourceBlockCol block)) ;If it exists in the source drawing
  44.          (getBlockObjects blkData) ;Get its subentities
  45.       )
  46.    )
  47.    sourceBlockLst
  48. )
  49.  
  50. ;BlockListData -- (list (list "BlockName1" (list vlaObjs...)) (list "BlkName2" (list vlaObjs2...)...))
  51. ;OldDBDoc/NewDBDoc - Dbx Documents. Old is the drawing with blocks to be redefined by the new block
  52. (defun updateOldBlocks (blockListData OldDBDoc NewDBDoc / BksColOld oldBlkData)
  53.    (setq BksColOld (vla-get-Blocks OldDBDoc))
  54.    (foreach blockData blockListData
  55.       (if (setq oldBlkData (_getitem BksColOld (car blockData)))
  56.          (progn
  57.             (vlax-for obj oldBlkData (vla-delete obj)) ;Delete the items in the old block
  58.             (vlax-invoke NewDBDoc 'copyobjects (cadr blockData) oldBlkData) ;Copy the new information from source.
  59.             ;Note: Source document MUST be open still per the DbxDocSource
  60.          )
  61.       )
  62.    )
  63. )
  64.  
  65. ;###########SUPPORT FUNCTIONS############
  66. (defun release (obj) (if (= 'vla-object (type obj)) (vlax-release-object obj)))
  67.  
  68. (defun _getitem ( col itm )
  69.    (if (not (vl-catch-all-error-p (setq itm (vl-catch-all-apply 'vla-item (list col itm)))))
  70.       itm
  71.    )
  72. )
  73.  
  74. (defun setDBXObject ( / vrs) ;Sets the DBX Object, from Lee
  75.    (if (or (not *dbx*) (= 'vla-object (type *dbx*)))
  76.       (setq *dbx* (vl-catch-all-apply 'vla-getinterfaceobject
  77.          (list (setq *acad* (vlax-get-acad-object))
  78.             (if (< (setq vrs (atoi (getvar 'acadver))) 16) "objectdbx.axdbdocument" (strcat "objectdbx.axdbdocument." (itoa vrs)))))
  79.       )
  80.    )
  81.    (if (or (null *dbx*) (vl-catch-all-error-p *dbx*)) (notifyExit "\nUnable to interface with ObjectDBX."))
  82. )
  83.  
  84. (defun setDBXDocument (dwgPath / dwl DbDocument)
  85.    ;Set our *dbx* Object
  86.    (setDBXObject)
  87.    (vlax-for doc (vla-get-documents *acad*)
  88.       (setq dwl (cons (cons (strcase (vla-get-fullname doc)) doc) dwl)) ;Used to make sure we are not opening already open drawings
  89.    )
  90.    (if
  91.       (or (setq DbDocument (cdr (assoc (strcase dwgPath) dwl))) ;Already Opened File, set doc to it
  92.          (and (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-open (list *dbx* dwgPath)))) ;Else, open the drawing via dbx
  93.             (setq DbDocument *dbx*) ;Set doc as the DBX object
  94.          )
  95.       )
  96.       DbDocument
  97.       (progn
  98.          (princ (strcat "\nUnable to interface with Drawing: " (cadr (fnsplitl dwgPath)) "). Drawing may be open!"))
  99.          nil
  100.       )
  101.    )
  102. )
  103.  
« Last Edit: March 20, 2021, 03:35:01 PM by MrSmith »

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1192
  • Marco
Re: Update block definition from block inside external DWG
« Reply #37 on: March 20, 2021, 05:12:26 AM »
I don't have much time now to go through your code… For attribute blocks I use ATTSYNC:

(setq InfLst (ALE_Block_Cmd_NentselBlock "Seleziona il blocco principale o annidato da aggiornare")) ; see: http://www.theswamp.org/index.php?topic=55966.msg599644#msg599644

(entupd (caddr InfLst)) (and (cadddr InfLst) (entupd (cadddr InfLst)))

(and (= (DXF 66 (cadr InfLst)) 1) (vl-cmdf "_.ATTSYNC" "_NAME" BlkNam))

MrSmith

  • Mosquito
  • Posts: 10
Re: Update block definition from block inside external DWG
« Reply #38 on: March 20, 2021, 06:18:37 PM »
No worries, I was just sharing in case someone else found it useful. The functionality is identical, as far as I can tell.

As for the attributes, I was afraid that case. Means you can't update it through DBX. Thanks for verifying!

Edit: After thinking about it, couldn't you delete the attribute blocks from the drawing itself and put them back with their correct attributes? My preliminary testing seems promising....
« Last Edit: March 21, 2021, 01:28:02 AM by MrSmith »

MrSmith

  • Mosquito
  • Posts: 10
Re: Update block definition from block inside external DWG
« Reply #39 on: March 21, 2021, 04:28:13 AM »
It seems to work.... the biggest problem with it is it deletes the blocks, which may or may not be an issue depending on the circumstance. Somehow, the AttSync command does not delete them.

Code - Auto/Visual Lisp: [Select]
  1. ;SyncAttributeBlocks => By MrSmith 3/21/2021
  2.  
  3. ;NOTE: Lightly tested, use at your own risk. Syncs blocks using VLA functions by deleting and re-inserting the block.
  4. (defun c:SyncAttributeBlocks ( / ssprompt ssList removeDuplicates toVLA blkName setAttributeValues ss)
  5.    ;********SUPPORT FUNCTIONS***********
  6.    (defun ssprompt   (filter msg / ss old)
  7.       (setq old (getvar "nomutt"))
  8.       (setvar "NOMUTT" 0)
  9.       (prompt msg)
  10.       (setvar "NOMUTT" 1)
  11.       (vl-catch-all-apply '(lambda () (setq ss (ssget filter))))
  12.       (setvar "NOMUTT" old)
  13.       ss
  14.    )
  15.    (defun ssList (ss / lst ct)
  16.       (if ss (progn (setq ct 0) (repeat (sslength ss) (setq lst (cons (ssname ss ct) lst) ct (+ ct 1)))))
  17.       lst
  18.    )
  19.    (defun removeDuplicates ( l ) ;; Unique  -  Lee Mac ;; Returns a list with duplicate elements removed.
  20.       (if l (cons (car l) (removeDuplicates (vl-remove (car l) (cdr l)))))
  21.    )
  22.    (defun toVLA (entity / out) ;Protects against errors to convert objects to VLA
  23.       (if (not (vl-catch-all-error-p (setq out (vl-catch-all-apply '(lambda () (vlax-ename->vla-object entity)) nil))))
  24.          out
  25.          nil
  26.       )
  27.    )
  28.    (defun blkName (vlaBlk)
  29.       (if (vlax-property-available-p vlaBlk 'effectivename)
  30.             (vla-get-effectivename vlaBlk)
  31.             (vla-get-name vlaBlk)
  32.       )
  33.    )
  34.    (defun setAttributeValues ( blk lst / itm )
  35.       (mapcar '(lambda (x) (if (setq itm (assoc (vla-get-tagstring x) lst)) (vla-put-textstring x (cdr itm)))) (vlax-invoke blk 'getattributes))
  36.    )
  37.    ;***********MAIN***********
  38.    (if
  39.       (and
  40.          (setq ss (ssPrompt '((0 . "Insert")) "Select Blocks to Sync:"))
  41.          (setq ss (mapcar 'tovla (sslist ss)))
  42.          (setq ss (vl-remove nil (mapcar '(lambda (x) (if (= ':vlax-true (vla-get-hasattributes x)) x nil)) ss)))
  43.          (setq ss (removeDuplicates (mapcar 'strcase (mapcar 'blkName ss))))
  44.       )
  45.       (syncAttributeBlocks ss (vla-get-ActiveDocument (vlax-get-acad-object)))
  46.       (alert "You did not select any attributed blocks to sync!")
  47.    )
  48. )
  49.  
  50. ;Syncs blocks using VLA functions by deleting the block and putting a new one in its place with the same values
  51. ;blockNameList - List of Block Names to Sync
  52. ;dbDoc - AutoCAD document
  53. (defun syncAttributeBlocks (blockNameList dbDoc / blockName atts data new)
  54.    (foreach block blockNameList
  55.       (setq blockName (strcase block))
  56.       (vlax-for la (vla-get-layouts dbDoc)
  57.          (vlax-for o (vla-get-block la) ;o is my vla block
  58.             (if
  59.                (and
  60.                   (= "AcDbBlockReference" (vla-get-objectname o)) ;Make sure o is a block
  61.                   (= :vlax-true (vla-get-hasattributes o)) ;Make sure o (the block) has attributes
  62.                   (= blockName (strcase (blkName o))) ;We found our block
  63.                   (setq data ;Get our block information
  64.                      (mapcar '(lambda (x) (vlax-get-property o x))
  65.                         '(EntityTransparency InsertionPoint Layer Linetype LinetypeScale Lineweight Material Normal PlotStyleName Rotation TrueColor Visible
  66.                            XEffectiveScaleFactor XScaleFactor YEffectiveScaleFactor YScaleFactor ZEffectiveScaleFactor ZScaleFactor
  67.                         )
  68.                      )
  69.                   )
  70.                )
  71.                (progn
  72.                   (foreach att (vlax-invoke o 'getattributes) ;Get Attribute info
  73.                      (setq atts (cons (cons (vla-get-tagstring att) (vla-get-textstring att)) atts))
  74.                   )
  75.                   (vla-delete o) ;Delete old block
  76.                   (setq new (vla-insertblock (vla-get-block la) (vlax-3D-point '(0 0 0)) blockName 1 1 1.0 0)) ;Insert a new block
  77.                   (foreach prop ;Update the new block with old properties
  78.                      '(EntityTransparency InsertionPoint Layer Linetype LinetypeScale Lineweight Material Normal PlotStyleName Rotation TrueColor Visible
  79.                      XEffectiveScaleFactor XScaleFactor YEffectiveScaleFactor YScaleFactor ZEffectiveScaleFactor ZScaleFactor)
  80.                      (vl-catch-all-apply 'vlax-put-property (list new prop (car data)))
  81.                      (setq data (cdr data))
  82.                   )
  83.                   (setAttributeValues new atts) ;Update the new blocks attribute values
  84.                   (mapcar '(lambda (x) (set x nil)) '(atts data new))
  85.                )
  86.             )
  87.          )
  88.       )
  89.    )
  90. )
  91.  

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1192
  • Marco
Re: Update block definition from block inside external DWG
« Reply #40 on: March 21, 2021, 06:32:34 AM »
I don't have much time now to make a full function, I have found this piece of code to play with blocks and different number of attribute, it is a 2016 year code I do not remeber to much... maybe can help… Sorry for italian note.
Code: [Select]
;             Block name   Layer name   Layout name
; BksInf  (("TITLEBLOCK"    "LAYERX"    "MODEL"     #<VLA-OBJECT IAcadBlockReference2 08330c34>) (...) ...) ; block list
;
      (setq BksCol (vla-get-blocks DbxDoc))
      (foreach ForElm BksInf
        (setq
          BlkNam (car    ForElm)
          BlkDef (ALE_Utl_GetItem BksCol BlkNam)       ; Obj definizione di blocco
          BkDInP (safearray-value (vlax-variant-value (vla-get-Origin BlkDef)))        ; InsertionPoint definizione di blocco
          BlkIns (cadddr ForElm)                ; Obj blocco inserito
          BlkScl (vla-get-XScaleFactor   BlkIns); scalaX blocco inserito
          BkIInP (safearray-value (vlax-variant-value (vla-get-InsertionPoint BlkIns))); InsertionPoint blocco inserito
          BkIAtt (vlax-invoke BlkIns 'GetAttributes); attributi blocco inserito - se si usa (vla-GetAttributes VlaObj) si ottiene un variant che bisogna trasformare e poi elaborare con vlax-for
        )
        (vlax-for ObjFor BlkDef ; attributi definizione di blocco
          (if (= (vla-get-objectname ObjFor) "AcDbAttributeDefinition")
            (setq BkDAtt (cons (list (vla-get-TagString ObjFor) ObjFor) BkDAtt))
          )
        )
        ; BkIAtt (#<VLA-OBJECT IAcadAttributeReference 000000003ce20898> #<VLA-OBJECT IAcadAttributeReference 000000003ce240d8> ...)
        ; BkDAtt (("FILE" #<VLA-OBJECT IAcadAttribute 000000003da926c8>) ("ACVER" #<VLA-OBJECT IAcadAttribute 000000003da90508>) ...)
        (cond
          ( (> (length BkDAtt) (length BkIAtt))
            (setq
              NewBlk
                (vla-InsertBlock
                  (vla-objectidtoobject DbxDoc (vla-get-ownerid BlkIns)) (vla-get-InsertionPoint BlkIns) (vla-get-Name BlkIns) BlkScl BlkScl BlkScl (vla-get-Rotation BlkIns)
                )
            )
            (vla-put-Layer NewBlk (vla-get-Layer BlkIns))
    (vla-put-Linetype NewBlk (vla-get-Linetype BlkIns))
            (foreach ObjFor BkIAtt ; lista attributi blocco inserito con TAG
              (setq AttLst (cons (list (vla-get-TagString ObjFor) ObjFor) AttLst))
            )
            (foreach ObjFor (vlax-invoke NewBlk 'GetAttributes); attributi NUOVO blocco inserito
              (and
                (setq AttInf (assoc (vla-get-TagString ObjFor) AttLst)) ; se trovo l'attributo nella lista attributi blocco inserito con TAG   
                (vla-Put-textstring ObjFor (vla-get-TextString (cadr AttInf)))
              )
            )
            (vla-Delete BlkIns)
          )
          ( T ; se gli attributi sono uguali o inferiori
            (foreach ObjFor BkIAtt
              (if (setq AttInf (assoc (vla-get-TagString ObjFor) BkDAtt)) ; se trovo l'attributo nella lista degli attributi in definizione di blocco   
                (progn
                  (setq AttObj (cadr AttInf))
                  (vla-put-Alignment ObjFor (vla-get-Alignment AttObj))
                  (vla-put-Layer ObjFor (vla-get-Layer AttObj))
                  (vla-put-Linetype ObjFor (vla-get-Linetype AttObj))
                  (vla-put-ScaleFactor ObjFor (vla-get-ScaleFactor AttObj))
                  (vla-put-StyleName ObjFor (vla-get-StyleName AttObj))
                  (vla-put-Rotation ObjFor (vla-get-Rotation AttObj))
                  (vla-put-Height ObjFor (* BlkScl (vla-get-Height AttObj)))
                  (setq
                    AtDInp (safearray-value (vlax-variant-value (vla-get-InsertionPoint AttObj)))
                    DeltaX (ALE_Attrib_CalcDeltaX BkIInP AtDInp BkDInP BlkScl)
                    DeltaY (ALE_Attrib_CalcDeltaY BkIInP AtDInp BkDInP BlkScl)
                  )
                  (vla-put-InsertionPoint ObjFor (vlax-3D-point (list DeltaX DeltaY 0)))
                  (setq
                    AtDInp (safearray-value (vlax-variant-value (vla-get-TextAlignmentPoint AttObj)))
                    DeltaX (ALE_Attrib_CalcDeltaX BkIInP AtDInp BkDInP BlkScl)
                    DeltaY (ALE_Attrib_CalcDeltaY BkIInP AtDInp BkDInP BlkScl)
                  ); nei testi con acAlignmentLeft la proprietà seguente non è modificabile
                  (vl-catch-all-apply 'vlax-put-property (list ObjFor 'TextAlignmentPoint  (vlax-3D-point (list DeltaX DeltaY 0))))
                );progn
              );if
            );foreach BkIAtt
          )
        );cond
      );foreach BksInf


 
(defun ALE_Attrib_CalcDeltaX (BkIInP AtDInp BkDInP BlkScl)
  (+ (car  BkIInP) (* (- (car  AtDInp) (car  BkDInP)) BlkScl))
)
;
(defun ALE_Attrib_CalcDeltaY (BkIInP AtDInp BkDInP BlkScl)
  (+ (cadr BkIInP) (* (- (cadr AtDInp) (cadr BkDInP)) BlkScl))
)
(defun ALE_Utl_GetItem (VlaCol KeyNam / VlaObj)
  (vl-catch-all-apply
   '(lambda ( )
      (setq VlaObj (vla-item VlaCol KeyNam))
    )
  )
  VlaObj
)

MrSmith

  • Mosquito
  • Posts: 10
Re: Update block definition from block inside external DWG
« Reply #41 on: March 21, 2021, 04:15:01 PM »
Looks very similar to what I did; however, it went an extra step with positioning the attributes. I'll have to try adding that and playing around with it. I know attributes will move around if they are not left justified and you modify them through DBX. Hopefully it will fix my issue with that.

Thanks!

MrSmith

  • Mosquito
  • Posts: 10
Re: Update block definition from block inside external DWG
« Reply #42 on: March 28, 2021, 11:49:08 PM »
Hey Marc, finally got a chance to test our the code you posted and it worked really well! Thanks for sharing. It fixed a problem I had with another LISP routine I'd written.  :-)

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1192
  • Marco
Re: Update block definition from block inside external DWG
« Reply #43 on: March 29, 2021, 08:56:08 AM »
Hey Marc, finally got a chance to test our the code you posted and it worked really well! Thanks for sharing. It fixed a problem I had with another LISP routine I'd written.  :)
:)