Make Block with ActiveX

code in VBA and Visual Lisp for comparison,
connect, establish application and document objects, draw line in modelspace, add a new block, draw line in the block, insert the block.


Public acadApp As AcadApplication
Public acadDoc As AcadDocument
Public mspace As AcadModelSpace

Sub demo()

'autocad is running and doc open
Set acadApp = GetObject(, "AutoCAD.Application")
Set acadDoc = acadApp.ActiveDocument
Set mspace = acadDoc.modelspace

Dim lineobj As AcadLine
Dim pt1(0 To 2) As Double, pt2(0 To 2) As Double
pt1(0) = 2: pt1(1) = 1: pt1(2) = 0
pt2(0) = 6: pt2(1) = 7: pt2(2) = 0

'Set lineobj = acadDoc.modelspace.AddLine(pt1, pt2)
Set lineobj = mspace.AddLine(pt1, pt2)

Dim pt3(0 To 2) As Double
pt3(0) = 0: pt3(1) = 0: pt3(2) = 0

Dim blks As AcadBlocks
Set blks = acadDoc.blocks

Dim blkdef As AcadBlock
Set blkdef = blks.Add(pt3, "Blk_Demo2")

Set lineobj = blkdef.AddLine(pt1, pt2)
Set lineobj = blkdef.AddLine(pt2, pt3)

Dim blkref As AcadBlockReference
Set blkref = mspace.InsertBlock(pt3, "Blk_Demo2", 1, 1, 1, 0)

End Sub
(vl-load-com)

   (setq acadApp (vlax-get-acad-object))

   (setq acadDoc (vla-get-ActiveDocument acadApp))

   (setq mSpace (vla-get-ModelSpace acadDoc))

   (setq pt1 (vlax-3d-point 1 1 0)
         pt2 (vlax-3d-point 7 5 0))
    (setq lineObj (vla-AddLine mSpace pt1 pt2))

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

    (setq blks (vla-get-blocks acadDoc))

    (setq blkdef (vla-Add blks pt3 "Blk_Demo1"))
    (setq lineobj (vla-AddLine blkdef pt1 pt2))
    (setq lineobj (vla-AddLine blkdef pt2 pt3))

    (setq blkref (vla-insertblock mspace pt3 "Blk_Demo1" 1 1 1 0 ))

side by side,

this is an intuitively different process than creating a block by manual drafting methods. the graphic methods such as addline are the same for drawing in modelspace and drawing in blockspace. modelspace is a type of block, autodesk tells us. we create a block with nothing in it, then use the object returned just as we obtain the modelspace object to put objects in modelspace.

this example is very similar to the autodesk activeX Insertblock help page. http://help.autodesk.com/view/OARX/2018/ENU/?guid=GUID-17F86FDD-B7FC-4F43-9F16-B4958F73A66D

Lisp Setup

To make pretty math graphs with lineweights, colors, background and good looking fonts with math symbols, we will need some basic setup tools.

Everybody has a lisp setup. This is the easy way, using the command function from lisp, but a DCL dialog cannot call the command function. It exits with error “unhandled exception.” Twas ever thus and evermore shall be.

(defun setup ()
(setq LT "continuous" LW "0.35")

(makelayer "Axis" 1 LT LW)
(makelayer "Directrix" 5 LT LW)
(makelayer "Focus" 5 LT LW)
(makelayer "Asymptote" 5 LT "Default")
(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)

(command "layer" "s" "graph" "")
(command "units" "2" "4" "1" "2" "0" "N" )
(command "setvar" "LWDISPLAY" 1)

(maketextstyle "Arial" "Arial")
(maketextstyle "Arial Narrow" "Arial Narrow")
(maketextstyle "Calibri" "Calibri")
(maketextstyle "Calibri Light" "Calibri Light")
(maketextstyle "Courier New" "Courier New")

(maketextstyle "Table1" "Arial Narrow")
(c:romans)
)


(defun makelayer (name color linetype lineweight )
(command "layer" "m" name "c" color "" "L" linetype "" "LW" lineweight "" "") )

(defun maketextstyle (name fontname )
(command "style" name fontname "0" "1.0" "0" "No" "No" ))

(defun c:romans()
(command "style" "RomanS" "romans" "0" "0.75" "0" "No" "No" "No"))


; background shades of gray
(defun bkg (rgbnum)
(setq hexnum (rgbhex rgbnum))

(setq acadobject (vlax-get-acad-object))
(setq acadpref (vlax-get-property acadobject 'preferences))
(setq acaddisp (vlax-get-property acadpref 'display))
(vlax-put-property acaddisp 'GraphicsWinmodelBackgrndColor hexnum) )


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

to run code above from a DCL dialog we need to replace the command functions with entmake or visual lisp activeX methods.

for textstyle creation
http://adndevblog.typepad.com/autocad/2012/12/how-to-programmatically-create-a-new-text-style-with-truetype-fonts-in-lisp.html

autolisp layer entmake search yields many results.

for reference get the dxf codes returned for objects –

Command: (entget (tblobjname “layer” “0”))
((-1 . )
(0 . “LAYER”)
(5 . “10”)
(102 . “{ACAD_XDICTIONARY”)
(360 . )
(102 . “}”)
(330 . )
(100 . “AcDbSymbolTableRecord”)
(100 . “AcDbLayerTableRecord”)
(2 . “0”)
(70 . 0)
(62 . 7)
(6 . “Continuous”)
(290 . 1)
(370 . -3)
(390 . )
(347 . )
(348 . ))

Command: (entget (tblobjname “style” “arial”))
((-1 . )
(0 . “STYLE”)
(330 . )
(5 . “21B”)
(100 . “AcDbSymbolTableRecord”)
(100 . “AcDbTextStyleTableRecord”)
(2 . “Arial”)
(70 . 0)
(40 . 0.0)
(41 . 1.0)
(50 . 0.0)
(71 . 0)
(42 . 0.2)
(3 . “Arial”)
(4 . “”))

makelayer and maketextstyle are remade with the same argument list –

(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 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))))

autocad will let us know if DXF does not like the structure of the DXF code. We have to find the actual font name and suffix the extension.

(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”)

similarly the lineweight must be changed from 0.35 to 35, there may be other minor differences, such as the value for “Default” that has to be figured out. query the actual object in the drawing with the entget function above.

Fonts consist of 256 characters. a table 16 X 16 can display them all. Addtable works closely with the Tablestyle creation program. I have a statement to load Make_Ts at the head of the FontTable program. The tablestyle program uses the current textstyle and names itself the same way. to make a font table with a different font, i change the current textstyle, then re-run fonttable. This is a good reference for viewing the entire table for symbols and also i expect it to be handy for cut and paste to find greek symbols.

The original verson of the lisp tablestyle creation was taken from Lee Ambrosius’ blog
http://hyperpics.blogs.com/beyond_the_ui/2012/07/creating-a-table-style-with-autolisp-and-the-activex-api.html

(vl-load-com)

(defun c:Fonttable()
    
(load "c:\\LISP\\Table\\Make_TS.LSP")
(make_ts)

(setq numrows 17 numcolumns 16 rowheight 0.25 colwidth 0.375)

   (setq acadObj (vlax-get-acad-object))
   (setq doc (vla-get-ActiveDocument acadObj))

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

   (setq modelSpace (vla-get-ModelSpace doc))
   (setq fTable (vla-Addtable modelSpace pt numrows numcolumns rowheight colwidth))
  
   (vla-settext fTable 0 0 (getvar "textstyle"))
    
   (vla-put-HeaderSuppressed ftable :vlax-true)

   (setq rownum 1 colnum 0 chrnum 0)

(repeat 16

  (repeat 16
      (vla-settext fTable rownum colnum (chr chrnum))
      (setq colnum (1+ colnum))
      (setq chrnum (1+ chrnum))) 

     (setq rownum (1+ rownum))
     (setq colnum 0)
  )
)


(defun Make_TS()
;original version from 
;;http://hyperpics.blogs.com/beyond_the_ui/2012/07/creating-a-table-style-with-autolisp-and-the-activex-api.html
; some of his code i changed i commented out as this file changes a lot depending on specific requirements
; and it is helpful to keep alternate methods and settings available.

;tablestyle uses and is named by current textstyle
(setq textstyle (getvar "textstyle"))

    ;; Get the AutoCAD application and current document
    (setq acadobj (vlax-get-acad-object))
    (setq doc (vla-get-ActiveDocument acadobj))

    ;; Get the Dictionaries collection and the TableStyle dictionary
    (setq dicts (vla-get-Dictionaries doc))
    (setq dictObj (vla-Item dicts "acad_tablestyle"))
    
    ;; Create a custom table style
    (setq key textstyle
          class "AcDbTableStyle")
    (setq custObj (vla-AddObject dictObj key class))

    ;; Set the name and description for the style
    (vla-put-Name custObj textstyle)
    (vla-put-Description custObj "Font named table style")

    ;; Sets the bit flag value for the style
    (vla-put-BitFlags custObj 1)

    ;; Sets the direction of the table, top to bottom or bottom to top
    (vla-put-FlowDirection custObj acTableTopToBottom)

    ;; Sets the supression of the table header
    ;; Does not seem to do anything in tablestyle
    ;; same statement using created table object must be in addtable
    (vla-put-HeaderSuppressed custObj :vlax-true)

    ;; Sets the horizontal margin for the table cells
    (vla-put-HorzCellMargin custObj 0.03)

    ;; Sets the supression of the table title
    (vla-put-TitleSuppressed custObj :vlax-false)

    ;; Sets the vertical margin for the table cells
    (vla-put-VertCellMargin custObj 0.03)

    ;; Set the alignment for the Data, Header, and Title rows
    ;; (vla-SetAlignment custObj (+ acDataRow acTitleRow) acMiddleLeft)
    (vla-SetAlignment custObj acDataRow acMiddlecenter)
    (vla-SetAlignment custObj acHeaderRow acMiddleCenter)
    (vla-SetAlignment custObj acTitleRow acMiddleCenter)

    ;; Set the background color for the Header and Title rows
    
    (setq colObj (vlax-create-object "AutoCAD.AcCmColor.21"))
    
    ;(vla-SetRGB colObj 98 136 213)
    ;(vla-SetBackgroundColor custObj (+ acHeaderRow acTitleRow) colObj)

    ;; Clear the background color for the Data rows
    (vla-SetBackgroundColorNone custObj acDataRow :vlax-true)

    ;; Set the bottom grid color for the Title row
    ;;63 is all gridlinetypes and 7 is all rowtypes
    (vla-SetRGB colObj 0 0 255)
    (vla-SetGridColor custObj 63 7 colObj)

;;     to set individual - bottom grid color for the Title row
;;    (vla-SetGridColor custObj acHorzBottom acTitleRow colObj)

   ;; Set the bottom grid lineweight for the Title row
    (vla-SetGridLineWeight custobj acHorzBottom acTitleRow acLnWt025)

    ;; Set the inside grid lines visible for the data and header rows
    (vla-SetGridVisibility custObj acHorzInside  (+ acDataRow acHeaderRow) :vlax-true)

    ;; Set the text height for the Title, Header and Data rows
    (vla-SetTextHeight custObj acTitleRow 0.25)
    (vla-SetTextHeight custObj acHeaderRow 0.125)
    (vla-SetTextHeight custObj acDataRow 0.125)

    ;; Set the text style
    ;;(vla-SetTextStyle custObj (+ acDataRow acHeaderRow acTitleRow) "Standard")
    (vla-SetTextStyle custObj (+ acDataRow acHeaderRow acTitleRow) (getvar "textstyle"))

    ;; Release the color object
    (vlax-release-object colObj)
   (setvar "ctablestyle" textstyle)

  (princ)
)

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.
http://www.lee-mac.com/readcsv.html

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)
(eval (read strfunc)) returns 8.82

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
  (load (strcat graph_progdir "catalog.lsp"))

 (setq dcl_id (load_dialog (strcat graph_progdir "graph.dcl")))
  (if (< dcl_id 0)
    (progn
      (alert "The graph.DCL file could not be loaded.")
      (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))
  (unload_dialog dcl_id)
  (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"))

;;*********************************************
;; Read CSV code from
;;http://www.lee-mac.com/readcsv.html
;;*********************************************
(setq data (LM:readcsv file))


(setq theList1  (mapcar 'car data))
(setq theList2  (mapcar 'cadr data))
(setq theList3  (mapcar 'caddr 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)
    (progn  (alert "The catalog.DCL file could not be loaded.")
      (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)
  (mapcar 'add_list theList1)
  (end_list)

  (start_list "list2" 3)
  (mapcar 'add_list theList2)
  (end_list)

  (start_list "list3" 3)
  (mapcar 'add_list theList3)
  (end_list)

  (start_list "list4" 3)
  (mapcar 'add_list theList4)
  (end_list)

  (start_list "list5" 3)
  (mapcar 'add_list theList5)
  (end_list)

  (start_list "list6" 3)
  (mapcar 'add_list theList6)
  (end_list)

  (start_list "list7" 3)
  (mapcar 'add_list theList7)
  (end_list)

  (start_list "list8" 3)
  (mapcar 'add_list theList8)
  (end_list)

  (start_list "list9" 3)
  (mapcar 'add_list theList9)
  (end_list)

  (start_list "list10" 3)
  (mapcar 'add_list theList10)
  (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))
  (unload_dialog dcl_id)

  ;(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 ()

  (setq dcl_id (load_dialog "c:\\lisp\\graph\\graph.dcl"))
  (if (< dcl_id 0)
    (progn
      (alert "The graph.DCL file could not be loaded.")
      (exit) ) )

  (if (not (new_dialog "graph" dcl_id))
    (progn
      (alert "DCL file loaded but not definition, internal problem with files")
      (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))

  (unload_dialog dcl_id)

  (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 )
  (setq result (eval (read strfunc)))
)


(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

Autocad DCL Dialog Forms

Dialog Control Language – DCL – was introduced in its final form 25 years ago. If you have created forms with VBA, DCL has a tiny fraction of the capability. It uses archaic unfamiliar terms and it is evidently hard to describe as no one does it well. My advice is to find a template and create some working code as you try to read about it. The best template and teaching approach I have used is Jeffery Sanders website. He has a good basic template at the bottom of the very first page.

JefferySanders AutoLisp DCL Tutorial

There are two components – the DCL file and the Lisp file. The DCL file looks confusing at first but its not. The basic element is the Tile, in VBA that is called a Control. There are only a few Tiles that the user actually uses – textbox, button, listbox, popup list, radio button and toggle. There are several other column and row spacings which are technically tiles but you can leave them out of your first programs. Each Tile has attributes, in VBA called Properties. The most important attribute is called a Key, in VBA that is just the Name. The structure of tile and attributes is not hard to learn if you just start typing. Develop your own style of formatting and indenting. As you add rows and column objects, indent the Tiles so the Colon for each level is in a vertical line on the page.

Here is my style that i can read at a glance without counting brackets.

The visual lisp IDE has a DCL preview tool that is essential to get working. It is broken by default (or perhaps neglect). AfraLISP has clear instructions here to change permissions on your autocad installation folder.

AfraLisp Previewing DCL Files

Autodesk help has a LSP-DCL example overview.

Example: Quick Overview of Dialog Boxes (DCL)

DCL

hello  : dialog {
	          label = "sample box";
               	  : text { label = "Hello world"; }
       ok_only;
}

LSP

(defun C:HELLO ( / dcl_id )
  (setq dcl_id (load_dialog "hello.dcl")) ; Load the DCL file.
  (if (not (new_dialog "hello" dcl_id))   ; Initialize the dialog.
    (exit)                                ; Exit if this does not work.
  )
  (start_dialog)                          ; Display the dialog box.
  (unload_dialog dcl_id)                  ; Unload the DCL file.
 (princ)
)

Running this quickly shows it runs, displays and closes but it does not do anything. There is no input from the user. The mystery of these files remains – how is user input processed when they close?

start-dialog is running when the dialog is displayed, when the dialog is closed, start-dialog returns a status number. if the builtin ok_cancel buttons are used in the dcl file, the numbers are 0 for cancel and 1 for ok. that is what is happening behind the scenes in the program above, though there is no ok button.

You can start modifying the above program by adding an ok button, and capture the integer returned by start_dialog as it closes the dialog. The built-in ok_cancel buttons have built-in keys of “accept” and “cancel.” With that knowledge you can build an action_tile statement in your lisp program that is run when that button is pushed. Eventually we need to run our own program when the ok button is pushed.

(action_tile “accept” “(done_dialog 1)”) will cause the start_dialog exit and return the number 1 when the ok button is pushed. that happens to be the same number as the default, you could choose any number and start_dialog will return that number. The string of lisp commands is quoted so it does not evaluate when first loaded. This is why you just have to start running code because its so hard to explain. This area of how it closes and how user input is captured is the key part that is hardest to get from the manuals.

To make this overview program do something user related lets take this intermediate step where we add an edit_box, an ok_cancel assembly and examine the start_dialog return values. Adding some error checking to the dcl loading is straightforward.

DCL

hello2  : dialog {
           label = "hello2";

                  : edit_box {
                               label = "type in the box";
                                 key = "hellobox";
                                  value = "hello world";
                                  width = 50; }

ok_cancel;
}

LSP

(defun c:hello2 ( / dcl_id)

;'can the file be found and loaded
;'load_dialog returns positive integer when successful
;'returns a negative integer when not successful

  (setq dcl_id (load_dialog "c:\\lisp\\dcl\\hello.dcl"))
  (if (< dcl_id 0)
   (progn
      (alert "The Hello.DCL file could not be loaded.")
      (alert "Check DCL file location is in Search Path")
      (exit)))

;'(alert (rtos dcl_id))

 ;'new_dialog returns T or nil
 (if (not (new_dialog "hello2" dcl_id))
        (progn
        (alert "DCL file loaded but not definition, internal problem with files")
        ;'this might even be inconsistent capitalization of the dialog name
        (exit)))

;'as an experiment uncomment these lines
;'these numbers are returned by start_dialog
;'they mean whatever you want them to mean - they overwrite default 0 and 1
;'accept and cancel are the built-in key names you need to know for the ok_cancel sub-assembly
;'(action_tile "accept" "(done_dialog 3)")
;'(action_tile "cancel" "(done_dialog 12)")

;'by default start_dialog returns 0 if cancel, 1 if OK, -1 if all boxes term_dialog
;'alternatively, if done_dialog argument is an integer > 1
;'then start_dialog returns that value which is user-application defined

(setq d (start_dialog))
(unload_dialog dcl_id)

(alert (itoa d))
)

now maybe we have some understanding of how the built-in buttons pass values behind the scenes to the start-dialog, we can do the same thing with explicitly created buttons in the dcl. we don’t have to do that, but perhaps it is simpler to see how it works. The last most important piece of the puzzle, where and how do we save user input? i take this technique from the jefferysanders template above, create a (savevars) function and put it in the action_tile statement for the ok button. Test the number returned by start_dialog after exiting the dialog to see if it gets used. now the helloworld demo file returns whatever the user types in to the box.

DCL

hello3  : dialog {
           label = "hello3";

                  : edit_box {
                               label = "type in the box";
                                 key = "hellobox";
                                  value = "hello world";
                                  width = 50; }

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

LSP

(defun c:hello3 ( / dcl_id)

;'can the file be found and loaded
;'load_dialog returns positive integer when successful
;'returns a negative integer when not successful

  (setq dcl_id (load_dialog "c:\\lisp\\dcl\\hello.dcl"))
  (if (< dcl_id 0)
   (progn
      (alert "The Hello.DCL file could not be loaded.")
      (alert "Check DCL file location is in Search Path")
      (exit)))

 ;'new_dialog returns T or nil
 (if (not (new_dialog "hello3" dcl_id))
        (progn
        (alert "DCL file loaded but not definition, internal problem with files")
        ;'this might even be inconsistent capitalization of the dialog name
        (exit)))

;'now using explicitly created button tiles rather than built-in
;'but it is not necessary, same results are with hello2.dcl
(action_tile "cancel" "(done_dialog 0)")
(action_tile "accept" "(savevars) (done_dialog 1)")


;'by default start_dialog returns 0 if cancel, 1 if OK, -1 if all boxes term_dialog
(setq d (start_dialog))


(unload_dialog dcl_id)

;'pop up contents of edit_box if ok is pushed
(if (= d 1) (alert textval))
)


(defun savevars ()
(setq textval (get_tile "hellobox")))

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.
2017-03-05_2

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.

2017-03-05_4

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.