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 C+C and Lisp
 
     
  CALSCRIPT quickstart
 
 
first steps writing your first CC script      
CALSCRIPT declarations rules for scripts      
CALSCRIPT commands        
 
CALSCRIPT: first steps

CALSCRIPT is the tool for creating CALSCRIPT objects. In many ways, these objects can be seen as an alternative to AutoCAD's dynamic blocks. However, CALSCRIPT objects are much easier to create, more flexible, and more versatile, and, especially due to the ability to communicate between objects, offer enormous potential that dynamic blocks completely lack. Furthermore, CALSCRIPT objects are very easy to create and edit using Lisp and can even be part of complex Lisp applications. The possibilities are endless.

For a first impression of how CALSCRIPT works and how to create and edit CALSCRIPT objects, please start with an empty drawing file. You should already have CADCAL+CALSCRIPT installed.

Let's first create a simple CALSCRIPT object. Enter the CC-SCRIPT command in the CAD command line, or select the "CS" icon from the CALSCRIPT toolbar. You will be prompted to select a script file (file extension *.SCR). The default directory is set in the CALSCRIPT.INI file to the "CALScriptDemo" subdirectory in the C+C installation directory. Please select the file "NICKSHOUSE.SCR." You will now be asked for an insertion point and a rotation angle, similar to inserting a block, and then for the properties individually defined in the script, in this case "WIDTH" and "HEIGHT." Either accept the default values ​​or enter your own.
This will create this CALSCRIPT object:

You can now treat this object like any block insertion in AutoCAD. You can move it, rotate it, copy it, etc., or even place it on a different layer or assign it a different color. But the really important thing is that you can change the individual properties of the CALSCRIPT object at any time. To do so, simply enter the CC-MODIFY command or select the "MOD" icon in the CALSCRIPT toolbar. You will be prompted for the new values ​​for the WIDTH and HEIGHT properties set for this object, and the object will be redrawn accordingly.
Create multiple copies of this CALSCRIPT object, whether using the AutoCAD COPY command or copy & paste, give these copies different colors, rotate them differently, and give them different values ​​for WIDTH and HEIGHT using CC-MODIFY.

These CALSCRIPT objects no longer require the script file from which they were originally created. All the "intelligence" of these objects is stored within them. You can share DWG files with such objects with third parties, and they can edit the properties of these objects just as you can. The only requirement is the installation of the free CADCAL+CALSCRIPT license.
This CALSCRIPT object is defined so that it can communicate with other objects, adopting their object coordinate system, rotation, and the insertion point of the "master" of the communication, offset by the "WIDTH" value. To do this, simply enter the CC-CONNECT command and select the white object on the far left as the master and the yellow object as the slave. The yellow object will then automatically be positioned next to the white object and adopt its rotation. If you want to move the slave using the AutoCAD MOVE command, it will automatically jump back to its intended position. You can now build entire communication chains by making a slave the master of other objects. Simply call CC-CONNECT again and specify the master and slave.

However, you can still change every property of every individual object using the
CC-MODIFY command. And if you change the WIDTH value of a master object, its slaves will automatically reposition themselves, as will the slaves of the slaves.


This object communication makes CALSCRIPT a very powerful tool for modeling complex systems. With extremely little programming effort—often none at all—users can modell, simulate and animate complex systems. Watch this example video of a gearbox made up of very simple CALSCRIPT objects that represent gears.



CALSCRIPT: writing your first script
 
To write a script, you can use any text editor such as Notepad, or the editors integrated in AutoCAD VLIDE or BricsCAD BLADE. Similar to defining dynamic blocks, you as the user naturally need to know how the final object will be created from variable properties. Thanks to GeomCAL or CADCAL, no programming is required for this; it's sufficient to know the mathematical relationships between the drawing elements to be created. You can simply open the file TUTORIAL.SCR from the CALScriptDemo subdirectory of your C+C installation directory.

If we want to recreate the NICKSHOUSE object, we only need to know how the five corner points are constructed from the WIDTH and HEIGHT variables. We're already using the ORIGIN variable as the origin point, which in our example should be the bottom left corner point. This is achieved with the GeomCAL or CADCAL statement
CAL P1=ORIGIN
Point P2 is the bottom right corner point, and it's calculated from P1 and the WIDTH variable quite simply:
CAL P2=P1+[WIDTH,0]
This means that the vector [WIDTH,0] is added to point P1. Vectors in GeomCAL/CADCAL are written in square brackets, with X, Y (and optionally Z) values ​​separated by commas. Point P3 is the corner point above P2, and is calculated from P2 and the vector [0,HEIGHT]:

CAL P3=P2+[0,HEIGHT]
Similarly, the corner point P4, which lies above P1, is calculated as follows:
CAL P4=P1+[0,HEIGHT]
Here, we calculate the ridge point from a point that lies midway between P3 and P4 on the X-axis, and half the HEIGHT above P3 on the Y-axis. For clarity, we'll do this in several steps. First, the X-value for the ridge point:

CAL ROOFX=rxof(P1)+WIDTH/2

The CAL function RXOF(pt) extracts the X-value from point PT, and we add half the WIDTH to it. Analogous:
CAL ROOFY=ryof(p1)+HEIGHT/2
And with this, we can define the ridge point:
CAL ROOFPT=[roofx,roofy]
And now we can draw the polyline over these 5 points:
._PLINE !p1 !p2 !p3 !roofpt !p4 !p3 !p1 !p4 !p2
We can reference the previously calculated variables in scripts just as we would in the AutoCAD command line, using a leading exclamation mark.
Please note that such command lines in scripts usually (there are some exceptions!) must be executed in the same way as in the AutoCAD command line. For example, the PLINE command must be terminated with an extra ENTER, which is expressed in scripts by a space. Therefore, there must be a space after the final !P2. You could also use a Lisp command instead of the script command ._PLINE. This doesn't require the leading exclamation marks for the variables, and an <ENTER> is represented by an empty string "". It would then look like this:
(command "._PLINE" p1 p2 p3 roofpt p4 p3 p1 p4 p2 "")
This would have exactly the same effect, but is probably easier to read.
CALSCRIPT will anyhow translate a script command into a Lisp command expression.


To run this script with the standard AutoCAD script command, we still need the variables ORIGIN, WIDTH, and HEIGHT. We can set these outside of the script in the AutoCAD command line before running the script, and that will work. However, it's safer to assign default values ​​to these variables in the script if they don't already exist. This is done with these three lines of Lisp code at the beginning of the script:
(if (not WIDTH) (setq WIDTH 60))
(if (not HEIGHT) (setq HEIGHT 80))
(if (not ORIGIN) (setq ORIGIN '(0 0 0))


We can now run this script in AutoCAD, as the CAL command used in the script is available in AutoCAD via GeomCAL. In BricsCAD, you need CADCAL, which is included as a standard component in your CADCAL+CALSCRIPT installation.

We can therefore specify the variables in the CAD system's command prompt:
command: (setq origin (getpoint "\ninsertion point: "))
command: (setq width 120)
command: (setq height 80)

and so we can execute the script file with the standard _SCRIPT command of AutoCAD or BricsCAD:
command: _SCRIPT
We select the generated script file and the polyline is created.

 Yes, we can use this script already with CALSCRIPT. Simply enter the command
CC-SCRIPT, and select the very same script file. Now you will be asked for an insertion point and an angle, and then an object will be created. Note that we don't be asked for the properties WIDTH and HEIGHT, and please know that this script only works, because we already have used the variable name ORIGIN in the script. This variable name is used in a CALSCRIPT script to draw the object relativ to this point. The properties WIDTH and HEIGHT are set to the default values which we have defined inside the script.

Now when we define the variable WIDTH outside the object, i.e. enter (setq WIDTH 120) at the command prompt, we can redraw (command
CC-REDRAW) the object which has been created by the CC-SCRIPT command. And, isn't this magic? The object will be redrawn with a width of 120. And we can make copies of that object, and we can give each single copy different values for WIDTH and HEIGHT, be simply defining the values before we CC-REDRAW an object.

So indeed a CALSCRIPT script is nothing else than an ordinary script file, which could be used with the standard SCRIPT command as well.


The CC-PROPERTIES declaration

Now, how can we modify the properties of an object without the need to define that properties outside the script? This is simply done by a single line in the script itself: At the beginning of the script we add the line
CC-PROPERTIES WIDTH,60,HEIGHT,80
That's all. The CC-PROPERTIES declaration defines the properties and their default values, Property names must not contain empty space, and each property name must have a default value, which is separated from the name by a comma. Any number of pairs of <name>,<default value> is allowed, separated by a comma from each other.

Now after we have added the CC-PROPERTIES declaration to the script, we can again execute the script by entefring CC-SCRIPT at the command prompt. And this time we are also asked for new values for WIDTH and HEIGHT. The newly created object now can modified with the CC-MODIFY command.

So this is all we need to do to create smart CALSCRIPT objects. After we have created a single CALSCRIPT object, we don't need the script anymore. Each copy of the script can be copied inside a DWG file or to another DWG file, and the user can give away a dwg file with CALSCRIPT objects, and the receiver only needs CADCAL+CALSCRIPT to edit the object's properties according to his needs.

The CC-SET-NAME declaration

There are other CALSCRIPT declarations which can make an object even smarter. The simpliest is to give the object a name with the declaration
CC-SET-NAME ANYNAME
This declaration does not much at the moment, but to attach XDATA under the name. This enables a programmer to select and filter objects with that name.

The CC-OVERWRITE declaration

Much more effect is done by the declaration CC-OVERWRITE. This is only valid when the user has defined a communication between objects with the CC-CONNECT command. The CC-OVERWRITE declaration must be followed by a list of variable names, which represent properties of the master object. The slave's properties will be overwritten by the properties of the master.
CC-OVERWRITE WIDTH,COLOR
This declaration has the effect that the slave objects will get the same property WIDTH as the master, and the same color as the master. As you see, not only the extra properties WIDTH and HEIGHT can be overwritten, but also ORIGIN, ROTATION, LAYER, COLOR, LINETYPE etc., and even OCS (the object coordinate system).

However, very often we don't want to overwrite an objects property by the master's property. When with established object communication an object's ORIGIN should be derived from the master's origin, but not be the same, then we can use variables that start with the name "MASTER:" followed by the property name. Since these variables only have values when there is a communication from a master, we need to integrate these variables with LISP using a IF construction. This is i.e. done in the NICKSHOUSE.SCR in the demo directory:
(if master:width (cal "self:origin=master:origin+[master:width,0,0]"))
In this case the variable SELF:ORIGIN of an object is calculated by the master's origin plus a vector with the master's WIDTH in x-direction only when there is a MASTER:WIDTH.

To reflect the fact that the lower right corner of a NICKSHOUSE object also depends on the rotation of that object, the SELF:ORIGIN is also calculated with the next line
(if master:rotation (cal "self:origin=rot(self:origin,master:origin,r2d(master:rotation))"))
With these both lines we can set the origin of a nickshouse object to the lower right corner of the master object, when a communication between two nickshouse objects is established. For the details of the math expressions used here please see this page.

The CC-EXPORT declaration

With the CC-EXPORT declaration an object can make it's internal variables accessible by other objects or by any program. The syntax is the very same as the CC-OVERWRITE declaration: simply write the list of variable names of the inside calculations of an object, separated by a comma from each other. The sample script BOOKCASE.SCR, which draws a 3D model of a bookcase, exports the material list which is needed to make a real bookcase. The exported values will be asccesible as XDATA.

The demo script BOOKCASE.SCR has the CC-ECPORT declaration
CC-ECPORT SIDES,PLINTH,SHELVES,TOP
The variables SIDES, PLINTH, SHELVES and TOP are defined within the object itself. It is important to know that it is irrelevant where inside the script the CC-EXPORT declaration is located. The exported values always show the value of the variable which is calulated at last.
To get access to the exported values you need to extract the XDATA from the object. This is done with the command CC-GET-EXPORTDATA
When you enter that command at the command prompt, you will receive the export data of a bookshelf object:
CC-GET-EXPORTDATA
((SIDES (2 400 1980.0 40)) (PLINTH (1 720.0 375.0 70)) (SHELVES (5 720.0 375.0 21)) (TOP (1 800 400 40)))
This means that this special bookcase object is made of 2 side elements, each 400x1980x40, 1 plinth element 720x375x70, 5 shelves 720x375x21 and a top element 800x400x40.

For programers the access to the export data is enabled by a Lisp function
(XDATA-GET <object-ename> "CALSCRIPT")
In case of the bookcase sample we i.e. get this data:
(setq data (xdata-get (car (entsel)) "CALSCRIPT"))
Select entity:
((DATA ((WIDTH 800) (DEPTH 400) (HEIGHT 2020))) (OBJECTNAME "BOOKCASE") (CALSCRIPT:VERSION "1.0 - 2025 June 12") (SCRIPTMODE "COMPILED") (COMPILATIONDATE "20250615.09244356") (BLOCKMAKEDATE "20250615.09244541") (EXPORT ((SIDES (2 400 1980.0 40)) (PLINTH (1 720.0 375.0 70)) (SHELVES (5 720.0 375.0 21)) (TOP (1 800 400 40)))))

The export data can be get via
(cadr (assoc 'EXPORT data))

The exported values can be used in object communication too. The variable MASTER:EXPORT contains the value of the master's export declaration and makes that accessible to a slave object. When i.e. a PLINTH object would be defined too, it could access the export data of a bookshelf object via object communication and use that to draw the plinth alone. There could be different plinth objects of different materials and material thickness, and these plinth objects could also export their individual material lists.


Rules for CALSCRIPT scripts

You can use any ordinary script file with CALSCRIPT, with one exception: script commands, CAL expressions and Lisp expressions must each be written in one single line of the script. CALSCRIPT does not yet support multi-line expressions.


CALSCRIPT commands

There are some CALSCRIPT commands to create and manipulate CALSCRIPT objects and their behaviour. All these commands are accessible either over the keyboard and the command line, or via the CALSCRIPT toolbar. All these commands can be undone via the "_U" command.


CC-SCRIPT
reads a script file and creates a CALSCRIPT object based on that script

CC-REDRAW
redraws a CALSCRIPT object. If that object is master to other objects, these will be redrawn too

CC-MODIFY
modifies the properties of a CALSCRIPT object. If that object is master to other objects, these will be redrawn too and react accordingly to the master's new properties.

CC-INFO
gives information about the selected object.

CC-CONNECT
establishes a communication channel between a master object and (almost) any number of slave objects. A slave can have only one single master, a master can have almost any number of slaves. A slave object can be master to other objects. The number of slaves of a master object is restricted by the memory that is accessible by XDATA. In the CALSCRIPT.INI file the maximum number of slaves under the control of one single master is defined, default value is 100.

It is possible to create circular communication channels, i.e. that the last object in a communication chain is defined as a master to the first object of that chain. In some cases such a circular communication chains is desired. To avoid endless loops which could only be stopped by killing the CAD program via task manager, CALSCRIPT defines a maximum number of communication events in a chain. This value is set in the CALSCRIPT.INI file, the default is 200 events. When the maximum is reached then the communication chain will stopp.

When an object is copied, the copy will automatically be completely disconnected. When a slave is erased, the master's list of slaves will be corrected automatically, and when a master object is erased, all it's slaves will become independend objects. UNDOing the ERASE command will automatically restore the object communication. The master and the slaves of an object can be seen with the
CC-INFO command, or in the object's XDATA-List:
(xdata-get <object's ename> "CALSCRIPT")

CC-DISCONNECT
Disconnects a single CALSCRIPT object completely. It will be independend from a former master, and will not control any slaves anymore. The slave objects become independend objects.

CC-DISCONNECT-MASTER
Disconnects a single master object from all it's slaves. The slaves become independend objects. The disconnected master can still be a slave to another master.

CC-DISCONNECT-SLAVE
Disconnects a single slave from it's master. The user must show a slave object to be disconnected. The former slave object becomes an independend object. The slaves of that object will remain it's slaves.

CC-COMPILESCRIPT

This command is for the Lisp programmers among the users, and for those, who want to learn Lisp programming. The user is asked to show a script file that he wants to be translated to Lisp, and the Lisp file to store that Lisp function.
You need to know that CALSCRIPT always translates scripts to Lisp, and that internally it always uses only this Lisp function. As a programmer you can use this translated scripts just as you use any other Lisp functions. You can integrate this Lisp code into your own Lisp applications, and give that away without paying royalties or license fees. The user has the only copyright on the scripts he created, and as well on the Lisp code which is made from that script.

For the nerds: it is possible to extract the Lisp function that is stored with each object. Since this Lisp function may need more memory than XDATA can hold, this Lisp is stored as a XDICTIONARY (a XRECORD object) with the object itself. You can access it via Lisp this way:
(cadr (assoc "LAMBDA"(XDICTIONARY-GET <object's ename> "CALSCRIPT")))
But you need to know that this function is not directly usable as the compiled function via the CC-COMPILESCRIPT command. To be able to store the Lisp function as XDICTIONARY to an object, the Lisp function needs to know what itself is. But a function doesn't normally know from it's inside, how it is defined. The CC-COMPLIESCRIPT command stores the Lisp function to itself under the variable name SELF:LAMBDA. To keep the memory usage of an object as small as possible, only the LAMBDA itself is stored in the XDICTIONARY.
The reason why the ASSOC expression is stored as a string "LAMBDA" and not the symbol 'LAMBDA is, that BricsCAD internally uses a not commonly used LAMBDA construction and will automatically replace the 'LAMBDA by the internally defined 'INTERNAL_LAMBDA when it is stored as a XDICTIONARY.

For more information about the relation between CALSCRIPT and Lisp, the creation and manipulation of CALSCRIPT objects via Lisp, or integration of CALSCRIPT objects into your own Lisp applications please see the page cc-lisp.html.
 




 

     
  (c) 2025 Tom Berger
Feriendorfstraße 6c, D-34308 Bad Emstal, Germany
berger@archtools.de