gscrib.geometry

Utilities for path generation and transformations.

This module provides tools for working with geometric paths and coordinate transformations. It includes functionality for tracing paths and applying transformations to coordinate systems.”

class gscrib.geometry.BoundManager

Bases: object

Bounds manager and validator.

get_bounds(name)

Retrieve the bounds for a given property.

Parameters:

name (str) – Parameter name

Returns:

The min and max bounds

Return type:

Tuple[Bound, Bound]

set_bounds(name, min, max)

Set the bounds for a given property.

Parameters:
  • name (str) – The property for which bounds are being set.

  • min (Bound) – The minimum value of the property.

  • max (Bound) – The maximum value of the property.

Raises:
  • ValueError – If bounds are not valid or property is unknown.

  • TypeError – If the type of min/max is incorrect.

Return type:

None

validate(name, value)

Validate whether a given value is within bounds.

Parameters:
  • name (str) – The property to validate.

  • value (Union[int, float, Point]) – The value to validate.

Raises:

ValueError – If bounds where defined for the property and the provided value is outside bounds.

Return type:

None

class gscrib.geometry.CoordinateTransformer

Bases: object

Coordinate system transformations using 4x4 matrices.

This class provides methods for transforming the coordinate system through operations such as translation, rotation, scaling, and reflection. It maintains a transformation stack for nested transformations.

Transformations are represented internally using 4x4 homogeneous transformation matrices, allowing for chaining of operations.

Example

>>> with CoordinateTransformer() as t:
...     t.translate(10.0, 0.0)
...     t.rotate(90, axis = 'z')
...     t.scale(2.0)
apply_transform(point)

Transform a point using the current transformation matrix.

Parameters:

point (Point | Sequence[float | None] | ndarray | None) – A Point or point-like object.

Returns:

A Point with the transformed (x, y, z) coordinates.

Return type:

Point

chain_transform(transform_matrix)

Chain a new transformation with the current matrix.

Parameters:

transform_matrix (ndarray) – A 4x4 transformation matrix to apply.

Raises:

ValueError – If the input matrix is not 4x4.

Return type:

None

delete_state(name)

Delete a named transformation state.

Raises:

KeyError – If the named state does not exist.

Parameters:

name (str)

Return type:

None

mirror(plane=Plane.ZX)

Apply a mirror transformation across a plane.

Parameters:

plane (Plane | str) – Mirror plane (“xy”, “yz”, or “zx”).

Raises:

ValueError – If the plane is not “xy”, “yz”, or “zx”.

Return type:

None

reflect(normal)

Apply a reflection transformation across a plane.

The reflection matrix is calculated using the Householder transformation: R = I - 2 * (n ⊗ n), where n is the normalized normal vector and ⊗ is outer product

Parameters:

normal (List[float]) – Normal as a 3D vector (nx, ny, nz)

Return type:

None

restore_state(name=None)

Restore the transformation state.

This reverts the transformation matrix and pivot point to the last saved state if no name is provided. If a name is given, it restores the transformation state associated with that name. This is useful for undoing temporary transformations or changes made after a save_state() call.

Parameters:

name (str | None) – Optional name of the saved state to restore.

Raises:
  • IndexError – If attempting to pop from an empty stack.

  • KeyError – If the named state does not exist.

Return type:

None

reverse_transform(point)

Invert a transformed point using the current matrix.

Parameters:

point (Point | Sequence[float | None] | ndarray | None) – A Point or point-like object.

Returns:

A Point with the inverted (x, y, z) coordinates.

Return type:

Point

rotate(angle, axis=Axis.Z)

Apply a rotation transformation around any axis.

Parameters:
  • angle (float) – Rotation angle in degrees.

  • axis (Axis | str) – Axis of rotation (‘x’, ‘y’, or ‘z’).

Raises:

KeyError – If axis is not ‘x’, ‘y’, or ‘z’.

Return type:

None

save_state(name=None)

Save the current transformation state.

This allows for temporary modifications to the transformation state, which can later be reverted using restore_state(). The current transformation matrix and pivot point are saved on the stack if a name is not provided, otherwise the state is saved with that name for later retrieval.

Parameters:

name (str | None) – Optional name for the saved state

Return type:

None

scale(*scale)

Apply uniform or non-uniform scaling to axes.

Parameters:

*scale (float) – Scale factors for the axes.

Return type:

None

Example

>>> matrix.scale(2.0) # Scale everything by 2x
>>> matrix.scale(2.0, 0.5) # Stretch in x, compress in y
>>> matrix.scale(2.0, 1.0, 0.5) # Stretch x, preserve y, compress z
Raises:

ValueError – If number of scale factors is not between 1 and 3.

Parameters:

scale (float)

Return type:

None

set_pivot(point)

Set the pivot point for subsequent transformations.

The pivot point is the reference around which transformations like rotation and scaling occur. For example, to rotate a circle around its center, set the pivot point to the circle’s midpoint before applying the rotation. By default it is set to the origin of coordinates.

Parameters:

point (Point | Sequence[float | None] | ndarray | None) – Pivot point in absolute coordinates.

Return type:

None

translate(x, y, z=0.0)

Apply a 3D translation transformation.

Parameters:
  • x (float) – Translation in X axis.

  • y (float) – Translation in Y axis.

  • z (float) – Translation in Z axis (default: 0.0).

Return type:

None

class gscrib.geometry.PathTracer(builder)

Bases: object

Generating G-code with interpolated motion paths.

This class provides methods to generate G-code commands for complex motion paths by approximating them with small linear segments. The path approximation resolution can be configured to balance between motion smoothness and G-code file size. Smaller resolution values result in smoother paths but generate more G-code commands.

Unlike standard G-code where arc movements are affected by the selected plane (G17/G18/G19), this class always traces paths on the XY plane by default. To transform paths to other planes or orientations, use the transformation methods provided by the builder (translate, rotate, scale, etc).

For complex transformations, the GCodeCore.transform property can be used as a context manager to ensure proper matrix stack handling. Transformations can be combined and will affect all subsequent path operations until the context is exited.

Example

>>> g.move(x=10, y=0)      # Move to start position
>>> g.set_resolution(0.1)  # Set 0.1mm resolution
>>> g.set_direction("cw")  # Set clockwise direction
>>>
>>> # Draw a quarter circle in XY plane
>>> g.trace.arc(target=(0, 10), center=(-10, 0))
>>>
>>> # Draw an arc rotated 45° around the X axis
>>> with g.current_transform():  # Save current transform
...     g.move(x=0, y=0)
...     g.transform.rotate(45, 'x')  # Rotate 45° around X axis
...     g.trace.circle(center=(0, 10))
... # Applied transforms are restored here
arc(target, center, **kwargs)

Trace an arc from the current position to a target point.

This method generates a series of linear segments that approximate a circular arc. The arc is traced around a center point, maintaining a constant radius throughout the motion.

The direction of the arc is determined by the last call to set_direction(). If Z is provided for the target point, the arc will perform helical interpolation.

Parameters:
  • target (Point) – Absolute or relative destination point (x, y, [z])

  • center (Point) – Center point (x, y) relative to the current position

  • **kwargs – Additional G-code parameters (added to each move)

Raises:

ValueError – If start and end points are not equidistant

Return type:

None

Example

>>> # Draw a quarter circle (90 degrees) clockwise
>>> g.move(x=0, y=10)
>>> g.set_direction("cw")  # clockwise
>>> g.trace.arc(target=(10, 0), center=(0, -10))
arc_radius(target, radius, **kwargs)

Trace an arc to target point with specified radius.

Creates an arc from the current position to the target point with the specified radius. Similar to G2/G3 commands, if the radius is positive, the shorter arc will be traced. When negative, the longer arc will be traced.

The direction of the arc is determined by the last call to set_direction(). If Z is provided for the target point, the arc will perform helical interpolation.

Parameters:
  • target (Point) – Absolute or relative destination point (x, y, [z])

  • radius (float) – Radius (positive for shorter arc, negative for longer)

  • **kwargs – Additional G-code parameters (added to each move)

Raises:

ValueError – If radius is too small for the given points

Return type:

None

Example

>>> # Draw a quarter circle with 10mm radius (shorter arc)
>>> g.move(x=0, y=0)
>>> g.trace.arc_radius(target=(10, 10), radius=10)
>>>
>>> # Draw the longer arc between the same points
>>> g.move(x=0, y=0)
>>> g.trace.arc_radius(target=(10, 10), radius=-10)
circle(center, **kwargs)

Trace a complete circle around a center point.

Creates a full 360-degree circular path around the specified center point, starting and ending at the current position. The direction of rotation is determined by the last call to set_direction().

Parameters:
  • center (Point) – Center point (x, y) relative to the current position

  • **kwargs – Additional G-code parameters (added to each move)

Return type:

None

Example

>>> # Draw a circle with 10mm radius
>>> g.move(x=10, y=0)
>>> g.set_direction("ccw")  # counter-clockwise
>>> g.trace.circle(center=(-10, 0))
estimate_length(samples, function)

Estimate the total length of a parametric curve.

Calculates an approximation of the curve length by sampling points along the curve and summing the distances between consecutive points. The accuracy of the estimation improves with a higher number of samples, but requires more computation time.

Parameters:
  • samples (int) – Number of points to sample along the curve

  • function (PathFn) – Parametric function f(theta)

Returns:

Estimated length of the curve in current work units.

Return type:

float

helix(target, center, turns=1, **kwargs)

Trace a helical path to target point with varying radius.

Creates a helical motion that can change radius as it moves from the current position to the target point. The motion is defined by a center point and the number of complete revolutions.

Parameters:
  • target (Point) – Absolute or relative destination point (x, y, [z])

  • center (Point) – Center point (x, y) relative to the current position

  • turns (int) – Number of complete revolutions to make (default: 1)

  • **kwargs – Additional G-code parameters (added to each move)

Raises:

ValueError – If turns is not positive

Return type:

None

Example

>>> # Create a spiral with 3 turns
>>> g.move(x=10, y=0)
>>> g.trace.helix(target=(5, 0), center=(-10, 0), turns=3)
>>>
>>> # Create a helix up 10mm with 2 turns
>>> g.move(x=10, y=0)
>>> g.trace.helix(target=(10, 0, 10), center=(-10, 0), turns=2)
parametric(function, length, **kwargs)

Approximate a parametric curve with linear segments.

Divides a parametric curve into small linear segments based on the current resolution setting. The curve is traced using G1(linear) movements to create a linear approximation of the desired path.

The curve is defined by a parametric function that maps an array of theta parameters in the range [0, 1] to points in space. The number of segments is calculated from the provided curve length and current resolution setting.

Parameters:
  • function (PathFn) – Parametric function f(theta)

  • length (float) – Total curve length in current work units

  • **kwargs – Additional G-code parameters (added to each move)

Raises:

ValueError – If the length parameter is not positive.

Return type:

None

Example

>>> def circle(thetas: ndarray) -> ndarray:
...     x = 10 * cos(2 * pi * thetas)
...     y = 10 * sin(2 * pi * thetas)
...     z = zeros(thetas.shape)
...     return column_stack((x, y, z))
>>>
>>> length = g.trace.estimate_length(100, circle)
>>> g.trace.parametric(circle, length)
polyline(targets, **kwargs)

Trace straight lines through the given points.

Creates a series of straight lines connecting all the specified points, starting from the current position.

Parameters:
  • targets (Sequence[Point]) – Sequence of control points (x, y, [z])

  • **kwargs – Additional G-code parameters (added to each move)

Raises:

ValueError – If not enought points are provided

Return type:

None

spiral(target, turns=1, **kwargs)

Trace a spiral path from current position to target point.

Creates a spiral motion that changes radius as it moves from the current position to the target point. If Z is provided for the target point, the spiral will perform helical interpolation.

Parameters:
  • target (Point) – Absolute or relative destination point (x, y, [z])

  • turns (int) – Number of complete revolutions to make (default: 1)

  • **kwargs – Additional G-code parameters (added to each move)

Raises:

ValueError – If turns is not positive

Return type:

None

spline(targets, **kwargs)

Trace a cubic spline through the given control points.

Creates a smooth curve that passes through all the specified control points, starting from the current position. The spline is approximated using linear segments based on the current resolution setting.

Parameters:
  • targets (Sequence[Point]) – Sequence of control points (x, y, [z])

  • **kwargs – Additional G-code parameters (added to each move)

Raises:

ValueError – If not enought points are provided

Return type:

None

Example

>>> # Draw a smooth curve through three points
>>> g.trace.spline([(5, 5), (10, -5), (15, 0)])
thread(target, pitch=1, **kwargs)

Trace a thread-like helical path to target point.

Creates a helical motion with constant radius from the current position to the target point. The motion is defined by the distance from the current position to the target Z height and the pitch.

Parameters:
  • target (Point) – Absolute or relative destination point (x, y, [z])

  • pitch (float) – Distance between turns in Z axis

  • **kwargs – Additional G-code parameters (added to each move)

Raises:

ValueError – If radius or pitch is not positive

Return type:

None

class gscrib.geometry.Point(x=None, y=None, z=None)

Bases: NamedTuple

A point in a 3D space.

This class represents a point in 3D space, where each coordinate (x, y, z) can be either a float value or None. None values indicate unknown or unspecified coordinates.

Most methods in gscrib.GCodeCore and gscrib.GCodeBuilder that accept Point objects are designed to work with point-like values, which can be a Point object or a sequence containing the (x, y, z) coordinates as numeric values.

The class supports basic arithmetic operations, that raise TypeError if any coordinates of the points are unknown. The method resolve can be used to create a new Point with any unknown coordinates set to zero.

Examples

>>> #Create points using different constructors:
>>> p1 = Point(1.0, 2.0, 3.0)      # All coordinates specified
>>> p2 = Point(x=1.0, z=3.0)       # Y coordinate is None
>>> p3 = Point.zero()              # Point at origin (0, 0, 0)
>>> p4 = Point.unknown()           # All coordinates are None
>>>
>>> # Using PointLike values
>>> g.move([1.0, 2.0, 3.0])        # Using a list
>>> g.move(point=(1.0, 2.0, 3.0))  # Using a tuple
>>> g.move(Point(1.0, 2.0, 3.0))   # Using a Point object
>>> g.move(x=1.0, y=2.0, z=3.0)    # Individual coordinates
>>>
>>> # Arithmetic operations
>>> p1 = Point(1.0, 2.0, 3.0)
>>> p2 = Point(2.0, 3.0, 4.0)
>>> p3 = p1 + p2  # Point(3.0, 5.0, 7.0)
>>> p4 = p2 - p1  # Point(1.0, 1.0, 1.0)
>>> p5 = p1 * 2   # Point(2.0, 4.0, 6.0)
>>> p6 = p1 / 2   # Point(0.5, 1.0, 1.5)
Parameters:
classmethod from_params(params)

Create a point from a dictionary of move parameters.

Parameters:

params (ParamsDict)

Return type:

Point

classmethod from_vector(vector)

Create a Point from a 4D vector

Parameters:

vector (ndarray)

Return type:

Point

classmethod unknown()

Create a point with unknown coordinates

Return type:

Point

classmethod zero()

Create a point at origin (0, 0, 0)

Return type:

Point

combine(o, t, m)

Update coordinates based on position changes.

Updates coordinates by comparing the current, reference, and target points. Individual coordinates are updated to the values from point ‘m’ following these rules:

  • If the current coordinate is not None.

  • If current is None but reference and target differ.

Parameters:
  • o (Point) – The reference position

  • t (Point) – The target point to update towards

  • m (Point) – Values to use when updating

Returns:

A new point with the coordinates combined

Return type:

Point

count(value, /)

Return number of occurrences of value.

index(value, start=0, stop=9223372036854775807, /)

Return first index of value.

Raises ValueError if the value is not present.

mask(x=None, y=None, z=None)

Create a new point with coordinates set to None if specified.

This method creates a new point where coordinates are set to None if their corresponding parameter is not None. This is useful for marking coordinates as unknown when they are involved in an operation.

Parameters:
  • x (float | None) – Set X to None if not None

  • y (float | None) – Set Y to None if not None

  • z (float | None) – Set Z to None if not None

Returns:

A new point with the specified coordinates.

Return type:

Point

replace(x=None, y=None, z=None)

Create a new point replacing only the specified coordinates.

Parameters:
  • x (float | None) – New X position or None to keep the current

  • y (float | None) – New Y position or None to keep the current

  • z (float | None) – New Z position or None to keep the current

Returns:

A new point with the specified coordinates.

Return type:

Point

resolve()

Create a new point replacing None values with zeros.

Return type:

Point

to_vector()

Convert point to a 4D vector

Return type:

ndarray

within_bounds(min_point, max_point)

Check if point lies within bounds defined by two points.

Coordinates that are None in either self, min_point, or max_point points are ignored in the comparison.

Parameters:
  • min_point (Point) – The minimum boundary point

  • max_point (Point) – The maximum boundary point

Returns:

True if all known coordinates are within bounds

Return type:

bool

x: float | None

Alias for field number 0

y: float | None

Alias for field number 1

z: float | None

Alias for field number 2

class gscrib.geometry.Transform(matrix, pivot)

Bases: object

Encapsulates a transformation state.

Parameters:
  • matrix (ndarray)

  • pivot (Point)

apply(point)

Transform the coordinates of a point.

Parameters:

point (Point) – A Point or point-like object.

Returns:

A Point with the transformed (x, y, z) coordinates.

Return type:

Point

reverse(point)

Invert he transformed coordinates of a point.

Parameters:

point (Point) – A Point or point-like object.

Returns:

A Point with the inverted (x, y, z) coordinates.

Return type:

Point