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

Storing Variable/Associate/Recall

11 REPLIES 11
SOLVED
Reply
Message 1 of 12
smaher12
1723 Views, 11 Replies

Storing Variable/Associate/Recall

I am looking for some way to store variables. For example in loop I want to

 

Enter a number

1

Enter hatch pattern

Ansi31

Enter a number

3

Enter hatch pattern

Ansi32

Enter a number

1

Enter hatch pattern <Ansi31>

Enter

Enter a number.... etc. etc.

 

Where do I begin?

11 REPLIES 11
Message 2 of 12
3wood
in reply to: smaher12

You can store matching variables in pair in a external txt file or Window Registry.

The content can be in a format like:

1, ANSI31

3, ANSI32

...

Then read the txt file content and create a list from there.

Message 3 of 12
smaher12
in reply to: 3wood

What if for one drawing 1 is ansi31 and for another 1 is ansi35?

Message 4 of 12
dgorsman
in reply to: smaher12

You need to define your needs.  Is this for one drawing, or one user, or one computer?  All of the above?  Only during the active AutoCAD session, or does it need to be kept between sessions?  That will determine where the settings would best be stored.

 

For storage options, you have several choices.  You can store values in a global LISP variable, which is good only for the life of the drawing (when closed, value is discarded).  If it needs to exist past the life of the drawing then you need a more permanent solution.  If it is intended only for a specific drawing you can look into XDATA or Extension Dictionaries and XRecords.  If it is more global scope, then you can store the settings in an external file (TXT INI/CFG, XML, CSV) or data store (database or other), or in the registry (HKEY_CURRENT_USER for per-user settings, HKEY_LOCAL_MACHINE for per-computer settings).

----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 5 of 12
scot-65
in reply to: dgorsman

In addition to dgorsman's suggestion:
Drawing specific use Dictionary - VLAX-LDATA-PUT.
Global storage, registry, yes, but you might have permissions issue. Look into SETCFG and GETCFG.
Global, for all workstations, external file stored on server.

Scot-65
A gift of extraordinary Common Sense does not require an Acronym Suffix to be added to my given name.


Message 6 of 12
smaher12
in reply to: dgorsman

It's only for the time the drawing is open. Looks like I got a little homework to do. Thank you.

Message 7 of 12
smaher12
in reply to: smaher12

Well this is as close as I come to getting the program to do what I want it to do.

Any advice, or better solution?

 

(defun c:22 ()
  (while
   (if $sd (= nil) (setq $sd 1))
     (setq sd (getreal (strcat "\nSpecify diameter <"(rtos $sd 2 1)">: ")))
   (if (= sd nil) (setq sd $sd))
     (setq $sd sd)

  (setq p1 (getpoint "\nSpecify point: "))
  (command "CIRCLE" p1 sd)

  (setq no (getint "\nSpecify number: "))

               (cond ((= no 1) 
                          (if (not pn1) (setq pn1 (getvar "hpname")))
                       (setvar "hpname" pn1))
	             ((= no 2)    
                          (if (not pn2) (setq pn2 (getvar "hpname")))
                       (setvar "hpname" pn2))
		     ((= no 3)    
                          (if (not pn3) (setq pn3 (getvar "hpname")))
                       (setvar "hpname" pn3))
               )

    (setq hp (getstring (strcat "\nSpecify pattern name <" (getvar "hpname") ">: ")))
      (if (not hp) (setq hp (getvar "hpname")))
           (command "-HATCH" "p" hp "1" "" p1 "")


               (cond ((= no 1)   (setq pn1 (getvar "hpname")))
	            ((= no 2)   (setq pn2 (getvar "hpname")))
		   ((= no 3)   (setq pn3 (getvar "hpname")))
               )
  );while
 (princ)
)

 

 

 

Message 8 of 12
Kent1Cooper
in reply to: smaher12


smaher12 wrote:

Well this is as close as I come to getting the program to do what I want it to do.

Any advice, or better solution?

 

(defun c:22 ()
  (while
   (if $sd (= nil) (setq $sd 1))
     (setq sd (getreal (strcat "\nSpecify diameter <"(rtos $sd 2 1)">: ")))
   (if (= sd nil) (setq sd $sd))
     (setq $sd sd)

  (setq p1 (getpoint "\nSpecify point: "))
  (command "CIRCLE" p1 sd)

  (setq no (getint "\nSpecify number: "))

               (cond ((= no 1) 
                          (if (not pn1) (setq pn1 (getvar "hpname")))
                       (setvar "hpname" pn1))
	             ((= no 2)    
                          (if (not pn2) (setq pn2 (getvar "hpname")))
                       (setvar "hpname" pn2))
		     ((= no 3)    
                          (if (not pn3) (setq pn3 (getvar "hpname")))
                       (setvar "hpname" pn3))
               )

    (setq hp (getstring (strcat "\nSpecify pattern name <" (getvar "hpname") ">: ")))
      (if (not hp) (setq hp (getvar "hpname")))
           (command "-HATCH" "p" hp "1" "" p1 "")

               (cond ((= no 1)   (setq pn1 (getvar "hpname")))
	            ((= no 2)   (setq pn2 (getvar "hpname")))
		   ((= no 3)   (setq pn3 (getvar "hpname")))
               )
  );while
 (princ)
)

 

If I'm interpreting correctly that the option to specify a different diameter and/or pattern should be offered for every Circle drawn/hatched....

 

Here's a way [untested -- time to hit the sack] to handle an initial default situation without a temporary variable, and to cover the number 1-2-3 [or as many as you want without additional code] choices with collective code.  [Also, (getstring) doesn't return nil on Enter, but rather the empty text string "", so (not hp) won't ever return T.]

 

(defun c:22 (/ done p1 no hp)

  (while (not done)
    (setq

      $sd

        (cond

          ((getreal (strcat "\nSpecify diameter <" (if $sd (rtos $sd 2 1) "1.0") ">: "))); use User input if not Enter

          ($sd); Enter for default, if value already established
          (1.0); Enter on first use [initial default]

        ); cond & $sd
      p1 (getpoint "\nSpecify point or <exit>: ")

    ); setq

    (if p1 ; User picked point

      (progn ; then
        (command "_.CIRCLE" p1 $sd)
        (setq no (getint "\nSpecify number: "))
        (if (eval (read (strcat "pn" (itoa no)))); covers all three [or more if you want] numbers

          (setvar 'hpname (eval (read (strcat "pn" (itoa no))))); then - make current

          (set (read (strcat "pn" (itoa no))) (getvar 'hpname)); else - put current into pn1/pn2/pn3/etc.

        ); if
        (setq hp (getstring (strcat "\nSpecify pattern name <" (getvar 'hpname) ">: ")))
        (if (= hp "") (setq hp (getvar 'hpname))); on Enter
        (command "-HATCH" "p" hp "1" "" p1 "")
        (set (read (strcat "pn" (itoa no))) (getvar 'hpname)); any no value
      ); progn [then]

      (setq done T); else [don't Circle/Hatch, and stop (while) loop, if Enter when asked to pick point]

    ); if [p1 or not]
  );while
  (princ)
); defun

 

You can also add error handling, Undo begin/end, maybe offer the last number chosen as a default after the first one, etc.

Kent Cooper, AIA
Message 9 of 12
smaher12
in reply to: Kent1Cooper

That kicks butt Kent!

The main goal was to retain the hatch pattern for the specified number. You nailed it.

Thanks again for your help.

Happy turkey day....

 

Message 10 of 12
Lee_Mac
in reply to: smaher12

Since LISP is inherently built for lists, I would suggest using an association list assigned to a single global variable to store the pattern associations, rather than multiple global variables for each number / pattern combination.

 

By using a single global variable, you have far more control of the data (since all of the data is in one place) and furthermore, a significantly reduced risk of the global variable symbol clashing with other symbols defined in the document namespace. Also, if you needed to remove the data at some point in the future, the use of a single list variable means that all data can be removed by nullifying a single variable, rather than iterating over & nullifying every defined symbol (which could be very difficult if there happened to be 'gaps' in the sequence of variable numbers).

 


 

@Kent: a few suggestions to help improve your code:

 

Be wary of the Object Snap settings, since coordinates supplied to commands (such as the CIRCLE command or -HATCH command) will be affected by the active Object Snap modes in operation and hence may result in unexpected results. This is usually remedied by using the "_non" or "_none" Object Snap modifier, or by temporarily disabling the OSMODE system variable.

 

Be careful if the user were to press ENTER when prompted for a number, since the getint function will return nil and the subsequent itoa function will error.

 

Note that the code is prompting for a diameter value, but will create circles of half this diameter, since the CIRCLE command prompts for a radius by default.

 

Be careful if the user should specify an invalid hatch pattern name, as the setvar 'hpname expression will error.

 


 

@smaher: the following code would be my suggestion for this task (assuming I have correctly understood what you are looking to achieve):

 

(defun c:22 ( / *error* cen cir dia hat num pat spc )

    (defun *error* ( msg )
        (LM:endundo (LM:acdoc))
        (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
            (princ (strcat "\nError: " msg))
        )
        (princ)
    )
    
    (if (null *dia*)
        (setq *dia* 1.0)
    )
    (if (null *hpl*)
        (setq *hpl* (mapcar 'strcase (LM:hatchpatternlist)))
    )
    (setq spc
        (vlax-get-property (LM:acdoc)
            (if (= 1 (getvar 'cvport))
                'paperspace
                'modelspace
            )
        )
    )
    
    (while
        (and
            (if (setq num (getint (strcat "\nSpecify number " (if *num* (strcat "<" (itoa *num*) ">: ") "<exit>: "))))
                (setq *num* num)
                (setq num *num*)
            )
            (or (setq pat (cdr (assoc num *lst*)))
                (progn
                    (while
                        (not
                            (or (= "" (setq pat (getstring (strcat "\nSpecify pattern <" (getvar 'hpname) ">: "))))
                                (member (strcase pat) *hpl*)
                            )
                        )
                        (princ (strcat "\n\"" pat "\" pattern not defined."))
                    )
                    (if (= "" pat)
                        (setq pat (getvar 'hpname))
                    )
                    (setq *lst* (cons (cons num pat) *lst*))
                )
            )
            (progn
                (initget 6)
                (if (setq dia (getdist (strcat "\nSpecify diameter <" (rtos *dia*) ">: ")))
                    (setq *dia* dia)
                    (setq dia *dia*)
                )
                (setq cen (getpoint "\nSpecify center <exit>: "))
            )
        )
        (LM:startundo (LM:acdoc))
        (setq hat (vla-addhatch spc achatchpatterntypepredefined pat :vlax-true achatchobject)
              cir (vla-addcircle spc (vlax-3D-point (trans cen 1 0)) (/ dia 2.0))
        )
        (vlax-invoke hat 'appendouterloop (list cir))
        (vla-put-patternscale hat (getvar 'hpscale))
        (vla-evaluate hat)
        (LM:endundo (LM:acdoc))
    )
    (princ)
)

;; Hatch Pattern List  -  Lee Mac
;; Returns a list of all hatch patterns defined in all PAT files found in the
;; support file search paths & working directory.

(defun LM:hatchpatternlist

    (
        /
        unique
        fixdir
        parsesupportpaths
        parsepatfile
        lst
    )

    (defun unique ( lst )
        (if lst (cons (car lst) (unique (vl-remove (car lst) (cdr lst)))))
    )

    (defun fixdir ( str )
        (vl-string-right-trim "\\" (vl-string-translate "/" "\\" str))
    )

    (defun parsesupportpaths ( str / pos )
        (if (setq pos (vl-string-position 59 str))
            (vl-remove "" (cons (substr str 1 pos) (parsesupportpaths (substr str (+ pos 2)))))
            (list str)
        )
    )

    (defun parsepatfile ( fn / fd hp ln )
        (if
            (and
                (setq fn (findfile fn))
                (setq fd (open fn "r"))
            )
            (progn
                (while (setq ln (read-line fd))
                    (if (wcmatch ln "`**`,*")
                        (setq hp (cons (strcase (substr ln 2 (1- (vl-string-position 44 ln)))) hp))
                    )
                )
                (close fd)
                (reverse hp)
            )
        )
    )
    
    (foreach dir (cons (getvar 'dwgprefix) (parsesupportpaths (getenv "ACAD")))
        (foreach pat (vl-directory-files dir "*.pat" 1)
            (setq lst (cons (parsepatfile (strcat (fixdir dir) "\\" pat)) lst))
        )
    )
    (vl-sort (unique (apply 'append lst)) '<)
)

;; Start Undo  -  Lee Mac
;; Opens an Undo Group.

(defun LM:startundo ( doc )
    (LM:endundo doc)
    (vla-startundomark doc)
)

;; End Undo  -  Lee Mac
;; Closes an Undo Group.

(defun LM:endundo ( doc )
    (while (= 8 (logand 8 (getvar 'undoctl)))
        (vla-endundomark doc)
    )
)

;; Active Document  -  Lee Mac
;; Returns the VLA Active Document Object

(defun LM:acdoc nil
    (eval (list 'defun 'LM:acdoc 'nil (vla-get-activedocument (vlax-get-acad-object))))
    (LM:acdoc)
)
                
(vl-load-com) (princ)

 

I hope this helps,

 

Lee

 

Message 11 of 12
Kent1Cooper
in reply to: Lee_Mac


@Lee_Mac wrote:

... 


 

@KenT: a few suggestions to help improve your code:

... 

Agreed -- most of those things I usually include or account for, but it was 2:30 in the morning, and I left them to be part of my suggested "etc."  I left their Circle and Hatch commands as they had them [e.g. the diameter-vs.-radius issue], not looking at them in depth since those weren't the question.  I suspect I would have found and corrected that one if I had gotten to testing it.

 

One thing I would suggest about yours:  One might often use several commands, in the same editing session of the same drawing, that leave global variables, and I would suggest making those variable names specific to the command.  Many routines will have reason to save a list into a global variable, and calling such a variable *lst*, if several routines do the same, means they'll overwrite each other's defaults.  Given the command name they chose, I would call that one *22lst* in this case, and likewise use *22dia*, *22num*, etc.

Kent Cooper, AIA
Message 12 of 12
Lee_Mac
in reply to: Kent1Cooper


@Kent1Cooper wrote:

Agreed -- most of those things I usually include or account for, but it was 2:30 in the morning...


 

I'm the same - when you can't sleep, code.

 


@Kent1Cooper wrote:

I would suggest making those variable names specific to the command.


 

Good suggestion -

 

Coincidentally, I would usually follow this practice with my published applications with both global variable and function symbols - though, I usually use the command or program name followed by a colon, e.g. 'tbox:app' as used in my Associative Textbox application - I'm not sure why I overlooked it in this code.

 

Thank you.

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

Post to forums  

Autodesk Design & Make Report

”Boost