CADCAL & CALScript for AutoCAD™ and BricsCAD™
  This is pure magic: create smart CAD objects and smart Lisp functions totally without any programming  
  Home CAL and DDCAL CALSCRIPT CALSCRIPT quickstart C+C and Lisp FAQ Pricing / Order Contact  
 

  CADCAL + CALScript and Lisp  
     
 
CADCAL and Lisp make your existing Lisp functions smart    
creating CALSCRIPT objects CALScript Lisp library    
modifying CALSCRIPT objects general Lisp library    
 

CADCAL and CALScript is programmed entirely in Lisp, and it's functionality is based on Lisp. Every math expression of CADCAL is translated to Lisp, and then this Lisp function will be executed to calculate the result of the math expression. And every CALScript script file is translated to Lisp, and then this Lisp function will be executed to create a CALScript object. Modifying the properties of a CALScript object is done by Lisp, and the object communication is done by Lisp.

All this Lisp functionality is available to the user too, thus enabling the user to create his own applications based on CADCAL and on CALScript objects.
     
  CADCAL and Lisp

When CADCAL executes a math expression, it first translates the math expression to Lisp, and then executes this Lisp. There is a Lisp function available to the user to translate math expressions to Lisp:
(cc-str->lisp <mathexpression>)
The math expression "p1+p2+p3" calculates the sum of three coordinate points. You can use (cal "p1+p2+p3") in your source code. (cc-str->lisp "p1+p2+p3") translates this math expression to (§§+ (LIST P1 P2 P3)), which can used alternatively to the CAL function call.

In his Lisp applications a developer can effectively use CADCAL directly. CADCAL's execution speed is so fast because in a drawing session any math expression needs to be translated only once. So when a math expression is executed via the CAL function in a loop, the time consuming process of translating the math expression to Lisp needs to be done only once, and all subsequent CAL calls in this loop can use the previously translated Lisp directly.

But when performance really is an issue then a developer can use the translated code directly in his application. Instead of i.e. using (cal "p1+p2+p3") you can use (§§+ (LIST P1 P2 P3)).


 
  creating CALSCript objects

When a user executes the CC-SCRIPT command, he is prompted to select a script file. The average user is unaware of how CALScript internally processes the script file. The following happens: CALScript translates the script file into a Lisp function, more specifically, an anonymous LAMBDA function. CALScript then asks the user for the function's arguments, which are specified in the CC-PROPERTIES declaration in the script, including the default values, as well as for the object's insertion point and its rotation angle, and the object will be created. The LAMBDA function is then stored in an XDICTIONARY of the created object. This LAMBDA function is then available in every DWG that contains the object.

The easiest way to create an executable Lisp function from a script file is to call the CC-COMPILESCRIPT command. The user is prompted to select an existing script file and then a new Lisp file in which to save the Lisp-translated script file. In this case, a named Lisp function is created, with the script file name as the function name. For example, this Lisp function is created from the NICKSHOUSE.SCR script file
:
(defun nickshouse (WIDTH HEIGHT SELF / ) ....)
It's noticeable that this object function, in addition to the arguments specified in the script's CC-PROPERTIES declaration, also has an additional argument called SELF. The name SELF is based on the fact that it allows you to specify the entity name of a CALScript object, which is then modified using the new arguments WIDTH and HEIGHT. Alternatively, SELF can be passed with NIL, in which case a new NICKSHOUSE object is created at the origin of the coordinate system with a rotation of 0. However, SELF can also be a list containing the insertion point and the rotation angle, and then a new object is created at the specified point and at the specified angle. The angle must be specified in radians. The CALScript object function can therefore be used both to create new object instances and to modify existing object instances.

A CALScript object can be created in different ways:

1. use the CC-SCRIPT command to select a script file

2. use the COPY command to copy an existing CALScript object

3. use the command CC-COMPILESCRIPT to create a Lisp function from a script file, load this Lisp function and execute it. When you have compiled the NICKSHOUSE.SCR script file to a NICKSHOUSE.LSP file you can load that and use (nickshouse 60 80 nil) to create a new object at '(0 0 0) and rotation angle 0, or use (setq inspt (getpoint "\nInspt: ")) (setq insangle (getangle inspt)) (nickshouse 60 80 (list inspt insangle)). If the object function has successfully created a new CALScript object, the function will return the entity name of the new object.

The
object's lambda function, which is stored as an XDICTIONARY in the CALScript object, looks slightly different than the Lisp function created using CC-COMPILESCRIPT. Besides the name, there's another difference: the Lisp function created using CC-COMPILESCRIPT contains an additional variable called SELF:LAMBDA, and the Lisp code of the LAMBDA function is assigned to this variable right at the beginning of the function. This allows the Lisp function to attach itself to the object even after it has been created. This is actually a bit like Munchausen, who was able to pull himself up by his own hair, or, more easily understood for English speakers, was able to "pull himself up by his own bootstraps".

This
object lambda function, stored in an XDICTIONARY with the object, can be easily extracted by any user. To do so, simply call the Lisp function
(xdictionary-get (car (entsel)) "CALSCRIPT")
When prompted
by (entsel), simply select the desired CALScript object, and for the NICKSHOUSE object you will get:
: (cadr (assoc "LAMBDA" (xdictionary-get (car (entsel)) "CALSCRIPT")))
Select entity: ((WIDTH HEIGHT SELF / SELF:NAME SELF:ENAME SELF:DATA ...


This LAMBDA function cannot be used directly to create new objects because it lacks one essential feature: the function itself. In order for the function to attach itself in an XDICTIONARY to the object, it must have knowledge of itself. To do this, the function is bound to the variable SELF:LAMBDA as a quoted list, and this assignment is included as the first list element (after the variable declaration) of the function list. The difference is easily recognizable by comparing it to the Lisp function created by CC-COMPILESCRIPT.



 
  modifying  CALScript objects

We've already learned the basic function for modifying CALScript objects in a DWG: modifying an object is done the object function itself. The object function can be used both to create new objects and to modify existing ones. It's also completely straightforward to replace CALScript objects with others, because it doesn't matter whether the entity name passed as the SELF argument represents the same object type or a different one.

In most cases, however, it's not necessary to first create the object function using CC-COMPILESCRIPT to change the properties of a CALScript object. This method is probably most useful when developing your own applications from object functions.
The easiest way to change an object's properties is with the CC-MODIFY command. This prompts the user to enter new values for the properties, and the previously selected object is then updated with these new values. If this object communicates with other objects as a master, its slave objects are also updated.

Analogous to the CC-MODIFY command function, there is also a Lisp function that is called as follows:
(cc-modify <ename> <arglist>)
A NICKSHOUSE object whose entity name was previously assigned to the variable EN using (setq en (car (entsel))) can therefore be easily modified using the function
(cc-modify en (list 120 40))
so that the new width is 120 and the new height is 40.

There's a problem for the programmer when using the Lisp function CC-MODIFY: they need to know how many and which arguments the object expects. The NICKSHOUSE object is defined in its script by the CC-PROPERTIES declaration to expect two numbers as arguments, which are then used as WIDTH and HEIGHT in the internal calculations. The arguments of a CALScript object can therefore be easily retrieved using the CC-PROPERTY-GET function:
(cc-property-get <ename> <argname>)
Here, <ename> is, of course, the entity name of the object, and <argname> is either an argument name (e.g., 'WIDTH'), a list of argument names (list 'WIDTH' 'HEIGHT'), or NIL.
If NIL is passed, all argument names and the current argument values are output. In the case of the NICKSHOUSE object, (cc-property-get en nil) returns this list: ((WIDTH 120) (HEIGHT 60)). The call (cc-property-get en 'HEIGHT) returns only the value for the argument name HEIGHT, which is 60.

Similar to the CC-PROPERTY-GET function for reading object properties, there is the CC-PROPERTY-SET function for assigning new values to object properties. The function (cc-property-set en 'HEIGHT 80) assigns the value 80 to the HEIGHT property of an object, and the object is updated accordingly. You can also change multiple properties with a single call to CC-PROPERTY-SET: (cc-property-set en (list (list 'HEIGHT 80) (list 'WIDTH 50)) nil) Please note that all properties to be changed, each with their name and value, are listed in the list passed as the second argument. In this case, the third argument to CC-PROPERTY-SET must be specified as NIL.




 
  make your existing Lisp functions smart

Most users will probably have a large number of Lisp functions available that generate CAD drawing elements from specified arguments. Each such function can be extended with CALScript without additional programming to create these CAD elements as CALScript objects, which can also be subsequently modified any time later with the CC-MODIFY command.

Please see the CALSCRIPTDEMO/dumblispsample.lsp file for an axample. This Lisp file defines a function dumblisp, that takes the arguments p1, wd and dp, and draws a simple rectangle with it's diagonal lines:
(defun dumblisp (p1 wd dp / p2 p3 p4)
  (setq p2 (list (+ (car p1) wd) (cadr p1))
          p3 (list (car p2) (+ (cadr p2) dp))
          p4 (list (car p1) (+ (cadr p1) dp))
  )
  (command "._pline" p1 p2 p3 p4 "_cl")
  (command "._line" p1 p3 "")
  (command "._line" p2 p4 "")
)
This function can be called in any other Lisp function, or at the command prompt.
(if (and (setq startpt (getpoint "\nStartpoint: "))
           (setq width (getpoint "\nWidth: "))
           (setq depth (getpoint "\nDepth: "))
  )
  (dumblisp startpt width depth)
)
Since in CAD scripts Lisp functions can be executed directly, the function call (dumblisp startpt width depth) can ce used in any CALScript script file too. In that case the predefined insertion point ORIGIN in a CALScript script file could be used as the STARTPT directly, and the CALScript declaration
cc-properties width,60,depth,80
would define the variables WIDTH and DEPTH as arguments, with 60 rs 80 as the default values.

So the script file would look like that:
cc-properties width,60,depth,80

(dumblisp origin width depth)
That's all. Really!
Just use the command CC-SCRIPT to create a CALScript object, and use CC-MODIFY to modify that object.
When you want the dumblisp Lisp file automatically by the script, just add the line
(if (not dumblisp) (load "CALSCRIPTDEMO/dumblispsample.lsp"))
in the script before the dumblisp function is executed.

And of course you can improve the script file even more, i.e. by switching to color "_BYBLOCK" before calling the dumblisp function, or by corresponging to object communication. Its all up to you.

And of course you can add more Lisp functions to the script file, and these Lisp files can be as complex as you want them to be, drawing really complex drawing parts.


 
CALScript Lisp library

Web site under construction. List of CALSCript Lisp functions will come soon ...
  general Lisp library

Web site under construction. List of Lisp library functions will come soon ...
 
     
     
  (c) 2025 Tom Berger
Feriendorfstraße 6c, D-34308 Bad Emstal, Germany
berger@archtools.de