AngelScript CSG – part 2

Download AngelScript CSG version V2.0-02, with IDE included
Windows 64bit here.
Linux (K)ubuntu 15.10 64bit here.

This is an update to the first article on AngelScript CSG, where the idea of using AngelScript as a language for Constructive Solid geometry (CSG) was introduced. Since the first article, I found the idea interesting enough to warrant implementation of more functionality so that the language could be tested a bit further. To do that, almost all of the OpenSCAD modelling features have now been implemented in AngelScript CSG, there is an up-to-date summary at bottom. ​​ If you want to give it a try, use the download link at the top of this article, it comes with several small samples, plus a language definition file for Notepad++ so you can edit *.as files with AngelScript CSG syntax highlighting.

Unlike OpenSCAD, AngelScript CSG is strongly typed and procedural. Procedural means it executes the script just like in most other languages, it isn't just a static declaration. These features makes the language very expressive and general, with lots of possibilities for the user to write own functions etc.

Currently, AngelScript CSG is implemented as a command line “compiler”. It reads an *.as file and creates a *.csg file of the same name. The *.csg file is compatible with OpenSCAD, currently used for model display and generation of STL files. ​​ 

In addition to implementing most of the features in OpenSCAD, there are also some unique features in AngelScript CSG, such as the ability to define polygons from 2-dimensional splines and the ability to define lofted surfaces from 3-dimensional splines. The lofted surface can then for example be used as basis for creating a polyhedron. This is illustrated in the following example:

Polyhedron generated from a lofted surface

The code:

// Angelscript CSG - Lofted surface/polyhedron example


shape@ main_shape()

{  ​​​​ 

 ​​ ​​ ​​​​ // Create 3 arrays with guide points

 ​​ ​​ ​​​​ pos3d@[] c1 = { pos3d(0, ​​ 0, 0), ​​ pos3d(100, 50, ​​ 5), pos3d(200, ​​ 0, 0) };

 ​​ ​​ ​​​​ pos3d@[] c2 = { pos3d(0,100,40), ​​ pos3d( 80,100,-15), pos3d(200,100,10) };

 ​​ ​​ ​​​​ pos3d@[] c3 = { pos3d(0,200, 0), ​​ pos3d(100, 150, 5), pos3d(200,200, 0) };


 ​​ ​​ ​​​​ // Create 3d spline curves and from them a lofted surface

 ​​ ​​ ​​​​ spline3d@[] curves = { spline3d(c1),spline3d(c2),spline3d(c3) };

 ​​ ​​ ​​​​ auto surface = loft3d( curves );

 ​​ ​​ ​​​​ 

 ​​ ​​ ​​​​ // Create polyhedron from the surface with a surface copy offset -1mm

 ​​ ​​ ​​​​ return polyhedron(surface,vec3d(0,0,-1));



void main()


 ​​ ​​​​ shape@ obj = main_shape();

 ​​ ​​​​ obj.write_csg(GetOutputFullPath('.csg'));


Another example is using the language features and create user written scripting functions to do general things like a “filleted union” of 2d shapes:

AngelScript CSG generated shape displayed in OpenSCAD via generated .csg file

The idea is to fillet all concave corners of any 2d shape with a single generic function. I am not sure it is possible to express something as generic as this directly in an OpenSCAD module, but I could be wrong. Notice the use of a or loop to assemble 2d shapes to union:


// fillet_union: function to fillet any concave corners

shape2d@ fillet_union(double r, shape2d@[] parts)


 ​​ ​​​​ shape2d@[] offset_parts;

 ​​ ​​​​ for(uint i=0; i<parts.size(); i++) {

 ​​ ​​ ​​ ​​ ​​​​ // offset each part outwards by +r (straight)

 ​​ ​​ ​​ ​​ ​​​​ offset_parts.push_back(soffset2d(parts[i],+r));

 ​​ ​​​​ }

 ​​ ​​​​ 

 ​​ ​​​​ // compute union & offset inwards by -r to fillet concave corners

 ​​ ​​​​ return offset2d(union2d(offset_parts),-r);



shape@ main_shape()

{  ​​​​ 

 ​​ ​​​​ double r ​​ = 50;  ​​​​ // radius of circle

 ​​ ​​​​ double rf = 10;  ​​​​ // radius of fillet

 ​​ ​​​​ 

 ​​ ​​​​ // collect some 2d primitives in an array (it can be any number)

 ​​ ​​​​ shape2d@[] parts = { circle(r), square(2*r), translate(2*r,2*r)*circle(r) };

 ​​ ​​​​ 

 ​​ ​​​​ // compute the fillet union

 ​​ ​​​​ return fillet_union(rf,parts);


void main()


 ​​ ​​​​ shape@ obj = main_shape();

 ​​ ​​​​ obj.write_csg(GetOutputFullPath('.csg'));


Obviously, anything that AngelScript CSG can generate can also be created in OpenSCAD in some way, but the above is a small taste of the expressiveness in a procedural and object oriented scripting language. There are things you can easily express in a language like this that is much harder (at least for me) to express in the static OpenSCAD language. Instead of expressing the CSG tree explicitly, one may write algorithms to create models and these can be saved as CSG data at any time in the process.

The fact that OpenSCAD is used as a back end is for convenience at this stage. Clearly, it limits what can be expressed to what exists in OpenSCAD. But this is more than enough to evaluate the usefulness of AngelScript as a general scripting language and in particular to its application in CSG modelling.

Details on the updated features

Essentially what happened was that the “csg_” prefixes mentioned in the first article were removed from the commands to make them less verbose. Also, a full set of 2d primitives and boolean operations was introduced. The booleans now have “2d” and “3d” suffixes as you cannot mix 2d and 3d primitives in boolean operations (the same is true in OpenSCAD if less visible).

Mirror transformations, 2d and 3d hull and minkowski were also included for completeness. For 2d, offset was included for both the “radius” and straight “delta” cases. For the booleans, alternate syntax is now allowed for up to 5 single objects without requiring an array, otherwise one can use arrays for any number of input objects.

The AngelScript CSG commands are in fact C++ classes exposed in the AngelScript language. Therefore, it is possible to realise type safety using a class hierarchy. Below is the class hierarchy for the commands that create 2d or 3d geometric objects.

Angelscript CSG command type hierarchy for geometric objects

AngelScript CSG command type hierarchy for transformation objects

Other command types include pos2d, spline2d, pos3d, vec3d, spline3d and loft3d.

Being objects, every command provides functions for retrieving data., this can be quite useful, below are a couple of examples for “cylinder” and the “rotate_x” command objects.

cylinder functions

rotate_x functions

With such functions, you can create explicit dependencies in the modelling of objects by using e.g. the radius of a cylinder as a parameter to another command, creating something that depends on the cylinder radius.

AngelScript CSG vs. OpenSCAD

Below is an updated list of the revised CSG related commands. For even more details, and documentation of the functions each object type provides, run the following command, where <filename> is your own AngelScript CSG file, or one of the provided samples.

> as_csg -doc <filename>.as

This will generate a file 'angelscript_csg_doc.txt' listing all the constructors and functions for all the command types.


Angelscript CSG


3d utilities


pos2d  ​​ ​​​​ (position in 2d space)

array type [x,y]

spline2d (spline curve in 2d space)


2d primitives


shape2d ​​ (abstract type)


circle(double r);


square(double size, bool center=false);


rectangle(double dx, double dy, bool center=false);


polygon(array<pos2d@> points);


polygon(pos2d@ p1,...);


2d booleans


union2d(array<shape2d@> shapes);

union() { ... } ​​ 

union2d(shape2d@ shape, …);


difference2d(array<shape2d@> shapes);

difference() { ... }

difference2d(shape2d@ shape, …);


intersection2d(array<shape2d@> shapes);

intersection() { ... }

intersection2d(shape2d@ shape, …);


hull2d(array<shape2d@> shapes);

hull() {...}

hull2d(shape2d@ shape, …);


minkowski2d(array<shape2d@> shapes);

minkowski() {...}

minkowski2d(shape2d@ shape, …);


offset2d(shape2d@ shape, double r);


soffset2d(shape2d@ shapes, double delta, bool chamfer=false);

offset(delta=…, chamfer=false/true)

3d utilities


pos3d  ​​ ​​​​ (position in 3d space)

array type [x,y,z]

vec3d  ​​ ​​​​ (vector in 3d space)

array type [x,y,z]

spline3d (spline curve in 3d space)


loft3d  ​​​​ (lofted surface)


3d primitives


solid  ​​​​ (abstract type)


cone(double h, double r);


cube(double size);


cuboid(double dx, double dy, double dz);


cylinder(double h, double r);


sphere(double r);






3d booleans


union3d(array<solid@> shapes);

union() { ... } ​​ 

union3d(solid@ shape, …);


difference3d(array<solid@> shapes);

difference() { ... }

difference3d(solid@ shape, …);


intersection3d(array<solid@> shapes);

intersection() { ... }

intersection3d(solid@ shape, …);


hull3d(array<solid@> shapes);

hull() {...}

hull3d(solid@ shape, …);


minkowski3d(array<solid@> shapes);

minkowski() {...}

minkowski3d(solid@ shape, …);


linear_extrude(shape2d@ shape, double height);

linear_extrude(height=..) { ... }

rotate_extrude(shape2d@ shape, double angle);

rotate_extrude(angle=..) { ... }

2d/3d transformations

tmatrix  ​​​​ (abstract type)

multimatrix([ …. ]);

rotate_x(double rx);


rotate_y(double ry);


rotate_z(double rz);


scale(double sx, double sy, double sz=1.0);


translate(double dx, double dy, double dz=0.0);


mirror(double dx, double dy, double dz);



Math functions


Other language features


One thought on “AngelScript CSG – part 2”

Leave a Reply

Your email address will not be published. Required fields are marked *