TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Lee Mac on June 09, 2009, 08:04:31 PM

Title: Opening Drawings using LISP
Post by: Lee Mac on June 09, 2009, 08:04:31 PM
I am trying to use LISP to open a drawing, and insert a block (purely for testing and learning purposes), however, I am receiving an error, and am not sure if I am approaching this in the correct way.

I am using the vla-open method, on the Documents Collection, then the vla-insertblock method on the ActiveDocument, as I understood that when the new drawing was opened, it then became the ActiveDocument.

This is a section of the code I am using:

Code: [Select]
(vla-open
  (vla-get-Documents
    (vlax-get-acad-object)) dwg :vlax-false)
(vla-insertBlock
  (vla-get-ModelSpace
    (vla-get-ActiveDocument
      (vlax-get-acad-object)))
  (vlax-3D-point '(0 0 0)) "test block" 1. 1. 1. 0.))))

Where "dwg" is just the filepath of a valid drawing name.

Any help and/or advice is appreciated as always,

Cheers,

Lee
Title: Re: Opening Drawings using LISP
Post by: CAB on June 09, 2009, 08:18:28 PM
You need to use ObjectDBX.

Re: Change the same details of a number of drawing titleblocks  (http://www.theswamp.org/forum/index.php?topic=7335.msg91135#msg91135)
DBX Testing   (http://www.theswamp.org/forum/index.php?topic=6307.0)
run a lisp in dwgs WITHOUT opening the dwgs?   (http://www.theswamp.org/forum/index.php?topic=7498.0)
Jeff_M or anyone familiar with ObjectDBX  (http://www.theswamp.org/forum/index.php?topic=3650.0)
Find Text in a Closed Drawing (http://www.theswamp.org/forum/index.php?topic=2671.0)
Block Adding  (http://www.theswamp.org/forum/index.php?topic=1821.0)
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 09, 2009, 09:14:53 PM
Thanks for your reply Alan,

I have seen another post on here with those links to ObjectDBX threads, but I wasn't sure if ObjectDBX was a necessity or not... is it the only way to accomplish this task...  **daunted by ObjDBX**

Thanks,

Lee
Title: Re: Opening Drawings using LISP
Post by: kdub_nz on June 09, 2009, 09:44:39 PM


Alan, I'd really like to know what sort of indexing system you keep for your links ... seems to be really effective :)
Title: Re: Opening Drawings using LISP
Post by: CAB on June 10, 2009, 12:37:17 AM
Lisp operates within the environment of a single drawing. When you switch drawings or open a new drawing you are in a separate environment as far as Lisp is concerned. This will cause the Lisp to stop working.
To overcome this limitation you must use ObjectDBX or run a Lisp via a Script. If you run a script which runs a Lisp you must use some tricks to pass variables from one drawing environment to another.

I've seen better explanations but I'm headed to bed & don't feel like looking for the eloquent explanation. :-(
Title: Re: Opening Drawings using LISP
Post by: CAB on June 10, 2009, 12:42:21 AM
Alan, I'd really like to know what sort of indexing system you keep for your links ... seems to be really effective :)
Sorry to disappoint you but I keep a hodge podge of links in a few files but my forte is research & remembering clues that lead me back to the source.
Title: Re: Opening Drawings using LISP
Post by: FengK on June 10, 2009, 04:32:01 AM
I am using the vla-open method, on the Documents Collection, then the vla-insertblock method on the ActiveDocument, as I understood that when the new drawing was opened, it then became the ActiveDocument.

i don't think that is the case. the active document does not change. but you can execute commands/lisps in the newly opened drawing using sendcommand.
Title: Re: Opening Drawings using LISP
Post by: Patrick_35 on June 10, 2009, 04:53:31 AM
Hi

Quote
you must use some tricks to pass variables from one drawing environment to another
Use the blackboard (vl-bb-set and vl-bb-ref)

@+
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 08:39:07 AM
Thanks for your responses guys, - I'd prefer to go down the ObjectDBX route than scripting, but one step at a time  :-)

I'll check out those links you posted Alan, and see where I can go with that - if I get stuck, no doubt I'll come running back...  8-)

Thanks for your time guys,

Lee
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 08:41:15 AM
I am using the vla-open method, on the Documents Collection, then the vla-insertblock method on the ActiveDocument, as I understood that when the new drawing was opened, it then became the ActiveDocument.

i don't think that is the case. the active document does not change. but you can execute commands/lisps in the newly opened drawing using sendcommand.

I read this from the ACAD help, which is where I got my information, but it has been wrong on things in the past:

Quote
VLA-OPEN
Opens an existing drawing file (DWG) and makes it the active document.
Title: Re: Opening Drawings using LISP
Post by: Patrick_35 on June 10, 2009, 08:50:05 AM
Quote
VLA-OPEN
Opens an existing drawing file (DWG) and makes it the active document.
To activate, use (vla-activate (vla-open ....))

@+
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 09:15:59 AM
Thanks Patrick - hadn't heard of vla-activate - nice one  8-)
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 02:32:23 PM
After taking a look at a few of the links as provided kindly by Alan, I have found that the users open the documents using expressions such as:

Code: [Select]
(setq odbx (vla-GetInterfaceObject *acad "ObjectDBX.AxDbDocument.16")

Where, I'm guessing, the ".16" is the ACAD version (in my case .18).

They then proceed to use:

Code: [Select]
(vla-open odbx)

And all else that follows, assumes odbx to be the ActiveDocument.

Am I correct in my thinking, or way way off the mark...    :?

Cheers,

Lee
Title: Re: Opening Drawings using LISP
Post by: T.Willey on June 10, 2009, 02:47:33 PM
Code: [Select]
(setq odbx (vla-GetInterfaceObject *acad "ObjectDBX.AxDbDocument.16")This gets the application used to use ODBX.

Code: [Select]
(vla-open odbx <FullFilePath>)This opens the drawing.  The drawing is not current by any means.  The ' odbx ' variable is the document now, and to interact with it, you have to use that variable, like you would use a variable assigned to the active document, with some restrictions.

This are my understandings of what is happening.
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 02:57:54 PM
Thank you for your insight Tim, it is much appreciated.

I currently have this code - which I using just as a learning tool, but I am having trouble handling the documents.

As a tester, I am just trying to make the code Draw a Circle at the origin in each drawing, then save and close the drawing, but I cannot seem to get it to work properly.

As I have said previously, I am new to this ObjectDBX game, so go easy on me folks   :wink:

Code: [Select]
;; ObjectDBX Tester  by Lee McDonnell (Lee Mac)
;; Credit to Tony Tanzillo for Directory Browser

(defun c:MacDwg (/ *error* *acad Shell fDir Dir dbx)
  (vl-load-com)

  (defun *error* (e)
    (if ov (mapcar 'setvar vl ov))
    (ObjRel (list Shell dbx *acad))
    (if (not (wcmatch (strcase e) "*CANCEL*,*EXIT*"))
      (princ (strcat "\n<< Error: " e " >>")))
    (princ))

  (setq *acad (vlax-get-acad-object)
        Shell (vla-getInterfaceObject *acad "Shell.Application")
        fDir (vlax-invoke-method Shell 'BrowseForFolder
               (vla-get-HWND *acad) "Select Directory: " 0))
  (if fDir
    (progn
      (setq Dir
        (vlax-get-property
          (vlax-get-property fDir 'Self) 'Path))
      (if (not (eq "\\" (substr Dir (strlen Dir))))
        (setq Dir (strcat Dir "\\")))
      (setq dbx (vla-getInterfaceObject
                  *acad "ObjectDBX.AxDbDocument.18"))
      (foreach dwg (mapcar
                     (function
                       (lambda (x)
                         (strcat Dir x)))
                     (vl-directory-files Dir "*.dwg" 1))
        (vla-open dbx dwg)
        (vla-addCircle (vla-get-ModelSpace dbx)
          (vlax-3D-point '(0 0 0)) 5)
        (vla-close dbx :vlax-true))))
 
  (ObjRel (list Shell dbx *acad))
  (gc)
  (princ))
           
(defun ObjRel (lst)
  (mapcar
    (function
      (lambda (x)
        (if (and (eq (type x) 'VLA-OBJECT)
                 (not (vlax-object-released-p x)))
          (vl-catch-all-apply
            'vlax-release-object (list x))))) lst))

Any help is of course appreciated - I admire your patience  :-)

Lee

Title: Re: Opening Drawings using LISP
Post by: T.Willey on June 10, 2009, 03:11:21 PM
No real reason to close the OBDX document.  ' Save ' doesn't work, the method, so you have to use ' SaveAs '.  So just use ' SaveAs ' after you have added your circle.
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 03:17:39 PM
No real reason to close the OBDX document.  ' Save ' doesn't work, the method, so you have to use ' SaveAs '.  So just use ' SaveAs ' after you have added your circle.

So in my code something like:

Code: [Select]
(vla-saveas dbx dwg)

I see you mention that you don't have to close the ODBX drawing... Even though I am using vla-open, is the drawing actually opened in this process?
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 03:19:18 PM
Tim, it worked! Your a genius  8-)
Title: Re: Opening Drawings using LISP
Post by: T.Willey on June 10, 2009, 04:15:15 PM
Tim, it worked! Your a genius  8-)

Good to hear, and you're welcome.  Not sure about the genius part though.   :wink:

When you release the ODBX variable, it will close the connection with the application.  The way I think of ODBX is, it is an autocad drawing reader/editor that only functions in single document mode, so when you open one the other one will close.  You can have more that one application of ODBX open, but they can all only have one drawing open at a time.  Hope that makes sense.
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 04:23:50 PM
When you release the ODBX variable, it will close the connection with the application.  The way I think of ODBX is, it is an autocad drawing reader/editor that only functions in single document mode, so when you open one the other one will close.  You can have more that one application of ODBX open, but they can all only have one drawing open at a time.  Hope that makes sense.

I think I understand - thanks  :-)

By the way, currently, I am performing my (vlax-release-object)'s at the end of my code (using a sub-routine ObjRel), and also in my Error Handler, but is it better to release the object as soon as I am finished with it? (like in the Directory Browser part for example). Or does it make no difference?

Thanks for your continued help Tim, it is appreciated - I am learning a ton today  :lol:

Lee
Title: Re: Opening Drawings using LISP
Post by: T.Willey on June 10, 2009, 04:49:34 PM
Most people I think would say to release as soon as your done with it.  This will just free up memory, as the computer doesn't have to hold pointers to said objects within memory.  When you start doing code that does more, and is more time consuming, then you might want to release objects as soon as you're done with them.

You're welcome.  If you're here to learn, then there are people here willing to teach.  That's why I'm here.  To learn.
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 06:53:19 PM
Ok, thanks for your advice Tim.   :-)

I hope I am not over-stepping the mark with all my questions, but I do have another:

I need to carry variables between document namespaces, would it be better to use functions such as: vl-bb-set, and vl-bb-ref or rather vl-propagate?

And, if using vl-bb-set/ref, is there a function you have to use to "wipe the blackboard clean" when finished?

Thanks as always,

Lee
Title: Re: Opening Drawings using LISP
Post by: T.Willey on June 10, 2009, 07:13:20 PM
I use ' vl-propagate '.  I think it is just personal preference.

As long as you're willing to do the work, then I'm sure most here will be willing to answer a few questions.  :-)
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 07:23:42 PM
OK, I have been experimenting with the blackboard functions - but may have to resort to vl-propagate if I cannot get this working...

Below is the code I have been working on (don't laugh  :-P ) - it is designed to Extract all attributes from a list of drawings, based on a user-specified block list.

I am trying to collect all the information that I need, before attempting to write it to Excel (I realise that there exists EATTEXT, but this is also a learning exercise more than anything...)

Ok, I have highlighted the part I am struggline with:

Code: [Select]
;;; ================= Global Attribute Extractor =================
;;;                        by Lee McDonnell
;;;
;;;    FUNCTION: MacAtt
;;;
;;;    Will Retrieve all Attributes from Blocks in a user
;;;    compiled list from Multiple Drawings in a Selected
;;;    Directory.
;;;
;;;    AUTHOR:
;;;
;;;    Lee McDonnell  (Copyright (c) June 2009)
;;;    (Contact Lee Mac, CADTutor.net, TheSwamp.org)
;;;
;;;    ADDITIONAL THANKS TO:
;;;    Tony Tanzillo
;;;    Tim Willey
;;;
;;;    VERSION:
;;;    1.0  ~  11.06.2009  ~ First Release
;;;
;;; ==============================================================

   
(defun c:MacAtt (/ *error* *acad ExFlag BlkLst
                   Shell fDir Dir dbx acVer ss attLst)
  (vl-load-com)

  ;; Error Handler

  (defun *error* (e)
    (if ov (mapcar 'setvar vl ov))
    (ObjRel (list Shell dbx *acad))
    (if (not (wcmatch (strcase e) "*CANCEL*,*EXIT*"))
      (princ (strcat "\n<< Error: " e " >>")))
    (princ))

  ;; Get Block List

  (while (not ExFlag)
    (setq Str (getstring t "\nAdd Block Name to List [Space to View List]: "))
    (cond ((eq "" Str)
           (setq ExFlag T))
          ((eq (chr 32) Str)
           (foreach x (reverse BlkLst)
             (print x)) (textscr))
          ((snvalid Str)
           (setq BlkLst (cons Str BlkLst)))
          (t (princ "\n** Invalid Block Name **"))))

  (if BlkLst
    (progn

  ;; Get Directory

  (setq *acad (vlax-get-acad-object)
        Shell (vla-getInterfaceObject *acad "Shell.Application")
        fDir (vlax-invoke-method Shell 'BrowseForFolder
               (vla-get-HWND *acad) "Select Directory: " 0))
  (if fDir
    (progn
      (setq Dir
        (vlax-get-property
          (vlax-get-property fDir 'Self) 'Path))
      (if (not (eq "\\" (substr Dir (strlen Dir))))
        (setq Dir (strcat Dir "\\")))
      (if (< (atoi (setq acVer (substr (getvar "ACADVER") 1 2))) 16)
        (setq acVer "") (setq acVer (strcat (chr 46) acVer)))
      (setq dbx (vla-getInterfaceObject
                  *acad (strcat "ObjectDBX.AxDbDocument" acVer)))
      (princ "\nProcessing...")

      ;; Iterate Drawings
     
     [color=red] (foreach dwg (setq dwLst
                     (mapcar
                       (function
                         (lambda (x)
                           (strcat Dir x)))
                       (vl-directory-files Dir "*.dwg" 1)))
        (vla-open dbx dwg)

        (setq attlst (vl-bb-ref 'attlst))

        (foreach blk BlkLst
          (if (setq ss
                (ssget "_X" (list
                              (cons 0 "INSERT")
                              (cons 2 blk)
                              (cons 66 1))))
            (progn
              (foreach att (mapcar
                             (function
                               (lambda (x)
                                 (vlax-safearray->list
                                   (vlax-variant-value
                                     (vla-getAttributes x)))))
                             (mapcar 'vlax-ename->vla-object
                                     (mapcar 'cadr (ssnamex ss))))
                (setq attLst
                  (cons (list (vla-get-TagString att)
                              (vla-get-TextString att)) attLst)))
              (setq attLst (cons blk attLst)))))
        (setq attLst (cons dwg attLst))

        (vl-bb-set 'attlst attlst)
       
        (vla-saveas dbx dwg)
        (princ (chr 46)))[/color]
      (alert (vl-princ-to-string (vl-bb-ref 'attlst)))
      (princ (strcat "\n<< " (rtos (length dwLst) 2 0) " Drawings Processed >>")))
    (princ "*Cancel*"))))

  ;; Garbage Collection
 
  (ObjRel (list Shell dbx *acad))
  (gc)
  (princ))

;; Release Objects ~ Requires List of Variables
           
(defun ObjRel (lst)
  (mapcar
    (function
      (lambda (x)
        (if (and (eq (type x) 'VLA-OBJECT)
                 (not (vlax-object-released-p x)))
          (vl-catch-all-apply
            'vlax-release-object (list x))))) lst))

 

I have tried to set the "data-list" to the blackboard namespace and then collect this during with the opening of every drawing. - But at the end, when I check the value of the blackboard variable (using "alert"), it only contains the drawing filenames, and no attribute information.

This leads me to believe that the error is not in the blackboard entry, but in the selection set collection. Perhaps one cannot collect a selection set in another document space?

Thanks for any input - as I say, I am new to this branch of LISP if some of my questions seem naive.

Thanks,

Lee
Title: Re: Opening Drawings using LISP
Post by: T.Willey on June 10, 2009, 07:37:39 PM
If you're using Odbx, then there is no need to use the backboard, or vl-propagate.  When using Odbx, you can only use ActiveX type code, so selection sets are out, but you can step though the drawing without it, and be about the same speed.

This shows how to get the attribute information from the blocks ( named within a list ) through only ActiveX controls.
Doc = valid document object
BlkNameList = list containing the name of blocks to get attributes from
AttList = will list the attributes in (tag . text) fashion

Hope it helps.

Code: [Select]
(vlax-for Lo (vla-get-Layouts Doc)
    (vlax-for Obj (vla-get-Block Lo)
        (if
            (and
                (= (vla-get-ObjectName Obj) "AcDbBlockReference")
                (vl-position (vla-get-Name Obj) BlkNameList)
            )
            (foreach Att (append (vlax-invoke Obj 'GetAttributes) (vlax-invoke Obj 'GetConstantAttributes))
                (setq AttList (cons (cons (vla-get-TagString Att) (vla-get-TextString Att)) AttList))
            )
        )
    )
)

I'm out for the rest of the day.  Have fun.   :wink:
Title: Re: Opening Drawings using LISP
Post by: Lee Mac on June 10, 2009, 07:55:06 PM
Many thanks for your help Tim - I am very grateful.

I shall look over your code and see what I can do  :wink: