Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

COPY ATTRIBUTES FROM OLD DWGS TO NEW TEMPLATE

19 REPLIES 19
Reply
Message 1 of 20
Anonymous
1085 Views, 19 Replies

COPY ATTRIBUTES FROM OLD DWGS TO NEW TEMPLATE

Hello,

 

I have a bunch of drawings that were created using old templates. I need to migrate them to a new template. All attributes have the same name in both templates. 

 

I have looked into ATTEXT and PROPULATE commands but they don't give me what I want. Lee Mac also doesn't seem to have what I'm looking for. 

 

I have a lot of DWGs and would like to automate the process. Ideally I'd like a button a user can click that would generate a new drawing using the new template with all attributes copied over. Any help is greatly appreciated!

 

Old template:

att1.PNG

New Template:

2att.PNG

 

Phil 

19 REPLIES 19
Message 2 of 20
Moshe-A
in reply to: Anonymous

@Anonymous  hi,

 

check this TBSUBST command.

 

At start there is a declaration of 2 constant variables: 

(setq NTB "NewTitleBlockName")

(setq OTB "OldTitleBlockName")

 

you need to replace "NewTitleBlock" with your new title block name and the same for the old title block name. failing to do that or miss spelling the block name, the command will fail to work.

also move aside the old TB and insert the TB in place.

 

this program is based on Lee's Mac wrapper for ssget (LM:ssget) - thank you Lee Mac for this wonderful function.

 

emjoy

moshe

 

 

(vl-load-com) ; load activex

; Title Block substitute
(defun C:TBSUBST (/ old_attrib_list ; local function
		    NTB OTB SSFILTER ss0 ss1 AcDbBlkRef0 AcDbBlkRef1 data^ attributes^ tag item)

 (defun old_attrib_list (AcDbObj / att^ lst)
  (setq att^ (vlax-invoke AcDbObj 'GetAttributes))

  (foreach attrib att^
   (setq lst (cons (cons (strcase (vla-get-tagString attrib)) (vla-get-textString attrib)) lst))
  )

  (foreach attrib att^
   (vlax-release-object attrib)
  )
 
  lst 
 ); make_attrib_list

  
 ; declar some constants
 (setq NTB "NewTitleBlockName")
 (setq OTB "OldTitleBlockName")
 (setq SSFILTER '("_:S:E+." ((0 . "insert") (66 . 1))))
  
 (if (and
       (setq ss0 (LM:ssget "\nSelect NEW title block: " SSFILTER)) ; thanks to Lee Mac
       (setq ss1 (LM:ssget "\nSelect OLD title block: " SSFILTER))
     )
  (progn
   (setq AcDbBlkRef0 (vlax-ename->vla-object (ssname ss0 0)))
   (setq AcDbBlkRef1 (vlax-ename->vla-object (ssname ss1 0)))
   (if (and
        (eq (strcase (vla-get-effectiveName AcDbBlkRef0)) (strcase NTB))
        (eq (strcase (vla-get-effectiveName AcDbBlkRef1)) (strcase OTB))
       ) 
    (progn
     (setq data^ (old_attrib_list AcDbBlkRef0))
     (setq attributes^ (vlax-invoke AcDbBlkRef1 'GetAttributes))

     (foreach AcDbAttrib attributes^
      (setq tag (strcase (vla-get-tagString AcDbAttrib)))
      (if (setq item (assoc tag data^)) 
       (vla-put-textString AcDbAttrib (cdr item))
      ) 
     ); foreach

     (foreach AcDbAttrib attributes^
      (vlax-release-object AcDbAttrib) 
     )
    ); progn
    (progn
     (vlr-beep-reaction)
     (prompt "\ninvalid block selection.")
    ); progn
   ); if

   (vlax-release-object AcDbBlkRef1)
   (vlax-release-object AcDbBlkRef0)
  ); progn
 ); if

 (princ) 
); C:TBSUBST


;; ssget  -  Lee Mac
;; A wrapper for the ssget function to permit the use of a custom selection prompt
;; msg - [str] selection prompt
;; arg - [lst] list of ssget arguments
 
(defun LM:ssget ( msg arg / sel )
 (princ msg)
 (setvar 'nomutt 1)
 (setq sel (vl-catch-all-apply 'ssget arg))
 (setvar 'nomutt 0)
 (if (not (vl-catch-all-error-p sel)) sel)
)

 

 

Message 3 of 20
Anonymous
in reply to: Moshe-A

Hi Moshe,

 

Thank you for your response. It doesn't look like this is exactly what I'm after but its on the right track.

 

This script you provided - both title blocks require being loaded in the same DWG, which I do not want. 

 

I would like to start with a DWG with the "old" template. I would like to run the script and have a new DWG be generated, using the new template file, and put in the correct attributes. 

 

I found this script from Lee Mac - http://www.lee-mac.com/updatetitleblock.html. This is very close to what I want. Instead of having to input the attributes into a CSV excel sheet, I'd like them to be pulled from the opened file. 

 

Phil 

Message 4 of 20
dbhunia
in reply to: Anonymous


@Anonymous wrote:

Hello,

 

I have a bunch of drawings that were created using old templates. I need to migrate them to a new template. All attributes have the same name in both templates. 

..........


If so Try this in SDI Mode.......(hopefully your new Title Block is a Wblock & not present in drawing)

 

(defun C:RTB ( / *error* sh folder SDI_Val LISPI_Val folderobject result Files_Folder Old_TB WB_fname doc ss block block_Name n)
	(vl-load-com)
	(defun *error* ( msg )
		(setvar 'SDI SDI_Val)(setvar 'LISPINIT LISPI_Val)
		(if (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*"))
			(princ (strcat "\nOops an Error : " msg " occurred."))
		)
		(princ)
	)  
	(setq SDI_Val (getvar 'SDI))
	(setq LISPI_Val (getvar 'LISPINIT))
	(setq sh (vla-getInterfaceObject (vlax-get-acad-object) "Shell.Application" ))
	(setq folder (vlax-invoke-method sh 'BrowseForFolder 0 "Select Folder of Drawings to Process" 512 ))
	(vlax-release-object sh)
	(setvar 'cmdecho 0)(setvar 'SDI 1)(setvar 'LISPINIT 0)
	(if folder
		(progn
			(setq folderobject (vlax-get-property folder 'Self))
			(setq result (vlax-get-property FolderObject 'Path))
			(vlax-release-object folder)
			(vlax-release-object FolderObject)
			(setq Files_Folder (vl-directory-files result "*.dwg"))
			(setq Old_TB (getstring t "\nEnter Name of the Title Block to be Replace: "))
			(setq WB_fname (getfiled "Select Wblock/File of New Title Block:" (getvar "dwgprefix") "dwg" 4))
			(command "save" (strcat (getvar "dwgprefix") (getvar "dwgname")) "Y")
			(setq n 0)
			(while (< n (length Files_Folder))
				(command "fileopen" (strcat result "\\" (nth n Files_Folder)))
				(vl-load-com)
				(setq doc (vla-get-activedocument (vlax-get-acad-object)))
				(setq ss (ssget "_X" (list '(0 . "INSERT")(cons 2 Old_TB))))
				(if(/= ss nil)
					(progn
						(setq block (vla-InsertBlock (vla-get-Modelspace doc) (vlax-3d-point 0 0) WB_fname 1 1 1 0))
						(setq block_Name (vla-get-name block))
						(foreach Ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss)))
							(vla-put-Name (vlax-ename->vla-object Ent) block_Name)
						)
						(vla-delete block)
						(vl-cmdf "save" (strcat result "\\New-" (nth n Files_Folder)))
					)
					(vl-cmdf "save" (strcat result "\\" (nth n Files_Folder)) "")
				)
				(setq n (+ 1 n))
			)
		)
	)
	(setvar 'SDI SDI_Val)(setvar 'LISPINIT LISPI_Val)(setvar 'cmdecho 1)
	(princ)
)

Debashis Bhunia
Co-Founder of Geometrifying Trigonometry(C)
________________________________________________
Walking is the First step of Running, Technique comes Next....
Message 5 of 20
Anonymous
in reply to: dbhunia

Hi Debashis,

 

Its nice to hear from you again. I hope all is well. Thank you for taking the time to help a stranger out!

 

I couldn't get your script to work for me. I could get it to run but it did not achieve the result I was hoping for - nothing seems to have changed in the DWG. 

 

I have had some success with this Lee Mac script (http://www.lee-mac.com/odbxbase.html) I am able to generate a list of attributes. Is there a way we can combine this script with Lee's title block updater script? (http://www.lee-mac.com/updatetitleblock.html)

 

Phil 

Message 6 of 20
dbhunia
in reply to: Anonymous

After watching "Lee's title block updater script"....... I get that your New title block is already present in drawing....

 

Now if your New and Old title block both are present in each Layout/Model, then you can try this after loading  (http://www.lee-mac.com/odbxbase.html) ....... it will update New TB according to Old TB Tag Name....

 

(defun c:Update_TB ( / Ch_Att_Value_All_Layout)

	(defun Ch_Att_Value_All_Layout ( doc / )
	
		(defun Ch_Att_Value_Each_Layout ( lay_obj / values attributes atttag attval)

			(vlax-for object (vla-get-block lay_obj)
				(if
					(and
						(= "AcDbBlockReference" (vla-get-objectname object))
						(= :vlax-true (vla-get-hasattributes object))
						(= "TITLE"	(if (vlax-property-available-p object 'effectivename)
										(vla-get-effectivename object)
										(vla-get-name object)
									)
						);;; Here "TITLE" is the Old Title Block Name ... Change it as you needed
					)
					(setq values
						(mapcar
							(function
								(lambda ( att )
									(cons
										(vla-get-tagstring att)
										(vla-get-textstring att)
									)
								)
							)
							(vlax-invoke object 'getattributes)
						)
					)
				)
			)
			(if values
				(vlax-for object (vla-get-block lay_obj)
					(if
						(and
							(= "AcDbBlockReference" (vla-get-objectname object))
							(= :vlax-true (vla-get-hasattributes object))
							(= "Title-N" (if (vlax-property-available-p object 'effectivename)
											(vla-get-effectivename object)
											(vla-get-name object)
										 )
							);;; Here "Title-N" is the New Title Block Name ... Change it as you needed
						)
						(progn
							(setq attributes (vlax-invoke object 'GetAttributes))
							(foreach att attributes
								(setq atttag (vla-get-tagString att))
								(if (setq attval (assoc atttag values)) 
									(vla-put-textString att (cdr attval))
								) 
							)
						)
					)
				)
			)
		)
		(vlax-for layout (vla-get-layouts doc)
			(Ch_Att_Value_Each_Layout layout)
		)
	)
    (LM:ODBX 'Ch_Att_Value_All_Layout nil t)
    (princ)
)

 


Debashis Bhunia
Co-Founder of Geometrifying Trigonometry(C)
________________________________________________
Walking is the First step of Running, Technique comes Next....
Message 7 of 20
Anonymous
in reply to: dbhunia

Hi Debashis, 

 

"Title block name"., what do you mean? The attribute name? Block? DWG file name? DWT file name? 

 

The user won't realize the DWG needs the new title block until they open the old DWG. Once they realize it needs updating, they will then run the program to replace everything. 

 

Phil 

Message 8 of 20
Sea-Haven
in reply to: Anonymous

Pretty sure had something the same. What happens when..

 

Open new dwg with correct title block

Copy and paste new title "block" into old dwg, block name must be the same.

Do you want to redefine "yes".

Then use Attsync to update all the blocks.

Message 9 of 20
Anonymous
in reply to: Sea-Haven

Thanks Sea.haven, but it looks like that just copies the format, and not the actual attributes.

5.PNG

4.PNG3.PNG

Message 10 of 20
Anonymous
in reply to: Anonymous

Perhaps I can be clearer.

 

We have a large database of OLD drawings. With an OLD title block. We have recently updated our title block. We want to convert all OLD drawings to the NEW title block.

 

Here is an example of the old title block:

USER1.PNG

Here is an example of the new title block:

dis2.PNG

I realize this is Rev 6 vs. Rev 9, but I hope you get the point, the information WILL BE the same.

 

Currently, we have a number of people that MANUALLY copy and paste the information from title block to title block.

 

Is there a better way we can do this with automation?

 

The title block attributes names are the same (DRAWN-BY, DRAWN-DATE, etc.). We can make the new title block attributes whatever we want.

 

Currently I have the new title block saved as a template (.DWT) but I can save it as a WBLOCK, any method is acceptable.

 

Ideally, the user can run the script, the old title block thrown away, and is replaced by the new title block, populated. 

Message 11 of 20
cadffmx
in reply to: Anonymous

Note, i "ignore" all other answers in hope for all we get the right informations from you

when you answering to my post:

 

We have a large database of OLD drawings. With an OLD title block.

We have recently updated our title block. (IN SOME DWT FILES, NOT IN THE OLD DRAWINGS)

We want to convert all OLD drawings to the NEW title block.

{ All attributes have the same name in both templates. }

AT THIS TIME (with given facts above), ALL YOU NEED IS TO REDEFINE THE BLOCK!
But the problem is that this isn't all what you want to do (but never explained it in details)*


My try to get the needed informations from you:

A)
As others mentioned before:
Upload one DWG OLD (with the old version) and one DWG NEW where you did whatever
you want by hand and you wish to do it by one click!

 

But because you did not manage to explain it in the past and did not provide any data, here's another approach:

I take the previous statements (same blockname, same attribute names) and offer the simple solution.
Then you will not be satisfied and can specifically address the "problems".

b)
Go to your NEW template
Use WBLOCK (Option BLOCK) and export your new block as DWG to C:\temp\TB.dwg

Go to your OLD file and copy and paste the next line to the commandline:
(progn (command "_.-INSERT" "TB=C:/TEMP/TB.DWG")(command)(command "_.ATTSYNC" "_NAME" "TB"))

Now, let's talk about the result.


*why i think that: Your picture "NEW" shows FIELDS and the old one NOT,
so it isn't the same content. Old content = simple text, NEW content = a field.

 

 

The only thing that bothers me a bit in the descriptions is when you talk about TEMPLATES, I hope this is not important

Sebastian

EESignature

Message 12 of 20
Sea-Haven
in reply to: Anonymous

My answer was the same as cadffm just posted off top of my head. Using aecconsole you may be able to script 100's of dwgs.

Message 13 of 20
cadffmx
in reply to: Sea-Haven

@Sea-Haven Yes, but we are the same opinion some basic knowledge is missing and we need to help to catch the fish ;D

I guess TO overread your ""Then use Attsync to update all the blocks.""

OR we talk about corrupt dynamic block, annotation block or or or.

 

?: Accoreconsole?  Very funny. TO is not able to do what he want in one file, he can not do it in 100 files,

but by accoreconsole he can (can't) do very fast, rofl.

 

Sebastian

EESignature

Message 14 of 20
dbhunia
in reply to: Anonymous

@Anonymous  

 

Save the New Title Block as a WBLOCK with different Name (Other your Existing Title Block Name in drawing). Then run the LISP.

 

The LISP will create a New Drawing at the same location of your Old Drawing with New Title Block. (As you asked earlier).

 

(defun c:RTB ( / path Option OBlk_Name WB_Name ss doc Dwg_Path Dwg_Name)
	(vl-load-com)
	(cond ((getenv "WB_Path")
		(setq path (getenv "WB_Path"))	
		(initget "Change")
		(setq Option (cond ((getkword (strcat "\nWblock/Drawing for New Title Block is <" (getenv "WB_Path") "> [Change]: "))) (path)))
	      )
	)
	(cond ((or (not (getenv "WB_Path"))(= "Change" Option))
		(setenv "WB_Path" (getfiled "Select Wblock/Drawing for New Title Block:" (getvar 'DWGPREFIX) "dwg" 4))
	      )
	)
        (cond ((setq OBlk_Name (vla-get-effectivename (vlax-ename->vla-object (car(entsel "\nSelect Title Block to Replace...")))))
		(if (not (wcmatch (strcase (getenv "WB_Path")) (strcase (strcat "*" OBlk_Name ".dwg"))))
		    (progn
			(setvar 'CMDECHO 0)(setvar 'ATTREQ 0)
			(command "_.INSERT" (getenv "WB_Path") "0,0,0" "" "" "")
			(setq WB_Name (vla-get-name (vlax-ename->vla-object (entlast))))
			(entdel (entlast))
			(setq ss (ssget "_X" (list '(0 . "INSERT")(cons 2 OBlk_Name))))
			(foreach Ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss)))
				(vla-put-Name (vlax-ename->vla-object Ent) WB_Name)
			)
			(command "_.ATTSYNC" "_NAME" WB_Name "_.PURGE" "_B" OBlk_Name "_N")
			(setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
			(setq Dwg_Path (vla-get-path doc))
			(setq Dwg_Name (vla-get-name doc))
			(vla-saveas doc (strcat Dwg_Path "\\" (substr Dwg_Name 1 (- (strlen Dwg_Name) 4)) "-New-TB.dwg"))
			(princ (strcat "\nNew Drawing Path & Name is: " (getvar 'DWGPREFIX) (getvar 'DWGNAME)))
			(setvar 'ATTREQ 1)(setvar 'CMDECHO 1)
		   )
		   (alert "\nSelect Wblock/Drawing & Block Name are same")
		)
	     )
	)
	(princ)
)

The above process was before seeing @cadffmx  post.......

 

@cadffmx  thanks for this block redefining trick. It is new thing for me.

 

(progn (command "_.-INSERT" "TB=C:/TEMP/TB.DWG")(command)(command "_.ATTSYNC" "_NAME" "TB"))

 

After this trick I should move like below....... 

 

(defun c:RTB ( / path Option OBlk_Name doc Dwg_Path Dwg_Name)
	(vl-load-com)
	(cond ((getenv "WB_Path")
		(setq path (getenv "WB_Path"))	
		(initget "Change")
		(setq Option (cond ((getkword (strcat "\nWblock/Drawing for New Title Block is <" (getenv "WB_Path") "> [Change]: "))) (path)))
	      )
	)
	(cond ((or (not (getenv "WB_Path"))(= "Change" Option))
		(setenv "WB_Path" (getfiled "Select Wblock/Drawing for New Title Block:" (getvar 'DWGPREFIX) "dwg" 4))
	      )
	)
	(cond ((setq OBlk_Name (vla-get-effectivename (vlax-ename->vla-object (car(entsel "\nSelect Title Block to Replace...")))))
		(setvar 'CMDECHO 0)(setvar 'ATTREQ 0)
		(command "_.INSERT" (strcat OBlk_Name "=" (getenv "WB_Path")) (command) "_.ATTSYNC" "_N" OBlk_Name)
		(setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
		(setq Dwg_Path (vla-get-path doc))
		(setq Dwg_Name (vla-get-name doc))
		(vla-saveas doc (strcat Dwg_Path "\\" (substr Dwg_Name 1 (- (strlen Dwg_Name) 4)) "-New-TB.dwg"))
		(princ (strcat "\nNew Drawing Path & Name is: " (getvar 'DWGPREFIX) (getvar 'DWGNAME)))
		(setvar 'ATTREQ 1)(setvar 'CMDECHO 1)
	      )
	)
	(princ)
)

Debashis Bhunia
Co-Founder of Geometrifying Trigonometry(C)
________________________________________________
Walking is the First step of Running, Technique comes Next....
Message 15 of 20
Sea-Haven
in reply to: dbhunia

The code can be cut down dramatically as you know the name of the new title block dwg and where it lives.

 

Use (getvar 'dwgname) then can do a simple saves as, the default is to save in same place as original dwg. Regarding this though I would expect a save as same name and dwg's have been backed up 1st else where other wise can use vl-filecopy to save else where 1st.

Message 16 of 20
Anonymous
in reply to: Sea-Haven

I am sorry for being so confusing. I will try to explain this more simply.

 

My company has existed for 15 years, and for the most part, has consistently used a specific title block to identify and mark our drawings. It is similar to the one below.

 

USER1.PNG

 

About a year ago, we moved to a new title block. This new title block uses black font everywhere, uses a different font, includes a different logo, updated website. Here is an example of the new one below.

 

dis2.PNG

 

I would like to write a script that will completely replace the OLD title block with the NEW one, and for it to transfer all the information. I don't want to specify locations or do it across multiple locations. I just want it to happen in the current drawing. 

 

The tags are the same in both OLD and NEW templates.

 

So I imagine the code should follow the following actions:

 

1. Search the OLD template for attribute data (tags that I can specify, if required)

2. Copies that data to a list, or variable

3. Removes the OLD template (deletes?)

4. Loads the NEW template in its place

5. Pastes the attribute data to the NEW template in the proper spots

Message 17 of 20
Scottu2
in reply to: Anonymous

Hello phenderson4XRAJ,

 

I think i understand your process,

Open old drawing then insert the new title block (different block name), perhaps offset to read both.

Then run the new lisp routine to Match the old title block with the new one (pick source then pick target)

I recommend, double check the data transfer before manually deleting the old title block.

 

Perhaps the code structure could be like:

The routine should scan the source block for attributes generating a list ((tag1 value1) (tag2 value2) (tag3 value3))

Then get (tag1 value1) and scan all the target block attributes for a match, if found the update it.

Program Feedback: The routine should display both tags updated and tags that did not as it scans.

repeat until you reach the end of the list.

 

Since it is not tag name specific it can be used for any matching of attributes.

 

Message 18 of 20
Sea-Haven
in reply to: Scottu2

You stated The title block attributes names are the same (DRAWN-BY, DRAWN-DATE, etc.)

 

Again save the new title block only to a dwg. Do this once only !!

 

Just insert the new titleblock dwg, into old dwg, anywhere it should ask to redefine, say yes, then attsync, it should all be done and correct.

Message 19 of 20
Scottu2
in reply to: Sea-Haven

sea.haven,

I would agree with that approach; however, I would prefer semi-automated with operator verification when dealing with old drawings.  The significant timer is automating the attribute-to-attribute vs cut & paste.

As the confidence of conversion gets high then the routine can change to auto-replace and save.

 

Message 20 of 20
Ajilal.Vijayan
in reply to: Scottu2

try this code

;; Get Attribute Values  -  Lee Mac
;; Returns an association list of attributes present in the supplied block.
;; blk - [vla] VLA Block Reference Object
;; Returns: [lst] Association list of ((<tag> . <value>) ... )

(defun LM:vl-getattributevalues ( blk )
    (mapcar '(lambda ( att ) (cons (vla-get-tagstring att) (vla-get-textstring att))) (vlax-invoke blk 'getattributes))
)

;; Set Attribute Values  -  Lee Mac
;; Sets attributes with tags found in the association list to their associated values.
;; blk - [vla] VLA Block Reference Object
;; lst - [lst] Association list of ((<tag> . <value>) ... )
;; Returns: nil

(defun LM:vl-setattributevalues ( blk lst / itm )
    (foreach att (vlax-invoke blk 'getattributes)
        (if (setq itm (assoc (vla-get-tagstring att) lst))
            (vla-put-textstring att (cdr itm))
        )
    )
)


(defun c:test( / ssPt ssPt2 blkEnt blkObj oldValues pos)
	;select the old template block
	(setq ssPt (ssget "_:S" '((0 . "INSERT"))))
	(setq blkEnt (ssname ssPt 0))
	(setq pos (cdr(assoc 10(entget blkEnt))))
	(setq blkObj (vlax-ename->vla-object blkEnt))
	;get the old attribute values
	(setq oldValues (LM:vl-getattributevalues blkObj))
	;delete old template
	(entdel blkEnt)
	;insert the new block in the same position of old block
	(command "_.-INSERT" "C:/newTemplate.dwg" pos 1 1 0)
	;get the last inserted block and explode it
	(command "explode" "last")
	;get the block in place after explode
	(setq ssPt2 (ssget "L"))
	;update the new block with old values
	(LM:vl-setattributevalues (vlax-ename->vla-object (ssname ssPt2 0)) oldValues)
)

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Customer Advisory Groups