Skip to main content

geop_core_topology/
coedge.rs

1use crate::{CoedgeId, VertexId};
2use geop_core_math::geop_error::{GeopError, GeopResult};
3use geop_core_math::scalars::Scalar;
4
5use super::ids::{EdgeId, FaceId};
6use super::model::Curve2;
7
8/// Whether a coedge traverses its underlying edge in the same direction
9/// (forward: start→end) or the opposite direction (reversed: end→start).
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum Sense {
12    Forward,
13    Reversed,
14}
15
16impl Sense {
17    pub fn opposite(self) -> Sense {
18        match self {
19            Sense::Forward => Sense::Reversed,
20            Sense::Reversed => Sense::Forward,
21        }
22    }
23}
24
25/// What a coedge's own `(u, v)` boundary segment is actually backed by.
26#[derive(Clone, Copy, Debug, PartialEq, Eq)]
27pub enum CoedgeGeometry {
28    /// A real, shared edge — this coedge is one of exactly the two
29    /// (opposite `Sense`) that trace it, one per adjoining face. The usual
30    /// case.
31    Edge(EdgeId),
32    /// A degenerate loop segment that sits at a single, already-existing
33    /// vertex the whole way — no edge, and (unlike `Edge`) no second
34    /// coedge sharing it, since there's nothing to share between two
35    /// faces: it belongs to exactly one face's own loop. This is how a
36    /// loop closes over a surface row that's collapsed to a single point
37    /// (e.g. a pole) — the loop still needs *some* pcurve tracing that
38    /// row's full parameter range even though there's no 3-D geometry
39    /// there to back a real edge. Adds neither a new vertex nor a new
40    /// edge, so it never needs to satisfy (or risk violating) the
41    /// Euler–Poincaré invariant euler operators preserve — it isn't one.
42    Vertex(VertexId),
43}
44
45#[derive(Clone, Debug)]
46pub struct Coedge<S: Scalar> {
47    pub geometry: CoedgeGeometry,
48    pub sense: Sense,
49    pub pcurve: Curve2<S>,
50    pub next: CoedgeId,
51    pub prev: CoedgeId,
52    // face
53    pub face: FaceId,
54}
55
56impl<S: Scalar> Coedge<S> {
57    /// This coedge's own edge — an error for a `Vertex`-backed coedge
58    /// (there's no edge to kill/compare/collect there). Convenience for
59    /// the (common) operators that only ever apply to edge-backed
60    /// coedges, e.g. `kve`/`kemr`/`ker`.
61    pub fn edge(&self) -> GeopResult<EdgeId> {
62        match self.geometry {
63            CoedgeGeometry::Edge(id) => Ok(id),
64            CoedgeGeometry::Vertex(v) => Err(GeopError::new(format!(
65                "coedge is vertex-backed (vertex {}), not edge-backed",
66                v.0
67            ))),
68        }
69    }
70}