FooCAD
FooCAD is a script-base 3D modelling application with a similar goal to OpenSCAD.
I like OpenSCAD, however, I find OpenSCAD lacking :
- The language isn't powerful enough
- Complex models become impossible to read
- Complex models are hard to write
- Some seemingly simple operations are hard / impossible.
So I've created an alternative, which uses a scripting language, which is (IMHO) much easy to use, as well as being much more feature full.
The language is called Feather.
It has all the "core" 2D and 3D primitives with which to build your models, such as Square, Circle, Cube, Sphere etc. as well as many more complex features, such as an ExtrusionBuilder (which have no parallels within OpenSCAD).
It also has the "normal" language features, such as variables, for loops, if statements etc. It compiles almost instantaneously, and is strongly typed, so the most common errors are reported immediately.
The FooCAD script generates OpenSCAD scripts (which you never need to look at), and the OpenSCAD application is used to preview your work. (FooCAD has no rendering code). I suggest having the FooCAD application in the left half of your screen, and OpenSCAD on the right. Each time you save the FooCAD script, OpenSCAD will update.
As well as designing models, the FooCAD application can also be the place where you slice and print your models. FooCAD doesn't have a slicer, or a printer, and instead integrates with Slic3r and OctoPrint. Pruser's version of Slic3r is also supported, as well as SuperSlicer.
You can stay within FooCAD; you don't need to open a slicer, and you don't need to use your browser to upload and print to OctoPrint.
Have a look at the Examples to see what a typical FooCAD file looks like.
Build from Source Code
The project uses the Gradle build tool :
./gradle
For a local copy of the API documentation :
./gradlew dokkaHtml
Comparisons with OpenSCAD
FooCAD's language (called Feather) is a complete scripting language.
It takes a procedural approach to building models, rather than a declarative one.
It has all the usual language constructs such as variables
, for
loops, if
statements etc.
- Shapes are objects with properties such as their size and position. For example, it is very easy to duplicate an object in a tiled pattern, because the "tile" method knows the size of the shape, and therefore hpw much to translate each tile.
- OpenSCAD files are write-only (revisit a project a year later and see how easy it is to understand!).
FooCAD uses a
traditional
syntax. Each step towards the final result can be assigned to a variable, and as long as you name them well, it is at least partially self documenting. You also read it from left to right (for some weird reason OpenSCAD chose right to left). For example, if you want a square rotated 90 degrees, you put the square first, and the rotation second! - Strongly typed arguments, so an error is reported when you pass an invalid argument. OpenSCAD very often fails silently when you pass garbage to a module.
- Full access to the points which make up 2D Shapes. It doesn't sound like a big deal, but it is! This opens up a vast array of possibilities. For example, getting the points which make up the 2D Text objects lets you create funky 3D text, where the edges are rounded, chamfered, or "routed" as you see fit.
- Generate preview images (png files) as easily as creating stl files.
- Generate BOM (Bill of Materials) (I use FooCAD for woodworking projects!)
- Say what you want, not how to get it. I often find OpenSCAD scripts very hard to read, because you have to say HOW to do something, rather what you want to do. The simplest example is centering an object along a single axis. In OpenSCAD, you have a translate(...) with two zeros, and a complicated expression. In FooCAD, use centerX(), centerY() or centerZ().
- Give me sugar. OpenSCAD gives the bare minimum primitives and transformations, and lets 3rd parties build upon them. I believe that some level of syntactic sugar should be added. A trivial example is translateX(n) instead of translate(n,0,0). There are many such niceties in FooCAD. Some of them are built into the classes themselves, and others are included as extensions.
- Create multiple models from a single source script. My projects are often made from more than 1 piece of plastic. A single FooCAD script can generate multiple 3D models.
- Import SVG diagrams as 2D shapes. Using FooCAD in conjunction with Inkscape is really easy. There is an SVG parser built in.
- Polygons vs Primitives. OpenSCAD wants you to build everything up from primitives, such as Square and Circle. It also lets you create an arbitrary polygon from a set of raw points. There is no middle ground. FooCAD on the other hand lets you build 2D shapes using PolygonBuilder, which includes simple lines, automatic rounded corners, bezier curves, circular and elliptical arcs. One of the reasons OpenSCAD is slow is because you are forced to use lots of difference() or intersection() (which are slow) because that's the only way to create the shapes you need. Also, if you find OpenSCAD limiting, you are stuck. With FooCAD, you can write whatever you want.
- OpenSCAD Extrusions are very limited. FooCAD's ExtrusionBuilder can make screw threads as well as weird and wonderful 3D monstrosities ;-)
- It's fast. Faster than OpenSCAD. This is very counterintuitive, because FooCAD relies on
OpenSCAD to display the results, as well as generate stl files.
However, in my experience, when you want to do something
even slightly tricky using OpenSCAD, you often have to revert to lots of
difference()
orintersection()
, and then OpenSCAD really slows down. To get the same results using FooCAD, I often end up using ExtrusionBuilder, which outputs a single polyhedron, and OpenSCAD parses and renders it really quickly. - Cavities. In OpenSCAD, we have the difference operator to form holes in objects, but if we combine two objects with holes, they don't combine in the way we may like. For example, if we have a pipe (a cylinder with a hole down the middle), and we combine it with another pipe at right angles, there will not be a free passage from one pipe to the other. FooCAD has the concept of a cavity, so that when you merge the pipes, the cavities will remain, there will be free passage from one pipe to the other.
I've also written a couple of classes specifically for woodworking. These introduce a slightly different approach to 3D modelling.
I am aware that FooCAD's approach isn't to everyone's taste. However, I believe that FooCAD users will be able to create better models (and do so quicker).
Extensions
If you find a gap in FooCAD's features, write your own extension. There are lots of built-in extensions too.
There are three types of extension :
- Script Extensions
- Model Extensions
- Shape Extensions
Script Extensions
add extra functions/classes which can then be used within your scripts.
For example, FooCAD does not include a Triangle primitive, but there is a Script Extension
called "Extras" which adds this feature.
A Shape extension
takes the Shape that your model produces, and returns another shape.
For example the Scale
extension can enlarge/shrink the output from your models.
Model extensions
are more powerful (and trickier) than Shape extensions
.
They form a wrapper around your model, so they can take actions before and after the
Model creates the Shape.
For example, they can change slicer settings and alter the generated GCode.
GUI and Command Line
FooCAD includes a GUI, which is a text editor with syntax highlighting for the Feather language. Whenever you save a foocad script, it will (optionally) automatically generate the scad file.
Because OpenSCAD can automatically re-render the scene whenever the scad file changes, saving the foocad file updates OpenSCAD's preview.
If you prefer, you can use a different text editor, and use the command line to generate the scad files from the foocad scripts.
Command Line Usage (abridged) :
foocad [OPTIONS] [SCRIPT_FILE...]
Options :
-g, --generate : Generates the scad file (and other targets)
--target=NAME : Specifies a target
The default is to generate a scad file.
-l, --list : Lists the targets
-h, --help : Shows this message
If neither --help, --generate or --list are specified, then the GUI application is started.
Example FooCAD Scripts
A simple cube :
class SimpleCube : Model {
fun build() = Cube( 5, 10, 30 )
}
Cube has no "center" parameter, but you can center ANY object :
class SimpleCube : Model {
fun build() = Cube( 5, 10, 30 ).center()
}
A translation :
class SimpleCube : Model {
fun build() = Cube( 5, 10, 30 ).translate( 10, 20, 30 )
}
A sequence of transformation can be applied one after another. Note the order is the opposite way round to OpenSCAD. Who thought it was a good idea to do everything backwards in OpenSCAD? ;-)
class SimpleCube : Model {
fun build() = Cube( 5, 10, 30 )
.translate( 10, 20, 30 )
.rotate( 45 )
.scale( 2, 1 )
}
Parts can be named :
class SimpleCube : Model {
fun build() : Shape3d {
val base = Cube( 10, 10, 2 ).centerXY()
val ball = Sphere( 5 ).toOriginZ()
return base + ball
}
There are numerous examples in the "Help" menu of the application. (Or find them in src/dist/Examples).
Status
It works! I've been using FooCAD for many years now. There's no way I'd ever consider writing an OpenSCAD script. IMHO FooCAD is vastly superior.
Limitations
ExtrusionBuilder is a bit quirky. It lets you extrude while morphing from one 2d shape to another. There is no 100% perfect algorithm to decide how the points of the first 2d shape should be joined to the second 2d shape, and the heuristic used by ExtrusionBuilder fails more often than I'd like.
ExtrusionBuilder's API isn't perfect either, and so at some point, I will introduce another way creating 3d shapes from sequences of 2d shapes. (But keeping ExtrusionBuilder for backwards compatibility).
The points and edges of many 3d shapes are NOT available to the model's script. In particular, 3d shapes formed by combining two or more shapes (plus/union, minus, intersection). This is because FooCAD doesn't know how to perform those operations, and leaves it up to OpenSCAD to calculate them.
This limitation will not be fixed any time soon, because the maths is hard, and I've not found a Java library which does the heavy lifting. (I could use the same library that OpenSCAD uses, but I don't want to get into the murky waters of calling native libraries from Java). Also, if a script relies on this feature, then it may be SLOW, because rendering a preview could take the same time as a full render.
Note, FooCAD DOES know how to perform 2d operations, so the vertices of 2d shapes are always available to your script. (except for the vertices of Shape3d.projection, which are never available).
You might expect the lack of vertices/edges of many 3d shapes to be very limiting, however, there's some magic which gets around most/all? of the limitations. As it is only union/difference/intersection which have undefined vertices/edges, we can split the shape into its constituent parts, perform transformations on each part separately, and then put the transformed parts back together in the same way as the originals.
Known Bugs
I keep a list of known bugs at the top of my todo list
Project Structure
The project is split into several modules :
###foocad-core The core classes, including the 2d and 3d primitives, and their transformations. Also contains the SVG Parser as well as a few utility functions.
You can use this module on its own. You can use it to create 3D models in an object-oriented manner from any JVM language, and generate scad files.
Its only dependency is the JTS Topology Suite's core (plus the Kotlin and Java runtimes).
##foocad-build
Contains additional tools to build various files from your 3d models.
Includes a make-like system, consisting of tasks
, which know how to build
various files.
For example the SCADTask
builds a .scad
file based on a .foocad
script.
The STLTask
builds a .stl
file from a .scad
file (using OpenSCAD).
These can be chained together, so that the .stl
file is built from the .foocad
script.
##foocad-construction
Depends on foocad-core
and foocad-build
.
This is a side-project, which will be of little interest to many, as it is related to woodworking rather than 3D printing.
Contains useful concepts such as Lumber, and Joint.
Includes BOMTask, which helps me create a shopping list for my woodworking projects ;-)
At some point I hope to rewrite it as a Feather script, and thus make it an extension rather than an integral part of FooCAD.
The 'root' module
Contains the GUI and command line version. Depends on all the other FooCAD modules, as well as the Feather language.
The GUI uses Glok
- my own GUI Toolkit similar to JavaFX
.
I initially wrote Glok
because one of my applications needed direct access to OpenGL Textures
for lightning fast rendering.
However, once I'd finished it, I liked it so much, that I began porting my other applications
to Glok
, even those that were fast enough using JavaFX
.
The root
modules is the only module with a "main" method entry point.
Creative Commons Attributions for Sound Effects
"ding.wav" by InspectorJ (www.jshaw.co.uk) from Freesound.org Original name : "Bike, Bell Ding, Single, 01-01.wav" [https://freesound.org/people/InspectorJ/sounds/484344/]
"error.wav" by Autistic Lucario (http://www.patreon.com/RyanSmith) from Freesound.org [https://freesound.org/people/Autistic%20Lucario/sounds/142608/]