Arbitrary Paths and Fills
Relevant source files
The following files were used as context for generating this wiki page:
Arbitrary paths and fills represent the core vector drawing capabilities within the guiltty project. This system allows developers to define complex 2D geometry using a series of points and apply solid color fills to closed shapes. The implementation is backend-agnostic, existing primarily within the guiltty-core crate, ensuring that complex rasterization logic remains separated from terminal-specific escape sequence encoding.
Sources: crates/guiltty-core/src/lib.rs:1-8, README.md:18-24
Data Structures and Representation
The geometry system is built on fundamental primitives that define points, rectangles, and the shapes themselves.
Path Definition
An arbitrary path is represented by the Shape::Path enum variant. It consists of a vector of Point structures and a boolean flag indicating whether the path is closed.
| Field | Type | Description |
|---|---|---|
points | Vec<Point> | An ordered list of pixel-addressable points. |
closed | bool | Determines if the path is filled (true) or stroked (false). |
Sources: crates/guiltty-core/src/lib.rs:327-340
The Fill Model
As of the current implementation, guiltty supports solid color fills. The Fill enum is designed to be extensible for future gradients or patterns.
pub enum Fill {
Solid(Color),
}
Sources: crates/guiltty-core/src/lib.rs:293-298
Scanline Rasterization and Fills
The primary mechanism for rendering closed paths is a scanline polygon fill algorithm. This algorithm is used not only for arbitrary paths but also for triangles, circles, and ellipses.
Even-Odd Rule
For closed paths, guiltty employs the even-odd rule. This rule determines the "insideness" of a point by drawing a ray from the point to infinity and counting how many path segments it crosses. An odd number of crossings means the point is inside; an even number means it is outside. This approach is chosen for its simplicity and its ability to correctly handle concave and self-intersecting polygons without requiring winding-direction semantics.
Sources: tasks/plan.md:73-77, crates/guiltty-core/src/lib.rs:462-475
Rasterization Process Flow
The following diagram illustrates the logic within fill_polygon_even_odd:
The scanline is sampled at y + 0.5 to avoid ambiguity when a vertex sits exactly on an integer coordinate.
Sources: crates/guiltty-core/src/lib.rs:479-520
Stroke Logic
When a path is marked as open (closed: false), it is rendered using stroke logic rather than fill logic.
Line Segments
Open paths are drawn as a series of connected line segments using Bresenham's line algorithm. To maintain performance, segments are clipped to the canvas bounds using the Liang-Barsky algorithm before walking the pixels.
Integration and Usage
The Canvas struct provides the high-level interface for these operations through draw_shape.
| Method | Parameters | Description |
|---|---|---|
draw_shape | &Shape, Fill | Dispatches to either stroke or fill logic based on the shape variant and closed flag. |
fill_polygon_even_odd | &[Point], Color | The internal engine for filling arbitrary closed polygons. |
stroke_path | &[Point], Color | Iterates through point pairs to draw lines for open paths. |
Sources: crates/guiltty-core/src/lib.rs:356-379
Summary
Arbitrary paths and fills provide guiltty with the flexibility to render complex vector geometry in the terminal. By utilizing the even-odd rule for fills and Liang-Barsky clipping for strokes, the system ensures robust and efficient rendering of both convex and concave shapes. This architecture allows for precise pixel-level control, which is subsequently transmitted to the terminal via the Kitty Graphics Protocol.
Sources: tasks/plan.md:70-84, crates/guiltty-kitty/src/lib.rs:1-10