3D Printing: Mandoline Slicer


  • 2021/09/16: publishing this blog-post finally
  • 2021/09/04: 0.8.6: supporting OFF, OBJ, AMF, 3MF and 3MJ in addition to STL
  • 2021/04/11: 0.8.5: more tests and Makefiles added
  • 2021/04/06: 0.8.4: SVG export working with example, various bug fixes
  • 2021/04/04: 0.8.3: first print actually working (extrusion calculation fixed, removed most un/retract for now)
  • 2021/04/02: starting write-up
20mm xyzHollowCalibrationCubeV2 sliced with Mandoline 0.8.5


Since I started to develop on the conic slicer slicer4rtn for the RTN, and starting to work on the more complex PAXSlicer for 5-axis printer like PAX option. So I was searching for a slicer to adapt for future projects to have more control of the slicer stage and learn of the actual details and so I came across Mandoline Py, a slicer coded in Python utilizing at its core pyclipper and at first glance it was well thought out, clean code, yet not many comments but function names and variables were explanatory – I was quite impressed by Revar Desmera, who was able to put this together in such a consistent manner.

There wasn’t much information available otherwise, and the author did not reply to my emails, so I looked at past closed issues at github, which gave me a bit background information, and the challenges Revar faced.

So, after a couple of weeks pondering and waiting for Revar to respond, April 4 2021 I began to adopt it and push it forward to become usable for me. I will document all future changes (or possible a fork of it) on this blog-post.


  • purely written in Python, compact source code, easy to read & understand
    • vector.py: base vector operations
    • point3d.py: x,y,z to index to x,y,z
    • line_segment3d.py: two points making a line, with caching
    • facet3d.py: three points making a triangle/facet, with caching
      • facet.slice_at_z(z)
    • geometry2d.py: uses pyclipper
      • provides path operations like offset, union, diff, clip, paths_contain (point in paths)
      • makes infill patterns like lines, grid, triangles, hexagons
    • model3d.py: STL reader & writer, OBJ, OFF, 3MF, AMF, 3MJ reader
      • indexing points, edges and facets
      • model.slice_at_z(z, lh) results in polygons/paths
    • slicer.py: slicing the model
      • generating perimeters
      • generating support
      • generating adhesion (skirt, brim, raft)
      • generating solid & sparse infill
      • pathing: coordinates perimeters, support, adhesion, infill paths
      • converting paths into Gcode (or SVG)
    • __init__.py: main entry point of mandoline program:
      • process arguments
      • load model and relevel, apply model operations (scale), check manifoldness
      • slice model
  • slice model into Gcode to print via FDM 3D printer
  • slice model to SVG slices (very experimental) for debugging purposes and possibly to post-process to pixel-based slices for SLA or SLS 3D printer (not yet tested)
  • load mutiple configs in sequence with -l config.ini, e.g. printer specifics, material settings
  • simple to query features/settings with -Q <term>


% mandoline
== Mandoline Py 0.8.5 == https://github.com/(Spiritdude|revarbat)/mandoline-py
usage: mandoline [-h] [-o OUTFILE] [-n] [-g] [-v] [-d] [--no-raft] [--raft] [--brim] [--no-support] [--support] [--support-all]
                 [-f MATERIAL,...] [-F FORMAT] [-l OPTNAME] [-M OPTNAME=VALUE] [-S OPTNAME=VALUE] [-Q OPTNAME] [-w]
                 [--help-configs] [--show-configs]

positional arguments:
  infile                Input model filename (STL).

optional arguments:
  -h, --help            show this help message and exit
  -o OUTFILE, --outfile OUTFILE
                        Slices model (STL) and write GCode or SVGs to file.
  -n, --no-validation   Skip performing model validation.
  -g, --gui-display     Show sliced paths output in GUI.
  -v, --verbose         Show verbose output.
  -d, --debug           Show debug output.
  --no-raft             Force adhesion to not be generated.
  --raft                Force raft generation.
  --brim                Force brim generation.
  --no-support          Force external support structure generation.
  --support             Force external support structure generation.
  --support-all         Force external support structure generation.
  -f MATERIAL,..., --filament MATERIAL,...
                        Configures extruder(s) for given materials, in order. Ex: -f PLA,TPU,PVA
  -F FORMAT, --format FORMAT
                        Set output format (gcode, svg)
  -l OPTNAME, --load OPTNAME
                        Load config file, containing <k>=<v> lines
                        Set model manipulation operation(s) (scale).
                        Set a slicing config option.
  -Q OPTNAME, --query-option OPTNAME
                        Display a slicing config option value.
  -w, --write-configs   Save any changed slicing config options.
  --help-configs        Display help for all slicing options.
  --show-configs        Display values of all slicing options.

   mandoline cube.stl
   mandoline -l myprinter.ini cube.stl
   mandoline -l myprinter.ini -S layer_height=0.3 cube.stl
   mandoline -l myprinter.ini -l petg.ini -S infill_type=Triangles cube.stl -o test.gcode
   mandoline -Q skirt





By default Mandoline slices STL into 3D printable Gcode:

% mandoline -l y3228.ini hollowCube.stl -S layer_height=0.3 -o test.gcode
== Mandoline Py 0.8.4 == https://github.com/revarbat/mandoline-py
Loading model "hollowCube.stl"
Loading configs from "y3228.ini"                                              
Slicing starting
+ Random offset -78,34
- Perimeters
- Support                                                                     
- Raft[ ], Brim[ ], and Skirt[x]                                              
- Infill (Grid)                                                               
- Pathing                                                                     
- Export GCode to "test.gcode"                                                
Took 0.85s total. Estimated build time: 0h 08m, filament used: 1.394m         


Mandoline (0.8.4+) also supports slicing into SVG, for debugging purpose and possibly can be post-processed into PNG to feed into a SLA or SLS 3D printer (no support-structure included yet).

% mandoline hollowCube.stl -o test.svg
== Mandoline Py 0.8.4 == https://github.com/revarbat/mandoline-py
Loading model "hollowCube.stl"                                              
Slicing starting
- Perimeters
- Export 66x SVGs to "test-*.svg"                                             
Took 0.23s total.       

Issues to Resolve

  • model slicing problems:
    • 3D Benchy incomplete, get more linient or auto-fix regarding non-manifolds:
      • 3DBenchy.stl loaded with manifold checking, 10x “non-manifold hole edges”:
        • Z = 9.087, 5.87
      • when disregarding that check with -n, then it results in various warnings “Incomplete Polygon …” which results in missing slices – major degration of 3D print
      • sliced with many warnings (Incomplete Polygon at z=... => missing layers) @0.2mm layer height: 240 layers, 4.011m with 1.75mm filament
      • sliced with many warnings (=> missing layers) @0.25mm layer height: 192 layers, 4.461m with 1.75mm filament
      • -M scale=0.5 with
        • @0.2mm layer height with warnings (=> missing layers): 120 layers, 0.674m with 1.75mm filament
        • @0.25mm layer height with warnings (=> missing layers): 96 layers, 0.634m with 1.75mm filament- fixing
    • Voron Design Cube v7 wrong sliced layers without warnings
  • random crashs of pyclipper: I noticed a basic model with random_pos=True enabled slices correct and another time when moved to another position fails to slice
  • properly do un/retract:
    • find out if perimeters/walls are crossed, if not, do not un/retract no matter what TYPE of extrusion is done
  • allow case-insensitive settings:
    • infill_type
    • support_type
    • adhesion_type
    • bed_geometry
  • brim, raft and skirt properly done (*_width vs *_lines and *_offset)
  • bottom_layer_extrusion_width
  • bottom_layer_speed
  • top_layer_speed
  • wall/shell/perimeter_speed
  • resolve “shell” vs “wall” vs “perimeter” in source variables, source comments and config
  • infill_type=Hexagons doesn’t work reliable, often infill is missing entirely
  • support 3MF, 3MJ input format beside STL, since 0.8.6: obj, off, amf, 3mf and 3mj
    • properly support multi-volume -> multi-material -> multi-tool
    • 3MF: examples, Debian package: python3-savitar, since 0.8.6 using XML parser
  • clean up multi-nozzle setup, remove GUI, remove material config but hand it over to a collection of .ini files to be selectable with -l my.ini … (not yet finalized how to achieve simple multi-nozzle config easy)
  • testing, testing and testing more
  • future developement
    • integrate geometry3d union, intersection for segmenting sub-volumes
    • analyze geometry from non-planar slicing perspective
    • integrate non-planar slicing: tilted, cyclindrical, conic and spherical at a deeper level
    • mature it to become optional for PAXSlicer 5-axis slicer
    • process metadata from .3mj either piece, sub-volume or face exact within the slicing (tool changing, fill density, slicing settings etc)


  • 2021/09/04: 0.8.6:
    • experimental OFF, OBJ, 3MF, 3MJ support
  • 2021/04/08: 0.8.5:
    • cli: -S shell_speed=s [mm/s]
  • 2021/04/06: 0.8.4:
    • SVG output: supporting slicing to SVG, using “-o test.svg“, very experimental
    • intern: model.scale([x,y,z]) implemented
    • cli: support for -M scale=s or -M scale=x,y,z
    • intern: fixed vector.py normalize() and __truediv__() supporting STL with bad normals
    • un/retract enabled again in code
  • 2021/04/04: 0.8.3:
    • cli & extending configs:
      • cool_fan_speed_{min/max}
      • cool_fan_full_layer=2, e.g. starting fan after e.g. layer 2 is reached, first layer is 0
      • start_gcode and end_gcode and new config type ‘str‘ as well
      • skirt_lines=3 only considered if skirt_layers != 0
      • gcode_comments=True|False: adding various useful info in Gcode
      • random_pos=True|False: randomize position of model on the build-plate
    • all the config included in Gcode given gcode_comments enabled
    • intern: carrying over ‘typ‘ (‘type’ in python 😉 ) of the extrusion in _raw_add_paths, to refine the retract/unretract, this allowed to
    • have output Gcode more descriptive with ;TYPE:.. like PERIMETER, INFILL, PRIME, BRIM, SKIRT, SUPPORT etc, given gcode_comments is enabled
    • cli: support -l or --load to load more configs (e.g. per printer, or material)
    • cli: support -Q <term> partial match
    • output “filament used …[m]” at the end of slicing
    • most un/retract disabled for now to confirm extrusion calculation working
    • prints simple models like 10/20mm cube and xyzHollowCalibrationCubeV2