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}