Additive manufacturing
Overview
Additive manufacturing builds a part up instead of cutting it down. The 3D-printing side of Rasmah turns a watertight mesh into a sequence of flat layers, traces perimeters (walls) and infill inside each layer, and emits the G-code that drives an extruder — the same design → tool path → controller code pipeline as milling, but with an extrusion axis.
The guiding principle is volume balance: the filament pushed into the hot end must exactly become the bead it deposits. A bead of length $L$, width $w$, and height $h$ has volume $Lwh$; the filament of diameter $d$ fed in has volume $E \cdot \pi (d/2)^{2}$. Setting them equal gives the extrusion length
\[E = \frac{L\,w\,h}{\pi (d/2)^{2}} .\]
Slicing
Slicing cuts the mesh into horizontal layers at the given layer height:
Rasmah.SliceLayer — Type
A single slice: its height and its closed contours, oriented so outer loops are counter-clockwise (positive area) and holes are clockwise (negative).
Rasmah.slice — Function
Slice a watertight mesh into ceil((zmax-zmin)/layer_height) layers from zmin upward. By default the whole vertical extent of the mesh is used.
Rasmah.slice_layer — Function
Slice a watertight mesh at one height, with contours oriented (outer CCW, holes CW) and sorted by |area| descending.
Rasmah.slice_contours — Function
Cross-section a watertight TriangleMesh by the plane z = z0, returning closed 3D loops (each a Vector{Vector{Float64}} of coplanar points).
Rasmah.layer_height — Function
layer_height(s) -> zThe height (z) of a SliceLayer.
Perimeters and infill
Each layer is filled in two stages: the perimeters (the walls, traced inward), then the infill (the interior pattern):
Rasmah.perimeters — Function
Perimeters (walls) of a layer: the contours offset inward walls times by the nozzle line_width (the first wall rides half a width inside the boundary).
Rasmah.infill_segments — Function
Infill scan segments of a layer for a given density/pattern. Density scales the line spacing so density=1 gives fully solid lines at line_width.
Rasmah.inset_contour — Function
Offset a single planar (CCW) contour inward by distance (positive shrinks). Each vertex is the intersection of its two incident edges offset inward by distance. Exact for convex polygons; concave self-intersections are left to the caller (use negative distance to grow, i.e. outward).
Rasmah.grid_infill — Function
Scanline (rectilinear) fill of a region with parallel lines at spacing, rotated by angle (radians, in the XY plane). Returns a vector of (a, b) 3D segments (z copied from the region).
Rasmah.triangular_infill — Function
Triangular infill: three grid_infill passes at 0°, 60°, 120°.
Rasmah.concentric_infill — Function
Concentric (offset) infill: repeated inward offsets of the outer contour at stepover, returning the contour rings.
m = surface_mesh(sphere(1.0))
plan = print_plan(m; layer_height=0.2, perimeters=2, infill_density=0.2)
length(plan.layers)11A unit sphere (1 m diameter) sliced at 0.2 m layers gives 11 layers.
Extrusion and G-code
The extrusion balance above becomes a number via extrusion_length, and the whole plan becomes a Marlin-flavoured program via print_gcode:
Rasmah.extrusion_length — Function
Extrusion length (mm of filament) needed to lay a bead of length, width, and height, from a filament_diameter feed. Volume balance: length·width·height = E·π·(d/2)².
Rasmah.PrintPlan — Type
PrintPlanA complete FDM print plan: the sliced layers plus the extrusion settings used to turn them into G-code.
Fields
layers: the slicedSliceLayers.perimeters: number of wall perimeters.infill_density: infill density (1 = solid).line_width: nozzle line width (m).layer_height: layer height (m).filament_diameter: filament diameter (m).
Rasmah.print_plan — Function
Build a print plan from a watertight mesh: slice it, then record the extrusion settings.
Rasmah.print_gcode — Function
Marlin-flavoured G-code for a print plan: home, heat, then per-layer perimeter and infill moves with extrusion (M83 relative E). Returns the full program text.
extrusion_length(10e-3, 0.4e-3, 0.2e-3, 1.75e-3)0.00033260135046143024Laying a 10 mm bead that is 0.4 mm wide and 0.2 mm tall from 1.75 mm filament needs about 0.33 mm of filament — the volume balance in one number.
gc = print_gcode(plan)
split(gc, '\n')[1:4]4-element Vector{SubString{String}}:
"; Rasmah print plan"
"M104 S210 ; set extruder temp"
"M140 S60 ; set bed temp"
"M190 S60 ; wait bed"Overhangs and supports
Faces that slope outward past a threshold need support, and the flat top face benefits from ironing:
Rasmah.overhang_angle — Function
Angle from the vertical (build direction) of each face normal, in radians: 0 for an up-facing face, π/2 for a vertical wall, π for a down-facing face.
Rasmah.unsupported_faces — Function
Count of down-facing faces steeper than max_angle from horizontal (i.e. the surface tilts down by more than max_angle), excluding faces resting on the build plate. These are the regions needing support.
Rasmah.support_mesh — Function
Generate a support volume for the overhanging faces of a mesh: a filled prism (from the overhang down to the build plate) returned as a triangle mesh (union of the support prisms). max_angle is the maximum printable overhang (from horizontal).
Rasmah.ironing_region — Function
Ironing: a dense top-surface pass that remelts the topmost solid layer for a smooth finish. Returns the top surface region (XY contours at the top height).
Rasmah.vase_mode — Function
Spiralize the outer contour of a mesh into a continuous single-wall vase: resample the outer contour at each layer and advance layer_height per lap, emitting a helical ToolPath (the Z rises continuously rather than in steps).
Next steps
Additive manufacturing closes the machining loop. Return to Milling, turning, and cutting for the subtractive side, or back to Manufacturing for the shared tool-path model that both sides produce.
