Help needed, MAP/CIVIL 3D - object data copy function

Help needed, MAP/CIVIL 3D - object data copy function

Michiel.Valcke
Advisor Advisor
2,138 Views
14 Replies
Message 1 of 15

Help needed, MAP/CIVIL 3D - object data copy function

Michiel.Valcke
Advisor
Advisor

Hello,

I have been working on a function that can copy Object Data from one object to another object (without OD).

The first step was quite easy (and succesful) where I find a source and target object. I list all the different tables attached to the source object, then attach them the target object and copy the column data one by one into the corresponding table of the target object.

In this step I'm trying to expand the function to account for the fact that the source object can have multiple records of the same table attached, and I'm trying to 'loop' my way around to getting all the records copied from the source to the target object. (a future step would be to build in a 'security' : what if the target object already has OD records of the to be copied tables attached to it?)

I've hit a snag though: somehow I manage to get the tables and their definition, and I can also find how many records are attached for each table. But when trying to copy the data to the target object, the right amount of records are attached to my target object, but only the first one (recnum=0) gets filled in. Other records remain blank.

This is my code so far (I know there must be a way to make it more lean, or to bypass the loops within loops) at the moment my concern is WHY the recnum>0 are not being copied/filled.

Thank you for your time and effort.

;----------------------------------------------
; Error Handler
;----------------------------------------------
(defun mhv:Error (st)
    ; Note in addition to errors, also triggered any time user presses Esc
    ; only way to distinguish, is the passed error string st
    ; on English installs: (exit) = "Function cancelled", Esc = "quit / exit abort"
    (if 
        (not 
            (member st (list "Function cancelled" "quit / exit abort ")
            ) ; so if it is not one of these error messages, then give me a code backtrace:
        )
        (vl-bt) 
    ) ; if statement

    (princ)
) ; Error Handler
;----------------------------------------------

;--------------------------------------------
; copy OD table + value from 1 object to another
;--------------------------------------------

(defun c:OD_COPY ( / *error* sourceobj tablelist tablelistlength tablelistsort tableoccurence tablecnt destobj x y tabledef columns 
                  quantity cnt ycnt rvalue fieldname)
  ; get a source object (with OD) name
  ; get all the tables for the object
  ; for each table
    ; get all the OD records + values
  ; get a destination object
  ; attach all the table to the object
  ; for each table
    ; set all the OD record values
  ; 

  (setq *error* mhv:Error) ; load the Error Handler

  (if
    (setq sourceobj (car (entsel "\nChoose a source object: "))
          tablelist (ade_odgettables sourceobj) ; get a list of all the attached table names
          tablecnt 0
          destobj (car (entsel "\nChoose a destination object: "))
    ) 
    
    (progn
      
      (foreach table tablelist
        
        (setq tableoccurence
              (cons table (ade_odrecordqty sourceobj table))
        )
        (setq tablelistsort (cons tableoccurence tablelistsort)) ; set a list with (table . occurrence) (table . occurrence)
         
      ) ; end of foreach
      
      (setq tablelistlength (length tablelistsort))
      
      (while
        (< tablecnt tablelistlength)
        (setq x (car (nth tablecnt tablelistsort)) ; get a single tablename
              y (cdr (nth tablecnt tablelistsort)) ; get the occurence of that tablename
              tabledef (ade_odtabledefn x) ; get the table definition
              columns (cdr (caddr tabledef)) ; get the records def (columns) from tabledef
              quantity (length columns) ; how many records are there in the tabledef
              cnt 0
              ycnt 0
        ) ; end of setq
        
        (if
            (null (member x (ade_odgettables destobj)))
            (repeat y (ade_odaddrecord destobj x))
        ) ; end of if (if the destination object does not have the tablename, attach it y times, otherwise do nil)
        ; if statement needs to be modified: what to do if destobj already has tables attached?
        
        (while
          (< ycnt y)
          
          (while
            (< cnt quantity)

            (setq rvalue nil
                  fieldname (cdr (car (nth cnt columns))) ; get the name of the record in the records def
                  rvalue (ade_odgetfield sourceobj x fieldname ycnt) ; get the value (different data types) in the source object
            )

            (ade_odsetfield destobj x fieldname ycnt rvalue) ; set the value in the destination object record
            
            (setq cnt (1+ cnt)) ; up the count
          ); end of while (for each occurence)
          
          (setq ycnt (1+ ycnt)) ; up the count
        ) ; end of while (for each record in the table x)

        (setq tablecnt (1+ tablecnt)) ; up the count
      ) ; end of while (for each attached table name)
    )
    
    (progn
    
    )
  ) ; end of if
  
  (princ) ; clean exit
  
) ; end of OD_COPY function


The code is build as:

 

  • Get the objects (enames)& a list of all attached tables
  • Get the occurence (# records) for each table name and save them in a list of dotted pairs (table . occurrence)
  • -While loop 1 (per table in the source object) : from the dotted pair: get the table definition, # columns, set counters
  • -Attach x (occurrence) records of the table to the target object
  • --While loop 2 : (per occurrence of the table) repeat below for each occurrence of the table
  • ---While loop 3 : (per column in the tabledef) : Get the recnum (occurrence nr) from loop 2 - in the source table get the value from table (loop1)/recnum (loop2)/column (loop3) - set the value in the target table/recnum/column

I will also attach a .lsp file with the code and an example .dwg that contains an object with multiple tables each with multiple records.

0 Likes
Accepted solutions (1)
2,139 Views
14 Replies
Replies (14)
Message 2 of 15

Michiel.Valcke
Advisor
Advisor

In attachement you can find a .lsp file and a test.dwg.

0 Likes
Message 3 of 15

Michiel.Valcke
Advisor
Advisor
Accepted solution

And just after I posted this, I found the error.

      (while
        (< tablecnt tablelistlength)
        (setq x (car (nth tablecnt tablelistsort)) ; get a single tablename
              y (cdr (nth tablecnt tablelistsort)) ; get the occurence of that tablename
              tabledef (ade_odtabledefn x) ; get the table definition
              columns (cdr (caddr tabledef)) ; get the records def (columns) from tabledef
              quantity (length columns) ; how many records are there in the tabledef
              ycnt 0
        ) ; end of setq
        
        (if
            (null (member x (ade_odgettables destobj)))
            (repeat y (ade_odaddrecord destobj x))
        ) ; end of if (if the destination object does not have the tablename, attach it y times, otherwise do nil)
        ; if statement needs to be modified: what to do if destobj already has tables attached?
        
        (while
          (< ycnt y)
          (setq cnt 0)
          
          (while
            (< cnt quantity)



The counter for my loop3 was reset to 0 in loop1 instead of loop2.

Sometimes you just need to look away for a few seconds to spot the error.

0 Likes
Message 4 of 15

АлексЮстасу
Advisor
Advisor

Hi, Michiel,

 

In case you don't know about it. There are COPY_OD.lsp - from Autodesk, 1998, UHODCOPY.VLX- from Udo Hübner, http://www.cad-huebner.de/ and 5 commands in ODEDIT (ObjectArx):
ODEDIT_COPY_OD, ODEDIT_COPY_OD_VALUE, ODEDIT_COPY_ALL, ODEDIT_COPY_ALL_VALUE and ODEDIT_COPY_VALUE.

Maybe something will come in handy.

 


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

Message 5 of 15

Michiel.Valcke
Advisor
Advisor

I was actually not aware of those commands, nor the .lsp file by Udo Hübner. Thank you so much for the tip.

For the development of my code it will not change much. In the end I have to fit it into a much larger routine, so this is a smaller part of it.

Message 6 of 15

АлексЮстасу
Advisor
Advisor

If you are doing Object Data, then I collect all the programs to work with them on my website in the Additionally section. From there can always take them freely.
Something can be useful, save time.
There are now 31 LISP programs, 1 free plugin and a library of LISP functions.
Some of these programs solve the same problem. And I would like to put your program there as well when you consider it finished.

 


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

Message 7 of 15

АлексЮстасу
Advisor
Advisor

Hi, Michiel,

 

If your program is ready, and it is not a pity to give it, then publish it or send it to me.
I'll put it in the OD routine collection on my website.

 


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 8 of 15

Michiel.Valcke
Advisor
Advisor

I won't be able to give you the entire routine (it wouldn't be much use since it fits into a company's greater workflow and expects certain tables and columns to be present) but I'll try to finish up the 'overwrite existing tables' option this weekend and I can share the standalone program with you. I'll let you know when it's ready.

Message 9 of 15

Michiel.Valcke
Advisor
Advisor

@АлексЮстасу 

You can find the lisp here in attachment, feel free to post it on your website.

It copies OD from one object to another, it also gives the user the choice of 3 override modi
All: suppress all pre-existing OD records in the target object

Yes: overwrite pre-existing OD records in the target object if they have the same table and record number

No (default): add the OD records to the target object, do not overwrite pre-existing OD records

It also contains an extra application OD_DELETE_MHV: this will remove all OD records from a chosen object.

Message 10 of 15

АлексЮстасу
Advisor
Advisor

Thank you!
Interesting!
Your OD copy option is clearly different.

 

But the OD_DELETE_MHV didn't work:

Command: OD_DELETE_MHV
Choose an object:; error: too many arguments

(2018)


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help

0 Likes
Message 11 of 15

Michiel.Valcke
Advisor
Advisor

I don't get the error on my end, but I have added an earlier working version in attachment (it doesn't have messaging prompts for the OD_DELETE), the rest is the same. Maybe this one will work better for you.

0 Likes
Message 12 of 15

CADaSchtroumpf
Advisor
Advisor

Hi,

A minor error in your first OD_COPY_MHV.lsp

In function OD_DELETE_MHV :

(prompt "\n" (strcat (itoa i) " records from the table " desttable " have been removed."))

must be:

(prompt (strcat "\n" (itoa i) " records from the table " desttable " have been removed."))

 

Message 13 of 15

CADaSchtroumpf
Advisor
Advisor

Here my function for copy  all OD. Another way of doing...

(defun c:ALL_copy_OD ( / ent lst_data nwent tbldef )
  (princ "\nSélectionner l'entité SOURCE")
  (while (not (setq ent (entsel))))
  (setq ent (car ent))
  (princ "\nSélectionner l'entité CIBLE")
  (while (not (setq nwent (entsel))))
  (setq nwent (car nwent))
  (if
    (or
      (numberp (vl-string-search "Map 3D" (vla-get-caption (vlax-get-acad-object))))
      (numberp (vl-string-search "Civil 3D" (vla-get-caption (vlax-get-acad-object))))
    )
    (progn
      (foreach n (ade_odgettables ent)
        (setq tbldef (ade_odtabledefn n))
        (setq lst_data
          (cons
            (mapcar
              '(lambda (fld / tmp_rec numrec)
                (setq numrec (ade_odrecordqty ent n))
                (cons
                  n
                  (while (not (zerop numrec))
                    (setq numrec (1- numrec))
                    (if (zerop numrec)
                      (if tmp_rec
                        (cons fld (list (cons (ade_odgetfield ent n fld numrec) tmp_rec)))
                        (cons fld (ade_odgetfield ent n fld numrec))
                      )
                      (setq tmp_rec (cons (ade_odgetfield ent n fld numrec) tmp_rec))
                    )
                  )
                )
              )
              (mapcar 'cdar (cdaddr tbldef))
            )
            lst_data
          )
        )
      )
      (cond
        (lst_data
          (mapcar
            '(lambda (x / ct)
              (while (< (ade_odrecordqty nwent (caar x)) (ade_odrecordqty ent (caar x)))
                (ade_odaddrecord nwent (caar x))
              )
              (foreach el (mapcar 'cdr x)
                (if (listp (cdr el))
                  (progn
                    (setq ct -1)
                    (mapcar
                      '(lambda (y / )
                        (ade_odsetfield nwent (caar x) (car el) (setq ct (1+ ct)) y)
                      )
                      (cadr el)
                    )
                  )
                  (ade_odsetfield nwent (caar x) (car el) 0 (cdr el))
                )
              )
            )
            lst_data
          )
        )
      )
    )
  )
  (prin1)
)
Message 14 of 15

Michiel.Valcke
Advisor
Advisor

ooh I love the mapcars xD, that is still a bit out of my reach to conceptualize it in my head, but I will surely study this and probably learn a lot from it. It looks so lean compared to my code. and so few variables needed.

looking for using MAP/Civil in the main (if ) is a nice way to insulate the user from using the lisp on another vertical and seeing a bunch of errors appear.

0 Likes
Message 15 of 15

АлексЮстасу
Advisor
Advisor

 

I have posted these your commands on website in Additionally.

I hope I described and translated it right.


-- Alexander, private person, pacifist, english only with translator 🙂 --

Object-modeling _ odclass-odedit.com _ Help