Skip to content

Add support for shape filling to whiskers#188

Open
abey79 wants to merge 12 commits into
pr45-intobezpathsfrom
pr5-whiskers-fill-support
Open

Add support for shape filling to whiskers#188
abey79 wants to merge 12 commits into
pr45-intobezpathsfrom
pr5-whiskers-fill-support

Conversation

@abey79

@abey79 abey79 commented Jan 18, 2026

Copy link
Copy Markdown
Owner

This PR builds on the previous ones to introduce hatch fill support. This required refactoring the layer state handling, so we can have separate stroke and fill routing, replacing the single set_layer() method.

It also fixes per-path color/stroke_width defaults: paths now inherit from their layer instead of defaulting to BLACK/1.0, which caused layer colors to be overridden (e.g. crescent strokes appearing black instead of the layer's CMY color in quadri_circle).

Removed API

Method Replacement
set_layer(layer_id) stroke_layer(Some(layer_id))
color(c) override_color(c) for per-path overrides, or layer(id).color(c) for layer defaults
stroke_width(w) override_stroke_width(w) for per-path overrides, or layer(id).pen_width(w) for layer defaults

New API

Method Description
layer(id) -> LayerHandle Configure a layer's properties (pen width, color, name, hatch angle)
stroke_layer(Option<LayerID>) Set which layer receives stroke output (None disables)
fill_layer(Option<LayerID>) Set which layer receives fill/hatch output (None disables)
stroke_only(layer) Shorthand: stroke on, fill off
fill_only(layer) Shorthand: fill on, stroke off
stroke_and_fill(layer) Shorthand: both on same layer
override_color(c) Per-path color override (overrides layer default)
override_stroke_width(w) Per-path stroke width override (overrides layer default)
clear_overrides() Reset per-path overrides so paths inherit from layer
push_style() / pop_style() Save/restore style state (layer routing + per-path overrides)
with_style(closure) Scoped style changes with automatic restore

New traits: IntoBezPaths / IntoBezPathsTolerance

The Draw::add_path signature now accepts IntoBezPathsTolerance (plural) instead of IntoBezPathTolerance. This preserves structural boundaries when converting multi-geometry types (e.g. geo::MultiPolygon yields one BezPath per polygon), which is critical for correct per-shape hatching. Single-geometry types get a blanket impl wrapping the result in a one-element Vec, so existing code is unaffected.

New example

  • fill_demo — demonstrates stroke/fill layer routing with a grid of shapes (circle, square, L-shape, polygon with holes) across three fill modes (none, horizontal, angled).

Default behavior change

Paths now default to None/None metadata (inheriting color and stroke width from their layer via resolve()). Previously, Sketch::new() set explicit BLACK/1.0 on every path, which silently overrode layer settings.

Migration guide

Setting color/pen width for a layer (most common case):

// Before
sketch.color(Color::DARK_RED).stroke_width(3.0);

// After — configure the layer directly
sketch.layer(0).color(Color::DARK_RED).pen_width(3.0);

Switching colors mid-drawing (per-path overrides):

// Before
sketch.color(Color::RED).circle(0., 0., 10.);
sketch.color(Color::BLUE).circle(0., 0., 20.);

// After — explicit override semantics
sketch.override_color(Color::RED).circle(0., 0., 10.);
sketch.override_color(Color::BLUE).circle(0., 0., 20.);
sketch.clear_overrides(); // back to layer defaults

Fill (hatching):

sketch.layer(1)
  .pen_width(0.5 * Unit::Mm)
  .hatch_angle(45.0_f64.to_radians());

sketch.stroke_layer(Some(0));
sketch.fill_layer(Some(1));
sketch.circle(100.0, 100.0, 50.0); // outline on layer 0, hatching on layer 1

This is part 6 of 6 in a stack made with GitButler:

@abey79 abey79 added whiskers Relates to whiskers or whiskers-derive breaking Breaking change feature New feature labels Jan 18, 2026
@abey79 abey79 force-pushed the pr4-metadata-refactor branch from 7268e0f to c064346 Compare February 8, 2026 10:05
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from d3d02ef to 6dfc072 Compare February 8, 2026 10:05
@abey79 abey79 force-pushed the pr4-metadata-refactor branch from c064346 to 953df45 Compare February 15, 2026 10:00
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch 2 times, most recently from de11ee0 to b7e27df Compare February 15, 2026 13:37
@abey79 abey79 force-pushed the pr4-metadata-refactor branch from 953df45 to 69fbf67 Compare February 21, 2026 13:08
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from 763c3c0 to 4838e7a Compare February 21, 2026 13:08
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch 2 times, most recently from ea243dc to 38d515f Compare February 21, 2026 13:48
@abey79 abey79 force-pushed the pr4-metadata-refactor branch from 69fbf67 to a0db2dd Compare February 22, 2026 13:13
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from 38d515f to cad2568 Compare February 22, 2026 13:13
@abey79 abey79 force-pushed the pr4-metadata-refactor branch from a0db2dd to 10d677b Compare February 22, 2026 20:28
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from cad2568 to 22cacc2 Compare February 22, 2026 20:28
@abey79 abey79 force-pushed the pr4-metadata-refactor branch from 10d677b to 69f7d5c Compare February 22, 2026 20:29
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from 22cacc2 to 06a14cb Compare February 22, 2026 20:29
@abey79 abey79 changed the base branch from pr4-metadata-refactor to pr45-intobezpaths February 22, 2026 20:44
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from 06a14cb to 5ef5e59 Compare February 22, 2026 21:03
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from 5ef5e59 to 53da09d Compare February 22, 2026 21:07
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from 53da09d to 6c07a27 Compare February 22, 2026 21:31
@abey79 abey79 force-pushed the pr45-intobezpaths branch from 60b6bfd to fbb909a Compare March 1, 2026 08:49
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from 6c07a27 to f856c2c Compare March 1, 2026 08:49
@abey79 abey79 force-pushed the pr45-intobezpaths branch from fbb909a to e473904 Compare March 1, 2026 09:15
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from f856c2c to bb22373 Compare March 1, 2026 09:15
abey79 added 12 commits March 1, 2026 10:31
- Removed target_layer field and set_layer() method
    - Added stroke_layer: Option<LayerID> and fill_layer: Option<LayerID> fields
    - Added style_stack: Vec<StyleState> for push/pop style
    - Added LayerHandle struct with pen_width(), color(), name(), hatch_angle() methods
    - Added routing methods: stroke_layer(), fill_layer(), stroke_only(), fill_only(), stroke_and_fill()
    - Added style stack: push_style(), pop_style(), with_style()
    - Updated add_path() to route to stroke/fill layers with hatching support
    - Added 13 unit tests
@abey79 abey79 force-pushed the pr45-intobezpaths branch from e473904 to 2358c23 Compare March 1, 2026 09:36
@abey79 abey79 force-pushed the pr5-whiskers-fill-support branch from bb22373 to 0dd86f2 Compare March 1, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Breaking change feature New feature whiskers Relates to whiskers or whiskers-derive

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant