-
-
Notifications
You must be signed in to change notification settings - Fork 119
/
edge.rs
130 lines (119 loc) · 4.58 KB
/
edge.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use fj_math::Point;
use crate::{
geometry::curve::Curve,
objects::Vertex,
storage::{Handle, HandleWrapper},
};
/// A directed edge, defined in a surface's 2D space
///
/// The concept of an "edge" in Fornjot is represented by two structs,
/// `HalfEdge` and [`GlobalEdge`]. `HalfEdge` has two attributes that make it
/// distinct from [`GlobalEdge`]:
///
/// - `HalfEdge` is directed, meaning it has a defined start and end vertex.
/// - `HalfEdge` is defined in the 2-dimensional space of a surface.
///
/// When multiple faces, which are bound by edges, are combined to form a solid,
/// the `HalfEdge`s that bound the face on the surface are then coincident with
/// the `HalfEdge`s of other faces, where those faces touch. Those coincident
/// `HalfEdge`s are different representations of the same edge. This edge is
/// represented by an instance of [`GlobalEdge`].
///
/// There are some requirements that a `HalfEdge` needs to uphold to be valid:
///
/// 1. Coincident `HalfEdge`s *must* refer to the same [`GlobalEdge`].
/// 2. `HalfEdge`s that are coincident, i.e. located in the same space, must
/// always be congruent. This means they must coincide *exactly*. The overlap
/// must be complete. None of the coincident `HalfEdge`s must overlap with
/// just a section of another.
///
/// That second requirement means that a `HalfEdge` might need to be split into
/// multiple smaller `HalfEdge`s that are each coincident with a `HalfEdge` in
/// another face.
///
/// # Implementation Note
///
/// There is currently no validation code to verify that coincident `HalfEdge`s
/// are congruent:
/// <https://github.com/hannobraun/Fornjot/issues/1608>
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct HalfEdge {
curve: Curve,
boundary: [Point<1>; 2],
start_vertex: HandleWrapper<Vertex>,
global_form: HandleWrapper<GlobalEdge>,
}
impl HalfEdge {
/// Create an instance of `HalfEdge`
pub fn new(
curve: Curve,
boundary: [Point<1>; 2],
start_vertex: Handle<Vertex>,
global_form: Handle<GlobalEdge>,
) -> Self {
Self {
curve,
boundary,
start_vertex: start_vertex.into(),
global_form: global_form.into(),
}
}
/// Access the curve that defines the half-edge's geometry
pub fn curve(&self) -> Curve {
self.curve
}
/// Access the boundary points of the half-edge on the curve
pub fn boundary(&self) -> [Point<1>; 2] {
self.boundary
}
/// Compute the surface position where the half-edge starts
pub fn start_position(&self) -> Point<2> {
// Computing the surface position from the curve position is fine.
// `HalfEdge` "owns" its start position. There is no competing code that
// could compute the surface position from slightly different data.
let [start, _] = self.boundary;
self.curve.point_from_path_coords(start)
}
/// Access the vertex from where this half-edge starts
pub fn start_vertex(&self) -> &Handle<Vertex> {
&self.start_vertex
}
/// Access the global form of the half-edge
pub fn global_form(&self) -> &Handle<GlobalEdge> {
&self.global_form
}
}
/// An undirected edge, defined in global (3D) coordinates
///
/// In contrast to [`HalfEdge`], `GlobalEdge` is undirected, meaning it has no
/// defined direction. This means it can be used to determine whether two
/// [`HalfEdge`]s map to the same `GlobalEdge`, regardless of their direction.
///
/// See [`HalfEdge`]'s documentation for more information on the relationship
/// between [`HalfEdge`] and `GlobalEdge`.
///
/// # Equality
///
/// `GlobalEdge` contains no data and exists purely to be used within a
/// `Handle`, where `Handle::id` can be used to compare different instances of
/// `GlobalEdge`.
///
/// If `GlobalEdge` had `Eq`/`PartialEq` implementations, it containing no data
/// would mean that all instances of `GlobalEdge` would be considered equal.
/// This would be very error-prone.
///
/// If you need to reference a `GlobalEdge` from a struct that needs to derive
/// `Eq`/`Ord`/..., you can use `HandleWrapper<GlobalEdge>` to do that. It will
/// use `Handle::id` to provide those `Eq`/`Ord`/... implementations.
#[derive(Clone, Debug, Default, Hash)]
pub struct GlobalEdge {}
impl GlobalEdge {
/// Create a new instance
///
/// The order of `vertices` is irrelevant. Two `GlobalEdge`s with the same
/// `curve` and `vertices` will end up being equal, regardless of the order
/// of `vertices` here.
pub fn new() -> Self {
Self::default()
}
}