TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Lee Mac on June 01, 2009, 10:30:48 AM

Title: Using VLA-ITEM
Post by: Lee Mac on June 01, 2009, 10:30:48 AM
I am not entirely confident in using this function, but I want to master it.

Currently, when extracting an item from a collection, I am using vlax-for to cycle through the collection, and using some kind of conditional within the loop to get the required object, for example:
Code: [Select]
(vlax-for lay (vla-get-layers
                (vla-get-ActiveDocument
                  (vlax-get-acad-object)))
  (if (eq "LayerName" (vla-get-Name lay))
    (setq layer lay)))

But is there a way to get at this item directly? I thought perhaps vla-item, but I may be mistaken.

[ And if it isn't Vla-item, then what exactly is Vla-item for...? ]

Many thanks for your time as always,

Cheers,

Lee
Title: Re: Using VLA-ITEM
Post by: CAB on June 01, 2009, 10:41:52 AM
Try this:
Code: [Select]
(setq LayerName "Duct")
(setq LayerCollection (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))))
(setq LayObj (vl-catch-all-apply 'vla-Item (list LayerCollection LayerName)))
If the layername does not exist the catch all will save you.
Title: Re: Using VLA-ITEM
Post by: CAB on June 01, 2009, 10:47:33 AM
Another way to get it. Not what you asked, I know.
Code: [Select]
(if (setq LayEnt (tblobjname "layer" Layername))
  (setq LayObj (vlax-ename->vla-object LayEnt))
)
Title: Re: Using VLA-ITEM
Post by: Lee Mac on June 01, 2009, 10:48:25 AM
Excellent Alan, thanks -

I have received some great help from RonJonP over at CADTutor on this also - and with your tip of using a touch of Error Trapping - this really helps.

Many thanks for your time, it is appreciated as always,

Cheers,

Lee
Title: Re: Using VLA-ITEM
Post by: CAB on June 01, 2009, 11:14:19 AM
Don't forget vlax-map-collection

Code: [Select]
(vlax-map-collection (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-Acad-Object)))
  (function (lambda(x) (if (vlax-property-available-p x 'objectname)
         (print (vla-get-objectname x)))))
)

OR
Code: [Select]
(vlax-map-collection (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-Acad-Object))) 'vlax-dump-object)
Title: Re: Using VLA-ITEM
Post by: gile on June 01, 2009, 11:48:52 AM
Hi,

Because vla-item returns an error if the item isn't found in the collection, I wrote a little function which uses vl-catch-apply so that the function returns the vla-object or nil.

Code: [Select]
(defun GetItem (col name / obj)
  (vl-catch-all-apply
    '(lambda () (setq obj (vla-item col name)))
  )
  obj
)

(GetItem (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))) "0")
returns : #<VLA-OBJECT IAcadLayer 06ca9ad4>
(GetItem (vla-get-Layers (vla-get-ActiveDocument (vlax-get-acad-object))) "test")
returns nil (if there's no "test" layer in the collection)

Using the same way, I have another one to get an object from its handle if it hasn't been erased (otherwise nil).

Code: [Select]
(defun HandleToObject (handle / obj)
  (vl-catch-all-apply
    '(lambda ()
       (setq obj (vla-HandleToObject
   (vla-get-ActiveDocument (vlax-get-acad-object))
   handle
)
       )
     )
  )
  obj
)
Title: Re: Using VLA-ITEM
Post by: Lee Mac on June 01, 2009, 12:05:15 PM
Don't forget vlax-map-collection

Code: [Select]
(vlax-map-collection (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-Acad-Object)))
  (function (lambda(x) (if (vlax-property-available-p x 'objectname)
         (print (vla-get-objectname x)))))
)

OR
Code: [Select]
(vlax-map-collection (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-Acad-Object))) 'vlax-dump-object)

Thanks Alan, I always seem to overlook vlax-map-collection when vlax-for always seems the easier method, but I am grateful for your informative examples  :-)

Thanks
Title: Re: Using VLA-ITEM
Post by: Lee Mac on June 01, 2009, 12:09:26 PM
Code: [Select]
(defun HandleToObject (handle / obj)
  (vl-catch-all-apply
    '(lambda ()
       (setq obj (vla-HandleToObject
   (vla-get-ActiveDocument (vlax-get-acad-object))
   handle
)
       )
     )
  )
  obj
)

Gile,

Thank you for your response,

I realise that your first example is similar to that posted by CAB earlier in this thread to handle errors returned from vla-item.

However, I do have a question regarding your second posted example,

Why would you use an Object's Handle in operations?

Excuse me if my question seems a little "simple", but I have never used an Object Handle in this way.

Thanks,

Lee
Title: Re: Using VLA-ITEM
Post by: gile on June 01, 2009, 12:43:03 PM
Quote
I realise that your first example is similar to that posted by CAB earlier in this thread to handle errors returned from vla-item.

Yes, but using GetItem avoid to write:
(if (not (vl-catch-all-error-p (setq LayObj (vl-catch-all-apply (vla-item ...))))) (do_something ...))
Just write:
(if (setq LayObj (GetItem ...)) (do_something ...))


Quote
Why would you use an Object's Handle in operations?

An entity's name can change from one editing session to the next, but an entity's handle remains constant. So if you need to store objects using xdatas, ldatas or xrecords in a dictionary from one session to another, you have to store their handles.
For example, I use this way to store the objects which are linked to some block reference in TotalArea.lsp (http://www.theswamp.org/index.php?topic=28604.0)
Title: Re: Using VLA-ITEM
Post by: Lee Mac on June 01, 2009, 01:24:00 PM
I have in fact used your TotalAreas.lsp - an impressive bit of kit indeed - well done.

Thank you for your superb explanation of object handles, I hadn't considered that aspect before, and originally thought that the object handle also changed with the entity name from session to session - thank you for clarifying this.

Cheers,

Lee
Title: Re: Using VLA-ITEM
Post by: gile on June 01, 2009, 01:37:25 PM
Thanks Lee Mac, you're welcome.
Title: Re: Using VLA-ITEM
Post by: CAB on February 04, 2010, 11:42:05 AM
Hi,

Because vla-item returns an error if the item isn't found in the collection, I wrote a little function which uses vl-catch-apply so that the function returns the vla-object or nil.

Code: [Select]
(defun GetItem (col name / obj)
  (vl-catch-all-apply
    '(lambda () (setq obj (vla-item col name)))
  )
  obj
)

gile,
I was doing some research & ran across this old thread.
Wouldn't (vlax-erased-p Obj) work as well as your (defun GetItem ?
Just wondering if there are any pitfalls with using vlax-erased-p
Title: Re: Using VLA-ITEM
Post by: Lee Mac on February 04, 2010, 02:41:40 PM
CAB,

I assume you may be referring to Gile's post about the HandletoObject method?

I don't see why vlax-erased-p would cause a problem, but I would be far more inclined to use:

Code: [Select]
(entget (handent <handle>))

Which returns nil with no error if the object is erased.

PS> This thread seems like ages ago, its amazing how much I have learnt from you guys since then...  :wink:

Lee
Title: Re: Using VLA-ITEM
Post by: CAB on February 04, 2010, 03:27:13 PM
I should have been more clear with my comment.
This is what I had in mind.
Code: [Select]
(defun GetItem (col name)
  (if (not (vlax-erased-p name))
    (vla-item col name)
  )
)

PS you've been on the "Fast Track"  8-)
Title: Re: Using VLA-ITEM
Post by: Lee Mac on February 04, 2010, 03:30:41 PM
Ooo, I've never seen it used in that way before...

At a first glance, without testing anything, I thought that vlax-erased-p just checked the erased flag of an object, so if an item never existed in a collection, then I would assume it would error out...

EDIT:

Code: [Select]
(GetItem (vla-get-layers *doc) "Lee")
; error: unable to get ObjectID: "Lee"
Title: Re: Using VLA-ITEM
Post by: jbuzbee on February 05, 2010, 07:25:07 AM
Lee Mac.

Completely off topic here: is that you in our avatar??

jb

p.s. No, that's NOT me in my avatar . . . ;)
Title: Re: Using VLA-ITEM
Post by: CAB on February 05, 2010, 08:21:37 AM
Ooo, I've never seen it used in that way before...

At a first glance, without testing anything, I thought that vlax-erased-p just checked the erased flag of an object, so if an item never existed in a collection, then I would assume it would error out...

EDIT:

Code: [Select]
(GetItem (vla-get-layers *doc) "Lee")
; error: unable to get ObjectID: "Lee"

Thanks Lee, that answers my question. Looks like gile has a keeper there. :-)
Title: Re: Using VLA-ITEM
Post by: Lee Mac on February 05, 2010, 11:47:51 AM
Lee Mac.

Completely off topic here: is that you in our avatar??

jb

p.s. No, that's NOT me in my avatar . . . ;)

Hey James,

No, not me in the avatar, but I do ride a CBR600F  :-)
Title: Re: Using VLA-ITEM
Post by: hermanm on February 08, 2010, 09:10:52 PM
Don't forget vlax-map-collection

Being as how this is LISP, one might expect vlax-map-collection to behave similar to mapcar, but noooo :(

Code: [Select]
;;vlax-map-collection returns the collection object, not a list
;;you must build the list yourself as a side effect (yuck!)
;;so here is a simple wrapper which is proper LISP, i.e. function returns a useful value

(defun map-collection (obj func / return)
(vlax-map-collection obj
  '(lambda (obj / )
      (setq return (cons (func obj) return))
   )
)
return
)

;;equivalent
(vlax-for item collection
  (setq return (cons (func item) return))
)
Title: Re: Using VLA-ITEM
Post by: Kerry on February 08, 2010, 10:05:40 PM
and it's slower (well, marginally) as well as uglier :)

Code: [Select]
(defun getLockedLayers1 (/ layNames)
    (vlax-map-collection
        (vla-get-layers (vla-get-activedocument (vlax-get-acad-object)))
        '(lambda (x)
             (if (= (vla-get-lock x) :vlax-true)
                 (setq layNames (cons (vla-get-name x) layNames))
             )
         )
    )
    (reverse layNames)
)

(defun getLockedLayers2 (/ layNames)
    (vlax-for item (vla-get-layers (vla-get-activedocument (vlax-get-acad-object)))
        (if (= (vla-get-lock item) :vlax-true)
            (setq layNames (cons (vla-get-name item) layNames))
        )
    )
    (reverse layNames)
)

(benchmark '((getLockedLayers1)
                     (getLockedLayers2)
            )
)
;=> ("X_NoPlot" "x-T50" "x-T35" "x-T25")

Benchmarking [M.P. 2005 < revised kdub 2005>] ..........
Elapsed milliseconds for 128 iteration(s)/ relative Timing :

    (GETLOCKEDLAYERS1).....1703 / 1.0185 <slowest>
    (GETLOCKEDLAYERS2).....1672 / 1.0000 <fastest>
Title: Re: Using VLA-ITEM
Post by: CAB on February 08, 2010, 11:06:33 PM
And what does this do for the time?  :evil:
Code: [Select]
(defun getLockedLayers1 (/ layNames)
    (vlax-map-collection (vla-get-layers (vla-get-activedocument (vlax-get-acad-object)))
        (function (lambda (x)
             (if (= (vla-get-lock x) :vlax-true)
                 (setq layNames (cons (vla-get-name x) layNames))
             )
         ))
    )
    (reverse layNames)
)
Title: Re: Using VLA-ITEM
Post by: Kerry on February 09, 2010, 03:12:18 AM
Yep .. good point !!

Benchmarking [M.P. 2005 < revised kdub 2005>] ..........
Elapsed milliseconds for 128 iteration(s) / relative Timing :
    (GETLOCKEDLAYERS1).....1172 / 1.0559 <slowest> ;<<<< using  vlax-map-collection
    (GETLOCKEDLAYERS2).....1125 / 1.0135                   ;<<<< using  vlax-for
    (GETLOCKEDLAYERS3).....1110 / 1.0000 <fastest>  ;<<<< using (function(lambda ... in place of '(lambda ...  with vlax-map-collection


but it's still ugly  :-P
... nah, it's not really  :)