axiolid_arrangement/entity.rs
1// SPDX-License-Identifier: MPL-2.0
2
3//! Arena records for the arrangement.
4//!
5//! Records hold only topology and position. Anything derived -- area,
6//! outline, adjacency -- is computed in `query.rs` rather than cached here,
7//! because a cached derivative is a second source of truth that edits have to
8//! remember to invalidate.
9
10use axiolid_core::Point2;
11
12use crate::id::{FaceId, HalfEdgeId, VertexId};
13
14impl FaceId {
15 /// The unbounded face, which every arrangement has from creation.
16 pub const OUTER: Self = Self::outer();
17}
18
19/// A point in the plane, with one outgoing half-edge as an entry into the
20/// edges around it.
21#[derive(Debug, Clone, Copy, PartialEq)]
22pub struct Vertex {
23 /// Where the vertex is.
24 pub position: Point2,
25 /// Any half-edge whose origin is this vertex, or `None` if isolated.
26 ///
27 /// Isolated vertices are legal: an edit can remove the last edge touching
28 /// a vertex without the vertex itself becoming invalid.
29 pub outgoing: Option<HalfEdgeId>,
30}
31
32/// One direction of an edge.
33///
34/// The twin runs the other way along the same geometric segment. Storing both
35/// directions is what makes "the face on the other side" a constant-time
36/// question rather than a search.
37#[derive(Debug, Clone, Copy, PartialEq)]
38pub struct HalfEdge {
39 /// Vertex this half-edge leaves from.
40 pub origin: VertexId,
41 /// The opposite half-edge along the same segment.
42 pub twin: HalfEdgeId,
43 /// Next half-edge counter-clockwise around `face`.
44 pub next: HalfEdgeId,
45 /// Previous half-edge around `face`.
46 pub prev: HalfEdgeId,
47 /// Face lying to the left of this half-edge.
48 pub face: FaceId,
49}
50
51/// A region of the plane bounded by a cycle of half-edges.
52#[derive(Debug, Clone, Copy, PartialEq)]
53pub struct Face {
54 /// Any half-edge on this face's outer boundary.
55 ///
56 /// `None` only for the unbounded face of an arrangement with no edges.
57 pub boundary: Option<HalfEdgeId>,
58}