Tag Archives: LabSlicer

LabSlicer, Vox3lSlicer, VoxGLSlicer


  • 2022/03/26: published
  • 2022/03/03: starting write-up, based on internal documentation


As part of getting to know the inner working of a slicer and have a toolkit for advanced non-planar slicer I had in mind, I started to code my own “laboratory slicer” or simply “LabSlicer” as an in-house project.

Its main features are:

  • Python-based, it’s slow for production but good enough to test new algorithms
  • PyClipper as offsetting & clipping engine
  • four stages clearly defined with API and file-format export/import:
    • mesh: import & export meshs
    • slice: slices 3d objects into 2d slices/polygons
    • route: routes polygons with wall/perimeter and infills, bottom/top layers, skirts/brims
    • gcode: takes routes and converts into G-code
  • LabSlicerCore: slicer available as library, with clear defined & simple API
  • easy to extend to non-planar slicing/routing/g-code, incl. 5-axis FDM


It may look like redundant to code another slicer and define those rather simple steps as such, but the benefits came days after I finished the basic layout and was able to exchange the mesh and slicing stage with voxel-based engine, or use OpenGL screenbuffer to slice and then hand over polygons to route and gcode stage – within 2-3 weeks I had 3 working slicers with different slicing engines.

By having a clear API the integration into various in-house projects was truly swift and the cross-fertilization paid off quickly and immensely. I might have taken me more time to learn to memorize Slic3r or CuraEngine API than writing a basic slicer myself. Granted that coding a slicer in Python limits its overall performance, compared to an optimized slicer like Cura; but to research and develop new slicing and routing algorithm coding with Python is fast, a couple of hundred lines in Python can represent ten thousands of lines of C++ code, not to mention wait time for compiling.

Four Stages of Slicing

It may appear to be simplistic at first sight, but it’s worth to clearly layout the main stages of slicing:


One has to import the geometry such as a mesh which circumscribes a volume.


The slicing stage takes the geometry and slices it into slices, which are a set of polygons which also describe holes – essentially an array of arrays of polygons.


The real work of the slicer is actually the routing, which means to plan extrusion paths:

  • walls or perimeters: offsetting or rather insetting 2D polygons
  • infill pattern: offsetting and clipping of 2D polylines
  • skirts and brims: offsetting at bottom via 2D polygons
  • bottom and top layers, also intermediary: difference & intersecting previous and next layers to determine delta areas (polygons) were, are or becoming bottom/top layers
  • support structures (not yet implemented)

Routes are held in an array of arrays of routes (polylines).

Off- and Insetting Polygons

At first sight it looks trivial, but in the details this isn’t trivial at all as offsetting or insetting can clash with itself or other polygons and fork into two or more polygons. Clipper as developed Angus Johnson has laid the ground for many slicers and does the heavy lifting and therefore unloads some of the burden and one can focus on higher level algorithms.


At this stage now all the slicing settings like travel and extrusion speeds, retraction and so on are factored in and further optimizations are done, given we know now all routes at a given (planar-)layer.

It’s easier to separate routing and actual creation of G-code as transforming routing, like for non-planar slicing, is more efficient than parsing G-code with more overhead.

From a development point of view the routing results is the most precious and worthwhile data; the other stages are rather simple, but routing is where the magick happens.


To give you a bit insight to how I coded it, I started with the API in mind, defined the 4 stages roughly, then the parameters and the data-structures and import/export file-formats, essentially all is encoded in JSON to keep things simple.

Within 2 days I had basic wall routing coded using PyClipper – I had some experience with coding with it at Mandoline (fork) but felt to start from scratch anyway – and I did not even try to slice yet but had a simple function returning the same square (polygon) no matter which slicing height – yes, starting with the simple 20mm cube.

Once I had the routing done, I coded the gcode stage, to create basic extrusion and preview the gcode with a G-code viewer – and added support start- and end-gcode with some sane defaults and sent it to my 3D printer – and the first print outs were bad, no retraction, no infill, single wall, no path/routing optimization.

After I matured routing and gcode stage, I focused on the slicing from mesh to polygons, which took most of the time, as I had to decide on the notion how holes are defined in a set of polygons, using clock-wise (CW) and counter-clock-wise (CCW) notion – the code grew quickly complex as I coded those polygon processing from scratch instead to use shapely library right away; but it was good to look so closely at the details, as when one wants to carry metadata of facets of the mesh to the polygon slice and routing stage to the final gcode, e.g. changing color, material or other special G-code, this chain or pipe to hand over metadata had to be possible.

I also kept the file format of routing somewhat open to support easily also non-planar routes, means, the coordinate could be more than x, y, z but also u, v, w (nozzle vector for 4-, 5- or 6-axis FDM) and layer thickness for non-planar slicing.


  • Vox3lSlicer: as I experimented with voxel-based geometries, such as reliable CSG operations when slicing with voxels, I replaced the mesh– and slice-stage with voxel-based functions, and then use the next two stages of route and gcode to create G-code; it was truly a matter of a couple of hours
  • VoxGLSlicer: utilizing OpenGL screenbuffer to “render” volume and easily slice within the GL engine, vectorize and feed the polygons into LabSlicerCore; the same, after a few hours I had another slicer


In-House Slicers

– full planar slicer
– 4 stages: mesh, slice, route, gcode
– experimental
– API defined
– LabSlicerCore library
– import/export data of each stage
– voxel-based planar slicer
– fast slicing
– uses LabSlicerCore library for route and gcode stage
– OpenGL based planar slicer
– fast slicing
– uses LabSlicerCore library for route and g-code stage
– non-planar slicer
– implements Class 1 + 21) Universal Slicing
– uses OpenZCAD2) engine to slice non-planar
– non-planar slicer
– implements Class 1 + 21) Universal Slicing
– uses mesh & gcode transformation


  1. Class 2 Universal Slicing only partially implemented (status 2022/03)
  2. OpenZCAD is alike OpenSCAD but with Python as base-language with multiple backends (OpenCASCADE, LibFive, Fogleman’s SDF)


All three slicers are in-house slicers where I do a lot of experimenting, changing rapidly and testing new algorithms, such as mapping coordinate systems and new routing procedures – for now there are no plans to publish them.

I recommend to look at my fork of Mandoline to learn about slicing, which is available at github but I have stopped to work on, it actually produces printable G-code unlike the original code of it.


Misc: XYZdims State 2022/02


  • 2022/02/20: finally published
  • 2022/02/08: ready to publish finally with some delay
  • 2022/01/28: not yet published, removed Universal Slicing details for future blog-post, added more photos and illustrations
  • 2022/01/16: starting write-up


Aside of the technical detailed filled blog-posts I like to start to post about the larger context of my inner motivations doing XYZdims.com – this is the first post “XYZdims State 2022/02”:

More Slicers

Recent in-house developments having more slicers to experiment with, in regards of slicing techniques as well lay the ground for more complex slicing and mapping/transformation operations to support arbitrary non-planar slicing (coming soon).

LabSlicer: The Mother

Big Picture of XYZdims – State 2022/02
(click on it and then zoom in, it’s a large image)

As I was working with Slicer4RTN and wrappers like Cura-CLI-Wrapper and Kiri:Moto Slicer (CLI wrapper), and adopting Mandoline fork – I realized I need to have my own slicer, so in November 2021 I started from scratch, as I thought I need to know every detail and so I exposed each step or stage:

  • mesh: load mesh, vertices & faces
  • slice: slice layers into sets of polygons
  • route: route the layer polygons with walls, infills etc
  • gcode: convert routes to G-code

A “lab(oratory) slicer” or simply LabSlicer was born – I defined each stage: API and file-format it takes in and spits out.

After a couple of weeks I had slicing into polygons, and routing of walls, basic infills, skirts, brims and eventually intermediary top & bottom layers resolved, and I was able to generate printable gcode:

Meanwhile LabSlicer as of version 0.1.5 has matured to print complex models reliably but rather performs slow compared to Slic3r or Cura.

As of 2022/02 I’m even use LabSlicer and its relatives (featured below) for productive 3D prints.

Vox3lSlicer: Voxels

Aside of LabSlicer I began to develop Vox3lSlicer which utilizes internally the OpenVDB voxel library, in order to slice planar and in the future non-planar as well, and also permit to slice voxel-based models efficiently.

A few tests with OpenSCAD Logo model (~20mm height) with various amount voxel samples, from low resolution to high resolution:

and with defined voxel sizes:

As LabSlicer matured and LabSlicerCore library came to life, Vox3lSlicer (2011/11) utilizes the stage route and gcode of LabSlicerCore to actually produce printable G-code.

Testing the retraction code and settings of Vox3lSlicer, rotating the model in order to avoid support structure altogether:

VoxGLSlicer: OpenGL Slicing

Early VoxGLSlicer tests

As I was looking for other slicing procedures I came across OpenGL-ST-Slicer, which utilizes a clever OpenGL setup with GLSL (Shader Language) to render a mesh to a framebuffer with the volume information, and so slicing is done solely in the GPU almost instantly – I extended this approach and glued it together with LabSlicerCore and I was able to produce also printable G-code – VoxGLSlicer was born (2022/01).

Due the limitation of the internal framebuffer width & height the resolution of the slicing changes with the size of the model aka “relative resolution”:

model width [mm]pixel size [mm] @ 2560 pixels
200.008 or 8 μm
500.019 or 19 μm
1000.039 or 39 μm
2000.078 or 78 μm
5000.19 or 195 μm
10000.39 or 390 μm

and just for illustration about “pixel size” related to a ~20mm model:

3 Slicers

After a few weeks coding (2021/11-2022/01), I was able to raise 3 slicers, each with their unique slicing approaches to create printable G-code, by having a common API and use symbiotic advantage of each other:

meshmesh.py1) multi-format mesh importeropenvdb STL importermesh.py1) multi-format mesh importer
sliceslicing mesh to polygons (vectorizing)slice voxels into polygons (vectorizing)screenbuffer into polygons (vectorizing)
routeroute polygons to routesLabSlicerCore’s routeLabSlicerCore’s route
gcodeconvert routes to G-codeLabSlicerCore’s gcodeLabSlicerCore’s gcode
+ traditional slicer with polygons
+ all stages fully implemented
– slow slicing2)
+ fast slicing
+ flexible resolution
+ reliable
+ fast slicing
– fixed screenbuffer size
– relative resolution

All three slicers are very experimental and play a significant role for the next step – Universal Slicing.


  1. mesh.py is loading/saving 3d meshs/models and some simple manipulations tuned toward my use cases
  2. mesh slicing not yet optimized

So any optimizing of routing (wall, infill, intermediary top/bottom layers etc) and gcode optimizing all three slicers benefit from.

YAGV & Nautilus Thumbnailer Supporting ArcWelder

After the implementing G2/G3 emulation for gcode2png as part of the G-code thumbnailer, I also added it to G-code viewer yagv fork of mine:


And just for sake of giving a bit of context, adding ArcWelderLib in the pipeline of Print3r via the configuration:

# first declare new post-processor named "arcwelder":
post_arcwelder = ArcWelder %i %o
# optionally, define it to be active (all the time):
post = arcwelder

or optionally enable it on the command-line:

% print3r print cube.stl --post=arcwelder

That’s it for now.