pub struct Skeleton { /* private fields */ }Expand description
The straight skeleton of a Polygon.
A skeleton is a planar graph of Nodes joined by Arcs. Build one with
skeleton or skeleton_constrained.
§Examples
use straight_skeleton::{skeleton, Point, Polygon};
// A 10x10 square's skeleton is an X: four boundary nodes, one centre node,
// four arcs running corner to centre.
let square = Polygon::from_outer(&[
Point::new(0, 0), Point::new(10, 0), Point::new(10, 10), Point::new(0, 10),
])?;
let skel = skeleton(&square)?;
assert_eq!(skel.node_count(), 5);
assert_eq!(skel.arc_count(), 4);
// The interior node is the centre, at offset 5 (half the width).
let centre = skel.nodes().iter().find(|n| !n.is_boundary()).unwrap();
assert_eq!(centre.position, Point::new(5, 5));
assert!((centre.offset - 5.0).abs() < 1e-4);
// ...and it is equidistant from all four input edges.
assert_eq!(centre.sources.len(), 4);Implementations§
Source§impl Skeleton
impl Skeleton
Sourcepub fn residual(&self) -> &[ResidualLoop]
pub fn residual(&self) -> &[ResidualLoop]
The wavefront loops that stopped rather than collapsing — the offset polygon a constrained skeleton leaves behind.
Empty for a plain skeleton, whose wavefront always shrinks away
to nothing. Non-empty only where skeleton_constrained’s limits bound
hard enough to stop a whole loop, and then there is one entry per loop
still standing: the outer offset outline, plus one around each hole that
survived.
This is the other half of a constrained result. The arcs are the
stubs reaching in from the boundary; this is the outline they stop on.
See ResidualLoop for why it is not made of arcs.
§Examples
use straight_skeleton::{skeleton_constrained, Point, Polygon};
// An L-shape, every wall stopped at 20.
let l = Polygon::from_outer(&[
Point::new(0, 0), Point::new(200, 0), Point::new(200, 100),
Point::new(100, 100), Point::new(100, 200), Point::new(0, 200),
])?;
let skel = skeleton_constrained(&l, &[20.0; 6])?;
// What is left is the same L, 20 in from every wall.
assert_eq!(skel.residual().len(), 1);
let mut corners: Vec<Point> =
skel.residual()[0].nodes.iter().map(|&n| skel.node(n).position).collect();
corners.sort();
assert_eq!(corners, vec![
Point::new(20, 20), Point::new(20, 180), Point::new(80, 80),
Point::new(80, 180), Point::new(180, 20), Point::new(180, 80),
]);Sourcepub fn node_count(&self) -> usize
pub fn node_count(&self) -> usize
Number of nodes.
Sourcepub fn arc_segment(&self, a: ArcId) -> (Point, Point)
pub fn arc_segment(&self, a: ArcId) -> (Point, Point)
Sourcepub fn closest_input_edges(&self, a: ArcId) -> [EdgeId; 2]
pub fn closest_input_edges(&self, a: ArcId) -> [EdgeId; 2]
The two input edges a given arc came from.
Every point along the arc is equidistant from these two edges’
supporting lines, and the arc separates their two faces. See Arc for
why this is exact rather than a search, and Node::sources for why
“came from” is more accurate than “closest to”.
§Examples
use straight_skeleton::{skeleton, Point, Polygon};
let square = Polygon::from_outer(&[
Point::new(0, 0), Point::new(10, 0), Point::new(10, 10), Point::new(0, 10),
])?;
let skel = skeleton(&square)?;
// Each of the square's four arcs bisects two adjacent input edges.
for a in skel.arc_ids() {
let [e0, e1] = skel.closest_input_edges(a);
assert_ne!(e0, e1);
}§Panics
Panics if a does not belong to this skeleton.
Sourcepub fn closest_input_edges_to_node(&self, n: NodeId) -> &[EdgeId]
pub fn closest_input_edges_to_node(&self, n: NodeId) -> &[EdgeId]
The input edges a given node came from.
See Node::sources, which this returns.
§Panics
Panics if n does not belong to this skeleton.
Sourcepub fn max_offset(&self) -> f32
pub fn max_offset(&self) -> f32
The largest offset reached by any node: the radius of the largest disc that fits inside the polygon.
For a roof, this is the ridge height. Returns 0 for an empty skeleton.
Sourcepub fn boundary_node(&self, v: VertexId) -> Option<NodeId>
pub fn boundary_node(&self, v: VertexId) -> Option<NodeId>
The boundary node sitting on a given input vertex.
§Examples
use straight_skeleton::{skeleton, Point, Polygon, VertexId};
let square = Polygon::from_outer(&[
Point::new(0, 0), Point::new(10, 0), Point::new(10, 10), Point::new(0, 10),
])?;
let skel = skeleton(&square)?;
let n = skel.boundary_node(VertexId(2)).unwrap();
assert_eq!(skel.node(n).position, Point::new(10, 10));Sourcepub fn face(&self, e: EdgeId) -> Option<Vec<NodeId>>
pub fn face(&self, e: EdgeId) -> Option<Vec<NodeId>>
The face of an input edge: the closed region the wavefront of that edge swept out, as a loop of nodes.
Every input edge has exactly one face, and the faces tile the polygon.
The returned loop starts with the edge’s own two endpoints, then follows
the skeleton arcs that bound the face back around. Each face is planar
when nodes are lifted to z = offset, which is exactly why a straight
skeleton builds roofs: one face is one roof plane. See the roof
example.
Returns None if the face cannot be walked, which should not happen for
a skeleton of a valid polygon.
§Examples
use straight_skeleton::{skeleton, EdgeId, Point, Polygon};
// Each of a square's four edges has a triangular face running to the
// centre.
let square = Polygon::from_outer(&[
Point::new(0, 0), Point::new(10, 0), Point::new(10, 10), Point::new(0, 10),
])?;
let skel = skeleton(&square)?;
let face = skel.face(EdgeId(0)).unwrap();
assert_eq!(face.len(), 3);
// A rectangle's long edges get quadrilateral faces, because the ridge
// gives them a fourth corner.
let rect = Polygon::from_outer(&[
Point::new(0, 0), Point::new(20, 0), Point::new(20, 10), Point::new(0, 10),
])?;
let skel = skeleton(&rect)?;
assert_eq!(skel.face(EdgeId(0)).unwrap().len(), 4); // long edge
assert_eq!(skel.face(EdgeId(1)).unwrap().len(), 3); // short edgeSourcepub fn input_edge_count(&self) -> usize
pub fn input_edge_count(&self) -> usize
How many input edges the polygon had.
Each one owns exactly one face, so this is also the
number of faces.
§Examples
use straight_skeleton::{skeleton, Point, Polygon};
let square = Polygon::from_outer(&[
Point::new(0, 0), Point::new(10, 0), Point::new(10, 10), Point::new(0, 10),
])?;
assert_eq!(skeleton(&square)?.input_edge_count(), 4);