Home           About           Downloads

QtCSG - Constructive Solid Geometry scripted from ECL

This project is the same as the earlier project, QtImagine except this also features an implementation of "Constructive Solid Geometry" operations that can be performed on 3D models such as difference, union and intersection. The algorithm for performing these operations comes from the UnBBoolean (http://unbboolean.sourceforge.net/) Java CSG implementation.

See the files csg-test.lisp, csg-test2.lisp and csg-test3.lisp for examples on how to use these features. To run them, note that they need to be loaded in order - first csg-test.lisp, then csg-test2.lisp, then finally csg-test3.lisp, since they reference objects that were created by earlier scripts.

Similarly, see init.lisp and live-render.lisp for a live rendering example script.

QtImagine - a skeleton project for live coding using ECL

QtImagine has been updated!

In the process of releasing QtLuaImagine, I cleaned up the code for QtImagine. All lisp code is now run through a (handler-bind) block so that error messages can be captured. What this means is that error messages are displayed in the main window, so no more need to flip between the console and the main window when an error occurs. Also, grey streams have been used to redirect trace output to the main window as well.

This project demonstrates the use of ECL in a Qt project to enable a 3D "live coding" environment.

The system calls the lisp functions (update) and (render) to update and render the frame respectively. These functions can be redefined at runtime at the REPL.

When QtImagine first starts, click the "Execute" button to load an example lisp source file containing example definitions of (update) and (render) which will produce a simple animation. Then, load the source file into your favourite text editor, make some changes, then load your freshly edited source file from the REPL by issuing the load command (load "live-render.lisp") to see the effect of your change instantly. Of course, you can also enter expressions and definitions at the REPL itself. The REPL features a command history.

Scripting simulations with ECL

I've been adding to the program mentioned in a previous post. The circuit simulator and origami crease pattern editor are drivable from the lisp repl, and the verlet physics based paper simulator has been implemented and is manipulated from the repl.

Also, the repl itself features command history.

Here is the list of functions currently available from the repl:


Initialises origami crease editor with a plain sheet of paper consisting of 1 four sided facet.

Clears the origami crease editor.

Takes 4 parameters (x1 y1 x2 y2) representing the 2 endpoints of a crease line.

Takes 2 vertex ids (nodeA nodeB) and uses them as the 2 endpoints of a crease line.

Takes 2 vertex ids (nodeA nodeB) and forms the crease from "folding" one vertex on the other. The crease line is the perpendicular bisector.

Takes 4 vertex ids (l1v1 l1v2 l2v1 l2v2) to describe the endpoints of 2 lines, and forms the crease from "folding" one line onto the other.

Takes 3 vertex ids (nodeF nodeA nodeB) and attempts to fold nodeF around the (nodeA nodeB) line by finding its mirror on the other side. It does the same with connected vertices as necessary.

Makes a verlet physics representation of the current crease pattern, so it can be manipulated in the verlet physics environment.


Takes 1 vertex id, and fixes that node in space.

Takes 1 vertex id, and frees that node if it was fixed.

Removes all position constraints

Takes 4 parameters (nodeF nodeA nodeB angle) and rotates nodeF around the axis defined by nodeA and nodeB using the angle parameter. As the system resolves this attempt to do this rotation, you'll see whether the system currently permits or rejects such a motion.

Returns the number of nodes.

Returns the number of struts.

Not implemented - will show the given node id.

Not implemented - will hide the given node id.

Not implemented - will show all node ids.

Not implemented - will hide all node ids.

Not implemented - will add a folding strut, which is the same as the crease struts, but is marked as a folding strut, because it can be removed when a given fold is completed.

Not implemented - will add a structural strut manually. For facets containing more than 3 edges, structural struts are necessary to keep those facets flat. For the crane model, all facets are triangular, so this isn't necessary yet.

Not implemented - will remove all folding struts.

Not implemented - will remove all structural struts.

Not implemented - will automatically add structural struts where needed for facets containing more than 3 edges.

Not implemented - will allow the user to manually invoke the verlet constraint resolver, rather than having it run all the time.


Takes 2 parameters (x y) and adds a new node at that location.

Takes 3 parameters (nodeA nodeB resistance) and creates a resistor connecting nodeA and nodeB using the resistance parameter.

Takes 3 parameters (nodeA nodeB voltage) and creates a voltage source connecting nodeA and nodeB using the voltage parameter.

Takes 3 parameters (nodeA nodeB voltage) and creates a current source connecting nodeA and nodeB using the current parameter.

Takes 3 parameters (component x y) and adds a tween vertex on one side of the component. For circuit rendering purposes.

Takes 3 parameters (component x y) and adds a tween vertex on one side of the component. For circuit rendering purposes.

Automatically finds the loops in the circuit. It is necessary to call this once modifications to the circuit are complete for the circuit to be simulated correctly.

Clears the current circuit.

Turns on the animated rendering of the current.

Turns on rendering of the components.

Turns on rendering of the nodes.

Turns on rendering of the loops.

Turns off the animated rendering of the current.

Turns off rendering of the components.

Turns off rendering of the nodes.

Turns off rendering of the loops.

Takes 3 parameters (componentID nodeFrom nodeTo) and disconnects the component from nodeFrom and connects it to nodeTo.

Takes a componentID as a parameter and deletes it.

Takes a nodeID as a parameters and deletes it if there is nothing connected to it.


Turn on live rendering

Turn off live rendering

Takes 6 parameters (x1 y1 z1 x2 y2 z2) that describe a 3D line, and renders it. This can only be called from within the paper-render function. Redefine the paper-render function at will at runtime.


Takes 2 parameters and adds them

Takes a list and adds the numbers in the list.


Press "Execute" when the program starts to load the script which computes the crane crease pattern:

Having a look at the crease pattern in the pattern editor:

Verlet physics paper manipulation and live rendering: Calling verlet-rotate from the repl to rotate the 4 corner vertices at once, 0.1 degrees at a time (the rotation continues due to momentum), then calling ogl-renderon to turn on live rendering, and modifying the paper-render function live by loading live-render.lisp (the function simul-rotate has been defined for convenience to do the simultaneous rotation):

Circuit simulator: Switching to the circuit simulator and loading a circuit (block-circuit.lisp):

Loading the scripts "block-circuit2.lisp" and "block-circuit3.lisp" to modify the circuit:

Embedding a Lisp interpreter into a Qt app

I've been working on a few things these past few months. This includes:
  • A crease pattern generator that can calculate the crease pattern a piece of paper will have based on the sequence of folds applied to it. Conceptualising the paper as a mesh of facets, and determining the operations that can be performed on facets such as splitting was the key to implementing this.
  • A circuit simulator that uses an iterative process to solve the circuit. Since Verlet physics is very successful at applying physical constraints (such as ensuring a point mass is fixed in space, or ensuring two point masses are always a fixed distance apart) using little more than repeatedly pushing objects according to the pressure that each constraint is applying, I thought I would try the same idea with electric circuits and the pressures of KVL and KCL.
When I managed to embed a Lisp interpreter into my app using ECL, I decided this is a suitable thing to tell other people about.
The advantages of scripting using Lisp in this way are numerous and exciting:
  • Its an excellent way to ease into the beauty of Lisp without abandoning my other work.
  • Initially, I can create Lisp bindings that manipulate the interface of the simulation such as adding components to the circuit, or applying specific folds. Doing this, I get loading/saving functionality for free, because my circuit/origami folds/other simulation configuration are defined in a lisp script. Also, I can manipulate my simulation “live” in the lisp repl while the simulation is running.
  • Gradually, I can transfer more and more of the simulation implementation to lisp. Doing so, I can enjoy a real “live coding” environment. I have fluxus to thank for the inspiration.
  • Lisp is a magnificent programming language. Having a Lisp repl in my app means I get a beautiful customisable programming language allowing me to describe a DSL without having to write a single line of parsing code.
The possibilities having a Lisp running in your app are breathtaking. In the past, the only thing that kept me from writing my own language to control my simulations was the mind numbing drudgery of writing parsers. Now, I get all the advantages of a custom language completely for free!
The “Lisp” tab is initially active. It features the Lisp REPL. The only C++ function it is hooked to is myadd – not very exciting from the user's point of view, but VERY exciting for me, since it shows that I can have lisp control the whole show!
Non lisp stuff (will be lispified later):
  • In the “Crease Pattern” tab, press “Push button” repeatedly to see the effect of applying a fold sequence.
  • In the “Circuit” tab, right click a component to select it, and drag the slider to change its parameter (voltage for voltage sources, current for current sources, resistance for resistors.). In between frames, the algorithm runs 100 passes to solve the circuit. You'll notice that the visualisation is inspired by Paul Falstad's circuit simulator – I just wanted to add more interactivity!