In this post, we look at the most powerful method available to "non-programmers" for customizing BricsCAD --- the LISP programming language. In this post learn how to use LISP in BricsCAD with a practical example plus there is an overview of LISP functions at the bottom of the page.
While toolbar and menu macros are easy to write and edit, they limit your ability to control BricsCAD.
For a full overview of LISP commands for BricsCAD, you can view the official, BricsCAD LISP Developer Guide.
LISP IN COMMANDS
Okay, so let's look at how to use LISP code for a practical purpose. For example, you may need to draw a linear array of seven circles to fit in a 9" space.
Start the Circle command, as follows:
: circle
2Point/3Point/RadTanTan/Arc/Multiple/ : (Pick a point.)Instead of typing the value for the diameter, enter the LISP equation, as follows:
Diameter/: (/ 9.0 7)
Diameter/: 1.28571BricsCAD draws a circle with a diameter of 1.28571 inches. You can use an appropriate LISP function anytime BricsCAD expects user input.
Now go on to the Array command, and draw the other six circles, as follows:
: array
Select entities to array: L
Entities in set: 1 Select entities to array: (Press enter.)
Type of array: Polar/: r
Number of rows in the array <1>: (Press enter.)
Number of columns <1>: 7
Horizontal distance between columns: (/ 0.9 7)
Horizontal distance between columns: 0.128571Once again, you use LISP to specify the array spacing, which happens to equal the circle diameter.
REMEMBERING THE RESULT: SETQ
In the above example, you used the (/ 9.0 7) equation twice: once in the Circle command and again in Array. Just as the M-key on a calculator lets it remember the result of your calculation, LISP can be made to remember the results of all your calculations.
To do this, employ the most common LISP function, known as setq. This curiously named function
is short for SET eQual to.
To save the result of a calculation, use the setq function together with a variable, as follows:
: (setq x (/ 9.0 7))
1.28571
:Here, x remembers the result of the (/ 9.0 7.0) calculation. Notice the extra set of parentheses. From algebra class, you probably recall equations like 'x = 7 + 9' and 'x = 7 / 9'. The x is known as a variable because it can have any value.
To prove to yourself that x contains the value of 1.28571, use BricsCAD's ! (exclamation) prefix, as follows:
: !x
1.28571
:The ! prefix (sometimes called "bang") is useful for reminding yourself of the value contained by a variable, in case you've forgotten, or are wondering what happened during the calculation.
LISP isn't limited to just one variable. You can make up any combination of characters to create variable names, such as pt1, diameter, and yvalue. The only limitation is that you cannot use LISP function names, such as setq, T, and getint. In fact, it is good to create variable names that reflect the content, such as the circle diameter calculated above. But you also want to balance a descriptive name, such as diameter, with minimized typing, such as x. A good compromise is dia.You make one variable equal another, as follows:
: (setq dia x)
1.28571: !dia
1.28571
:Redo the Circle and Array commands, this time using variable dia, as follows:
: circle
2Point/3Point/RadTanTan/Arc/Multiple/: (Pick a point.)
Diameter/:<Radius >
!dia
Diameter/:<Radius >
1.28571
: array
Select entities to array: L
Entities in set: 1 Select entities to array: (Press enter.)
Type of array: Polar/: r
Number of rows in the array <1>: (Press enter.)
Number of columns <1>: 7
Horizontal distance between columns: !dia
Horizontal distance between columns: 0.128571BricsCAD draws precisely the same seven circles, using the value 1.28571 stored in dia.
LISP Function Overview
LISP is so powerful that it can manipulate almost any aspect of the BricsCAD drawing. In the following tutorial, you get a taste of the many different kinds of functions LISP offers you for manipulating numbers and words. As we start on our whirlwind tour of several groups of LISP functions, start BricsCAD, and then type the examples in the Prompt History window (press F2) at the ':' command prompt.
MATH FUNCTIONS
In addition to the four basic arithmetic functions, LISP has many of the mathematical functions you might expect in a programming language. The list includes trigonometric, logarithmic, logical, and bit manipulation functions; one type of function missing is matrix manipulation.
For example, the min function returns the smallest (minimum) of a list of numbers:
: (min 7 3 5 11)
3
To remember the result of this function, add setq with variable minnbr, as follows:
: (setq minnbr (min 7 3 5 11))
3
Now each time you want to refer to the minimum value of that series of numbers, you can refer to variable minnbr. Here's an example of a trig function, sine:
: (sin minnbr)
0.14112
Returns the sine of the angle of 3 radians.
TIP You must provide the angle in radians, not degrees. This is many times an inconvenience, because often you work with degrees, but must convert them to radians.
Fortunately, LISP can do this for you, as long as you code it correctly. Recall that there are 2*
pi (approximately 6.282) radians in 360 degrees. For example, to get the sine of 45 degrees, you have to indulge in some fancy footwork:
: (sin (* (/ 45 180.0) pi))
0.707107
Here I divided the degrees (45) by 180, then multiplied by pi. Either the 45 or the 180 needs a decimal ( .0 ) to force division by real numbers, rather than by integers.
By the way, pi is the only constant predefined in LISP, and is equal to 3.1415926. That means you just type pi, instead of 3.1415926 each time you need the value of pi in a function. To see this for yourself, use the exclamation mark at the command prompt:
: !pi
3.14159
LISP displays the result to six decimal places, even though it performs calculations to 32-bit accuracy.
GEOMETRIC FUNCTIONS
Since CAD deals with geometry, LISP has a number of functions for dealing with geometry.
Distance Between Two Points
The LISP distance function is similar to BricsCAD's Dist command: it returns the 3D distance between two points. To see how it works, first assign x,y-coordinates to a pair of points, p1 and p2, as follows:
: (setq p1 '(1.3 5.7)) (1.3 5.7)
: (setq p2 '(7.5 3.1 11)) (7.5 3.1 11)
: (distance p1 p2) 6.72309
You may have missed that single quote mark in front of the list of x,y-coordinates, as in: '(1.3 5.7). That tells LISP you are creating a pair (or triple in the case of x,y,z) of coordinates, and that it should not evaluate the numbers. Technically, the ' mark creates a list of numbers.
To separate the coordinates use spaces, not commas. Note that when you leave out the z-coordinate, LISP assumes it equals 0.0000.
The Angle from 0 Degrees
Other geometric functions of interest include finding the angle from 0 degrees (usually pointing east) to the line defined by p1 and p2:
: (angle p1 p2)
5.88611
The result is returned in radians: 5.88611.
The Intersection of Two Lines
The intersection of two lines is determined by the inters function:
: (inters pt1 pt2 pt3 pt4)
Entity Snaps
In the following function, you are finding the midpoint of the line that starts at p1. You apply the osnap function and specify the type of osnap; LISP returns the x,y,z-coordinates of the entity snap point. The entity must actually exist.
: line
From point: !p1
To point: !p2
To point: (Press enter.)
: (osnap p1 "mid")
(4.4 4.4 5.5)
Here "mid" refers to the midpoint entity snap mode.
The other geometric functions include textbox (for finding the rectangular outline of a line of text) and Polar, which returns a 3D point of a specified distance and angle.
CONDITIONAL FUNCTIONS
You could say that conditional functions are most important, because they define the existence of a programming language. It is conditionals that allow a computer program to "think" and make decisions. Conditional functions check if one value is less than, equal to, or greater than another value. They check if something is true; or they repeat an action until something is false.
If you're not sure if it's a programming language or merely a macro language, check for conditionals.
Toolbar macros, for example, have no conditionals; they are not a programming language.
Here is an example of how conditional functions operate: if the floor-to-ceiling distance is greater than eight feet, then draw 14 steps; else, draw 13 steps. Notice that there are two parts to the statement: the if part is the true part; the else part is the false part. Do something if it is true; otherwise, so something else if it is false.
Similar wording is used in LISP's condition functions. Enter the following at the ':' prompt:
: (if (> height 96) (setq steps 14) (setq steps 13)) 13
Let's break down this code to see how the if function compares with our statement:
(if | If |
---|---|
(> | greater than |
height | floor-to-ceiling distance is |
96) | 8 feet; |
Then | |
(setq steps 14) | use 14 steps. |
Else | |
(setq steps 13) | use 13 steps. |
) |
Other Conditionals
The if function is limited to evaluating just one conditional. The cond functions evaluate many conditions. The repeat function executes a specific number of times, while the while function executes code for as long as it is true.
STRING AND CONVERSION FUNCTIONS
You can manipulate strings (text consisting of one or more characters) in LISP, but to a lesser extent than numbers. For example, you can find the length of a string as follows:
: (strlen "BricsCAD World")
16
The strlen (short for STRing LENgth) function tells you that "BricsCAD World" has 16 characters in it, counting the space. Notice how "BricsCAD World" is surrounded by quotation marks. That tells LISP you are working with a string, not a variable.
If you were to type (strlen BricsCAD World), LISP tries to find the length of the strings held by variables BricsCAD and World. For example:
: (setq BricsCAD "A software package") "A software package"
: (setq world "the planet earth")
"the planet earth"
: (strlen BricsCAD world)
34
Joining Strings of Text
Other string functions change all characters to upper or lower case (strcase), returns part of a string (substr), searches and replaces text in a string (subst) and joins two strings together (strcat), as follows:
: (strcat BricsCAD " used all over " world)
"A software package used all over the planet earth"
That's how you create reports, such as "13 steps drawn", by mixing variables and text.
Converting Between Text and Numbers
Related to string functions are the conversion functions, because some of them convert to and from strings. For example, earlier I showed how to convert degrees to radians. That's fine for decimal degrees, like 45.3711 degrees. But how do you convert 45 degrees, 37 minutes and 11 seconds, which BricsCAD represents as 45d37'11"? That's where a conversion function like angtof (short for ANGle TO Floating-point) comes in. It converts an angle string to real-number radians:
: (angtof "45d37'11"" 1)
0.796214
Here we've supplied angtof with the angle in degrees-minutes-seconds format. However, LISP isn't smart enough to know, so we tell it by means of the mode number, 1 in this case.
This (and some other functions) use the following as mode codes:
Mode | Meaning | Example |
---|---|---|
0 | Decimal degrees | 45.3711 |
1 | Degrees-minutes-seconds | 45d 37′ 11″ |
2 | Grad | 100.1234 |
3 | Radian | 0.3964 |
4 | Surveyor Units | N 45d37’11″E |
Notice the similarity between the mode numbers and the values of system variable AUnits --- and the modes used by Diesel. The coincidence is no accident. When you don't know ahead of time the current setting of units, you make use of this fact by specifying the mode number as a variable, as follows:
: (angtof "45d37'11"" (getvar "aunits"))
0.796214
Here we use getvar (short for GET VARiable), the LISP function that gets the value of a system variable. We used getvar to get aunits, which holds the state of angular display as set by the Units command.
Notice how the seconds indicator ( " ) is handled: ". That's so it doesn't get confused with the closing quote mark ( " ) that indicates the end of the string.
Other Conversion Functions
Other conversion functions convert one unit of measurement into another (via the cvunit function and the default.unt file), an integer number into a string (itos), a character into its ASCII value (ascii: for example, letter A into ASCII value 65), and translates (moves) a point from one coordinate system to another (trans).
The default.unt file is found in the C:\Users*<login>
\AppData\Roaming\Bricsys\BricsCAD\V20\ en_US\Support* folder.
EXTERNAL COMMAND FUNCTIONS
"Powerful" often equates to "complicated," yet one of LISP's most powerful functions is its simplest to understand: the command function. As its name suggests, command executes BricsCAD commands from within LISP.
Think about it: this means that it is trivial to get LISP to draw a circle, place text, zoom a viewport, whatever. Anything you type at the ':' command prompt is available with the command function. Let's see how command works by drawing a circle. First, though, let's recall how the Circle command operates:
: circle
2Point/3Point/RadTanTan/Arc/Multiple/<Center of circle>
: 2,2
Diameter/<Radius>
: D
Diameter of circle: 1.5
Switching to the command function, you mimic what you type at the ':' prompt, as follows.
: (command "circle" "2,2" "D" "1.5")
Notice how all typed text is in quotation marks. After you enter that line of code, BricsCAD responds by drawing the circle:
: circle
2Point/3Point/RadTanTan/Arc/Multiple/<Center of circle>
: 2,2
Diameter/<Radius>
<1.2857>: D
Diameter of circle <2.5714>: 1.5
Let's look at one of the more complex commands to use with the command function, Text. When we use the Text command, BricsCAD presents these prompts:
: text
Text: Style/Align/Fit/Center/Middle/Right/Justify/<Start point>
: 5,10
Height of text <0.2000>: 1.5
Rotation angle of text <0>: (Press enter.) Text: Tailoring BricsCAD
Converted to LISP-ese, this becomes:
:(command "text" "5,10" "1.5" "" "Tailoring BricsCAD")
And BricsCAD responds with:
: text
Text: Style/Align/Fit/Center/Middle/Right/Justify/<Start point>
: 5,10 Height of text <1.5000>: 1.5 Rotation angle of text <0>: Text: Tailoring BricsCAD and then draws the text.
For the 'Rotation angle:' prompt, we simply pressed the enter key. Notice how that is dealt with in the LISP function: "" --- a pair of empty quotation marks.
You use the same "" to end commands that automatically repeat themselves, such as the Line command:
: (command "line" "1,2" "3,4" "")
When you don't include that final "", then you leave BricsCAD hanging with a 'End point:' prompt and your LISP routine fails.
By now it should be clear to you that you have to really know the prompt sequence of BricsCAD's 100s commands to work effectively with the command function. The easiest way to get a handle on those is to purchase one of the "quick reference" books on the market, which list commands in alphabetical order, along with the complete prompt sequence. And, as we see in a minute, check that the quick reference book has a listing of all system variables, their default value, and the range of permissible values.
Alternatively, check the BricsCAD Help center.
Command Function Limitation
But the command function has a failing. Earlier, I said, "Anything you type at the ':' command prompt is available with the command function." I now place emphasis on the word "type." The command function breaks down completely when it comes to dialog boxes. That's right: any command that uses a dialog box won't work with the command function --- nor, for that matter, with the macros we looked at in previous posts. It is for this reason that BricsCAD includes command-line versions of almost every (but not all) command.
Accessing System Variables
While you can use the command function to access system variables, LISP has a pair of more direct functions: getvar and setvar.
Getvar gets the value of a system variable, while setvar changes (sets) the value.
For example, system variable SplFrame determines whether the frame of a spline polyline is displayed; by default, the value of SplFrame is 0: the frame is not displayed, as confirmed by getvar:
: (getvar "splframe")
0
To display the frame, change the value of SplFrame to 1 with setvar as follows:
: (setvar "splframe" 1)
1
We have, however, made a crass assumption: that the initial value of SplFrame is 0. Zero is the default value, but not necessarily the value at the time that you run the LISP routine. How do we know what the value of SplFrame is before we change it? We'll answer that question later. Stay tuned.
GETXXX FUNCTIONS
It's one thing to execute a command that draws a new entity, such as the circle and text we drew above with the command function. It is trickier working with entities that already exist, such as moving that circle or editing the text. That's where the a group of functions known collectively as Getxxx comes into play. These functions get data from the screen. Some of the more useful ones include:
getpoint -- Returns the x,y,z-coordinate of a picked point.
getangle -- Returns the angle in radians.
getstring -- Returns the text typed by the user.
getreal -- Returns the value of a real number typed by the user.
Here's how to use some of these with the Text command. Let's redo the code with getstring so
that LISP prompts us for everything first, then executes the Text command. Here is the first line of
code, which prompts the user to input some text:
: (setq TxtStr (getstring T "What do you want to write? "))
What do you want to write?
Notice that extra "T"; that's a workaround that lets getstring accept a string of text with spaces. When you leave out the T, then getstring accepts text up to the first space only, If you were to enter "Tailoring BricsCAD", you would end up with just "Tailoring" and no "BricsCAD."
Also in the line of code above, the setq function stores the phrase, such as "Tailoring BricsCAD," in the variable TxtStr.
In the next line of code, we use the getreal function to ask for the height of text, which is a real number (decimal) entered by the user.
: (setq TxtHt (getreal "How big do you want the letters? "))
How big do you want the letters? 2
2.0
Notice how getreal converts the 2 (an integer) to a real number, 2.0. The value is stored in variable TxtHt.
Next, we use the getangle function to ask for the rotation angle of the text:
: (setq TxtAng (getangle "Tilt the text by how much? "))
Tilt the text by how much? 30
0.523599
Notice how getangle converts the 30 (a decimal degree) into radians, 0.523599. The value is stored in variable TxtAng.
Then, we use the getpoint function to ask the user for the insertion point of the text:
: (setq TxtIns (getpoint "Where do you want the text to start? "))
Where do you want the text to start? (Pick a point.)(27.8068 4.9825 0.0)
Notice how getpoint returns the x, y, and z values of the coordinate, even though z is zero. The user can pick a point on the screen, or enter a coordinate pair (x,y) or triple (x,y,z).
Finally, we execute the Text command with the four variables:
: (command "text" TxtIns TxtHt TxtAng TxtStr) text Justify/Style:
Height <1.5000>: 2.000000000000000
Rotation angle <0>: 0.523598775598299
Text: Tailoring BricsCAD
: nil
There! We've just customized the Text command to our liking. Not only did we change the prompts that the user sees, but we used LISP to change the order of the prompts.
SELECTION SET FUNCTIONS
To work with more than one entity at a time, LISP has a group of functions for creating selection sets. These all begin with "SS", as in:
- SsAdd Adds entities to selection sets.
- SsDel Deletes entities from selection sets.
- SsGetFirst Reports the number of selected entities.
- SsLength Reports the number of entities in the selection set.
- SsMemb Checks if entities are part of a selection set.
- SsName Identifies the nth entity in a selection set.
- SsSetFirst Highlights objects in a selection set.
BricsCAD's Select command can deal only with one selection set at a time; in contrast, the LISP SSxxx commands can work with up to 128 selection sets.
ENTITY MANIPULATION FUNCTIONS
The really powerful LISP functions are the ones that go right in and manipulate the drawing database. Unlike the command function, which is powerful but simple, the entity manipulation functions are powerful and complicated. Here's a summary of what some of these are:
- EntMake Creates new entities.
- EntGet Gets the data that describes entities in drawings.
- EntMod Changes entities.
- EntDel Erases entities from the database.
- TblObjName Gets the names of entities in symbol tables.
The "Ent" prefix is short for entity. The "symbol table" refers to the part of the drawing database that stores the names of layers, text styles, and other named entities in the drawing.
To create and manipulate entities, these LISP functions work with a variant on the DXF format, known as "dotted pairs." For example, to work with a layer named RightOfWay, you employ the following format:
"2 . RightOfWay"
The quotation marks indicate the start and end of the data, while the dot in the middle separates the two values: The 2 is the DXF code for layer names, and RightOfWay is the name of the layer. You can see that to work with these entity manipulation functions, you need a good grasp of the DXF format.
ADVANCED LISP FUNCTIONS
There is a whole host of LISP functions that you may never use in your BricsCAD programming career. For example, there are LISP functions for controlling the memory, such as gc (garbage collection) and mem (memory status). Another set of LISP functions are strictly for loading and displaying dialog boxes, such as load_dialog and new_dialog.
Download BricsCAD free for 30-days
Start Using BricsCAD Today
Permanent or subscription licenses that work in all languages, in all regions.
- Introduction
- 55 Tips for BricsCAD Users
- Settings
- Changing the Environment
- Custom User Interface
- Introduction to the Customize Dialog Box
- Customize the Menu Bar & Context Menus
- Toolbars and Button Icons
- Writing Macros and Diesel Code
- Ribbon Tabs and Panels
- Keystroke Shortcuts, Aliases & Shell Commands
- Mouse, Double-click & Tablet Buttons
- Absolutely Everything You Need to Know About The Quad
- Rollover Properties
- Workspaces and the User Interface
- Designing Tool & Structure Panels
- Creating Simple & Complex Linetypes
- Patterning Hatches
- Decoding Shapes & Fonts
- Coding with Field Text
- Writing Scripts
- Programming with LISP (Introduction)
- LISP Functions