# how to use CADCAL as a Lisp code generator

in LISP

CADCAL (attached t this post) has been developed as a full replacement for AutoCAD's GeomCAL, but now has been enhanced to do parametric scripting, and to automatically generate full working Lisp code, with which you can build complex Lisp applications.

CADCAL can be used just the same as GeomCAL, and so you can call the same math expressions as in GeomCAL, and use the results of that expressions as input for your CAD work, i.e.

(cal "(2*cur+cur)/3")

returns the point at 1/3 of the distance between the two points, which the user must pick with the cursor.

But internally CADCAL is working a little bit different than GeomCal. CADCAL's parser (the part of the program that converts the input string to something that a computer can understand) first translates the string to a Lisp expression, which then is evaluated. Parsing is very computing intensive and therefore time consuming, and when CADCAL once has translated a math expression, then it stores the Lisp expression for future use over the full drawing session. When in a loop the same math expression ist called 1000 times, CADCAL only needs to parse it a single time, and the other 999 times it can use the Lisp expression directly. This makes CADCAL really fast.

The user can do this translation for his own purposes. Simply use the CC-STR->LISP function:

(CC-STR->LISP "(2*cur+cur)/3")

returns

(§§/ (§§+ (LIST (§§* 2 (§§CUR)) (§§CUR))) 3)

The Lisp functions used in this Lisp expression are predefined in CADCAL. Since VisualLisp/AutoLisp doesn't allow macro programming (this is what makes Lisp to a "real" Lisp), there is no way to defun a function like +. The + function allows an arbitrary number of arguments, and AutoLisp only allows defining functions with a fix number of arguments. So the §§+ function from CADCAL, which can add any number of numbers or vectors, has only one single argument: a list, containing all arguments.

Now with the DCL frontend for CADCAL or GeomCAL (accessible by the command DDCAL) we also get a history of the last 30 math expressions used by CAL in this DWG file. Download CADCAL (see link below) and open the ./demo/nickshouse.scr, and call the DDCAL command to see what this means. Such a history of CAL calls is nothing else than a script. We can calculate the relevant coordinate points of any drawing part, and let it draw automatically. The first solution was, to integrate the drawing work too into CAL calls. So there ist a CADCAL function PLINE(p1,p2,p3 ...) which creates a polyline over all the points in the argument list. And in this argument list the user can also integrate program options like "_a" for an arc, or "_cl" for "close".

But then it turned out that many companies since decades already defined the drawing of their parts as scripts. They used GeomCAL for the calculations, and ordinary command scripts for the drawing work.

So CADCAL now can translate not only the CAL calls in scripts to Lisp, but the whole script,
including lines with Lisp code and all direct command calls.

There are two ways to do a translation. The function (CC-SCRIPTCORE->LISP <scriptfilename>) creates a 1:1 translation of the script, combining the translation of each single script line into a LAMBDA. There also is a command function SCRIPTCORE, which asks you for the
scriptfilename before. I.e. this script

(if (not origin) (setq origin '(0 0 0)))
(if (not long) (setq long 80))
(if (not wide) (setq wide 100))
;;
(setq p1 ORIGIN)
CAL P2=P1+[long,0]
CAL P3=P1+[long,wide]
CAL P4=P1+[0,wide]
._pline !p1 !p2 !p3 !p4 _cl
._line !p1 !p3
._line !p2 !p4

is translated to that LAMBDA:

(LAMBDA NIL
(IF (NOT ORIGIN)
(SETQ ORIGIN '(0 0 0))
)
(IF (NOT LONG)
(SETQ LONG 80)
)
(IF (NOT WIDE)
(SETQ WIDE 100)
)
(SETQ P1 ORIGIN)
(SETQ P2 (§§+ (LIST P1 (LIST LONG 0))))
(SETQ P3 (§§+ (LIST P1 (LIST LONG WIDE))))
(SETQ P4 (§§+ (LIST P1 (LIST 0 WIDE))))
(COMMAND "._pline" P1 P2 P3 P4 "_cl")
(COMMAND "._line" P1 P3 "")
(COMMAND "._line" P2 P4 "")
)

But there is another, much more powerful way. It requires that the parameters of the script above are defined by the special CADCAL expression

CAL IMPORT(long,80,wide,120)

This has the very same effect as declaring the variables LONG and WIDE with default values as
in Lisp or in a CAL expression. But this single extra line enables CADCAL to define a much more complex Lisp function with LONG and WIDE as arguments. And this function then can create a drawing, which can be modified parametrically any time later.

Now the script looks like that:

CAL IMPORT(long,80,wide,120)
;;
(setq p1 ORIGIN)
CAL P2=P1+[long,0]
CAL P3=P1+[long,wide]
CAL P4=P1+[0,wide]
._pline !p1 !p2 !p3 !p4 _cl
._line !p1 !p3
._line !p2 !p4

BTW: ORIGIN is a predefined variable for CADCAL scripts. When the user did not define it before the script execution, then ORIGIN will be set to (0 0 0). The user can use the CALSCRIPT command to execute the script, but similar as with a block insertion now he will be asked for an insertion point (=ORIGIN), the rotation, and the values for the arguments LONG and WIDE.

Now the user can call the CADCAL function (CC-CALSCRIPT->LISP <scriptfilename>) or the command function CALSCRIPT->LISP to get this more complex LAMBDA:

(LAMBDA (LONG WIDE / OLDCMDECHO LISPLST RESULT IMPORTDATA
CC:IMPORT P2 P3 P4 NEWSSET LASTENT LST CC:LAMBDAFUNCTION)
... <too long for a post, do a test with the demo files>
)

This LAMBDA takes the arguments LONG and WIDE which have been defined in the IMPORT() declaration in the script, and all variables defined in the script using the CAL expression "varname=..." are defined as local variables. This LAMBDA is directly executable and will create the same parametrical drawing part as the CALSCRIPT command.

When you download the current beta version of CADCAL (attached to this post) and available for free from www.archtools.de/cadcal.zip), you can see the demo file NICKSHOUSE.LSP (attached), which has been created automatically from the NICKSHOUSE.SCR (attached, rename the SCR.TXT to SCR, since the forum software does not allow the SCR extension). Only the word "LAMBDA" has been replaced py "DEFUN NICKSHOUSE", and then a C:NICKSHOUSE command function asks the user for insertion point, rotation, and the values for the arguments, and then calls the automatically created function, now renamed to (nickshouse long wide).

Installation: extract the ZIP file to any directory and, if not already done so, add
this directory to the search path for support files of your BricsCAD system.

• Just a comment

CAL P2=P1+[long,0]

(setq p2 (mapcar '+ p1 (list X Y Z)))

(setq p2 (mapcar '+ p1 (list 80 120 0.0)))

• Hello Alanh,

what do you want to tell us with your comment? Indeed this is not a comment, but is just telling us the trivial information, that any CADCAL/GeomCAL expression can always bei expressed in Lisp (or in any other programming language)? And yes: the CADCAL function CC-STR→LISP shows very efficiently, that now every user without any knowledge of Lisp can translate a CAL expression to Lisp.

So, what's the reason for your comment?