July 20, 2010

Insertion Point of an AEC Object in AutoLISP

If you have ever tried to use AutoLISP to automate a task involving an AEC Object, you may have found that the ENTGET function does not return as much information for an AEC Object as it does for an AutoCAD object. A question posted to the Autodesk AutoCAD Architecture Customization Discussion Group, asking how the insertion point of a Multi-View Block might be obtained in AutoLISP, prompted me to see if I could figure out how to do just that. I knew that the Visual LISP ActiveX (VLAX) functions allowed for direct access to an object's properties. Unfortunately, the amount of time I have available for fun* things like writing AutoLISP code shrank significantly right around the time that the VL/VLAX/VLR functions were introduced, so I have never become proficient with them. Since this task was fairly simple, I thought I would take a shot at it anyway.

Using the 2010 Help (the 2011 Help no longer appears to have the AutoCAD Architecture ActiveX Reference section), I was able to determine that Multi-View Blocks (as well as a number of other AEC Objects) have a Location property that holds the "insertion point" as a variant three-element array of doubles. That means that the value is not pre-declared as a specific data type ("variant") and that it contains an array of three, double-precision real numbers ("doubles"), which is what you would expect to describe a 3D point. From previous experince, however, I knew that I would not be able to just assign that property value to an AutoLISP variable and use it with AutoLISP functions. I scanned through the VLAX functions, and saw the VLAX-VARIANT-VALUE function, the description of which indicated that it would return the value of a variant. That sounded like it was just what I wanted, but I found that for a variant containing an array, the return value was a "safearray", and that was not the simple list of three real numbers I needed. Fortunately, I also found the VLAX-SAFEARRAY->LIST function, which converts a "safearray" to an AutoLISP-style list of three real numbers. This may be less "safe", but it is far more useful when using AutoLISP functions.

The following code is what I posted in reply in the Discussion Group. There is no error checking in the subroutine, so it will crash if the entity name passed belongs to an object of a type that does not have a Location property. I am assuming that the calling routine will only pass entity names of objects that have a Location property; if that is not possible, then the subroutine would need to verify that the passed entity name belongs to a appropriate object type before trying to obtain the Location property. If the subroutine tests for appropriate object type, then a special "alert" return value should be included to inform the calling routine that an inappropriate entity name was passed.
(defun AECINS (ename / ob ptarray ptins)
(setq ob (vlax-ename->vla-object ename))
(setq ptarray (vlax-get-property ob 'Location))
(setq ptins (vlax-safearray->list (vlax-variant-value ptarray)))

* - Yes, I suppose it is sad that I find writing AutoLISP code "fun".

No comments: