Visual LISP, AutoLISP and General Customization

Visual LISP, AutoLISP and General Customization

Reply
Mentor
rapidcad
Posts: 198
Registered: ‎05-24-2011
Message 1 of 13 (618 Views)
Accepted Solution

Filtering the results of a safearray list?

618 Views, 12 Replies
12-20-2011 07:10 AM

As an Autolisp kludge, I’m not too accomplished to ask for help – that’s for sure!  I am trying to understand how to work with safearrays so that I can modify a dynamic block property reporting tool that I found here on the forums. I’d like to take the following code and filter out the extraneous properties so that the user doesn’t get information overload.  Here’s the code that I’m starting with – works nicely:

 

(defun c:dbinfo (/ obj v vval sal salnth count)

(setq obj (vlax-ename->vla-object (car (entsel "\nSelect Dynamic Block: "))))

(setq v (vla-getdynamicblockproperties obj))

(setq vval (vlax-variant-value v))

(setq sal (vlax-safearray->list vval))

;;;;I‘m thinking of filtering here

(setq salnth (length sal))

(setq count 0)

(while (/= count salnth)

(vlax-dump-object (nth count sal))

(setq count (+ count 1))

)

(setq count nil)

(princ)

  (textscr)

)

So, how do I filter the safearray list (down two levels to property names) so I can remove origins and other unimportant properties? Here’s the two property names I am trying to filter out:

(or (= (car y) "Origin") (= (substr (car y) 1 8) "Position"))

 

I’m beating my head against the wall trying to figure out how to take sal and redefine it like:

(/= (or (= (car y) "Origin") (= (substr (car y) 1 8) "Position")))

Of course, that doesn’t work with a safearray.

 

Anyone know how this is done?

 

Thanks in advance...

Ronald A. Powell
CAD Developer/Operator
TGW Systems Inc.
Spring Lake, MI

Hi Ronald,

 

Here are a few ways to accomplish your goal:


 

(defun c:dbinfo ( / ent obj props )
(if
(and
(setq ent (car (entsel "\nSelect Dynamic Block: ")))
(eq "AcDbBlockReference" (vla-get-objectname (setq obj (vlax-ename->vla-object ent))))
(eq :vlax-true (vla-get-isdynamicblock obj))
)
(progn
(setq props
(vl-remove-if
(function
(lambda ( prop )
(setq prop (strcase (vla-get-propertyname prop)))
(or
(eq "ORIGIN" prop)
(eq "POSITION" (substr prop 1 8))
)
)
)
(vlax-safearray->list
(vlax-variant-value (vla-getdynamicblockproperties obj))
)
)
)
(mapcar 'vlax-dump-object props)
)
)
(princ)
)
(vl-load-com)

 

Or, you can use the undocumented vlax-invoke function which will return the data as a native AutoLISP data type (i.e. a List), to avoid dealing with Variants/SafeArrays:


 

(defun c:dbinfo ( / ent obj props )
(if
(and
(setq ent (car (entsel "\nSelect Dynamic Block: ")))
(eq "AcDbBlockReference" (vla-get-objectname (setq obj (vlax-ename->vla-object ent))))
(eq :vlax-true (vla-get-isdynamicblock obj))
)
(progn
(setq props
(vl-remove-if
(function
(lambda ( prop )
(setq prop (strcase (vla-get-propertyname prop)))
(or
(eq "ORIGIN" prop)
(eq "POSITION" (substr prop 1 8))
)
)
)
(vlax-invoke obj 'getdynamicblockproperties)
)
)
(mapcar 'vlax-dump-object props)
)
)
(princ)
)
(vl-load-com)

 

Or, with a foreach loop:


 

(defun c:dbinfo ( / ent obj props pname )
(if
(and
(setq ent (car (entsel "\nSelect Dynamic Block: ")))
(eq "AcDbBlockReference" (vla-get-objectname (setq obj (vlax-ename->vla-object ent))))
(eq :vlax-true (vla-get-isdynamicblock obj))
)
(progn
(foreach prop (vlax-invoke obj 'getdynamicblockproperties)
(setq pname (strcase (vla-get-propertyname prop)))
(if
(not
(or
(eq "ORIGIN" pname)
(eq "POSITION" (substr pname 1 8))
)
)
(setq props (cons prop props))
)
)
(mapcar 'vlax-dump-object props)
)
)
(princ)
)
(vl-load-com)

 

Or, using mapcar:

 

(defun c:dbinfo ( / ent obj props )
(if
(and
(setq ent (car (entsel "\nSelect Dynamic Block: ")))
(eq "AcDbBlockReference" (vla-get-objectname (setq obj (vlax-ename->vla-object ent))))
(eq :vlax-true (vla-get-isdynamicblock obj))
)
(progn
(setq props
(apply 'append
(mapcar
(function
(lambda ( prop / pname )
(setq pname (strcase (vla-get-propertyname prop)))
(if
(not
(or
(eq "ORIGIN" pname)
(eq "POSITION" (substr pname 1 8))
)
)
(list prop)
)
)
)
(vlax-invoke obj 'getdynamicblockproperties)
)
)
)
(mapcar 'vlax-dump-object props)
)
)
(princ)
)
(vl-load-com)

 

There's a few options available :smileyhappy:

 

*Expert Elite*
Lee_Mac
Posts: 1,270
Registered: ‎12-29-2009
Message 2 of 13 (609 Views)

Re: Filtering the results of a safearray list?

12-20-2011 11:11 AM in reply to: rapidcad

Hi Ronald,

 

Here are a few ways to accomplish your goal:


 

(defun c:dbinfo ( / ent obj props )
    (if
        (and
            (setq ent (car (entsel "\nSelect Dynamic Block: ")))
            (eq "AcDbBlockReference" (vla-get-objectname (setq obj (vlax-ename->vla-object ent))))
            (eq :vlax-true (vla-get-isdynamicblock obj))
        )
        (progn
            (setq props
                (vl-remove-if
                    (function
                        (lambda ( prop )
                            (setq prop (strcase (vla-get-propertyname prop)))
                            (or
                                (eq "ORIGIN" prop)
                                (eq "POSITION" (substr prop 1 8))
                            )
                        )
                    )
                    (vlax-safearray->list
                        (vlax-variant-value (vla-getdynamicblockproperties obj))
                    )
                )
            )
            (mapcar 'vlax-dump-object props)
        )
    )
    (princ)
)
(vl-load-com)

 

Or, you can use the undocumented vlax-invoke function which will return the data as a native AutoLISP data type (i.e. a List), to avoid dealing with Variants/SafeArrays:


 

(defun c:dbinfo ( / ent obj props )
    (if
        (and
            (setq ent (car (entsel "\nSelect Dynamic Block: ")))
            (eq "AcDbBlockReference" (vla-get-objectname (setq obj (vlax-ename->vla-object ent))))
            (eq :vlax-true (vla-get-isdynamicblock obj))
        )
        (progn
            (setq props
                (vl-remove-if
                    (function
                        (lambda ( prop )
                            (setq prop (strcase (vla-get-propertyname prop)))
                            (or
                                (eq "ORIGIN" prop)
                                (eq "POSITION" (substr prop 1 8))
                            )
                        )
                    )
                    (vlax-invoke obj 'getdynamicblockproperties)
                )
            )
            (mapcar 'vlax-dump-object props)
        )
    )
    (princ)
)
(vl-load-com)

 

Or, with a foreach loop:


 

(defun c:dbinfo ( / ent obj props pname )
    (if
        (and
            (setq ent (car (entsel "\nSelect Dynamic Block: ")))
            (eq "AcDbBlockReference" (vla-get-objectname (setq obj (vlax-ename->vla-object ent))))
            (eq :vlax-true (vla-get-isdynamicblock obj))
        )
        (progn
            (foreach prop (vlax-invoke obj 'getdynamicblockproperties)
                (setq pname (strcase (vla-get-propertyname prop)))
                (if
                    (not
                        (or
                            (eq "ORIGIN" pname)
                            (eq "POSITION" (substr pname 1 8))
                        )
                    )
                    (setq props (cons prop props))
                )
            )
            (mapcar 'vlax-dump-object props)
        )
    )
    (princ)
)
(vl-load-com)

 

Or, using mapcar:

 

(defun c:dbinfo ( / ent obj props )
    (if
        (and
            (setq ent (car (entsel "\nSelect Dynamic Block: ")))
            (eq "AcDbBlockReference" (vla-get-objectname (setq obj (vlax-ename->vla-object ent))))
            (eq :vlax-true (vla-get-isdynamicblock obj))
        )
        (progn
            (setq props
                (apply 'append
                    (mapcar
                        (function
                            (lambda ( prop / pname )
                                (setq pname (strcase (vla-get-propertyname prop)))
                                (if
                                    (not
                                        (or
                                            (eq "ORIGIN" pname)
                                            (eq "POSITION" (substr pname 1 8))
                                        )
                                    )
                                    (list prop)
                                )
                            )
                        )
                        (vlax-invoke obj 'getdynamicblockproperties)
                    )
                )
            )
            (mapcar 'vlax-dump-object props)
        )
    )
    (princ)
)
(vl-load-com)

 

There's a few options available :smileyhappy:

 

Lee Mac ProgrammingTwitterExchange App StoreDropbox (500MB free)
Expert Elite
With Mathematics there is the possibility of perfect rigour, so why settle for less?
*Expert Elite*
Lee_Mac
Posts: 1,270
Registered: ‎12-29-2009
Message 3 of 13 (607 Views)

Re: Filtering the results of a safearray list?

12-20-2011 11:13 AM in reply to: Lee_Mac

You may also be interested in my set of Dynamic Block Functions.

 

Lee

Lee Mac ProgrammingTwitterExchange App StoreDropbox (500MB free)
Expert Elite
With Mathematics there is the possibility of perfect rigour, so why settle for less?
Mentor
rapidcad
Posts: 198
Registered: ‎05-24-2011
Message 4 of 13 (600 Views)

Re: Filtering the results of a safearray list?

12-20-2011 12:30 PM in reply to: Lee_Mac

Thanks so much, Lee.:robothappy:

 

I just got it working when you posted these much more professional solutions! I will eventually use one of these because you've put all the entity proofing in there (such as strcase). Here's what I came up with after finding an example of someone picking apart a dynamic block safearray on a visit to the swamp:

 

(defun c:dbinfo (/ obj v vval sal tot i)
(setq obj (vlax-ename->vla-object (car (entsel "\nSelect Dynamic Block: "))))
  (if (= (vlax-get-property obj 'isdynamicblock) :vlax-true)
    (progn
      (setq v  (vla-getdynamicblockproperties obj)
      vval (vlax-variant-value v)
      sal  (vlax-safearray->list vval)
      tot  (length sal)
      i  0
      )
(while (< i tot)
  (if (and (/= (vlax-get-property (nth i sal) "PropertyName") "Origin")
    (/= (substr (vlax-get-property (nth i sal) "PropertyName") 1 8) "Position"))
    (progn
      (vlax-dump-object (nth i sal))
      (princ "\n")
    (setq i (1+ i))
    )
    (setq i (1+ i))
  )
      )
  (princ)
  (textscr)
    )
  )
  )

 

I just tried all three of yours and actually, all four of these work flawlessly. I will have to try them on wrong entities to see how they handle it, but I bet yours will work fine. Mine might get hung up due to sloppy code!

 

I will still tune this up some as a learning exercise. I already see how you moved the argument into a vl-remove-if and really made the code concise. I'm still quite unfamiliar with the vl extensions (and only a novice at autolisp too). I have been to your page a few months ago for the first time and I got a few chunks of code there to put together my own version of a dynamic block property setter which I am using in conjunction with a command tool to insert dyn blocks off the palette while reading my own running variables to control their particular properties.

 

I have to say a hearty THANK YOU for all you do for guys like me. I love your web page!  As I get deeper into progamming I'll be visiting more often!

Ronald A. Powell
CAD Developer/Operator
TGW Systems Inc.
Spring Lake, MI
*Expert Elite*
Lee_Mac
Posts: 1,270
Registered: ‎12-29-2009
Message 5 of 13 (593 Views)

Re: Filtering the results of a safearray list?

12-20-2011 01:30 PM in reply to: rapidcad

You're very welcome Ronald; I'm really glad that you can benefit from my website and programs - and of course, if you have any questions about any of the code I have posted here or on my site, just ask.

 

Lee

Lee Mac ProgrammingTwitterExchange App StoreDropbox (500MB free)
Expert Elite
With Mathematics there is the possibility of perfect rigour, so why settle for less?
Mentor
rapidcad
Posts: 198
Registered: ‎05-24-2011
Message 6 of 13 (591 Views)

Re: Filtering the results of a safearray list?

12-20-2011 01:44 PM in reply to: Lee_Mac

Absolutely! Here's the one I settled on (with just a little mod)..

 

Works exactly as intended even if selection is wrong type.

 

;;;from Lee Mac on the Autodesk forums as a reply to my question
;;;modified by Rapidcad 12-20-11 for TGW to alert the user upon errors

 

(defun c:dbinfo ( / ent obj props )
  (vl-load-com)
    (if
        (and
            (setq ent (car (entsel "\nSelect Dynamic Block: ")))
            (eq "AcDbBlockReference" (vla-get-objectname (setq obj (vlax-ename->vla-object ent))))
            (eq :vlax-true (vla-get-isdynamicblock obj))
        )
        (progn
            (setq props
                (vl-remove-if
                    (function
                        (lambda ( prop )
                            (setq prop (strcase (vla-get-propertyname prop)))
                            (or
                                (eq "ORIGIN" prop)
                                (eq "POSITION" (substr prop 1 8))
                            )
                        )
                    )
                    (vlax-safearray->list
                        (vlax-variant-value (vla-getdynamicblockproperties obj))
                    )
                )
            )
            (mapcar 'vlax-dump-object props)
    (princ)(textscr)    )
      (alert "\n You'll need to pick again - please select a DYNAMIC block.")
    )
   
)

Ronald A. Powell
CAD Developer/Operator
TGW Systems Inc.
Spring Lake, MI
Mentor
devitg
Posts: 1,705
Registered: ‎03-14-2004
Message 7 of 13 (508 Views)

Re: Filtering the results of a safearray list?

03-28-2013 09:38 AM in reply to: rapidcad

Hi Lee, thanks for your help .

Last day I dig and dig on Dynamicblocks and reach only to get the Prop names , now I can set a new value to one of them. 

 

Another , as with NENTSEL one can get a simple entity , in a simple block , there is  a way to get the prop name just picking on the "simple entity" to get the Prop Name ?

 

Gabriel.

 

 

Contributor
inventordeepan
Posts: 17
Registered: ‎09-15-2014
Message 8 of 13 (132 Views)

Re: Filtering the results of a safearray list?

09-15-2014 09:47 PM in reply to: Lee_Mac

hi , lee  mac

thank you for the program .

i  need to change the value of dynamic property which i have seen , can you help me with it for example i have to alter the program . can i need source code fofr it , i cant understand your porgram in the lee mac programming website .

kindly help and reply asap..

 

 

my problem , say for instance i  have created a rectangle and made it a blocked a, added stretch parameter and made it into a dynamic block, now my query is using your above mentioned code i can view the dynamic block name and its present value, now i need to alter the value of the dynamic block , so i need source code for it , if not lee mac some one else too plse help ... :smileyhappy:

 

Contributor
inventordeepan
Posts: 17
Registered: ‎09-15-2014
Message 9 of 13 (128 Views)

Re: Filtering the results of a safearray list?

09-15-2014 10:18 PM in reply to: Lee_Mac

hi dear lee ,mac i used the code from your website and i edited it as per my program , wen i run my program it came two few arguments error , plse tel me where i went wrong

 

;; blk - [vla] VLA Dynamic Block Reference object
;; prp - [str] Dynamic Block property name (case-insensitive)

;;my dynamic proerty name is Distance1 i used default name  of the dynamic property for my program

(defun c:hanew  ( blk Distance1 )
(vl-load-com)
(setq blk ( car (entsel )))
(setq blk (vlax-ename->vla-object blk ))
    (setq Distance1 (strcase Distance1))
    (vl-some '(lambda ( x ) (if (= Distance1 (strcase (vla-get-propertyname x))) (vlax-get x 'value)))
        (vlax-invoke blk 'getdynamicblockproperties)
    )
)

 

 

 

plse reply asap  :smileyhappy: :smileyhappy:

*Expert Elite*
Lee_Mac
Posts: 1,270
Registered: ‎12-29-2009
Message 10 of 13 (106 Views)

Re: Filtering the results of a safearray list?

09-16-2014 11:45 AM in reply to: inventordeepan

Hi inventordeepan,

 

There is no need to modify the code for my function, simply call the function with the appropriate arguments, e.g.:

 

(defun c:test ( / sel val )
    (if (setq sel (ssget "_+.:E:S" '((0 . "INSERT"))))
        (if (setq val (LM:getdynpropvalue (vlax-ename->vla-object (ssname sel 0)) "Distance1"))
            (progn
                (princ "\nThe value of \"Distance1\" is: ")
                (princ val)
            )
            (princ "\nThe selected block does not contain the dynamic parameter \"Distance1\".")
        )
    )
    (princ)
)

;; Get Dynamic Block Property Value  -  Lee Mac
;; Returns the value of a Dynamic Block property (if present)
;; blk - [vla] VLA Dynamic Block Reference object
;; prp - [str] Dynamic Block property name (case-insensitive)

(defun LM:getdynpropvalue ( blk prp )
    (setq prp (strcase prp))
    (vl-some '(lambda ( x ) (if (= prp (strcase (vla-get-propertyname x))) (vlax-get x 'value)))
        (vlax-invoke blk 'getdynamicblockproperties)
    )
)

(vl-load-com) (princ)

 

LM:getdynpropvalue function from here.

Lee Mac ProgrammingTwitterExchange App StoreDropbox (500MB free)
Expert Elite
With Mathematics there is the possibility of perfect rigour, so why settle for less?
Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Do you have 60 seconds to spare? The Autodesk Community Team is revamping our site ranking system and we want your feedback! Please click here to launch the 5 question survey. As always your input is greatly appreciated.