Skip to main content

ResidualLoop

Struct ResidualLoop 

Source
pub struct ResidualLoop {
    pub nodes: Vec<NodeId>,
    pub edges: Vec<EdgeId>,
}
Expand description

A loop of the wavefront that stopped rather than collapsing: the offset polygon a skeleton_constrained leaves behind.

§What it is

The wavefront of a plain skeleton always shrinks away to nothing — that is what it means for the skeleton to be finished. Limits change that. Once every edge around some loop has stopped, the loop stops too, and simply stays there. What it stays as is the input polygon offset inward by the limit: the flat left in the middle of a truncated roof.

So a constrained skeleton is not only the stubs reaching in from the boundary. It is those stubs and the outline they stop on, and this is that outline.

    +-------------------------+        +-------------------------+
    |                         |        | \                     / |
    |                         |        |   +-----------------+   |
    |                         |   ->   |   |    residual     |   |
    |                         |        |   +-----------------+   |
    |                         |        | /                     \ |
    +-------------------------+        +-------------------------+
       every edge limited                the arcs stop at the limit,
                                         and this is where they stop

§Why it is not made of Arcs

Because it would be a lie about what an Arc is. Every arc bisects the supporting lines of exactly two input edges, which is what makes Arc::sources meaningful and what the whole provenance story rests on. A residual segment is parallel to one input edge and belongs to it alone. Putting one in arcs would break the invariant every consumer of sources relies on, so it lives here with the shape it actually has: each segment names the one edge it came from.

§Winding

Inherited from the input, so the polygon’s interior stays on the left of every segment: the loop around the outer boundary runs counter-clockwise, and a loop around a hole runs clockwise.

§Examples

use straight_skeleton::{skeleton, skeleton_constrained, Point, Polygon};

let square = Polygon::from_outer(&[
    Point::new(0, 0), Point::new(100, 0), Point::new(100, 100), Point::new(0, 100),
])?;

// Stop every edge at 20: what is left is the 60x60 square in the middle.
let skel = skeleton_constrained(&square, &[20.0; 4])?;
let flat = &skel.residual()[0];
assert_eq!(flat.len(), 4);

let mut corners: Vec<Point> = flat.nodes.iter().map(|&n| skel.node(n).position).collect();
corners.sort();
assert_eq!(corners, vec![
    Point::new(20, 20), Point::new(20, 80), Point::new(80, 20), Point::new(80, 80),
]);

// An unconstrained skeleton has none: its wavefront always collapses.
assert!(skeleton(&square)?.residual().is_empty());

Fields§

§nodes: Vec<NodeId>

The loop’s corners, in wavefront order.

These are ordinary skeleton nodes — the far ends of the arcs that stopped here — so their Node::offset is where the wavefront got to.

§edges: Vec<EdgeId>

The input edge each segment came from: edges[i] owns the segment from nodes[i] to nodes[i + 1], wrapping at the end.

Always the same length as ResidualLoop::nodes. Every point on that segment is min(offset, limit) from edges[i]’s supporting line, and parallel to it.

Implementations§

Source§

impl ResidualLoop

Source

pub fn len(&self) -> usize

How many corners, and so also how many segments.

Source

pub fn is_empty(&self) -> bool

Whether the loop is empty. It never is; this exists to satisfy the convention that a type with len has is_empty.

Source

pub fn segments(&self) -> impl Iterator<Item = (NodeId, NodeId, EdgeId)> + '_

The segments, as (from, to, source edge), in wavefront order.

§Examples
use straight_skeleton::{skeleton_constrained, Point, Polygon};

let square = Polygon::from_outer(&[
    Point::new(0, 0), Point::new(100, 0), Point::new(100, 100), Point::new(0, 100),
])?;
let skel = skeleton_constrained(&square, &[20.0; 4])?;

// Four sides, each parallel to the wall it came from.
let sides: Vec<_> = skel.residual()[0].segments().collect();
assert_eq!(sides.len(), 4);

Trait Implementations§

Source§

impl Clone for ResidualLoop

Source§

fn clone(&self) -> ResidualLoop

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ResidualLoop

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for ResidualLoop

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for ResidualLoop

Source§

impl PartialEq for ResidualLoop

Source§

fn eq(&self, other: &ResidualLoop) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for ResidualLoop

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for ResidualLoop

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.