From be4bfd6d02dfe67a59579665b78b30f1ef01403f Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Thu, 20 Nov 2025 16:21:24 -0600 Subject: [PATCH 1/3] Add better docs to Contours --- src/topology.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/topology.rs b/src/topology.rs index 2cd70f3..36fdacc 100644 --- a/src/topology.rs +++ b/src/topology.rs @@ -1686,9 +1686,52 @@ impl Default for Contour { } } -/// A collection of [`Contour`]s. +/// A collection of [`Contour`]s, representing a set. /// /// Can be indexed with a [`ContourIdx`]. +/// +/// A `Contour` represents a set as a hierarchical collection of closed paths, where +/// each path has the set on its left (in a Y-down coordinate system). A very simple +/// set is represented as just a single closed path: +/// +/// ```text +/// ╭───<───╮ +/// │xxxxxxx│ +/// │xxxxxxx│ +/// ╰───>───╯ +/// ``` +/// +/// (The `x`s represent the interior of the set, and the arrows show the orientation +/// of the curve.) +/// +/// Two disjoint sets are represented as two unrelated closed paths: +/// +/// ```text +/// ╭───<───╮ +/// │xxxxxxx│ +/// │xxxxxxx│ ╭───<───╮ +/// ╰───>───╯ │xxxxxxx│ +/// │xxxxxxx│ +/// ╰───>───╯ +/// ``` +/// +/// The hierarchical structure appears when you have sets with holes: a set with a single +/// hole is represented as a contour (the outer boundary) with a child contour (the inner +/// boundary). Notice how the curves are oriented to that the set is always on the left. +/// +/// ```text +/// ╭───<──────╮ +/// │xxxxxxxxxx│ +/// │xxx╭>─╮xxx│ +/// │xxx│ │xxx│ +/// │xxx╰─<╯xxx│ +/// │xxxxxxxxxx│ +/// ╰──────>───╯ +/// ``` +/// +/// A set can have multiple holes (and so a contour can have multiple children), +/// and those holes can contain more parts of the set. So in general, the +/// collection of contours forms a forest. #[cfg_attr(test, derive(serde::Serialize))] #[derive(Clone, Debug, Default)] pub struct Contours { @@ -1728,7 +1771,11 @@ impl Contours { ret } - /// Iterates over all of the contours. + /// Iterates over all of the contours, ignoring the hierarchical structure. + /// + /// For example, if you're creating an SVG path out of all these contours then + /// you don't need the hierarchical structure: the SVG renderer can figure that + /// out by itself. pub fn contours(&self) -> impl Iterator + '_ { self.contours.iter() } From 13be791f45aed2f0a5b8f6f0cea5a30f261b01e5 Mon Sep 17 00:00:00 2001 From: jneem Date: Fri, 21 Nov 2025 12:29:25 -0600 Subject: [PATCH 2/3] Update src/topology.rs Co-authored-by: Mike Wilkerson <11575183+mlwilkerson@users.noreply.github.com> --- src/topology.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/topology.rs b/src/topology.rs index 36fdacc..ccc6b3a 100644 --- a/src/topology.rs +++ b/src/topology.rs @@ -1717,7 +1717,7 @@ impl Default for Contour { /// /// The hierarchical structure appears when you have sets with holes: a set with a single /// hole is represented as a contour (the outer boundary) with a child contour (the inner -/// boundary). Notice how the curves are oriented to that the set is always on the left. +/// boundary). Notice how the curves are oriented so that the set is always on the left. /// /// ```text /// ╭───<──────╮ From fcaa1224ffa8ba835acf4d3fd9b4f6ba4d8468cd Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Fri, 21 Nov 2025 12:39:47 -0600 Subject: [PATCH 3/3] Add a paragraph on winding numbers --- src/topology.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/topology.rs b/src/topology.rs index ccc6b3a..2a503c4 100644 --- a/src/topology.rs +++ b/src/topology.rs @@ -1732,6 +1732,12 @@ impl Default for Contour { /// A set can have multiple holes (and so a contour can have multiple children), /// and those holes can contain more parts of the set. So in general, the /// collection of contours forms a forest. +/// +/// Because of the way we organize the contour directions, the set described by +/// our contours has a winding number of 1 and its complement has a winding +/// number of 0. In particular, if you gather up all the contours and put them +/// in an SVG, it won't make a difference whether you fill them with a non-zero +/// or an even-odd fill rule. #[cfg_attr(test, derive(serde::Serialize))] #[derive(Clone, Debug, Default)] pub struct Contours {