Author Topic: calling functions using variable  (Read 3174 times)

0 Members and 1 Guest are viewing this topic.

cvcolomb

  • Guest
calling functions using variable
« on: June 06, 2012, 05:32:32 PM »
My LISP is a little rusty, please overlook the sloppy code of this WIP. This is an interesting problem however, first attempt posted in the .NET Forum.

I have a client with an extensive set of routines to set layer color, visibility, and other layer state properties in Viewports. These are standard LISP functions defined with (defun c:<name>()... We need to be able to automate the refreshing of Viewports by calling the last LISP function used on a particular viewport. I need to open and refresh dozens and dozens of View files.

I've been able to create a set of functions to record each command in a Dictionary keyed by the Viewports handle. I have a LISP routine created which loops through all Layouts present, activates each Viewport, then gets the appropriate command (actually a LISP function, do recall) from the stored library. One final sticking point I haven't been able to figure out...

When I retrieve the stored command, I've defined a string variable 'storedCommand' or something. I can't simply send this to the command line with (command storedCommand), the function definition isn't recognized. Neither can I call the function with (c:storedCommand) because this uses the text after the c:, not its evaluation. I also tried (c:(read storedCommand)) without luck, when in this form C: is not recognized as a function definition.

Even though it would be a bear to implement and maintain, I thought of defining a 2nd copy of the (defun c:.... functions without the C:, but you run into the same problem. (storedCommand) is not evaluated but looked at as the name itself. In other words if I have (setq storedCommand "blue") I cannot figure out how to access this function (blue) using the variable.

Difficult to explain, any questions & comments are welcome and appreciated.

Any ideas? Here's the code which is iterating through viewports and retreiving the stored commands.

Code: [Select]
(defun c:cvv (/ ViewDict eset cntr Viewports vp AcadApp AcadDoc Layouts lay vpHandle record ssl savedCommand)
  (vl-load-com)
  (setvar "cmdecho" 0 )
  (setq ViewDict (get-or-create-Dict))
  (setq AcadDoc (vla-get-activedocument (vlax-get-acad-object)))
  (setq Layouts (layoutlist))
 
  (foreach lay Layouts;get list of paperspace layouts
   
    (setvar "ctab" lay);set Layout current
    (command "mspace"); Enter model space in Layout Viewport
   
    (if (setq Viewports ; Gather viewports from current Layout
       (ssget "x"
      (list (cons 0 "VIEWPORT") (cons 410 (getvar "ctab")))
       )
)
      (progn
(setq cntr (sslength Viewports)); cntr = number of Viewports
(while (> cntr 1); Viewport 1 is the Layout itself
  (COMMAND "CVPORT" CNTR); set Viewport Current
  (setq cntr (- cntr 1)); cntr decrimented, now equal to array index
  (setq ssl (ssget "x" '((0 . "VIEWPORT") (68 . 1)))); get current viewport
  (setq vp (entget (ssname ssl 0))); get the entity list
  (setq vpHandle (cdr (assoc 5 vp))); get the viewport Handle from it's entity list
  (setq record (dictsearch ViewDict vpHandle)); try to get a saved record
  (setq savedCommand (cdr (assoc 1 record))); view saved command from record for debug
  ;(setq savedCommand (strcat "cmd_" savedCommand)) attempt at a workaround by defining new Lisp function without the C:
  (if record (c:(read savedCommand))); this line gives "no function definition C:"
  )
)
      )
    );end foreach
  (setvar "cmdecho" 0 )
  (princ)
)

BlackBox

  • King Gator
  • Posts: 3770
Re: calling functions using variable
« Reply #1 on: June 06, 2012, 05:43:17 PM »

Having read your post, and only glanced at your code, methinks there is a simpler way of doing what you're after... But I don't have time to hop into VLIDE at the moment.

In the mean time... Have you looked into using the EVAL function?  :?
"How we think determines what we do, and what we do determines what we get."

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: calling functions using variable
« Reply #2 on: June 07, 2012, 04:34:36 AM »
Yep, the eval might work for you. You say you've got a "dictionary" which catalogues all the defuns you wish to have run. So I'm guessing you have a list of defun names as strings, if so you need to use read as well. E.g.
Code - Auto/Visual Lisp: [Select]
  1. (setq DefunList '("c:Func1" "c:Func2" ... "c:FuncN")) ;A list of command functions as strings
  2. ;; Now call each of those
  3. (foreach func DefunList ((eval (read func))))
Or if the list is not strings but symbols:
Code - Auto/Visual Lisp: [Select]
  1. (setq DefunList '(c:Func1 c:Func2 ... c:FuncN)) ;A list of command functions as symbols
  2.  ;; Now call each of those
  3.  (foreach func DefunList ((eval func)))
Note this is only going to work on defun with no arguments, if your defuns require arguments then you need to use the apply function to send those arguments to each function.

Also if the c: defuns ask for user input, you're out of luck. Lisp can't send something through command / vl-cmd to a lisp command. You could try using SendString, but since it's asynchronous mileage may vary.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

BlackBox

  • King Gator
  • Posts: 3770
Re: calling functions using variable
« Reply #3 on: June 07, 2012, 06:35:05 AM »

In the mean time... Have you looked into using the EVAL function?  :?

Yep, the eval might work for you. You say you've got a "dictionary" which catalogues all the defuns you wish to have run. So I'm guessing you have a list of defun names as strings, if so you need to use read as well.

*Announcer voice*

RenderMan throws the rock down court, and Irneb takes the rock to the hole!



*Alley oop*  :-D
"How we think determines what we do, and what we do determines what we get."

cvcolomb

  • Guest
Re: calling functions using variable
« Reply #4 on: June 07, 2012, 10:45:48 AM »
Hi guys, I appreciate the input. Indeed, I have the functions I need to call as strings.

I don't we have a solution yet however, try running this abbreviated version.

Code: [Select]
(defun c:test1()
  (princ "Test 1 ran")
  )

(defun c:runTest(/ fun1 )
(setq fun1 "c:test1")

(eval (read fun1))

)

Lee Mac

  • Seagull
  • Posts: 12922
  • London, England
Re: calling functions using variable
« Reply #5 on: June 07, 2012, 10:49:22 AM »
Code - Auto/Visual Lisp: [Select]
  1. (defun c:test1 ( )
  2.     (princ "Test 1 ran")
  3. )
  4.  
  5. (defun c:runTest ( / fun1 )
  6.     (setq fun1 "(c:test1)")
  7.     (eval (read fun1))
  8. )

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: calling functions using variable
« Reply #6 on: June 07, 2012, 11:53:49 AM »
cvcolomb ... note my code from my previous post. The eval turns the symbol (as obtained from read) into a reference which needs to be called as a function ... i.e. one extra set of parentheses.
Code - Auto/Visual Lisp: [Select]
  1. (defun c:test1 ()
  2.   (princ "Test 1 ran")
  3. )
  4.  
  5. (defun c:runTest ( / fun1)
  6.   (setq fun1 "c:test1")
  7.   ((eval (read fun1)))
  8. )
Or you can do it like Lee's shown, by adding the parentheses to the string itself. Though that means the string is turned into a list, which is called as if it's a function.
« Last Edit: June 07, 2012, 11:57:40 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

cvcolomb

  • Guest
Re: calling functions using variable
« Reply #7 on: June 07, 2012, 12:06:58 PM »
YES! Excellent work fellows, thanks!

Indeed, it was the extra set of parens I was missing -- something I'd tried in previous iterations but had missed this time.

OK, crisis one down thanks to the swamp...now on to crisis 2 ;-]