# Specific method for parametric drawing programs

The hard part of coding parametric drawing program whether in lisp or VBA is managing the large number of points. The program turns into many lines of hard to read data apparently randomly named. A sketch has to be made with points labeled and equations or formulas entered. It all might make sense during the coding, but probably won’t a few weeks later when a change has to be made even if the sketch(s) is found. It won’t be obvious how the points are calculated or why lines are drawn from pt7 to pt21 to pt3. There is no one right way but I have recently worked on both lisp and vba programs and have some specific but not comprehensive suggestions. This is a special theory for creating the xy data but not a general theory for the entire program.

There are two basic ways to manage your drawing subroutine. It can accept points or xy data. Try both ways. Both methods need xy data.

In Lisp I use Visual Lisp objects rather than the “command” method. The object method can draw directly in to a block definition, and it can directly change the layer property. It requires a point object, but that can be created and passed as a parameter or the xy data can be passed and the point created in the subroutine.

For lisp I made a point creation routine and passed points to the subroutine which runs the Addline method.

(defun pt ( x y ) (vlax-3d-point x y 0))

In a very simple box example this gets called as

(setq pt1 (pt 0 0) pt2 (pt L 0) pt3 (pt L W) pt4 (pt 0 W))

Then the line routine would be

(defun linep (pt1 pt2 obj lyr / lineobj)
(setq lineobj (vla-AddLine obj pt1 pt2))
(vla-put-layer lineobj lyr) )

And be called as

(linep pt1 pt2 ms "hidden")

Or you could pass xy data

(defun line (x1 y1 x2 y2 obj lyr / pt1 pt2 lineobj)
(setq pt1 (vlax-3d-point x1 y1 0)
pt2 (vlax-3d-point x2 y2 0))
(setq lineobj (vla-AddLine obj pt1 pt2))
(vla-put-layer lineobj lyr) )

In VBA every variable has to be declared previous to use, so you might lean towards passing xy data. Assume you want to draw a notched rectangle and make it a polyline. You make a sub specifically for this purpose. After setting the xy data coordinates, any six vertex closed polyline can be drawn with

Call p6_box(x1, y1, x2, y1, x2, y2, x3, y2, x3, y3, x1, y3)

Sub p6_box(p1 As Double, p2 As Double, p3 As Double, p4 As Double, p5 As Double, p6 As Double, _
p7 As Double, p8 As Double, p9 As Double, p10 As Double, p11 As Double, p12 As Double)

Dim pt(0 To 11) As Double
pt(0) = p1: pt(1) = p2
pt(2) = p3: pt(3) = p4
pt(4) = p5: pt(5) = p6
pt(6) = p7: pt(7) = p8
pt(8) = p9: pt(9) = p10
pt(10) = p11: pt(11) = p12
objent.Closed = True
End Sub

This makes no sense without a sketch but the sub p6_box can draw any closed polyline with 6 points configured any way you need it.

Our notched box is L X W with an A X B notch, drawn with the lower left corner at 0,0. There are 3 X coordinates and 3 Y coordinates.
X1=0 , X2=L-B , X3=L
Y1=0 , Y2=A , Y3=W

You can turn this box around any way you wish, move the notch to the middle, put a hole in the middle. Just label xy coordinates as needed in order from the origin. This is how you organize your xy data without duplication in a straightforward way. Sometimes its convenient to also label points, sometimes its not required, but the xy data must always be figured from the parameters as the first step.

In VBA we would probably draw in counterclockwise order.

Call p6_box(x1, y1, x2, y1, x2, y2, x3, y2, x3, y3, x1, y3)

Now it should make sense. The xydata starts at the origin. Subroutines can be written so declared point variables are not required, or required. If you have a lot of sub-routines, just declare your x1, x2, etc as public to avoid re-declaring.

In programming 101 they strongly suggest that your subroutines be simple and single purpose. Just about every autocad parametric program I have seen or written has been a mess at the actual geometry creation level. For instance in this example, the parameters A and B, L and W may need to have complicated formulas behind them. Put those upstream of the actual sub-routine that draws the geometry. Make the geometry creation as simple as possible. Pass the actual parameters if possible, do not develop them. Interface is top down thinking, but geometry is bottom up.
Such as

Sub draw_notch_box(W As Double, L As Double, A As Double, B As Double)
x1 = 0
x2 = L - B
x3 = L
y1 = 0
y2 = A
y3 = W
Call p6_box(x1, y1, x2, y1, x2, y2, x3, y2, x3, y3, x1, y3)
End Sub

You will be able to read that next year if you remember that xy data starts at the origin.

# Axis Lisp and Utilities

Here is a lisp DCL program primarily to draw XY Axis or XYZ Axis. The user inputs values for min, max, tick length and tick increment. Circles instead of lines work well for the Z axis tick marks. In addition there are some simple routines for loading layers and textstyles. I put my fonttable program link here. The screen background can be changed to any gray value from white to black by inputting a value between 0-255. That gives us tools to make attractive graph presentations.

An Axis is a collection of lines. The easy way to draw lines in lisp is with the command function.

(defun demo1 ()
(setq pt1 (list 1 2 3)
pt2 (list 2 4 6))
(command “line” pt1 pt2 “”))

The line command is terminated with the empty quote. To add more line segments, add more points before the termination. This draws a triangle.

(defun demo2 ()
(setq pt1 (list 0 0 0)
pt2 (list 2 3 3)
pt3 (list 4 0 0))
(command “line” pt1 pt2 pt3 pt1 “”))

if the point are real numbers, not variables, the list can be quoted in-line. The line function also can use the “C” option to close the figure.

(defun demo3 ()
(command “line” ‘(0 0 0) ‘(2 3 3) ‘(4 0 0) “c” ))

a line subroutine can be used and re-used. this one is 2D. 3D can be implemented the same way.

(defun line1 (x1 y1 x2 y2)
(setq pt1 (list x1 y1 0)
pt2 (list x2 y2 0))
(command “line” pt1 pt2 “”))

(defun demo4 ()
(line1 0 0 2 3)
(line1 2 3 4 0)
(line1 4 0 0 0))

The visual lisp method to make a line is Addline. It works in either modelspace or populating a block (or paperspace). These spaces have to be set up as objects. Addline is a member of their class, so in VBA it becomes modelspace.Addline or blockdef.Addline. Once the necessary environment is made, the lines can be drawn as a block definition as easily as modelspace objects. Another advantage is that layer is just a property of the line. In more complex parametric drawing projects it is easier to specify the layer as a property of the line in the line creation subroutine than it is to change the current layer in the system before drawing the line. In this program the axis drawing is simple enough that it uses the current layer. The line subroutines below work as written for either modelspace or blockdefinition.

(defun demo5 ()

(line2 0 0 2 3 ms)
(line2 2 3 4 0 ms)
(line2 4 0 0 0 ms) )

(defun line2 (x1 y1 x2 y2 obj / pt1 pt2 lineobj)
(setq pt1 (vlax-3d-point x1 y1 0)
pt2 (vlax-3d-point x2 y2 0))
(setq lineObj (vla-AddLine obj pt1 pt2)) )

(defun demo6 ()

(line3 0 0 2 3 ms “Bold”)
(line3 2 3 4 0 ms “Center”)
(line3 4 0 0 0 ms “Hidden”) )

(defun line3 (x1 y1 x2 y2 obj lyr / pt1 pt2 lineobj)
(setq pt1 (vlax-3d-point x1 y1 0)
pt2 (vlax-3d-point x2 y2 0))
(setq lineobj (vla-AddLine obj pt1 pt2))
(vla-put-layer lineobj lyr) )

Here is the full Axis program with drawing utilities, sans the DCL file.

;; location of axis.lsp and dcl
(setq axis_progdir "c:\\lisp\\axis\\")

(defun axis ()

(setq dcl_id (load_dialog (strcat axis_progdir "axis.dcl")))
(if (< dcl_id 0)
(progn
(exit) ) )

(if (not (new_dialog "axis" dcl_id))
(progn
(alert "DCL file loaded but not definition, internal problem with files" )
(exit) )   )

(set_axis_vars)

(action_tile "resetform" "(set_axis_vars)")
(action_tile "backcolor" "(backcolor)")

(action_tile "xyaxis" "(savevars) (done_dialog 2)")
(action_tile "xyzaxis" "(savevars) (done_dialog 3)")
(action_tile "fonttable" "(done_dialog 4)")

(action_tile "cancel" "(done_dialog 0)")

(setq ddiag (start_dialog))

(if (= ddiag 2) (xy_axis) )
(if (= ddiag 3) (xyz_axis) )
(if (= ddiag 4) (fonttable) )
)

(defun set_axis_vars ()
(set_tile "xmin" "-12")
(set_tile "xmax" "12")
(set_tile "xinc" "1")
(set_tile "xtick" "0.5")

(set_tile "ymin" "-12")
(set_tile "ymax" "12")
(set_tile "yinc" "1")
(set_tile "ytick" "0.5")

(set_tile "zmin" "-6")
(set_tile "zmax" "6")
(set_tile "zinc" "1")
(set_tile "ztick" "0.25")

(set_tile "blkname" "XY_Axis")
(set_tile "bgcolor" "64")  )

(defun savevars()
(setq xmin (atof (get_tile "xmin")))
(setq xmax (atof (get_tile "xmax")))
(setq xinc (atof (get_tile "xinc")))
(setq xtick (atof (get_tile "xtick")))

(setq ymin (atof (get_tile "ymin")))
(setq ymax (atof (get_tile "ymax")))
(setq yinc (atof (get_tile "yinc")))
(setq ytick (atof (get_tile "ytick")))

(setq zmin (atof (get_tile "zmin")))
(setq zmax (atof (get_tile "zmax")))
(setq zinc (atof (get_tile "zinc")))
(setq ztick (atof (get_tile "ztick")))

(setq blkname (get_tile "blkname")) )

(defun xy_axis ( )
(draw_xy_axis xmin xmax xinc xtick ymin ymax yinc ytick blkname))

(defun xyz_axis ( )
(draw_xyz_axis xmin xmax xinc xtick ymin ymax yinc ytick zmin zmax zinc ztick blkname))

(maketextstyle "Arial" "Arial.ttf")
(maketextstyle "Arial Narrow" "ArialN.ttf")
(maketextstyle "Calibri" "Calibri.ttf")
(maketextstyle "Calibri Light" "CalibriL.ttf")
(maketextstyle "Courier New" "Cour.ttf")
(maketextstyle "Symbol" "Symbol.ttf")
(setvar "textstyle" "Calibri")  )

(setq LT "continuous" LW 35)
(makelayer "Axis" 1 LT LW)
(makelayer "Directrix" 5 LT LW)
(makelayer "Focus" 5 LT LW)
(makelayer "Asymptote" 5 LT -3)
(makelayer "Graph" 7 LT LW)

(makelayer "1" 1 LT LW)
(makelayer "2" 2 LT LW)
(makelayer "3" 3 LT LW)
(makelayer "4" 4 LT LW)
(makelayer "5" 5 LT LW)
(makelayer "6" 6 LT LW)
(makelayer "7" 7 LT LW)
(makelayer "8" 8 LT LW)
(makelayer "9" 9 LT LW)

(setvar "clayer" "Axis")
(setvar "LWDISPLAY" 1) )

(defun backcolor ( )
(setq rgbnum (atoi (get_tile "bgcolor")))
(bkg rgbnum)  )

(defun setfonttable ( )
(fonttable)  )

(DEFUN maketextstyle (name fontname)
(entmake (list (cons 0 "STYLE")
(cons 100 "AcDbSymbolTableRecord")
(cons 100 "AcDbTextStyleTableRecord")
(cons 2  name)
(cons 3  fontname)
(cons 70 0)
(cons 40 0.0)
(cons 41 1.0)
(cons 50 0.0)
(cons 71 0))) )

(DEFUN makelayer (name color Linetype Lineweight)
(entmake (list (cons 0 "LAYER")
(cons 100 "AcDbSymbolTableRecord")
(cons 100 "AcDbLayerTableRecord")
(cons 2  name)
(cons 70 0)
(cons 62 color)
(cons 6 Linetype)
(cons 290 1)
(cons 370 Lineweight)))  )

(defun bkg (rgbnum)
(setq hexnum (rgbhex rgbnum))

(defun RGBhex (RGBnum / r g b)
(setq r (lsh RGBnum 16))
(setq g (lsh RGBnum 8))
(setq b RGBnum)
(+ r g b)  )

Draw_Axis.LSP is in a separate file. FontTable was posted previously. The Axis is created as a block. There is an editbox on the DCL form for the block name. When making blocks with Visual Lisp objects, if the block already exists, the new entities will simply be added to the definition. This is not what is intended, so a utility must be used to delete the old block definition. This is not possible if the block is inserted into the drawing, so another utility must be used to first delete instances, then the definition can be deleted. I found these routines on message boards. I wont post them since they are not mine. They are not long and work well. Be aware you need to devise your own solution or tolerance to this problem.

;draw_axis_lsp

(defun line (x1 y1 x2 y2 obj)
(setq pt1 (vlax-3d-point x1 y1 0)
pt2 (vlax-3d-point x2 y2 0))
(setq lineObj (vla-AddLine obj pt1 pt2)) )

(defun linexyz (x1 y1 z1 x2 y2 z2 obj)
(setq pt1 (vlax-3d-point x1 y1 z1)
pt2 (vlax-3d-point x2 y2 z2))
(setq lineObj (vla-AddLine obj pt1 pt2)) )

(defun draw_xtick (x ticklen obj)
(setq pt1 (vlax-3d-point x (- (/ ticklen 2.0)) 0)
pt2 (vlax-3d-point x (+ (/ ticklen 2.0)) 0))
(setq lineObj (vla-AddLine obj pt1 pt2)) )

(defun draw_ytick (y ticklen obj)
(setq pt1 (vlax-3d-point (- (/ ticklen 2.0)) y 0)
pt2 (vlax-3d-point (+ (/ ticklen 2.0)) y 0))
(setq lineObj (vla-AddLine obj pt1 pt2)) )

(defun circle (x1 y1 z1 rad obj / pt1 circleobj)
(setq pt1 (vlax-3d-point x1 y1 z1))

(defun draw_ztick (z ticklen obj)
(setq pt1 (vlax-3d-point (- (/ ticklen 2.0)) 0 z)
pt2 (vlax-3d-point (+ (/ ticklen 2.0)) 0 z))
(setq lineObj (vla-AddLine obj pt1 pt2)) )

(defun x_axis (xmin xmax xinc ticklen obj)
(setq numpts (fix (1+ (/ (- xmax xmin) xinc))))
(line xmin 0 xmax 0 obj)
(setq inc 1)

(repeat numpts
(setq x (+ xmin (* (- inc 1) xinc)))
(setq inc (1+ inc))
(draw_xtick x ticklen obj) )
)

(defun y_axis (ymin ymax yinc ticklen obj)
(setq numpts (fix (1+ (/ (- ymax ymin) yinc))))
(line 0 ymin 0 ymax obj)
(setq inc 1)

(repeat numpts
(setq y (+ ymin (* (- inc 1) yinc)))
(setq inc (1+ inc))
(draw_ytick y ticklen obj) )
)

(defun z_axis (zmin zmax zinc ticklen obj)
(setq numpts (fix (1+ (/ (- zmax zmin) zinc))))
(linexyz 0 0 zmin  0 0 zmax obj)
(setq inc 1)

(repeat numpts
(setq z (+ zmin (* (- inc 1) zinc)))
(setq inc (1+ inc))
(circle 0 0 z (/ ticklen 2) obj) )
;(ztick z ticklen obj) )
)

(defun draw_xy_axis (xmin xmax xinc xtick ymin ymax yinc ytick blkname)

(del_blk blkname)

(setq pt0 (vlax-3d-point 0 0 0))

(setq blkdef (vla-Add blks pt0 blkname))

(x_axis xmin xmax xinc xtick blkdef)
(y_axis ymin ymax yinc ytick blkdef)

(setq blkref (vla-insertblock mspace pt0 blkname 1 1 1 0 ))
)

(defun draw_xyz_axis (xmin xmax xinc xtick ymin ymax yinc ytick zmin zmax zinc ztick blkname)

(del_blk blkname)

(setq pt0 (vlax-3d-point 0 0 0))

(setq blkdef (vla-Add blks pt0 blkname))

(x_axis xmin xmax xinc xtick blkdef)
(y_axis ymin ymax yinc ytick blkdef)
(z_axis zmin zmax zinc ztick blkdef)

(setq blkref (vla-insertblock mspace pt0 blkname 1 1 1 0 ))
)

# Curve Catalog

AutoLisp DCL Curve Graphing with curve “recipes” – equation, x value ranges, x value increment – saved and retrieved in an excel CSV file. Curve parameters in an excel list can be edited, sorted and re-organized. A sub-form Curve Catalog is popped up, data filled from the CSV file. User selects curve. Parameters are input to the Graph screen.

The code to Read the Excel.CSV file was written by Lee Mac and downloaded from his premier lisp site.

Graphing mathematical equations with autolisp –
as an example,
(setq strfunc “(* a x x )”)
(setq a 2) returns 2
(setq x 2.1) returns 2.1
Strfunc returns “(* a x x )”
(read strfunc) returns (* A X X)

With this we can set up a function to return a result for any legal lisp statement and values x a b c d.
The function is passed as a string, strfunc. X is passed in as a Real. X will vary with each call from xmin to xmax by increment xinc,
The global vars for a_dim b_dim c_dim and d_dim do not vary.

(defun func_eval (x strfunc / a b c d)
(setq a a_dim b b_dim c c_dim d d_dim )
(setq result (eval (read strfunc))) )

The equations must be input in lisp form, prefix notation with the operator first in a list, expressions nested. As long as it is legal lisp, the above code will interpret it. The loop to draw the curve is basic lisp using the command function for either line or pline.

;; location of
;; graph.lsp and dcl
;; catalog.lsp and dcl
;; curve_catalog.csv

(setq graph_progdir "c:\\lisp\\graph\\")

(defun c:graph ()
;catalog sub form program

(setq dcl_id (load_dialog (strcat graph_progdir "graph.dcl")))
(if (< dcl_id 0)
(progn
(exit) ) )

(if (not (new_dialog "graph" dcl_id))
(progn
(alert "DCL file loaded but not definition, internal problem with files" )
(exit) )   )

(set_graph_vars)
(action_tile "catalog" "(catalog) (set_graph_vars)")
(action_tile "graphlines" "(savevars) (done_dialog 2)")
(action_tile "graphpolylines" "(savevars) (done_dialog 3)")
(action_tile "cancel" "(done_dialog 0)")

(setq ddiag (start_dialog))
(if (= ddiag 2) (graphlines) )
(if (= ddiag 3) (graphpolylines) )
)

(defun savevars	()
(setq xmin (atof (get_tile "xmin")))
(setq xmax (atof (get_tile "xmax")))
(setq xinc (atof (get_tile "xinc")))
(setq a_dim (atof (get_tile "a_dim")))
(setq b_dim (atof (get_tile "b_dim")))
(setq c_dim (atof (get_tile "c_dim")))
(setq d_dim (atof (get_tile "d_dim")))
(setq strfunc (get_tile "equation"))
)

(defun set_graph_vars ()
(if xmin
(set_tile "xmin" (rtos xmin 2 2))
(set_tile "xmin" "-3.0")  )

(if xmax
(set_tile "xmax" (rtos xmax 2 2))
(set_tile "xmax" "3.0")  )

(if xinc
(set_tile "xinc" (rtos xinc 2 2))
(set_tile "xinc" "0.1")  )

(if a_dim
(set_tile "a_dim" (rtos a_dim 2 2))
(set_tile "a_dim" "2")  )

(if b_dim
(set_tile "b_dim" (rtos b_dim 2 2))
(set_tile "b_dim" "3")  )

(if c_dim
(set_tile "c_dim" (rtos c_dim 2 2))
(set_tile "c_dim" "4")  )

(if d_dim
(set_tile "d_dim" (rtos d_dim 2 2))
(set_tile "d_dim" "5")  )

;initial equation ax^2 + bx + c
(if (null strfunc)
(set_tile "equation" "(+ (* a X X) (* b X) c)")
(set_tile "equation" strfunc)  )
)

(defun func_eval (x strfunc / a b c d)
(setq	a a_dim    b b_dim   c c_dim   d d_dim  )
(setq result (eval (read strfunc))) )

(defun graphlines ()	;working with all global variables from savevars

(setq numlines (/ (- xmax xmin) xinc))
(setq i 1)
(setq x1 xmin)
(setq y1 (func_eval x1 strfunc))

(repeat (fix numlines)

(setq x2 (+ xmin (* i xinc)))
(setq y2 (func_eval x2 strfunc))

(setq pt1 (list x1 y1))
(setq pt2 (list x2 y2))

(command "line" pt1 pt2)
(command)

(setq x1 x2)
(setq y1 y2)

(setq i (1+ i))
)
)

(defun graphpolylines ()    ;working with all global variables from savevars

(setq numlines (/ (- xmax xmin) xinc))
(setq x1 xmin)
(setq y1 (func_eval x1 strfunc))
(setq pt1 (list x1 y1))

(command "pline" pt1)

(setq i 1)
(repeat (fix numlines)

(setq x2 (+ xmin (* i xinc)))
(setq y2 (func_eval x2 strfunc))

(setq pt2 (list x2 y2))

(command pt2)
(setq i (1+ i))
)
(command)
)

Graph.DCL is straightforward

Each curve then is defined by its lisp string, xmin, xmax, xinc and the specific values of A B C and D if they are used. Those 8 variables can be saved in an Excel file, a list of curve recipes, and input to the Graph program through a nested dialog called Catalog. A couple extra information columns are added.

The Excel format is called CSV, Comma Separated Values. It is actually a text file. It can be loaded directly into a text editor. Autolisp has tools to read this format. Excel is very handy for displaying and managing it. Lee Mac’s program reads the table and returns a list of rows with each cell a separate item in the sub-list. With Lisp tools we can take that and re-display the CSV file in DCL list boxes.

I only make one list box active to user selection, the box with the legal lisp equation. the other boxes are for user reference. all list boxes are given the same height and handled the same way so the rows line up. When the user selects an equation, its parameters are written to the textboxes, however he has to select OK to dismiss the dialog and use the parameters. Selecting cancel will abandon the values and return the previous screen with the values unchanged.

Here is Catalog LSP, called from the button on Graph. much of its length is just from loading the 10 listboxes and dealing with variables.

;catalog_lsp called from graph_lsp

(defun catalog_setup ()
(setq file (strcat graph_progdir "curve_catalog.csv"))

;;*********************************************
;;*********************************************

(setq theList1  (mapcar 'car data))

(setq theList4  (mapcar '(lambda (abc) (nth 3 abc)) data))
(setq theList5  (mapcar '(lambda (abc) (nth 4 abc)) data))
(setq theList6  (mapcar '(lambda (abc) (nth 5 abc)) data))
(setq theList7  (mapcar '(lambda (abc) (nth 6 abc)) data))
(setq theList8  (mapcar '(lambda (abc) (nth 7 abc)) data))
(setq theList9  (mapcar '(lambda (abc) (nth 8 abc)) data))
(setq theList10  (mapcar '(lambda (abc) (nth 9 abc)) data))
)

(defun catalog ()
(catalog_setup)

(setq dcl_id (load_dialog (strcat graph_progdir "catalog.dcl")))
(if (< dcl_id 0)
(exit) ) )

(if (not (new_dialog "catalog" dcl_id))
(progn (alert "DCL file loaded but not definition, internal problem with files")
(exit) ) )

(set_catalog_vars)

(start_list "list1" 3)
(end_list)

(start_list "list2" 3)
(end_list)

(start_list "list3" 3)
(end_list)

(start_list "list4" 3)
(end_list)

(start_list "list5" 3)
(end_list)

(start_list "list6" 3)
(end_list)

(start_list "list7" 3)
(end_list)

(start_list "list8" 3)
(end_list)

(start_list "list9" 3)
(end_list)

(start_list "list10" 3)
(end_list)

;only list that is pickable is lisp equation
(action_tile "list3" "(list-pick)")

(action_tile "ok" "(savevars) (done_dialog 2)")
(action_tile "cancel" "(done_dialog 0)")

(setq ddiag (start_dialog))

;(if (= ddiag 2) (nothing) )
;not required - savevars in ok button writes vars
;catalog button in graph lsp reads vars to screen
)

(defun savevars	()
(setq xmin (atof (get_tile "xmin")))
(setq xmax (atof (get_tile "xmax")))
(setq xinc (atof (get_tile "xinc")))

(setq a_dim (atof (get_tile "a_dim")))
(setq b_dim (atof (get_tile "b_dim")))
(setq c_dim (atof (get_tile "c_dim")))
(setq d_dim (atof (get_tile "d_dim")))

(setq strfunc (get_tile "equation"))
)

(defun list-pick ()
(setq listval (get_tile "list3"))
(setq curve_recipe (nth (atoi listval) data))

(set_tile "equation" (nth 2 curve_recipe))
(set_tile "xmin" (nth 3 curve_recipe))
(set_tile "xmax" (nth 4 curve_recipe))
(set_tile "xinc" (nth 5 curve_recipe))
(set_tile "a_dim" (nth 6 curve_recipe))
(set_tile "b_dim" (nth 7 curve_recipe))
(set_tile "c_dim" (nth 8 curve_recipe))
(set_tile "d_dim" (nth 9 curve_recipe))
)

;code same as set_graph_vars, keeping them separate for now
(defun set_catalog_vars ()
(if xmin
(set_tile "xmin" (rtos xmin 2 2))
(set_tile "xmin" "-3.0") )

(if xmax
(set_tile "xmax" (rtos xmax 2 2))
(set_tile "xmax" "3.0") )

(if xinc
(set_tile "xinc" (rtos xinc 2 2))
(set_tile "xinc" "0.1") )

(if a_dim
(set_tile "a_dim" (rtos a_dim 2 2))
(set_tile "a_dim" "2") )

(if b_dim
(set_tile "b_dim" (rtos b_dim 2 2))
(set_tile "b_dim" "3") )

(if c_dim
(set_tile "c_dim" (rtos c_dim 2 2))
(set_tile "c_dim" "4") )

(if d_dim
(set_tile "d_dim" (rtos d_dim 2 2))
(set_tile "d_dim" "5") )

;initial equation ax^2 + bx + c
(if (null strfunc)
(set_tile "equation" "(+ (* a X X) (* b X) c)")
(set_tile "equation" strfunc) )
)

and last, the DCL file for Catalog, again much of its length is repeating operations for the many listboxes

catalog:dialog {
label = "Curve Catalog";

:row {
:list_box {
label ="Notes";
key = "list1";
height = 35;
width = 35;
multiple_select = false;
fixed_width_font = true;
value = "0"; }

:list_box {
label ="Description";
key = "list2";
height = 35;
width = 35;
multiple_select = false;
fixed_width_font = true;
value = "0"; }

:list_box {
label ="Function - *** PICK FROM THIS LIST ***";
key = "list3";
height = 35;
width = 50;
multiple_select = false;
fixed_width_font = true;
value = "0"; }

:list_box {
label ="Xmin";
key = "list4";
height = 35;
width = 7;
multiple_select = false;
fixed_width_font = true;
value = "0"; }

:list_box {
label ="Xmax";
key = "list5";
height = 35;
width = 7;
multiple_select = false;
fixed_width_font = true;
value = "0"; }

:list_box {
label ="Xinc";
key = "list6";
height = 35;
width = 7;
multiple_select = false;
fixed_width_font = true;
value = "0"; }

:list_box {
label ="A_Dim";
key = "list7";
height = 35;
width = 7;
multiple_select = false;
fixed_width_font = true;
value = "0"; }

:list_box {
label ="B_Dim";
key = "list8";
height = 35;
width = 7;
multiple_select = false;
fixed_width_font = true;
value = "0"; }

:list_box {
label ="C_Dim";
key = "list9";
height = 35;
width = 7;
multiple_select = false;
fixed_width_font = true;
value = "0"; }

:list_box {
label ="D_Dim";
key = "list10";
height = 35;
width = 7;
multiple_select = false;
fixed_width_font = true;
value = "0"; }
}

:row {
:edit_box {
label = "Xmin";
key = "xmin";}
:edit_box {
label = "Xmax";
key = "xmax";}
:edit_box {
label = "Xinc";
key = "xinc";}

:edit_box {
label = "A_dim";
key = "a_dim";}
:edit_box {
label = "B_dim";
key = "b_dim";}
:edit_box {
label = "C_dim";
key = "c_dim";}
:edit_box {
label = "D_dim";
key = "d_dim";}
}

:row {
:edit_box {
label = "Y = ";
key = "equation";}
}

:row {
: button {
label = "OK";
key = "ok";
is_default = true; }

: button {
label = "Cancel";
key = "cancel";
is_default = false;
is_cancel = true; }
}

}

# AutoLisp DCL Equation Graphing

here is a start. equations have to be input in Lisp format. prototype, barely tested beyond initial ah ha!

Both line and polyline mode are enabled. The program remembers variables from run to run, so if you input a new equation, it will come up on next run.

(defun c:graph ()

(if (< dcl_id 0)
(progn
(exit) ) )

(if (not (new_dialog "graph" dcl_id))
(progn
(exit) ) )

(setgraphvars)

(action_tile "graphlines" "(savevars) (done_dialog 2)")
(action_tile "graphpolylines" "(savevars) (done_dialog 3)")
(action_tile "cancel" "(done_dialog 0)")

(setq ddiag (start_dialog))

(if (= ddiag 2)
(graphlines) )

(if (= ddiag 3)
(graphpolylines) )
)

(defun savevars	()
(setq xmin (atof (get_tile "xmin")))
(setq xmax (atof (get_tile "xmax")))
(setq xinc (atof (get_tile "xinc")))

(setq a_dim (atof (get_tile "a_dim")))
(setq b_dim (atof (get_tile "b_dim")))
(setq c_dim (atof (get_tile "c_dim")))
(setq d_dim (atof (get_tile "d_dim")))

(setq str_equation (get_tile "equation"))
)

(defun setgraphvars ()
(if xmin
(set_tile "xmin" (rtos xmin 2 2))
(set_tile "xmin" "-3.0") )

(if xmax
(set_tile "xmax" (rtos xmax 2 2))
(set_tile "xmax" "3.0") )

(if xinc
(set_tile "xinc" (rtos xinc 2 2))
(set_tile "xinc" "0.1") )

(if a_dim
(set_tile "a_dim" (rtos a_dim 2 2))
(set_tile "a_dim" "2") )

(if b_dim
(set_tile "b_dim" (rtos b_dim 2 2))
(set_tile "b_dim" "3") )

(if c_dim
(set_tile "c_dim" (rtos c_dim 2 2))
(set_tile "c_dim" "4") )

(if d_dim
(set_tile "d_dim" (rtos d_dim 2 2))
(set_tile "d_dim" "5") )

;initial equation ax^2 + bx + c
(if (null str_equation)
(set_tile "equation" "(+ (* a X X) (* b X) c)")
(set_tile "equation" str_equation) ) )

(defun resetgraph ()
(set_tile "xmin" "-3.0")
(set_tile "xmax" "3.0")
(set_tile "xinc" "0.1")

(set_tile "a_dim" "2")
(set_tile "b_dim" "3")
(set_tile "c_dim" "4")
(set_tile "d_dim" "5")

(setq str_equation "(+ (* a X X) (* b X) c)") ;initial equation
(set_tile "equation" str_equation)	; ax^2 + bx + c
)

(defun func_eval (x strfunc / a b c d)
(setq	a a_dim   b b_dim   c c_dim   d d_dim )
)

(defun graphlines ()	;working with all global variables from savevars

(setq strfunc str_equation)	; could clean this up

(setq numlines (/ (- xmax xmin) xinc))
(setq i 1)
(setq x1 xmin)
(setq y1 (func_eval x1 strfunc))

(repeat (fix numlines)

(setq x2 (+ xmin (* i xinc)))
(setq y2 (func_eval x2 strfunc))

(setq pt1 (list x1 y1))
(setq pt2 (list x2 y2))

(command "line" pt1 pt2)
(command)

(setq x1 x2)
(setq y1 y2)

(setq i (1+ i))
)
)

(defun graphpolylines ()   ;working with all global variables from savevars

(setq strfunc str_equation)	; eval read strfunc

(setq numlines (/ (- xmax xmin) xinc))
(setq x1 xmin)
(setq y1 (func_eval x1 strfunc))
(setq pt1 (list x1 y1))

(command "pline" pt1)

(setq i 1)
(repeat (fix numlines)

(setq x2 (+ xmin (* i xinc)))
(setq y2 (func_eval x2 strfunc))

(setq pt2 (list x2 y2))

(command pt2)
(setq i (1+ i))
)

(command)

)

Graphs below are cos, sin and cos * sin
(cos X) White
(sin X) Red
(* (sin X) (cos X)) Blue

# Lisp Parabola

This is pretty simple. Its a start. Func1 defines the equation ax^2 + bx + c with the specific values of a b and c and returns the value when passed the current value of X.  C:para calls the parabola function and sets the x minimum, maximum and x increment.

screenshot from the visual lisp editor.

if instead of unconnected lines, we want to graph with a 2D Polyline, the command is PLine, it takes the same point list. We start the Pline command with the first point, then enter the loop and calculate the next point each time through the loop, leaving the command processor running and just feeding it one point each time.

For graphing polar equations – Polar Coordinates – P(R,Ɵ) – A point is defined by how far it is from the origin (R – Radius) and what angle (Ɵ – Theta) a line from the origin to the point makes with the horizontal axis. (I am using A for angle instead of Ɵ in the code)

To change the command from separate lines to connected polyline, we start the pline command outside the loop and only calculate one point in the loop, just as for the rectangular cartesian program.

# AutoLisp 2.5

about 1986 R.C. Bradlee published a Xeroxed page book “Programming Autocad” which featured the Autolisp command set as of autocad version 2.5. Selection Sets had just been added. Entity names could be retrieved and properties modified but new entitities had to be added with the Command function (command “Line” pnt1 …). This would be a good starter section for learning the language, not overwhelming but not trivial. Some or most of the links seem to paste in from the Autodesk 2017 help reference. I rearranged and edited the entries into my own idea of fuzzy categories. A disclaimer – this is not an official list of Lisp 2.5 but just my reconstruction. Some functions i left out either inadvertently, or i assume they are obsolete, or simply i dont see a need for them.

Descriptions below all belong to Autodesk. Here is there notice cut / pasted from their help page.

Math and booleans are first and easiest to master.

 + (add) (+ [number number …]) Returns the sum of all numbers – (subtract) (- [number number …]) Subtracts the second and following numbers from the first and returns the difference * (multiply) (* [number number …]) Returns the product of all numbers / (divide) (/ [number number …]) Divides the first number by the product of the remaining numbers and returns the quotient 1+ (increment) (1+ number) Returns the argument increased by 1 (incremented) 1- (decrement) (1- number) Returns the argument reduced by 1 (decremented) abs (abs number) Returns the absolute value of the argument atan (atan num1 [num2]) Returns the arctangent of a number in radians cos (cos ang) Returns the cosine of an angle expressed in radians exp (exp number) Returns the constant e (a real) raised to a specified power (the natural antilog) expt (expt base power) Returns a number raised to a specified power fix (fix number) Returns the conversion of a real into the nearest smaller integer float (float number) Returns the conversion of a number into a real gcd (gcd int1 int2) Returns the greatest common denominator of two integers log (log number) Returns the natural log of a number as a real max (max [number number …]) Returns the largest of the numbers given min (min [number number …]) Returns the smallest of the numbers given rem (rem [num1 num2 …]) Divides the first number by the second, and returns the remainder sin (sin ang) Returns the sine of an angle as a real expressed in radians sqrt (sqrt number) Returns the square root of a number as a real ~ (bitwise NOT) (~ int) Returns the bitwise NOT (1’s complement) of the argument logand (logand [int int …]) Returns the result of the logical bitwise AND of a list of integers logior (logior [int int …]) Returns the result of the logical bitwise inclusive OR of a list of integers lsh (lsh [int numbits]) Returns the logical bitwise shift of an integer by a specified number of bits atom (atom item) Verifies that an item is an atom boundp (boundp sym) Verifies whether a value is bound to a symbol listp (listp item) Verifies that an item is a list not (not item) Verifies that an item evaluates to nil null (null item) Verifies that an item is bound to nil numberp (numberp item) Verifies that an item is a real or an integer minusp (minusp number) Verifies that a number is negative zerop (zerop number) Verifies that a number evaluates to zero = (equal to) (= numstr [numstr …]) Returns T if all arguments are numerically equal, and returns nil otherwise /= (not Equal to) (/= numstr [numstr …]) Returns T if the arguments are not numerically equal, and nil if the arguments are numerically equal > (greater than) (< numstr [numstr …]) Returns T if each argument is numerically less than the argument to its right, and returns nil otherwise >= (greater than or equal to) (<= numstr [numstr …]) Returns T if each argument is numerically less than or equal to the argument to its right, and returns nil otherwise < (less than) (> numstr [numstr …]) Returns T if each argument is numerically greater than the argument to its right, and returns nil otherwise <= (less than or equal to) (>= numstr [numstr …]) Returns T if each argument is numerically greater than or equal to the argument to its right, and returns nil otherwise and (and [expr …]) Returns the logical AND of a list of expressions boole (boole func int1 [int2 …]) Serves as a general bitwise Boolean function eq (eq expr1 expr2) Determines whether two expressions are identical equal (equal expr1 expr2 [fuzz]) Determines whether two expressions are equal or (or [expr …]) Returns the logical OR of a list of expressions angtos (angtos angle [mode [precision]]) Converts an angular value in radians into a string ascii (ascii string) Returns the conversion of the first character of a string into its ASCII character code (an integer) atof (atof string) Returns the conversion of a string into a real atoi (atoi string) Returns the conversion of a string into an integer chr (chr integer) Returns the conversion of an integer representing an ASCII character code into a single-character string itoa (itoa int) Returns the conversion of an integer into a string rtos (rtos number [mode [precision]]) Converts a number into a string

Lists and Loops contain the core LIST Processing commands

 type (type item) Returns the type of a specified item eval (eval expr) Returns the result of evaluating an AutoLISP expression quote (quote expr) Returns an expression without evaluating it repeat (repeat int [expr …]) Evaluates each expression a specified number of times, and returns the value of the last expression while (while testexpr [expr …]) Evaluates a test expression, and if it is not nil, evaluates other expressions; repeats this process until the test expression evaluates to nil if (if testexpr thenexpr [elseexpr]) Conditionally evaluates expressions cond (cond [(test result …) …]) Serves as the primary conditional function for AutoLISP foreach (foreach name lst [expr …]) Evaluates expressions for all members of a list progn (progn [expr …]) Evaluates each expression sequentially, and returns the value of the last expression command (command [arguments] …) Executes an AutoCAD command defun (defun sym ([arguments] [/variables …]) expr … ) Defines a function setq (setq sym1 expr1 [sym2 expr2 …]) Sets the value of a symbol or symbols to associated expressions getvar (getvar “varname”) Retrieves the value of an AutoCAD system variable setvar (setvar “varname” value) Sets an AutoCAD system variable to a specified value load (load filename [onfailure]) Evaluates the AutoLISP expressions in a file *error* (*error* string) A user-definable error-handling function list (list [expr …]) Takes any number of expressions and combines them into one list length (length lst) Returns an integer indicating the number of elements in a list last (last lst) Returns the last element in a list nth (nth n lst) Returns the nth element of a list reverse (reverse lst) Returns a list with its elements reversed car (car lst) Returns the first element of a list cdr (cdr lst) Returns the specified list, except for the first element of the list caddr cadr cons (cons new-first-element lst) The basic list constructor append (append lst …) Takes any number of lists and runs them together as one list member (member expr lst) Searches a list for an occurrence of an expression and returns the remainder of the list, starting with the first occurrence of the expression assoc (assoc item alist) Searches an association list for an element and returns that association list entry apply (apply function lst) Passes a list of arguments to a specified function mapcar (mapcar function list1 … listn) Returns a list of the result of executing a function with the individual elements of a list or lists supplied as arguments to the function lambda (lambda arguments expr …) Defines an anonymous function

Strings and File I/O are pretty straighforward

 read (read [string]) Returns the first list or atom obtained from a string strcat (strcat [string1 [string2 …]) Returns a string that is the concatenation of multiple strings strlen (strlen [string …]) Returns an integer that is the number of characters in a string substr (substr string start [length]) Returns a substring of a string vl-string-subst (vl-string-subst new-str pattern string [start-pos]) Substitutes one string for another, within a string open (open filename mode) Opens a file for access by the AutoLISP I/O functions read-char (read-char [file-desc]) Returns the decimal ASCII code representing the character read from the keyboard input buffer or from an open file read-line (read-line [file-desc]) Reads a string from the keyboard or from an open file write-char (write-char num [file-desc]) Writes one character to the screen or to an open file write-line (write-line string [file-desc]) Writes a string to the screen or to an open file close (close file-desc) Closes an open file

The last category is Autocad graphic interfacing commands. ( I am leaving out a few things I think may be less useful or obsolete or inadvertently)