How RapCAD will do CAM.

The intention of RapCAD is to provide a programmers IDE that will allow the user to not only model their ideas, but also prototype and manufacture those ideas. Initially the focus is to support additive machines like Reprap and Makerbot. However maybe people will want to use it one day for controlling subtractive machines such as CNC routers, or Laser cutters. To support this I wanted to add as much flexibility as I could to the process of converting the description of the model into GCODE instructions that will create the model.

The idea is to use a special type of RapCAD script called an .rcam script that will perform the slicing dicing and generate paths that will be used by the GCODE generation code.

/* Manufacture module called by RapCAD.
* RapCAD will measure the bounds of the
* final model and pass the model to the
* manufacture module. The size of the
* model is made available via the $bounds
* vector. The manufacture module will be
* called for each layer, the output should
* be a 2D path.
*/
module manufacture(){
   echo("Printing object of size: ",$bounds);
   echo("Printing layer: ",$layer," of ",layers());
   infill(0.4) {
     inset(0.4) {
      slice(h=0.4,cut=$layer*0.4) {
       child(0);
      }
     }
   }
}

/* Layers function called by RapCAD.
* RapCAD will call this function to determine
* the number of layers in the model
*/
function layers() = $bounds.z/0.4;

Apart from the file name extention this script is only different from a standard RapCAD script by the definition of a module which must be called manufacture(), and a function which must be called layers(). The idea is that RapCAD will have all the modules needed for turning a primitive into a set of paths. The paths will then be sent to the GCODE generation routines. The most important module needed for turning a primitive into a path is the offset() module. In Fused Filament Fabrication, we have to shrink the shape by half the thickness of the filament, so that when the model is constructed it fills out to the correct size. A more obvious module is the slice() module, which is responsible for turning the three dimensional form into the two dimensional slices that are build up on top of each other during the printing process. In addition to others there will be an infill() module that given a two dimensional offset polygon will turn it into path roads ready for conversion to GCODE.

When RapCAD is asked to generate GCODE for the given design it first compiles and renders the description into a primitive and adds the result to a cache. The bounding box of the primitive is calculated and then the layers() function within the .rcam script is called to determine how many manufacturing cycles will need to be made. Then the manufacture module is called for each cycle, each time passing the full cached primitive and an incremented value accessible via the $layer variable.

RapCAD will come installed with a standard .rcam script designed for a reprap machine, but I hope that by giving people the flexibility to tweak the scripts, new and better ones will be written.

That’s the plan, now I just have to implement it!


As promised there is a new release of RapCAD available. This months release of RapCAD can be installed by following the instructions on the new download page

For those who want to know what has been added please see the release notes

RapCAD preview release

I decided to build a binary release of RapCAD so that people can have a look at how things are coming along without having to compile it. Its very much in a pre-alpha state so don’t expect to be able to just try out your latest greatest design and just expect it to work. Furthermore it can’t currently create any output in the form of an STL file or GCode, so it really is just a release that will let you preview a design. That said there are some nice features that I would like people to try out and see what they think. Language features such as true variables and functions with bodies seem redundant now when other projects such as openscadpy are boasting full python language integration. Having said that RapCAD scripts and OpenSCAD scripts are a DSL which is nice to use and since it has no general purpose language features such as reading or writing files, network access, etc. The scene descriptions are inherently more secure. While the authors of the software RapCAD, OpenSCAD and openscadpy are known and trusted, the authors of scene description scripts uploaded to to Thingiverse may or may not be trusted. By limiting the language features to the domain of scene description this mitigates any risk.

The features that I am developing now could go into openscad eventually, although some of the things that I am doing would require a substantial re-write of the openscad backend, such as dropping openscads 2D subsystem. (It turns out that the entire 2D subsystem can actually be done using 3D shells that have no internal volume, including boolean set operations) For those who want to try out this release instructions for installation on three popular operating systems; Windows, Ubuntu and MacOSX, can be found in the Download Page

I intend to create binary releases about once a month from now on. Next month I hope to have a release with OFF file export (Its supported natively by CGAL so should be easy to implement) and maybe native support for Bezier surfaces since I have been very interested in the work done by WilliamAAdams here is a sneak peak:

The linear_extrude is not quite working the way I would like yet, as currently it evaluates it by creating a volume for each facet and doing a union of all of these volumes. With it taking 2 seconds for each volume union, the total rendering time is a completely unacceptable 39 minutes! I would like it to work by just creating one volume, but I haven’t worked out how to find the perimeter of the Bezier surface yet.

On the other hand creating a convex hull of two Bezier surfaces works at a comparatively much more acceptable speed, about 18 seconds.

RapCAD is Rendering!

Last month I was saying I was going to hook the OpenSCAD back-end into RapCAD. It turned out to be simpler to just implement a backend myself. I started off implementing the GLView widget. I would have had to have done this anyway, since I didn’t want to hook any of OpenSCADs GUI code. I learned a lot doing this, and I think my version has better performance than OpenSCADs version so I will be proposing some performance enhancements to be backported into OpenSCAD at some point, as well as completing a feature request in the TODO list which is to have ruler ticks on the axis. I implemented something similar for RapCAD which is the outline of the 200x200mm printable area, so it should be quite easy. The next thing I put together was a CGALRenderer class, which converts CGAL primitives into openGL. The design is based on the Strategy Pattern rather than OpenSCAD’s messy rendering function pointer callback, I think this is something that could potentially benefit OpenSCAD as well, so I have already started to backport these changes in a cgal-renderer-refactor branch.

Once these two things were implemented everything seemed to come together quite quickly. So recently I have been adding all the bells and whistles and fun features like “ThingDoc” style code comments. Convex Hull for 2D & 3D primitives, and Minkowski that works with mixed 2D and 3D primitives.

Talk with Marius

I have been trying to understand and document the windows build process for OpenSCAD so that Marius and Clifford might soon be able to publish a new release.

While doing this Marius and I got talking. Specifically he wanted to know whether the work I had done for RapCAD on variables would work in the OpenSCAD back end. I told him a bit about the parser I had implemented, and how I thought that a strong concept of Statements within the language syntax would be needed to support this. We agreed that (like many projects) the OpenSCAD language has evolved over time, and its evolution had led the design to a more Declarative syntax rather than a Procedural one.

Marius also asked me whether it makes sense to write my own language or rather use an existing one. I explained that my main motivation for re-writing alot of what already exists in OpenSCAD was

  1. I was finding it fun
  2. I can understand things much easier if its my own work.
  3. Its easier to do research in a new project, than try and modify some existing codebase.

l like to think of RapCAD as my own research experiment, into an ‘Openscad 2.0’ language spec, and other potential re-factorings that might someday be applied. Marius added that in many ways that was what Clifford had done, when he took MetaCAD, and re-wrote it in C over a summer holiday.

Another thing we talked about is the possibility that some day OpenSCAD might drop CGAL as its back end rendering subsystem, and perhaps adopt something like OpenCASCADE. It makes sense to try and integrate RapCAD’s scripting engine with the OpenSCAD rendering engine in much the same way as efforts like pySCAD have done.

One idea that Marius presented to me was that of a low level API that projects like pySCAD and RapCAD could use. The API might be text based vastly simplified to a description/modeling language that only supports the basic primitives such as polyhedrons, which all other shapes can be defined in terms of, as well as csg operation nodes, and transformations which can all be defined in terms of multmatrix.

In summary I am focusing my efforts on connecting up my existing code to just the rendering functions of OpenSCAD, and modifying OpenSCAD so that it has a generic API for projects like pySCAD, SolidPython and CloudSCAD can use as well.

Not Just a GUI Thing

I haven’t done a lot with RapCAD recently, and its time for my monthly post. What I thought I would write about is my reaction to posts on the OpenSCAD mailing list regarding turning it into a Python language library. First and foremost I think the idea is a great way to provide extensibility.

As Tony Buser says:

Access to such features would be potentially very powerful to do unforeseen things… then there’s string processing – that could be very handy with parametric scripts (look at what I had to do to handle strings in my bitmap text module) Filesystem access would be really nice for loading external data. Interesting things could be done in terms of dynamic objects if the script could call webservices…

For the power user these sorts of things are great. However I wonder if the desire to have Python support is driven by the lack of some features in OpenSCAD, such as:

  • True variables.
  • Functions with bodies.
  • Working scope blocks.
  • Statements allowed inside For and If
  • Determine how many elements are in an array or characters in a string.
  • Get the nth character of a string, and get it’s ASCII code.
  • Vector operations.

(Credit to Leemon Baird who suggested some of these)

My reaction is that we can have both a domain specific language, which is nice for the end user, and a set of language bindings to allow the power user to do advanced things, with their general purpose language of choice. I am currently trying to work out how this could be done in RapCAD, and making the RapCAD scripting language itself just one of the bindings.

With respect to the RapCAD scripting language itself, I also want to add support for the features as described above. RapCAD is not just a GUI thing. I have actually been writing an improved grammar, which I turned into a bison parser. I have also applied some Design Patterns such as Builder and Visitor to my code which may allow easier integration with external languages. Finally as mentioned before I have implemented True Variables, Functions with bodies, and some support for Vector operations.

On the face of it RapCAD just looks like a GUI front end to OpenSCAD, but that’s not actually what it is please feel free to look at the code and post any comments.

Syntax Highlighting

I have implemented syntax highlighting in RapCAD using the same lexical analysis engine as the script parser and evaluator uses.

I wanted to do this for two reasons, firstly flex is comparatively faster than the example QT SyntaxHighlighter implementation which uses QRegExp’s. This is partly because the lexer is built at compile time, where as QRegExp’s are compiled at runtime. The second reason for using flex as the backend to the highlighter was to ensure that there are no ambiguities between the syntax highlighter and the language definition.

I have also started to look at how to make the scripts output 3D shapes using CGAL. Its certainly not a trivial task, but I am starting to understand things.

Basic Evaluation

RapCAD has now got to the point where scripts can be evaluated at a text level. What I mean by this is that modules functions statements and expressions can be evaluated and the results of those evaluations can be output to stdout using the echo module. There is no 3D output yet, so most of this is pretty trivial, but it has been fun for me to learn how to write code in C++. I still need to improve usage of ‘const correctness’ and consider using references instead of pointers, but on the whole I am happy with what I have managed so far. It might be of interest to mention at this stage that I have implemented “Variables that will” and Functions with function bodies are coming along. is implemented.

In the meantime as I have discovered how to do things by implementing them in RapCAD, I have been able to supply similar fixes to OpenSCAD, the most notable being support for nested includes.

Fuzz Testing

After completing implementation of the RapCAD parser I decided to give it a thorough test against as many files as possible. I created a script that scoured thingiverse and created a list of thingiverse scad asset urls.

I then ran the RapCAD parser against all of the downloaded scad scripts to see how it fared. The test includes 515 scad scripts, of these 380 seem to parse without problems, and 135 throw up syntax errors.
I have been investigating these errors. I found that 60 of the errors are accounted for by the fact that I am not supporting implicit includes (a deprecated feature in OpenSCAD). The remaining 75 are caused by the fact that I have created a more strict grammar for RapCAD. Hopefully this will mean my RapCAD parser is a more robust and less ambiguous. I will attempt to justify all of the syntax “improvements” and suggest changes that the OpenSCAD developers can consider.

Here is a list of those syntax errors:
Continue reading Fuzz Testing

Parsing

For the purpose of understanding tools like Bison and Flex, I have been building a parser for RapCAD despite the fact that it will probably one day use a library version of OpenSCAD as the back end. My reasons for doing this are two fold, firstly I have never writtern a parser in Bison or a Lexer in Flex before, I have only writtern a trivial Recursive Decent Parser using .NET and Its something I have wanted to try for a while. Secondly I am interested to see how to implement such things as “variables that will”, and functions with function bodies, so that I might sometime provide a patch for OpenSCAD so that it can also do these things.

Things are moving steadily along, and I am now able to parse a simple test file containing the following:

module foo(a,b=1+2,c=1-2,d=1/2,e=1%2,f=12,h=1*2)
{
}

The parser then reads the text and turns it into an abstract syntax tree representation, which is stored in various objects. The objects all have a toString() method which when called produces following text dump:

Module: foo
Parameters: Param: a Param: b Expression: (Literal: 1 Operator: + Literal: 2 ) Param: c Expression: (Literal: 1 Operator: - Literal: 2 ) Param: d Expression: (Literal: 1 Operator: / Literal: 2 ) Param: e Expression: (Literal: 1 Operator: % Literal: 2 ) Param: f Expression: (Literal: 1 Operator: Literal: 2 ) Param: h Expression: (Literal: 1 Operator: * Literal: 2 )
Done.

So, I am thinking about the parsing of functions now, and its got me wondering about function bodies. There is a problem which I am not sure the best way to resolve. I would like to allow a function to have a function body consisting of statements. It would be meaningless however to have a module instance inside a function body, but for the current grammar to work a module instance is a type of statement. I have two options, either re-write my grammar to make a module instance inside a function body as a syntax error, or the other option which would simply be to make the syntax acceptable, but when it comes to evaluate it it will be a compile error.

OpenSCAD synergy

All this talk of RapCAD hasn’t gone un-noticed by the OpenSCAD maintainer(s). Recently on the OpenSCAD mailing list Marius Kintel has stepped forward and stated that he is now the core maintainer of OpenSCAD. He has also outlined his goals which are similar in essence to my own. Opening up development and try to build a better developer community, as well as hosting better forums/mailing lists bugtrackers and source code management. Based on this and other feedback, I have decided to change my approach somewhat. It doesn’t make all that much sense to duplicate the work of a project that is being actively developed and Marius has agreed that an OpenSCAD evaluation library could benefit multiple projects currently under development. So I will be offering any contributions I can that help OpenSCAD take this direction, and focus on developing RapCAD as a front-end thin wrapper application around this library.