Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Filtering the results of a safearray list?

13 REPLIES 13
SOLVED
Reply
Message 1 of 14
rapidcad
2862 Views, 13 Replies

Filtering the results of a safearray list?

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 😎 "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 😎 "Position")))

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

 

Anyone know how this is done?

 

Thanks in advance...

ADN CAD Developer/Operator
13 REPLIES 13
Message 2 of 14
Lee_Mac
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 Smiley Happy

 

Message 3 of 14
Lee_Mac
in reply to: Lee_Mac

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

 

Lee

Message 4 of 14
rapidcad
in reply to: Lee_Mac

Thanks so much, Lee.Robot Happy

 

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 😎 "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!

ADN CAD Developer/Operator
Message 5 of 14
Lee_Mac
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

Message 6 of 14
rapidcad
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.")
    )
   
)

ADN CAD Developer/Operator
Message 7 of 14
devitg
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.

 

 

Message 8 of 14
inventordeepan
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 ... 🙂

 

Message 9 of 14
inventordeepan
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  🙂 🙂

Message 10 of 14
Lee_Mac
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.

Message 11 of 14
inventordeepan
in reply to: Lee_Mac

hi lee mac thank you for your response can you please check your personal mail , i have sent you a message regarding my requirement , so plse check and help me , thanks a lot for your immediate response

Message 12 of 14
inventordeepan
in reply to: Lee_Mac

thank you lee mac you are more than frd to me , i owe you buddy

Message 13 of 14
inventordeepan
in reply to: Lee_Mac

hi dr lee mac i hope you can help me with it ,

i need to do some calculation in excell and use the answer as values to my autolisp prog

i mean lik for instance i need to add cell a1  an a2 value and assign it to  a variable in autolisp code say to variable a , frm net i got some source to get data from excell . so i request you dr programmer whether you know  any code to input values to cells in a new excel sheet and also perform some addition and den retrive value from excell sheet and assign it to a variable say setq a excel data .

 

 

plse some one help asap

 

 

thank you in advance ...Smiley Wink

Message 14 of 14
DABUMA
in reply to: Lee_Mac

Hi Lee,

thanks for all the great lisp you had posted in many forums, as you said is simple to call the function with the apropiate arguments, but for beginers like me is dificult to call the functions when we need them = ).

What I am trying to do is combine one lisp you posted in other blog INSBLKCEN (inserts a block at the centre of selected blocks) which is amazing but, my block works with a lookups values and I would like to try to change automatically the lookup when the block is inserted, therefore I want to store the CANNOSCALE variable and then asociate this value with the lookup in this block. this is just an overall view of what I am trying to achive. 

 

Now I would like to ask you if you could explan or post how to call the function you have in your web site

;; Set Dynamic Block Property Value  -  Lee Mac
;; Modifies the value of a Dynamic Block property (if present)
;; blk - [vla] VLA Dynamic Block Reference object
;; prp - [str] Dynamic Block property name (case-insensitive)
;; val - [any] New value for property
;; Returns: [any] New value if successful, else nil

(defun LM:setdynpropvalue ( blk prp val )
    (setq prp (strcase prp))
    (vl-some
       '(lambda ( x )
            (if (= prp (strcase (vla-get-propertyname x)))
                (progn
                    (vla-put-value x (vlax-make-variant val (vlax-variant-type (vla-get-value x))))
                    (cond (val) (t))
                )
            )
        )
        (vlax-invoke blk 'getdynamicblockproperties)
    )
) 

 thank you very much in advance

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost