TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: HasanCAD on September 27, 2010, 09:43:10 AM

Title: How to create subroutine?
Post by: HasanCAD on September 27, 2010, 09:43:10 AM
I do not know if this question is logic or foolish but I want to learn how to create and use subroutine
for example this subroutine
Code: [Select]
(defun _FormatDate ( format )
    (menucmd (strcat "m=$(edtime,$(getvar,DATE)," format ")"))
  )

And used as
Code: [Select]
(_FormatDate "DD MON YYYY")
In this code
Code: [Select]
(defun c:myDate ( / _FormatDate _CreateLayer _CreateMText
pickedpoint
; mTextHeight is Global
)
  (vl-load-com)

  (defun _FormatDate ( format )
    (menucmd (strcat "m=$(edtime,$(getvar,DATE)," format ")"))
  )

  (defun _CreateLayer ( name colour )
    (or (tblsearch "LAYER" name)
      (entmakex  (list ...  ) ) ) )

  (defun _CreateMText ( point string layer height )
    (entmakex  (list ...   ) ) )

  (if
    (and
      (setq pickedpoint (getpoint "\nPick Point for Date: "))
      (setq mTextHeight
     (cond
       ((getdist (strcat "\nSpecify MText Height <" (rtos (setq mTextHeight (cond ( mTextHeight ) ( (getvar 'TEXTSIZE) )))) "> : "))) ( mTextHeight )))
    )
    (progn
      (_CreateLayer "Clock" 3)
      (_CreateMText (trans pickedpoint 1 0)
(strcat "{\\fTimes New Roman|b0|i0|c0|p34;\\C2;" [color=red](_FormatDate "DD MON YYYY") [/color] "}") "Clock" mTextHeight )
      )
    )
  (princ)
)

Regards
Title: Re: How to create subroutine?
Post by: roy_043 on September 27, 2010, 11:10:47 AM
It seems you already know how to create and use a subroutine. :-)
Your code basically looks OK to me.
Title: Re: How to create subroutine?
Post by: CAB on September 27, 2010, 11:37:42 AM
That may not be his code but an example he is trying to understand. :-)
Title: Re: How to create subroutine?
Post by: HasanCAD on September 27, 2010, 04:06:06 PM
That may not be his code but an example he is trying to understand. :-)
This code created by Lee and I want to understand how to create and use
Title: Re: How to create subroutine?
Post by: BlackBox on September 27, 2010, 04:12:24 PM
That may not be his code but an example he is trying to understand. :-)
This code created by Lee and I want to understand how to create and use

Maybe you should learn about attribution first, no?  :wink:
Title: Re: How to create subroutine?
Post by: Kerry on September 27, 2010, 04:29:25 PM
now that attribution is out of the way ..

exactly what don't you understand ??

Title: Re: How to create subroutine?
Post by: BlackBox on September 27, 2010, 04:54:00 PM
exactly what don't you understand ??

I cannot speak for the OP, but my first hurdle was to understand that a subroutine could simply be a routine that was called from within another routine, or be locally defined within the calling routine itself (as the OP's/Lee's? code demonstrates).

Second (for me) was understanding the terminology (i.e., Subroutine, Function, etc.)

Then I believe I needed to grasp that a routine does not need to be complete, or a full program itself so-to-speak (what do you mean it does one thing!? I have 50 more to do!), and could be responsible for only one particular function (to return a result) in order to be stored to a variable (i.e., a Toolbox function).

Title: Re: How to create subroutine?
Post by: Lee Mac on September 27, 2010, 06:41:50 PM
I really like subroutines.

They save a ton of time writing programs and also make programs easier to follow as each step is compartmentalised (phew..).

- Time saving because you don't have to write the same functionality over and over again, you can just look into your toolbox/library and dig out the code that does what you want.

- Programs are easier to follow because each subfunction has its own purpose and so, once the subfunctions are understood, the program can be read like a book.

On creating subfunctions...

Think about the bare essentials needed for the functionality you require. I'm talking about the information that the function can't live without. These are your arguments. For Example, the text string for a subfunction to create a text object, or even the point for the same subfunction.

Try to make the subfunction as generic as possible. Don't specialise. This will make it more useful over a wider range of functions. Going back to the Text object creation: don't hardcode the layer into the function, supply it as an argument. Then - should another program call the subfunction but want the object on a different layer than before, the subfunction needn't be modified, but rather called with different data.

Anyway, I shan't waffle, I'm sure others have more informative sentiments to add.

Lee Mac
Title: Re: How to create subroutine?
Post by: dgorsman on September 28, 2010, 10:40:40 AM
Thought should be given to whether the sub will be fail-proof or not.  In some circumstances you always want the sub to return, in which case agressive error handling should be implemented.  Other times it might make more sense to skip the overhead and just have it halt execution (with an appropriate warning, of course).
Title: Re: How to create subroutine?
Post by: JohnK on September 28, 2010, 12:24:53 PM
Thought should be given to what the sub will return. boole, int, string, etc. as well and how its used--or can be used--in the main (one of the reasons why i have some hesitations for using a boole instead of a conditional--but some people think a boole is more fancy to use and will gain them some clout amongst forum users-).
Title: Re: How to create subroutine?
Post by: dgorsman on September 28, 2010, 01:02:34 PM
Thought should be given to what the sub will return. boole, int, string, etc. as well and how its used--or can be used--in the main (one of the reasons why i have some hesitations for using a boole instead of a conditional--but some people think a boole is more fancy to use and will gain them some clout amongst forum users-).

The lack of a distinct "false" equivalent to "T" instead of the more general purpose "nil" has bitten me more than once...  :whistle:
Title: Re: How to create subroutine?
Post by: MP on September 28, 2010, 01:05:10 PM
?? Not sure I follow.

(null nil) >> T
Title: Re: How to create subroutine?
Post by: Krushert on September 28, 2010, 06:23:07 PM
When should one "store" a subroutine(s) inside the routine or outside and called in.  

I place all my subroutines in the routine but I got a real mess brewing with a handful of routines that used the same subroutines.  I am thinking that parse out the subroutines.  :oops: :?
Title: Re: How to create subroutine?
Post by: CAB on September 29, 2010, 10:35:01 AM
Well there are plenty of examples of subroutines or sub-functions. I will give you my short explanation.

A Sub routine/function is nothing more than a function called nu another function as opposed to being called form the command line.
That function called form the command line (could be a menu or button doing the calling) is the TOP function and when completed
this function should return you to the command line.

Any functions called from this function directly or indirectly may be called a sub-function.

There you have it.

In order to use these functions you must call them with the correct name and the correct number of arguments.
The sub-function may return a useful value for your routine to make use of. More on that later.

The name of functions may be c:MyFunction ,(defun  c:MyFunction (), in which case the routine is usually a top function and may be called from the
command line by entering MyFunction  You may also call this function from another function this way (MyFunction).
Note that arguments are not used in this situation so any variables must be global variables or created by the function c:MyFunction.
That is not the usual way a function is called. The more common situation is to create a function named MyFunction, (defun  MyFunction (),

The Global variable vs Local variable has been discussed so I won't relive it here except to say that the Global variables should be
used sparingly as it is good programming practice.

Therefore you should try to pass variables to your subroutine as arguments. So MyFunction should be defined like so:
(defun  MyFunction (argument1 argument2 argument3 / localVariables)
Some people test the variable type for there arguments like (= (type argument1) 'STR) for a string and then correct it or
return an error flag. Others feel that the subroutine should fail so you can fix the calling function so that it sends the expected
variable type. Most of the time I prefer the latter. But there are times when you want a very versatile subroutine that will
except say an <entity name> or <vla object> type and make the conversion as needed in the sub-function.


As for When to use a sub-function, that is a personal preference.
I use them if I repeat a process more than once. Although if the code lines are few & they are repeated two or three times I may
not create a sub-function. Another case is when I want the code to appear clear & straight forward to the reader I may elect
to remove some code to a sub-function just for readability.
An example is making a polyline using entmake. The code takes up space & therefore I may use a sub-function MakePline to
simplify the code appearance.

Code: [Select]
               ((setq newpline ([b]makePline[/b] space (append RibPtLst1 (reverse RibPtLst2))))
                (vla-put-layer newpline Flexlayer)
                (if FlexColor
                  (vla-put-color newpline FlexColor)
                )
               
See how it simplifys the apearance:

Code: [Select]
  ;;  Expects pts to be a list of 2D or 3D points
  (defun makePline (spc pts)
    (if (= (length (car pts)) 2) ; 2d point list
      (setq pts (apply 'append pts))
      (setq
        pts (apply 'append (mapcar '(lambda (x) (list (car x) (cadr x))) pts))
      )
    )
    (setq
      pts (vlax-make-variant
            (vlax-safearray-fill
              (vlax-make-safearray vlax-vbdouble (cons 0 (1- (length pts))))
              pts
            )
          )
    )
    (vla-addlightweightpolyline spc pts)
  )
 
 
Usually you make all your sub-functions local to the main Lisp routine.
If the function is used by many of your Lisp's then you may want to create a file of the common sub-functions and
load the when you start a DWG. I do this with a lisp called AlansAutoload.lsp which is loaded in every DWG.

Here is a sample of whats in the lisp

Code: [Select]
(princ "\nAlansAutoLoad lisp is starting...>>>>>>>>>>>>>>>")
(setq *usermode* "CAB") ; turn on debug mode
;;  See Debug.lsp for use

(vl-load-com)

;;; ===============================================
;;;    Lisp Routine Loader
;;;    AUTOLOAD only loads the routine when needed
;;; ===============================================

;;;------  Lisp name -- Function name("n1$" "n2$") -------  Discription  -----------------------
(AUTOLOAD "AlignAllDCL CAB" '("AlignAll")) ; Align Text or Objects
(AUTOLOAD "MacAlignV5" '("MacAlign"))
(AUTOLOAD "MacAlignV5(mtext)" '("MacAlignm"))
(AUTOLOAD "Angle Bisect" '("BISECT")) ;
(AUTOLOAD "AreaPrt" '("AreaPrt")) ; Print the Area of "POLYLINE"  "LWPOLYLINE" "CIRCLE" "ELLIPSE"
(AUTOLOAD "arrow line" '("arw")) ; draw a arrow line on stairs, plan view
(AUTOLOAD "ArrowDrainage" '("darrow")) ; draw a drainage arrow
(AUTOLOAD "Arrows by Tim W" '("DPA")) ; draw a hollow arrow, by Tim Willey


(load "vl-SubRoutines.lsp" "vl-SubRoutines.lsp not found")
(load "ACADSet_Variables CAB" "ACADSet_Variables CAB.lsp not found") ; loads & runs
(load "QLeader CAB" "QLeader CAB.lsp not found") ; loads qleader Set & Get
;;  Set my default qleader settings
(acet-ql-set '((40 . 0.0) (60 . 0) (61 . 0)
      (62 . 1) (63 . 1)   (64 . 0) (65 . 0)
      (66 . 0) (67 . 3)   (68 . 0) (69 . 0)
      (70 . 0) (71 . 1)   (72 . 0) (170 . 0)))

(defun C:DOB() (setq ss (ssget)) (command "DRAWORDER" ss "" "B") (princ) )
(defun C:DOF() (setq ss (ssget)) (command "DRAWORDER" ss "" "F") (princ) )
(defun C:DOA() (setq ss (ssget)) (command "DRAWORDER" ss "" "A") (princ) )
(defun C:DOU() (setq ss (ssget)) (command "DRAWORDER" ss "" "U") (princ) )

;;Make 2D point from 3D point
(defun 3dP->2dP (3dpt) (list (car 3dpt) (cadr 3dpt)))

(defun dxf (code lst) (cdr (assoc code lst)))

;;;  Convert  Radians to Degrees
  (defun rtd (r) (* 180.0 (/ r pi)))

;;; Convert DEGREES TO RADIANS
  (defun dtr (d) (/ (* d pi) 180.0))
 
 
(defun c:ResetCAB()
  (load "AlansAutoLoad.lsp")
  (princ)
)
;; ****************
;;  End Of File
;; ****************


That's all I have time for today.
PS  I created this over several short sessions so there may be some rambling. :-)
( My 2 Cents)
Title: Re: How to create subroutine?
Post by: Krushert on September 29, 2010, 12:47:56 PM
No rambling that I saw.  Just good information. 
When I get time to start reworking those routines I will be back with questions. 
Thanks.
Title: Re: How to create subroutine?
Post by: HasanCAD on September 30, 2010, 03:02:26 PM
...
That's all I have time for today.
PS  I created this over several short sessions so there may be some rambling. :-)
( My 2 Cents)

Exactly what I want to know
Waiting for your free time for more explanation

Thanks
HasanCAD