Help with Blocks / Attributes

Hi,

My client periodically sends out a dwg that contains many block definitions that are to be used in drawings that are produced for them by people such as me. In the latest release from them one of the blocks has had the insertion point position redefined within the set of entities that comprise the block. When I import all the blocks from the dwg into an existing drawing, the positions at which the new block is inserted is offset by the difference between the positions of the insertion point in the old and new definition. The problem I have is that the attribute positions do not shift, therefore there is a cumbersome manual process needed to either move the attributes or totally repopulate the attributes from scratch for each instance. I assume that this is expected default behaviour as the attributes may have been manually repositioned and it might not be desirable to destroy these changes.

My question is, is there a way of importing a new block definition to replace an existing one, but to instruct Bricscad to carry across attribute values but to position the atttributes as per the imported definition, rather than leave them where they are? An alternative would be if the entities that comprise a block can be moved whilst leaving the attribute positions unchanged.

Thanks

Jamie

Comments

  • Hi Jamie,

    the problem that you have is that any Block Redefinition (insertion Point etc.) changes

    all graphic Entities in the Block BUT NOT the Attributes of the existing Blocks in the Drawing.

    In AutoCAD you have BATTMAN to Sychronize the Attributes of existing Blocks with the NEW BLOCK DEFINITION

    but in Bricscad (to my knowledge ?) not. So the best way is to use the old Autolisp Program Attredef.lsp to do that:

    How to procceed...:

    1. Save the attached code to a file called attredef.lsp in the bricscad directory

    2. Load the file in Bricscad by typing in the command prompt: >    (load "attredef.lsp")

    3  Copy one of the "old" Blocks with the "not moved" Attributes and explode the copy !

    4  call the Autolisp command with  AT or ATTREDEF

    5  Follow the prompts.....

        Name of Block you wish to redefine:   (Type in the Name of the redefined Block)

        Select objects for new Block...
        Select entities:                              
    (select all graphic entities and Blocks in the correct sequence !!)

        Insertion base point of new Block:   (here you should select the new Insertion Point !!!!)

     

    You are hopefully DONE and all Blocks and Attributes look fine.

     

    Regards

    Konstantin

    Here is the code:

    ; Next available MSG number is    13 
    ; MODULE_ID ATTREDEF_LSP_
    ;;;
    ;;; attredef.lsp
    ;;;
    ;;; Copyright 1988, 1990, 1992, 1994, 1996 by Autodesk, Inc.
    ;;;
    ;;; Permission to use, copy, modify, and distribute this software
    ;;; for any purpose and without fee is hereby granted, provided
    ;;; that the above copyright notice appears in all copies and
    ;;; that both that copyright notice and the limited warranty and
    ;;; restricted rights notice below appear in all supporting
    ;;; documentation.
    ;;;
    ;;; AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
    ;;; AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
    ;;; MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
    ;;; DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
    ;;; UNINTERRUPTED OR ERROR FREE.
    ;;;
    ;;; Use, duplication, or disclosure by the U.S. Government is subject to
    ;;; restrictions set forth in FAR 52.227-19 (Commercial Computer
    ;;; Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
    ;;; (Rights in Technical Data and Computer Software), as applicable.
    ;;;
    ;;;.
    ;;;
    ;;; DESCRIPTION
    ;;;
    ;;; This program allows you to redefine a Block and update the
    ;;; Attributes associated with any previous insertions of that Block.

    ;;; All new Attributes are added to the old Blocks and given their
    ;;; default values.

    ;;; All old Attributes with equal tag values to the new
    ;;; Attributes are redefined but retain their old value.

    ;;; And all old Attributes not included in the new Block are deleted.

    ;;; Note that if handles are enabled, new handles will be assigned to
    ;;; each redefined block.
    ;;;
    ;;; --------------------------------------------------------------------------;

    ;;;
    ;;; Oldatts sets "old_al" (OLD_Attribute_List) to the list of old Attributes
    ;;; for each Block. The list does not include constant Attributes.
    ;;;
    (defun oldatts (/ e_name e_list cont)
    (setq oa_ctr 0
    cont T
    e_name b1
    )
    (while cont
    (if (setq e_name (entnext e_name))
    (progn
    (setq e_list (entget e_name))
    (if (and (= (cdr (assoc 0 e_list)) "ATTRIB")
    ;; NOT a constant attribute -- (cdr (assoc 70 e_list)) != 2)
    (/= (logand (cdr (assoc 70 e_list)) 2) 2))
    (progn
    (if old_al
    (setq old_al (cons e_list old_al))
    (setq old_al (list e_list))
    )
    (setq oa_ctr (1+ oa_ctr)) ; count the number of old atts
    )
    ;; else, exit
    (setq cont nil)
    )
    )
    (setq cont nil)
    )
    )
    )
    ;;;
    ;;; Newatts sets "new_al" to the list of new Attributes in the new Block.
    ;;; The list does not include constant Attributes.
    ;;;
    (defun newatts (ssetn ssl / i e_name e_list)
    (setq i 0 na_ctr 0)
    (while (< i ssl)
    (if (setq e_name (ssname ssetn i))
    (progn
    (setq e_list (entget e_name))
    (if (and (= (cdr (assoc 0 e_list)) "ATTDEF")
    ;; NOT a constant attribute -- (cdr (assoc 70 e_list)) != 2)
    (/= (logand (cdr (assoc 70 e_list)) 2) 2))
    (progn
    (if new_al
    (setq new_al (cons e_list new_al))
    (setq new_al (list e_list))
    )
    (setq na_ctr (1+ na_ctr)) ; count the number of new atts
    )
    )
    )
    )
    (setq i (1+ i))
    )
    na_ctr
    )
    ;;;
    ;;; Compare the list of "old" to the list of "new" Attributes and make
    ;;; the two lists "same" and "preset". "Same" contains the old values of
    ;;; all the Attributes in "old" with equal tag values to some Attribute
    ;;; in "new" and the default values of all the other Attributes. "Preset"
    ;;; contains the preset Attributes in old with equal tag values to some
    ;;; Attribute in new.
    ;;;
    (defun compare (/ i j)
    (setq i 0
    j 0
    pa_ctr 0
    same nil
    va_ctr 0
    preset nil)
    ;; "i" is a counter that increments until the number of new attributes
    ;; is reached.
    (while (< i na_ctr)
    (cond
    ;; If there are old attributes AND the tag strings of the old and new
    ;; attributes are the same...
    ((and old_al
    (= (cdr (assoc 2 (nth j old_al))) (cdr (assoc 2 (nth i new_al)))))
    ;; IS a preset attribute -- (cdr (assoc 70 e_list)) == 8)
    (if (= (logand (cdr (assoc 70 (nth i new_al))) 8) 8)
    ;; If the attribute is a preset attribute then add it to the list
    ;; of preset attributes and increment the counter "pa_ctr".
    ;; IS a preset attribute -- (cdr (assoc 70 e_list)) == 8)
    (progn
    (if preset
    (setq preset (cons (nth j old_al) preset))
    (setq preset (list (nth j old_al)))
    )
    (setq pa_ctr (1+ pa_ctr)) ; count preset atts
    )
    ;; Else, add it to the list of same attributes "same".
    (if same
    (setq same (cons (cdr (assoc 1 (nth j old_al))) same))
    (setq same (list (cdr (assoc 1 (nth j old_al)))))
    )
    )
    ;; If the attribute must be verified, increment counter "va_ctr".
    ;; NOT a preset attribute -- (cdr (assoc 70 e_list)) != 8)
    (if (and (/= (logand (cdr (assoc 70 (nth i new_al))) 8) 8)
    ;; IS a verified attribute -- (cdr (assoc 70 e_list)) == 4)
    (= (logand (cdr (assoc 70 (nth i new_al))) 4) 4))
    (setq va_ctr (+ 1 va_ctr))
    )
    (setq i (1+ i))
    (setq j 0)
    )
    ;; If the number of old attributes equals the old attribute counter "j"
    ((= j oa_ctr)
    ;; If this attribute is not a preset attribute, but is not in the
    ;; old list, then add it to the list "same".
    ;; NOT a preset attribute -- (cdr (assoc 70 e_list)) != 8)
    (if (/= (logand (cdr (assoc 70 (nth i new_al))) 8) 8)
    (if same
    (setq same (cons (cdr (assoc 1 (nth i new_al))) same))
    (setq same (list (cdr (assoc 1 (nth i new_al)))))
    )
    )
    ;; NOT a preset attribute -- (cdr (assoc 70 e_list)) != 8)
    (if (and (/= (logand (cdr (assoc 70 (nth i new_al))) 8) 8)
    ;; IS a verified attribute -- (cdr (assoc 70 e_list)) == 4)
    (= (logand (cdr (assoc 70 (nth i new_al))) 4) 4))
    (setq va_ctr (+ 1 va_ctr))
    )
    (setq i (1+ i))
    (setq j 0)
    )
    ;; Increment the old attribute counter "j"...
    (t
    (setq j (1+ j))
    )
    )
    )
    )
    ;;;
    ;;; Find the entity for each of the "preset" Attributes in the newly
    ;;; inserted Block.
    ;;;
    (defun findpt ()
    (setq test T)
    (setq en (entnext e1))
    (setq e_list (entget en))
    (while test
    (if (and (= (cdr (assoc 0 e_list)) "ATTRIB") (= (cdr (assoc 2 e_list)) tag))
    (setq test nil)
    (progn
    (setq ex en)
    (setq en (entnext ex))
    (if e_list
    (setq e_list (entget en))
    )
    )
    )
    )
    )
    ;;;
    ;;; Insert a new Block on top of each old Block and set its new Attributes
    ;;; to their values in the list "same". Then replace each of the "preset"
    ;;; Attributes with its old value.
    ;;;
    (defun redef (/ xsf ysf zsf ls i e1 v)
    (command "_.UCS" "_E" b1) ; define the block's UCS
    (setq xsf (cdr (assoc 41 (entget b1)))) ; find x scale factor
    (setq ysf (cdr (assoc 42 (entget b1)))) ; find y scale factor
    (setq zsf (cdr (assoc 43 (entget b1)))) ; find z scale factor
    (setq ls (length same))
    (setq i 0)
    (command "_.INSERT" bn "0.0,0.0,0.0" "_XYZ" xsf ysf zsf "0.0")
    (while (< i ls) ; set attributes to their values
    (command (nth i same))
    (setq i (1+ i))
    )
    (while (< 0 va_ctr)
    (command "") ; at prompts, verify attributes
    (setq va_ctr (1- va_ctr))
    )
    (setq i 0)
    (setq e1 (entlast))
    (while (< 0 pa_ctr) ; edit each of the "preset" attributes
    (setq tag (cdr (assoc 2 (nth i preset))))
    (setq v (cdr (assoc 1 (nth i preset))))
    (findpt) ; find the entity to modify
    (setq e_list (subst (cons 1 v) (assoc 1 e_list) e_list))
    (entmod e_list) ; modify the entity's value
    (setq i (1+ i))
    (setq pa_ctr (1- pa_ctr))
    )
    (command "_.UCS" "_P") ; restore the previous UCS
    )
    ;;;
    ;;; System variable save
    ;;;
    (defun modes (a)
    (setq mlst '())
    (repeat (length a)
    (setq mlst (append mlst (list (list (car a) (getvar (car a))))))
    (setq a (cdr a)))
    )
    ;;;
    ;;; System variable restore
    ;;;
    (defun moder ()
    (repeat (length mlst)
    (setvar (caar mlst) (cadar mlst))
    (setq mlst (cdr mlst))
    )
    )
    ;;;
    ;;; Internal error handler
    ;;;
    (defun attrerr (s) ; If an error (such as CTRL-C) occurs
    ; while this command is active...
    (if (/= s "Function cancelled")
    (princ (strcat "\nError: " s))
    )
    (moder) ; restore saved modes
    (setq *error* olderr) ; restore old *error* handler
    (princ)
    )
    ;;;
    ;;; Main program
    ;;;
    (defun C:ATTREDEF (/ k n olderr bn sseto ssetn pt ssl new_al
    old_al same preset b1 oa_ctr va_ctr na_ctr
    )
    (setq k 0
    n 0
    test T
    olderr *error*
    *error* attrerr
    )

    (modes '("CMDECHO" "ATTDIA" "ATTREQ" "GRIDMODE" "UCSFOLLOW"))
    (setvar "cmdecho" 0) ; turn cmdecho off
    (setvar "attdia" 0) ; turn attdia off
    (setvar "attreq" 1) ; turn attreq on
    (setvar "gridmode" 0) ; turn gridmode off
    (setvar "ucsfollow" 0) ; turn ucsfollow off

    (while
    (progn
    (setq bn (xstrcase (getstring
    "\nName of Block you wish to redefine: ")))
    (if (tblsearch "block" bn)
    (progn
    (setq sseto (ssget "_x" (list (cons 2 bn))))
    (setq test nil)
    )
    (progn
    (princ "\nBlock ")
    (princ bn)
    (princ " is not defined. Please try again.\n")
    )
    )
    )
    )
    (if sseto
    (progn
    (while
    (progn
    (princ "\nSelect objects for new Block... ")
    (if (null (setq ssetn (ssget)))
    (princ "\nNo new Block selected. Please try again.")
    (setq test nil)
    )
    )
    )
    ;; find the list of new attributes
    (setq na_ctr (newatts ssetn (sslength ssetn)) )
    (if (> na_ctr 0)
    (progn
    (initget 1)
    (setq pt (getpoint "\nInsertion base point of new Block: "))
    (setq ssl (sslength sseto))
    ;; redefine the block
    (command "_.UNDO" "_GROUP")
    (command "_.BLOCK" bn "_Y" pt ssetn "")
    (while (< k ssl)
    (setq b1 (ssname sseto k)) ; For each old block...
    (setq old_al nil)
    (oldatts) ; find the list of old attributes,
    (compare) ; compare the old list with the new,
    (redef) ; and redefine its attributes.
    (entdel b1) ; delete the old block.
    (setq k (1+ k))
    )
    (command "_.REGENALL")
    (command "_.UNDO" "_END")
    )
    (princ "\nNew block has no attributes. ")
    )
    )
    (princ (strcat "\nNo insertions of block " bn " found to redefine. "))
    )
    (moder) ; restore saved modes
    (setq *error* olderr) ; restore old *error* handler
    (princ)
    )

    (defun c:at () (c:attredef))
    (princ
    "\nC:ATtredef loaded. Start command with AT or ATTREDEF.")
    (princ)

     

  • Hi Konstantin,

    Thank you very much indeed for this. I shall give it a go and let you know how it goes.

    Regards

    Jamie

  • Hi Jamie,

    If you would to consider a solution via an add-on tool for Bricscad, read on....

    Our GeoTools add-on product has a solution for exactly the same problem that you are describing. The GT_REPBLK (Replace Block) command under the Block Tools Menu can replace one block with another (or with an updated defintiion of the same name) across the drawing or on selected ones. It can read the definition from external DWG files as well as from internal (DWG symbol table) definition. It can handle attributes as well and similarly named attributes will be carried forward and not lost. You even have the option to maintain the manually edited positions, rotations and heights of attributes so that they appear exactly where they were last set painstakingly by your drafters.

    You might want to give it a try and download a 30-day fullly functional version.

    http://www.coordsys.com/geotools

    There are 259 other productivity tools which might interest you as well - in GeoTools for Bricscad.

    Let me know if you have any questions or problems with the tools.

    Regards
    Rakesh Rao
    Coordinate Systems, Bangalore

     

     

     

     

     

  • Thanks Rakesh. Your product looks good but may be overkill for my modest CAD needs. I'll have a think about it.

    Jamie

  • Konstantin, I tried the LISP. It redefined the block but all attribute values were reset to their defaults. Did I do something wrong?

    Jamie

  • Hi Jamie,

    i think you do something wrong in step 3 or 5 or both...

     

    step3 : Copy one of the "old" Blocks with the "not moved" Attributes and explode the copy ! 


    just explode  a new copy of one of the blocks displaying the attributes in the wrong

    way
    , due to the redefinition of the insertion point in the external file.

    You should have now on the screen the definition components of the block displayed,

    the graphic entities + attribute definitions (ATTDEFs) ;   not the attributes with their values

    So now you can proceed with step4 and Step5.

    In step5 at the Second prompt : 

    Select objects for new Block...
        Select entities:          

     HERE you should select  all entities and ATTDEFS produced after the EXPLODE command

    The entities produced by the explode operation...the exploded Block    

    Here you make propably a mistake  ?????

    Hope it works this time ...if not  let me know 

    I cant' figure out something else for the moment

    It's late in Germany now almost 24:00   so until tomorrow

    Konstantin


  • Hi Konstantin,

    It doesn't seem to work I'm afraid. All the attribute values go back to defaults. Also, shouldn't it just be possible to explode one of the shifted blocks and the redefine it with the same name? However there seems to be a bug in Bricscad because when I do this all the entities are shifted a long way from their current locations. Thanks for trying to help, I'll just do things the long winded way.

    Jamie

This discussion has been closed.