Skip to content

Toolpath Strategies

A strategy answers one question: given this geometry, what sequence of positions should the tool visit?

All strategies inherit from ToolpathStrategy and return a ToolpathCollection.


FollowCurveStrategy

Generates a toolpath that follows a predefined curve point-by-point. The simplest and most fundamental strategy.

from toolpath_engine import FollowCurveStrategy, Curve

helix = Curve.helix(center=(0, 0, 0), radius=40, pitch=5, turns=4)

paths = FollowCurveStrategy().generate(
    curve=helix,
    feed_rate=600,        # mm/min
    spacing=1.0,          # resample curve to this point spacing (mm); 0 = use as-is
    path_type="deposit",  # stored as metadata on each point
)

Use this for:

  • Weld paths, deposition paths, laser scan lines
  • Any process where you've already defined the exact path geometry

RasterFillStrategy

Generates parallel raster passes across a surface — like the infill pattern in a 3D printer slicer, or a lawn-mowing pattern.

from toolpath_engine import RasterFillStrategy, Surface

top_plate = Surface.plane(origin=(0, 0, 80), normal=(0, 0, 1), size=60)

paths = RasterFillStrategy().generate(
    surface=top_plate,
    spacing=3.0,      # distance between parallel passes (mm)
    feed_rate=500,
    step_size=0.5,    # point spacing along each pass (mm)
    path_type="deposit",
)

Use this for:

  • Area coverage: coating, cladding, surface finishing
  • Layer-by-layer additive deposition on flat surfaces

ContourParallelStrategy

Generates offset contour passes inward (or outward) from a boundary — like the perimeter shells in a 3D printer.

from toolpath_engine import ContourParallelStrategy, Curve

boundary = Curve.circle(center=(0, 0, 80), radius=30, num_points=64)

paths = ContourParallelStrategy().generate(
    boundary=boundary,
    stepover=3.0,      # offset distance between passes (mm)
    num_passes=4,      # number of inward passes
    feed_rate=700,
    path_type="deposit",
)

Use this for:

  • Building up walls around a boundary
  • Island filling from the outside in
  • Spiral-in patterns for circular features

How it works

Each pass is generated by _offset_curve_2d(), which offsets the boundary curve in the XY plane using a simple inward normal calculation:

  1. For each point on the boundary, compute the inward-facing normal (perpendicular to the curve tangent, rotated 90° in XY)
  2. Translate the point by stepover * pass_index along that normal
  3. Resample the offset curve to the requested point spacing

The Z coordinate of all points is taken from the input boundary — the strategy does not vary Z between passes.

Parameters

Parameter Type Default Description
boundary Curve required The outer (or inner) boundary to offset from
stepover float 3.0 Distance between each offset pass (mm)
num_passes int 4 Number of offset passes to generate
feed_rate float 500 Feed rate for all points (mm/min)
step_size float 0.5 Point spacing along each pass (mm)
path_type str "deposit" Metadata tag stored on each point

Current limitations

  • 2D offset only_offset_curve_2d operates in XY. It does not follow 3D surface curvature. For curved surfaces, the offset passes will drift from the surface normal as the curve bends in Z.
  • No hole support — offset passes can self-intersect for highly concave boundaries. No clipping or pruning of self-intersections is currently implemented.
  • Fixed Z — all passes share the Z of the input boundary. Use FollowCurveStrategy with a pre-computed 3D path if you need Z variation between passes.

Setting process parameters on a collection

After generating paths, attach process parameters to all points at once:

paths.set_param("wire_feed", 3.0)
paths.set_param("laser_power", 2000)
paths.set_param("shielding_gas_flow", 15.0)

These are stored in point.process_params and mapped to G-code output letters via PostConfig.param_codes.


Writing a custom strategy

Subclass ToolpathStrategy and implement generate():

from toolpath_engine.strategies.base import ToolpathStrategy
from toolpath_engine.core.toolpath import Toolpath, ToolpathPoint, ToolpathCollection
from toolpath_engine.core.primitives import Position, Orientation

class SpiralStrategy(ToolpathStrategy):
    def generate(self, radius, pitch, turns, feed_rate=500, **kwargs):
        import math
        points = []
        n = int(turns * 72)
        for i in range(n):
            t = i / 72  # turns elapsed
            angle = 2 * math.pi * t
            x = radius * math.cos(angle)
            y = radius * math.sin(angle)
            z = pitch * t
            points.append(ToolpathPoint(
                position=Position(x, y, z),
                orientation=Orientation(0, 0, -1),
                feed_rate=feed_rate,
            ))
        tp = Toolpath(points=points)
        return ToolpathCollection(toolpaths=[tp])