Skip to content

Releases: barebaric/raygeo

v0.13.2

28 Jun 19:57

Choose a tag to compare

What's Changed

  • New precision parameter for adaptive wavefronts — controls the angular step when sweeping wavefront arcs; improves performance and fidelity of adaptive clearing engagement paths
  • Fix: reengagement search for adaptive clearing — correctly handles cases where the reengagement point search would skip valid positions near narrow-region boundaries

Full Changelog: https://github.com/anomalyco/raygeo/compare/v0.13.1...v0.13.2

v0.13.1

28 Jun 17:59

Choose a tag to compare

What's Changed

  • New adaptive clearing debug tool — interactive Streamlit-based step-through inspector for adaptive clearing operations
  • Fix: bezier command parsing for legacy formats — proper handling of bezier curves in older SVG/CAM files
  • Better adaptive clearing diagnostic plots — improved visualization of narrow regions and centre-island detection
  • De-duplicated debug logging macros — consolidated debug log infrastructure into a shared module
  • Polyline tests ported to Python — moved test coverage from Rust to Python test suite

v0.13.0

27 Jun 20:52

Choose a tag to compare

Release v0.13.0

Highlights

  • Improved adaptive_wavefronts() results — better quality wavefront generation
  • Numerous performance improvements — sweep_area(), build_link_segments with rayon, lazy MAT trimming, profiling infrastructure
  • Reorganized ops module: ops.polyline split into ops.assembly.polyline + ops.transform.link; ops.assembly.hsm split into ops.assembly.entry + ops.assembly.wavefront
  • Removed unreliable adaptive_peeling() and associated HSM pipeline
  • New geo.algo.engagement module: point_engagement, angular_engagement, compute_engagement, disk_segment_area
  • New geo.algo.rootfind module: bisect, illinois, secant solvers with tracking variants and bracket_grid
  • New geometry helpers: does_polygon_enclose_circle, get_polygon_heading_at, walk_polygon_from_point, rotate_point, normalize_angle_signed, does_rect_contain_rect
  • SpatialGrid gains a remove() method

Migration Guide: v0.12.1 → v0.13.0

Module Moves

ops.polyline split into ops.assembly.polyline + ops.transform.link

v0.12.1 v0.13.0
raygeo.ops.polyline.polyline_to_ops raygeo.ops.assembly.polyline.polyline_to_ops
raygeo.ops.polyline.link_passes raygeo.ops.transform.link.link_passes
raygeo.ops.polyline.find_pass_entry raygeo.ops.transform.link.find_pass_entry
raygeo.ops.polyline.find_pass_exit raygeo.ops.transform.link.find_pass_exit
raygeo.ops.polyline.LinkStrategy raygeo.ops.transform.link.LinkStrategy

Old: from raygeo.ops.polyline import polyline_to_ops, link_passes, LinkStrategy
New: from raygeo.ops.assembly.polyline import polyline_to_ops / from raygeo.ops.transform.link import link_passes, LinkStrategy

ops.assembly.hsm split into ops.assembly.entry + ops.assembly.wavefront

v0.12.1 v0.13.0
raygeo.ops.assembly.hsm.adaptive_entry raygeo.ops.assembly.entry.adaptive_entry
raygeo.ops.assembly.hsm.adaptive_wavefronts raygeo.ops.assembly.wavefront.adaptive_wavefronts

Old: from raygeo.ops.assembly.hsm import adaptive_entry, adaptive_wavefronts
New: from raygeo.ops.assembly.entry import adaptive_entry / from raygeo.ops.assembly.wavefront import adaptive_wavefronts

Removed (No Replacement)

  • adaptive_peeling() — too unreliable, removed entirely
  • find_cutting_arc(), link_arcs_to_ops(), split_ordered_wavefronts(), PyWavefrontGraph — part of removed HSM pipeline
  • does_rect_intersect_rect() — duplicate of do_rects_intersect()
  • find_next_resume(..., medial_axis=...)medial_axis parameter dropped
  • ResumePoint.link_path field removed
  • Tool.step / Tool.step_with_bias — merged into single step method

Removed Modules

Module Migration
raygeo.ops.polyline ops.assembly.polyline + ops.transform.link
raygeo.ops.assembly.hsm ops.assembly.entry + ops.assembly.wavefront

New Public API

raygeo.geo.algo.engagementpoint_engagement, angular_engagement, compute_engagement, disk_segment_area

raygeo.geo.algo.rootfindbisect, bisect_tracked, bracket_grid, illinois, illinois_tracked, secant, secant_tracked

New geometry helpersdoes_polygon_enclose_circle, get_polygon_heading_at, walk_polygon_from_point, rotate_point, normalize_angle_signed, does_rect_contain_rect, SpatialGrid.remove

Quick Migration

# polyline / link
# Old:
from raygeo.ops.polyline import polyline_to_ops, link_passes, LinkStrategy
# New:
from raygeo.ops.assembly.polyline import polyline_to_ops
from raygeo.ops.transform.link import link_passes, LinkStrategy

# HSM assembly
# Old:
from raygeo.ops.assembly.hsm import adaptive_entry, adaptive_wavefronts
# New:
from raygeo.ops.assembly.entry import adaptive_entry
from raygeo.ops.assembly.wavefront import adaptive_wavefronts

# Removed — no replacement:
# adaptive_peeling(), find_cutting_arc(), link_arcs_to_ops(),
# split_ordered_wavefronts(), PyWavefrontGraph

v0.12.1

23 Jun 23:21

Choose a tag to compare

Breaking changes

  • Removed machining terminology from the geo layer — several functions
    and parameters renamed to use geometry-domain names:
    • trochoid_along_3d: tool_diameterdiameter
    • ClearedArea.expand: tool_pathpath, tool_radiusradius
    • MedialAxis.compute: tool_radiusmin_clearance
    • offset.find_deepest_cores: valid_tool_arearegions
  • append_end_fillets: the single side parameter is split into
    start_side and end_side, fixing fillet direction at V-junctions

New features

  • descending_radius_fillet — new fillet function that tries descending
    radii until one fits, replacing the manual trim_to_safe_fillet_span /
    try_fillet_one_end cascade
  • cut_power parameter on adaptive_entry, adaptive_peeling,
    adaptive_wavefronts, and link_arcs_to_ops for laser power control
  • PyWavefrontGraph gains segments, segment_directions, and
    arc_segments properties exposing V-junction-split sub-segments

Bug fixes

  • Fix duplicate cutlines emitted by split_ordered_wavefronts
  • Fix wrong fillet direction on arcs with V-junctions (split arcs before
    determining turn sign so each half gets its own direction)
  • Fix adaptive peeling corner coverage — all bites now incorporated
    unconditionally, with a perimeter fallback when find_cutting_arc fails
  • Fix CDT panics from degenerate geometry and peeling hangs on pinched
    frontiers
  • Fix link_arcs_to_ops MAT reconstruction when passed raw (nodes, edges)

Full commit log: https://github.com/anomalyco/raygeo/compare/v0.12.0...v0.12.1

v0.12.0

23 Jun 01:27

Choose a tag to compare

v0.12.0

Highlights

  • Layered architecture: geoopscnc layering established with HSM motion assembly moved from geo to ops::assembly.
  • CNC terminology: Laser-centric naming replaced with CNC-milling terminology (cut_speedfeed_rate, travel_speedrapid_rate, air_assistCoolantMode, etc.).
  • 2D/3D naming convention: All functions now follow bare = 2D, _3d = 3D.
  • Polygon/Polyline module split: Polyline functions moved from polygon to dedicated polyline module.
  • New geometry primitives: Medial axis routing, A* pathfinding, FEM meshing, spiral/helix/ramp/trochoid primitives, polylabel, offset improvements.
  • New CNC module: raygeo.cnc with Tool, StateStrategy, EntryStrategy, and adaptive_clear_hsm orchestrator.

Breaking changes

See the full migration guide below.

CNC terminology rename

  • State.cut_speedState.feed_rate
  • State.travel_speedState.rapid_rate
  • State.active_laser_uidState.active_head_uid
  • State.spindle_speedState.spindle_rpm
  • Ops.set_cut_speed()Ops.set_feed_rate()
  • Ops.set_travel_speed()Ops.set_rapid_rate()
  • Ops.set_laser()Ops.set_head()
  • Ops.set_spindle_speed()Ops.set_spindle_rpm()
  • ops.travel_distance()ops.distance()
  • enable_air_assist() removed → use set_coolant()
  • estimate_time/estimate_command_times parameter rename: default_cut_speeddefault_feed_rate, default_travel_speeddefault_rapid_rate
  • get_frame(speed=)get_frame(feed_rate=)
  • CommandType.SetCutSpeedSetFeedRate, SetTravelSpeedSetRapidRate, SetLaserSetHead, SetSpindleSpeedSetSpindleRpm
  • CommandType.EnableAirAssist/DisableAirAssist removed → SetCoolant

Coolant mode enum

  • State.air_assist: boolState.coolant: Option<CoolantMode>
  • CoolantMode values: Off, Flood, Mist, Air

ScanMode uppercase

  • ScanMode.SegmentedScanMode.SEGMENTED
  • ScanMode.FullSweepScanMode.FULL_SWEEP

JoinStyle enum

  • offset_polygon(..., join_style="round")offset_polygon(..., join_style=JoinStyle.Round)
  • offset_contour_group(..., join_style="miter")offset_contour_group(..., join_style=JoinStyle.Miter)
  • Rust: offset_polygon_with_style renamed back to offset_polygon

Rect/Rect3D struct change

  • Rect(x1, y1, x2, y2)Rect { min: Point, max: Point }
  • Rect.0/.1/.2/.3Rect.min.x/.y, Rect.max.x/.y
  • Rect3D.x_min/.x_max/.y_min/.y_max/.z_min/.z_maxRect3D.min/.max

2D/3D naming

  • circumcenter is now 2D; circumcenter_3d is 3D (swap)
  • simplify_polylinesimplify_polyline_3d (2D wrapper removed)
  • midpointmidpoint_3d, transform_pointtransform_point_3d
  • normal_from_clockwisenormal_from_clockwise_3d
  • generate_helixgenerate_helix_3d, generate_spiralgenerate_spiral_3d, generate_rampgenerate_ramp_3d, trochoid_alongtrochoid_along_3d
  • smooth_polylinesmooth_polyline_3d
  • flatten_to_pointsflatten_to_points_3d
  • resample_polyline (3D) moved from geo.algo.smooth to geo.shape.polygon3d

Module reorganization

  • ops.lead_in_outops.assembly.lead_in_out (re-exported)
  • ops.overscanops.assembly.overscan (re-exported)
  • ops.tabsops.assembly.tabs (re-exported)
  • ops.polylineops.assembly.polyline (re-exported)
  • ops.rasterops.assembly.raster (re-exported)
  • Polygon module split: polyline functions moved to geo.shape.polyline

New features

CNC orchestration (raygeo.cnc)

  • Tool, ToolShape, ToolMaterial classes
  • StateStrategy with constant() factory
  • EntryStrategy with helix/ramp support
  • adaptive_clear_hsm — full HSM clearing orchestrator

Geometry additions

  • Medial axis computation and MAT path routing
  • A* pathfinding with rasterized grid
  • FEM PDE meshing with Laplace solver
  • Flat Archimedean spiral primitive
  • ClearedArea with fragments(), bites(), bite_in_direction(), incorporate(), all_bites(), remaining_in_inset(), add_cleared_polygons()
  • Adaptive entry (helix/spiral + zigzag ramp) and adaptive wavefronts
  • Polylabel: find_largest_circle, pole-of-inaccessibility algorithm
  • Offset improvements: find_deepest_cores, compute_inset_region, apply_minimum_curvature
  • JoinStyle enum (Miter/Round/Square) for offset operations
  • Fillet arc ends, safe sweep end detection
  • walk_along_polyline_3d, walk_along_polygon_3d, fillet_polyline_3d
  • polyline_to_ops, link_passes, find_pass_entry/find_pass_exit
  • apply_lead_in_out, apply_overscan, apply_tab_gaps, apply_tab_power
  • get_ray_polygon_intersection, does_line_cross_polygon, get_segment_segment_distance
  • get_polyline_closest_point, trim_polyline_at, trim_polyline_angular_ends
  • split_polyline_at_v_junctions, resample_polygon
  • get_polygon_boundary_distance, get_polygon_vertex_centroid
  • shortcut_path smoothing, shortcut + Gaussian relaxation
  • deduplicate_polyline_3d, get_polyline_end_tangent_3d
  • fit_cubic_bezier, nearest_tangent_circle_on_bezier
  • arc_through_point, generate_arc_between_two_points, generate_linking_arc
  • interpolated_segment_3d, circumcenter_2d
  • get_polygon_area_3d, get_polygon_signed_area_3d
  • order_nearest_neighbor, blend_tangent, get_polyline_turn_sign
  • compute_valid_tool_area

Ops additions

  • Ops::apply_state(&State) for domain-neutral state emission
  • Ops.distance(), Ops.cut_distance()
  • CoolantMode enum

Migration Guide

Migration Guide

1. 2D/3D Naming Convention

Function names now consistently follow the rule: bare = 2D, _3d = 3D.

Tier 1 — Pair inversions

circumcenter / circumcenter_3d swap

The 3D circumcenter (takes Point3D) was renamed from circumcenter to circumcenter_3d. The 2D circumcenter (takes Point) was renamed from circumcenter_2d to circumcenter.

 // Rust
-use raygeo::geo::shape::point::circumcenter;     // was 3D, now 2D
+use raygeo::geo::shape::point::circumcenter_3d;  // 3D circumcenter (returns Option<Point3D>)
+use raygeo::geo::shape::point::circumcenter;      // 2D circumcenter (returns (Point, f64))
 # Python
-from raygeo.geo.shape.point import circumcenter        # was 3D
-from raygeo.geo.shape.point import circumcenter_2d      # was 2D
+from raygeo.geo.shape.point import circumcenter_3d     # 3D circumcenter
+from raygeo.geo.shape.point import circumcenter         # 2D circumcenter

simplify_polylinesimplify_polyline_3d

 // Rust
-use crate::geo::algo::simplify::simplify_polyline;
+use crate::geo::algo::simplify::simplify_polyline_3d;

The Python 2D wrapper was removed entirely — only simplify_polyline_3d exists:

 # Python
-from raygeo.geo.algo.simplify import simplify_polyline  # removed
-from raygeo.geo.algo.simplify import simplify_polyline_3d
+from raygeo.geo.algo.simplify import simplify_polyline_3d  # only name

Convert 2D calls by adding z=0:

-result = simplify_polyline([(0, 0), (5, 5), (10, 0)], tolerance=0.5)
+result = simplify_polyline_3d([(0, 0, 0), (5, 5, 0), (10, 0, 0)], tolerance=0.5)

Tier 3 — Misnamed _2d helpers → _xy

Private functions that accept Point3D but only measure XY:

File Old name New name
src/ops/assembly/tabs.rs bezier_arc_length_2d bezier_arc_length_xy
src/ops/assembly/tabs.rs distance_2d distance_xy
src/ops/optimize.rs dist_2d dist_xy

No Python impact (all private).

Tier 4 — 3D orphans → _3d suffix

Functions that return 3D types and have no 2D counterpart:

Point operations

 // Rust
-use crate::geo::shape::point::midpoint;
-use crate::geo::shape::point::transform_point;
+use crate::geo::shape::point::midpoint_3d;
+use crate::geo::shape::point::transform_point_3d;
 # Python
-from raygeo.geo.shape.point import midpoint
-from raygeo.geo.shape.point import transform_point
+from raygeo.geo.shape.point import midpoint_3d
+from raygeo.geo.shape.point import transform_point_3d

Arc operations

 // Rust
-use crate::geo::shape::arc::normal_from_clockwise;
+use crate::geo::shape::arc::normal_from_clockwise_3d;

No Python impact (no direct binding).

Helix / Spiral / Ramp / Trochoid

 // Rust
-use crate::geo::algo::helix::generate_helix;
-use crate::geo::algo::spiral::generate_spiral;
-use crate::geo::algo::ramp::generate_ramp;
-use crate::geo::algo::trochoid::trochoid_along;
+use crate::geo::algo::helix::generate_helix_3d;
+use crate::geo::algo::spiral::generate_spiral_3d;
+use crate::geo::algo::ramp::generate_ramp_3d;
+use crate::geo::algo::trochoid::trochoid_along_3d;
 # Python
-from raygeo.geo.algo.helix import generate_helix
-from raygeo.geo.algo.spiral import generate_spiral
-from raygeo.geo.algo.ramp import generate_ramp
-from raygeo.geo.algo.trochoid import trochoid_along
+from raygeo.geo.algo.helix import generate_helix_3d
+from raygeo.geo.algo.spiral import generate_spiral_3d
+from raygeo.geo.algo.ramp import generate_ramp_3d
+from raygeo.geo.algo.trochoid import trochoid_along_3d

Smoothing

 // Rust
-use crate::geo::algo::smooth::smooth_polyline;
+use crate::geo::algo::smooth::smooth_polyline_3d;
 # Python
-from raygeo.geo.algo.smooth import smooth_polyline
+from raygeo.geo.algo.smooth import smooth_polyline_3d

Fitting

 // Rust
-use crate::geo::algo::fitting::flatten_to_points;
+use crate::geo::algo::fitting::flatten_to_points_3d;
 # Python
-from raygeo.geo.algo.fitting import flatten_to_points
+from raygeo.geo.algo.fitting import flatten_to_points_3d

Tier 5 — Rect re-export

Rect is now exporte...

Read more

v0.11.0

21 Jun 22:05

Choose a tag to compare

v0.11.0 (2026-06-22)

78 commits since v0.10.0. ~10 400 insertions across 113 source files.


Breaking Changes

See the full Migration Guide below.

  1. Rect — tuple struct → named fields (min/max as Point)
  2. Rect3D — flat fields → min/max as Point3D
  3. offset_polygon() gained a required JoinStyle parameter (Python defaults to "miter")
  4. trochoid_along() output — added longitudinal component (true trochoidal loop)
  5. ScanMode variants renamed to UPPER_CASE (SegmentedSEGMENTED, FullSweepFULL_SWEEP)

New Modules

  • raygeo.geo.algo.astar — A* pathfinding with rasterized grid support, obstacle avoidance, and configurable heuristics.
  • raygeo.geo.algo.cleared_area — Incremental union of tool-swept polygons with SpatialGrid-windowed queries. Supports incorporate, frontier, bites, fragments, remaining_in_inset, and add_cleared_polygons.
  • raygeo.geo.algo.fillet — Fillet arc-end trimming and linking primitives extracted from the HSM module.
  • raygeo.geo.algo.medial_axis — Delaunay-circumcenter Medial Axis Transform with per-branch boustrophedon routing (mat_path).
  • raygeo.geo.algo.polylabel — Pole of inaccessibility with hole/island support (find_largest_circle, get_polygon_closest_point).
  • raygeo.geo.algo.spiral — Flat Archimedean spiral primitive (generate_spiral / SpiralOptions).
  • raygeo.mesh — Full PDE meshing pipeline: constrained Delaunay triangulation (spade), linear FEM Laplace solver (nalgebra CG), gradient field computation, spiral tracing across triangle meshes, and remeshing. Submodules: build, laplace, gradient, pde, remesh, types.

HSM (High Speed Machining)

  • Adaptive clearing wavefronts — inside-out expansion loop with frontier-based clipping, simplification, and multi-island support.
  • Adaptive peeling — peeling algorithm for centred seed circles with full-ring cutting arc generation and filleted arc-end linking.
  • Adaptive entry — Helix → spiral (wide area) or ZigZag ramp (tight slot) with AdaptiveEntryOptions / AdaptiveEntryResult.
  • ClearedArea methodsincorporate, frontier, bites, fragments, remaining_in_inset, add_cleared_polygons.
  • Constrained path smoothingsmooth_path() with shortcut + Gaussian relaxation, obstacle clearance, integrated into link_filleted_arcs and AdaptiveWavefrontOptions.
  • compute_inset_region — replaces compute_valid_tool_area throughout the HSM pipeline.

New Functions (existing modules)

raygeo.geo.shape

  • point: circumcenter
  • arc: arc_through_point, get_polyline_turn_sign
  • bezier: fit_cubic_bezier, nearest_tangent_circle_on_bezier
  • circle: find_tangent_circle_centers, nearest_tangent_circle_on_polyline
  • line: does_line_cross_polygon, get_segment_segment_distance, longest_line_through_point, get_interior_angle, interpolated_segment_3d
  • polygon: apply_minimum_curvature, get_circle_polygon, get_polygon_closest_point, get_polygons_closest_point, get_polyline_bounds, get_segment_swept_polygon, does_path_sweep_intersect_polygon, get_polyline_closest_point, trim_polyline_at, trim_polyline_angular_ends
  • polygon3d: walk_along_polyline_3d, walk_along_polygon_3d, deduplicate_polyline_3d, fillet_polyline_3d, get_polygon_area_3d, get_polygon_signed_area_3d, interpolated_segment_3d

raygeo.geo.algo

  • fitting: arc_between_two_points (exposed as generate_arc_between_two_points), generate_linking_arc
  • interp: barycentric_interpolate, barycentric_weights
  • intersect: get_ray_line_intersection, get_ray_polygon_intersection
  • offset: compute_inset_region, find_deepest_cores (binary-search core detection)
  • smooth: smooth_path

Refactors

  • ops/assembly — New submodule consolidating hsm, lead_in_out, overscan, polyline, raster/, and tabs. HSM assembly moved from geo.algo to ops.assembly and refactored to return Ops containers.
  • Rect / Rect3D — Converted to use glam vector types (DVec2/DVec3). Rect now { min: Point, max: Point }; Rect3D now { min: Point3D, max: Point3D }.
  • glam migration — Manual scalar math (hypot, sqrt, manual dot/cross, manual lerp, manual normalize) replaced with glam methods across all geo modules.
  • offset_polygon — Restored original name (was temporarily offset_polygon_with_style), added proper JoinStyle enum for Python API.
  • ScanMode — Python-facing variants renamed to PEP8 UPPER_CASE via #[pyo3(name = "...")].
  • Module cleanup — Redundant aliases removed, local imports moved to module level, type annotations fixed in polygon stubs.

Infrastructure

  • PDE meshingspade-based constrained Delaunay triangulation with TriangleMesh, boundary tagging, Steiner point insertion.
  • FEM Laplace solver — Linear FEM elements with conjugate-gradient solve (nalgebra/nalgebra-sparse), gradient field computation, convergence history.
  • Profilingsrc/prof.rs with RAII prof_guard for operation timing.
  • New dependenciesspade = "2", nalgebra = "0.35", nalgebra-sparse = "0.12".
  • Visual testingtools/visual_test.py split into submodule with one file per page; example image generator avoids re-generation if timestamps are unchanged.
  • Makefile — Added venv target for virtual environment setup.

Removals

  • morph_spiral module removed (did not work well enough).
  • geo.algo.hsm completely removed; remaining function moved to ops.assembly.hsm.
  • compute_valid_tool_area replaced by compute_inset_region.

Migration Guide: v0.10.0 → v0.11.0

This section covers only changes that break code written for v0.10.0.
New features (modules, functions added since v0.10.0) are not listed —
they require no migration.


1. Rect type: tuple struct → named fields

src/types.rs:47

// v0.10.0
pub struct Rect(pub f64, pub f64, pub f64, pub f64);
//                          x_min   y_min   x_max   y_max

// v0.11.0
pub struct Rect {
    pub min: Point,   // DVec2
    pub max: Point,   // DVec2
}

Rust code that constructs or destructures Rect as a 4-tuple will not
compile:

// BROKEN
let r = Rect(0.0, 0.0, 10.0, 20.0);
let Rect(x1, y1, x2, y2) = r;

// FIXED
let r = Rect::new(0.0, 0.0, 10.0, 20.0);
let x1 = r.min.x;
let y1 = r.min.y;
let x2 = r.max.x;
let y2 = r.max.y;

Python impact: The Python API still passes Rect as
(x_min, y_min, x_max, y_max) tuples. Python code does not need
changes.


2. Rect3D type: flat fields → min/max

src/types.rs:181

// v0.10.0
pub struct Rect3D {
    pub x_min: f64,
    pub x_max: f64,
    pub y_min: f64,
    pub y_max: f64,
    pub z_min: f64,
    pub z_max: f64,
}

// v0.11.0
pub struct Rect3D {
    pub min: Point3D,
    pub max: Point3D,
}

Replace field access:

Old New
r.x_min r.min.x
r.y_max r.max.y
r.z_min r.min.z
r.z_max r.max.z

Construction changes from Rect3D { x_min: ..., x_max: ..., ... } to
Rect3D::new(min_pt, max_pt) or Rect3D { min: ..., max: ... }.


3. offset_polygon() gained a JoinStyle parameter

src/geo/shape/polygon.rs:648

The function name is unchanged, but the Rust signature now requires a
JoinStyle argument. Python binding keeps the old signature by
defaulting to "miter".

// Rust — new required parameter
offset_polygon(&poly, offset, JoinStyle::Miter);
offset_polygon(&poly, offset, JoinStyle::Round);
offset_polygon(&poly, offset, JoinStyle::Square);
# Python — backwards compatible, defaults to JoinStyle.Miter
from raygeo.geo.shape.polygon import JoinStyle

offset_polygon(poly, offset)                 # defaults to Miter
offset_polygon(poly, offset, JoinStyle.Miter)
offset_polygon(poly, offset, JoinStyle.Round)
offset_polygon(poly, offset, JoinStyle.Square)

4. trochoid_along() output geometry changed

src/geo/algo/trochoid.rs:108-109

v0.10.0 produced a sine-wave oscillation perpendicular to the carrier
path. v0.11.0 adds a longitudinal (tangential) component, making it a
true trochoidal loop where the tool reverses direction in each cycle:

// v0.10.0 — simple lateral sine wave
let x = pos.x + lateral * normal.x;
let y = pos.y + lateral * normal.y;

// v0.11.0 — true trochoidal loop
let longitudinal = loop_radius * theta.sin();
let x = pos.x + lateral * normal.x + longitudinal * tangent.x;
let y = pos.y + lateral * normal.y + longitudinal * tangent.y;

This improves chip evacuation and limits tool engagement angle, but the
output path is completely different from v0.10.0 — expect longer
paths with backward/forward motion. Tests that assert exact point
positions on trochoidal paths will fail.


5. ScanMode enum variants renamed to UPPER_CASE

src/python/ops/raster.rs:26-28

PEP8 convention — enum members now use UPPER_CASE:

# v0.10.0
ScanMode.Segmented
ScanMode.FullSweep

# v0.11.0
ScanMode.SEGMENTED
ScanMode.FULL_SWEEP

All default parameters in rasterize_mask_lines, rasterize_mask_scan,
rasterize_multi_pass, and rasterize_power_modulation default to
ScanMode.SEGMENTED (same value, just renamed).

No Rust-level changes required — the Rust enum variants remain
Segmented / FullSweep; only the Python-facing names were updated via
#[pyo3(name = "...")].

Python code using ScanMode.Segmented or ScanMode.FullSweep must be
updated to the uppercase forms.

v0.10.0

17 Jun 11:41

Choose a tag to compare

v0.10.0 — CNC generalization & geometry primitives

This release generalizes the API from laser-specific terminology to generic CNC machining terms and introduces new geometry generation primitives.

Migration Guide

1. State — renamed fields

Old field New field
state.air_assist (bool) state.coolant (CoolantMode)
state.cut_speed state.feed_rate
state.travel_speed state.rapid_rate
state.active_laser_uid state.active_head_uid

State.__init__ keyword args renamed accordingly.

2. air_assistCoolantMode enum

The boolean air_assist is replaced by CoolantMode in raygeo.ops.state:

from raygeo.ops.state import CoolantMode

# Before
state.air_assist = True
ops.enable_air_assist(False)

# After
state.coolant = CoolantMode.AIR
ops.set_coolant(CoolantMode.OFF)

Variants: OFF, FLOOD, MIST, AIR.

3. Ops builder methods — renamed

Old New
set_cut_speed(speed) set_feed_rate(feed_rate)
set_travel_speed(speed) set_rapid_rate(rapid_rate)
set_laser(uid) set_head(uid)
enable_air_assist(bool) set_coolant(CoolantMode)
speed(idx) rate(idx)
laser_uid(idx) head_uid(idx)
get_frame(power=, speed=) get_frame(power=, feed_rate=)

4. Time estimation — renamed parameters

# Before
ops.estimate_time(default_cut_speed=..., default_travel_speed=...)

# After
ops.estimate_time(default_feed_rate=..., default_rapid_rate=...)

Same for estimate_command_times().

5. CommandType — renamed variants

Old New
SET_CUT_SPEED SET_FEED_RATE
SET_TRAVEL_SPEED SET_RAPID_RATE
SET_LASER SET_HEAD
ENABLE_AIR_ASSIST (removed)
DISABLE_AIR_ASSIST (removed)

New variant: SET_COOLANT.

6. CommandInfo — renamed properties

Old New
.speed .feed_rate

New: .rapid_rate, .spindle_rpm, .coolant.

7. Serialization format

Dict/JSON/numpy serialization field names changed to match new naming. Old serialized data is not backward-compatible.

8. allow_rapid_change()

Now compares coolant instead of air_assist.

New Features

  • Geometry primitives: raygeo.geo.algo.helix, .ramp, .trochoid, .offset (concentric offsets)
  • polyline_to_ops() — convert polylines to Ops
  • link_passes() — link passes with retract/stay-down strategies
  • find_pass_entry() / find_pass_exit() — consolidated entry/exit detection
  • State.spindle_rpm field + set_spindle_rpm() builder
  • State.coolant field + set_coolant() builder

Internal

  • Codebase refactoring: decomposed large functions, consolidated entry/exit logic
  • Added rustfmt.toml with 80-char line width
  • Makefile dependency installation

v0.9.0

16 Jun 17:08

Choose a tag to compare

What's New

3D Polygon Operations

  • Add 3D polygon boolean and offset wrappers, including plane-offset support
  • Add 3D analytical and transform polygon wrappers with full API documentation
  • Add simplify_polyline for 3D polylines

2D/3D Separation & Architecture

  • Implement 2D/3D separation with planar-only docs, Z-fix in offset, projection helpers, 2D clipping split, planar namespace, and tests
  • Upgrade Command::Arc from 2D to 3D (center_offset: Point3D, normal: Point3D)

Breaking Change

  • Replace custom Point/Point3D structs with glam::DVec2/glam::DVec3 type aliases

Improvements

  • Promote spatial_gridspatial_grid2d from nest2d to geo::algo
  • Deduplicate nfp_convex_fast by routing to minkowski2d::get_no_fit_polygon

Bug Fixes

  • Fix perpendicular_3d handedness and endpoint offset direction

Documentation

  • Improve API doc generation with multi-line param/returns descriptions, PEP8 signature wrapping, shorter type names, and Python code blocks
  • Return value descriptions are now in tables, fix notation markup
  • Add API doc visualizations for polygon3d functions

raygeo v0.8.0

15 Jun 19:33

Choose a tag to compare

What's Changed

SVG processing

  • Add extract_svg_metadata(), parse_svg_length(), svg_length_to_mm(), and svg_length_to_px() helpers.
  • Add svg_string_to_geometry_by_layer() — extract per-layer geometry from SVG strings.
  • Add unit conversion helpers to the SvgMetadata Python class.
  • Fix SVG arc import/export bugs and derive large-arc flag at export.
  • Remove BORDER_SIZE from SVG coordinate transform.

Image preprocessing (new module)

  • Add preprocess module with Otsu thresholding and connected-component analysis.
  • Add denoise_binary() and compute_adaptive_threshold().

Scanline / rasterisation

  • Add extract_zero_power_segments() for zero-power segment extraction from scanlines.
  • Add transform_to_cylinder() and rasterize_scanlines().

Geometry / fitting

  • Add convert_arcs_to_beziers() for arc-to-bezier conversion.
  • Remove redundant create_arc_cmd and create_line_cmd from the fitting module.

Documentation

  • Add complexity documentation to each API function.
  • Add many more visual examples and auto-generated doc images.
  • Add a visualization for apply_minimum_run_length().

Full Changelog: v0.7.1...v0.8.0

v0.7.1

14 Jun 16:39

Choose a tag to compare

What's Changed

Math engine

  • Integrate glam math crate — replace manual matrix operations, Point/Point3D operators, remove mat4_mul.
  • Fix map_geometry_to_frame matrix column ordering.

SVG parsing

  • Use svgtypes crate for SVG path data parsing instead of custom tokenizer.

Geometry / ops

  • Fix travel path optimizer not respecting the "flip" flag.
  • Refactor is_bezier_flat extraction from linearize_bezier_adaptive, use explicit stack.
  • Refactor add mutable buffer params to linearize, smooth, and intersection functions.
  • Unconditionally compile ops modules (lead_in_out, merge_lines, overscan, tabs, transform).

Documentation

  • Add docs and auto-generated visual example images.
  • Add more visual examples, improve existing ones, fix tables in API docs.
  • Concave hull visual test now allows uploading an SVG.
  • Add showcase image to README.

Full Changelog: https://github.com/rayforge/raygeo/compare/v0.7.0...v0.7.1