CARLA
DoublyConnectedEdgeList.h
Go to the documentation of this file.
1 // Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
2 // de Barcelona (UAB).
3 //
4 // This work is licensed under the terms of the MIT license.
5 // For a copy, see <https://opensource.org/licenses/MIT>.
6 
7 #pragma once
8 
9 #include "GraphTypes.h"
10 #include "Position.h"
11 #include "Util/ListView.h"
12 
13 #include <array>
14 #include <list>
15 
16 namespace MapGen {
17 
18  /// Simple doubly-connected edge list structure. It only allows adding
19  /// elements, not removing them.
20  class CARLA_API DoublyConnectedEdgeList : private NonCopyable
21  {
22  // =========================================================================
23  // -- DCEL types -----------------------------------------------------------
24  // =========================================================================
25 
26  public:
27 
29 
30  struct Node;
31  struct HalfEdge;
32  struct Face;
33 
34  struct Node : public GraphNode
35  {
37 
38  Node(const Position &Pos) : Position(Pos) {}
39 
40  Node &operator=(const Node &) = delete;
41 
43  {
44  return Position;
45  }
46 
47  private:
49  HalfEdge *LeavingHalfEdge = nullptr;
50  };
51 
52  struct HalfEdge : public GraphHalfEdge
53  {
55 
56  HalfEdge &operator=(const HalfEdge &) = delete;
57 
58  private:
59  Node *Source = nullptr;
60  Node *Target = nullptr;
61  HalfEdge *Next = nullptr;
62  HalfEdge *Pair = nullptr;
63  Face *Face = nullptr;
64  };
65 
66  struct Face : public GraphFace
67  {
69 
70  Face &operator=(const Face &) = delete;
71 
72  private:
73  HalfEdge *HalfEdge = nullptr;
74  };
75 
76  using NodeContainer = std::list<Node>;
77  using NodeIterator = typename NodeContainer::iterator;
78  using ConstNodeIterator = typename NodeContainer::const_iterator;
79 
80  using HalfEdgeContainer = std::list<HalfEdge>;
81  using HalfEdgeIterator = typename HalfEdgeContainer::iterator;
82  using ConstHalfEdgeIterator = typename HalfEdgeContainer::const_iterator;
83 
84  using FaceContainer = std::list<Face>;
85  using FaceIterator = typename FaceContainer::iterator;
86  using ConstFaceIterator = typename FaceContainer::const_iterator;
87 
88  // =========================================================================
89  // -- Constructors and destructor ------------------------------------------
90  // =========================================================================
91 
92  public:
93 
94  /// Create a DoublyConnectedEdgeList with two nodes, two edges and one face.
95  explicit DoublyConnectedEdgeList(const Position &Position0, const Position &Position1);
96 
97  /// Create a DoublyConnectedEdgeList consisting of a cycle of N nodes.
98  template <size_t N>
99  explicit DoublyConnectedEdgeList(const std::array<Position, N> &Cycle)
100  : DoublyConnectedEdgeList(Cycle[0u], Cycle[1u])
101  {
102  static_assert(N > 2u, "Not enough nodes to make a cycle!");
103  for (auto i = 2u; i < Cycle.size(); ++i) {
104  AddNode(Cycle[i], Nodes.back());
105  }
106  ConnectNodes(Nodes.front(), Nodes.back());
107  }
108 
110 
111  // =========================================================================
112  /// @name Adding elements to the graph -------------------------------------
113  // =========================================================================
114  /// {
115  public:
116 
117  /// Add a node at @a NodePosition and attach it to @a OtherNode.
118  ///
119  /// The time complexity is O(n*log(n)) where n is the number of edges
120  /// leaving @a OtherNode.
121  ///
122  /// @return The newly generated node.
123  Node &AddNode(const Position &NodePosition, Node &OtherNode);
124 
125  /// Split @a HalfEdge (and its pair) at @a Position.
126  ///
127  /// The time complexity is O(n*log(n)) where n is the number of edges
128  /// leaving @a HalfEdge's source.
129  ///
130  /// @return The newly generated node.
131  Node &SplitEdge(const Position &Position, HalfEdge &HalfEdge);
132 
133  /// Connect two nodes by a pair of edges.
134  ///
135  /// It is assumed that both nodes are connected by the same face.
136  ///
137  /// The time complexity is O(n0*log(n0) + n1*log(n1) + nf) where n0 and n1
138  /// are the number of edges leaving @a Node0 and @a Node1 respectively, and
139  /// nf is the number of edges in the face containing both nodes.
140  ///
141  /// @return The newly generated face.
142  Face &ConnectNodes(Node &Node0, Node &Node1);
143 
144  /// @}
145  // =========================================================================
146  /// @name Counting graph elements ------------------------------------------
147  // =========================================================================
148  /// @{
149  public:
150 
151  size_t CountNodes() const
152  {
153  return Nodes.size();
154  }
155 
156  size_t CountHalfEdges() const
157  {
158  return HalfEdges.size();
159  }
160 
161  size_t CountFaces() const
162  {
163  return Faces.size();
164  }
165 
166  /// @}
167  // =========================================================================
168  /// @name Accessing graph elements -----------------------------------------
169  // =========================================================================
170  /// @{
171  public:
172 
174  {
175  return ListView<NodeIterator>(Nodes);
176  }
177 
179  {
180  return ListView<ConstNodeIterator>(Nodes);
181  }
182 
184  {
185  return ListView<HalfEdgeIterator>(HalfEdges);
186  }
187 
189  {
190  return ListView<ConstHalfEdgeIterator>(HalfEdges);
191  }
192 
194  {
195  return ListView<FaceIterator>(Faces);
196  }
197 
199  {
200  return ListView<ConstFaceIterator>(Faces);
201  }
202 
203  /// @}
204  // =========================================================================
205  /// @name Accessing graph pointers -----------------------------------------
206  // =========================================================================
207  /// @{
208  public:
209 
210  // -- Primary pointers -----------------------------------------------------
211 
212  static Node &GetSource(HalfEdge &halfEdge)
213  {
214  check(halfEdge.Source != nullptr);
215  return *halfEdge.Source;
216  }
217 
218  static const Node &GetSource(const HalfEdge &halfEdge)
219  {
220  check(halfEdge.Source != nullptr);
221  return *halfEdge.Source;
222  }
223 
224  static Node &GetTarget(HalfEdge &halfEdge)
225  {
226  check(halfEdge.Target != nullptr);
227  return *halfEdge.Target;
228  }
229 
230  static const Node &GetTarget(const HalfEdge &halfEdge)
231  {
232  check(halfEdge.Target != nullptr);
233  return *halfEdge.Target;
234  }
235 
236  static HalfEdge &GetPair(HalfEdge &halfEdge)
237  {
238  check(halfEdge.Pair != nullptr);
239  return *halfEdge.Pair;
240  }
241 
242  static const HalfEdge &GetPair(const HalfEdge &halfEdge)
243  {
244  check(halfEdge.Pair != nullptr);
245  return *halfEdge.Pair;
246  }
247 
248  static Face &GetFace(HalfEdge &halfEdge)
249  {
250  check(halfEdge.Face != nullptr);
251  return *halfEdge.Face;
252  }
253 
254  static const Face &GetFace(const HalfEdge &halfEdge)
255  {
256  check(halfEdge.Face != nullptr);
257  return *halfEdge.Face;
258  }
259 
260  static HalfEdge &GetLeavingHalfEdge(Node &node)
261  {
262  check(node.LeavingHalfEdge != nullptr);
263  return *node.LeavingHalfEdge;
264  }
265 
266  static const HalfEdge &GetLeavingHalfEdge(const Node &node)
267  {
268  check(node.LeavingHalfEdge != nullptr);
269  return *node.LeavingHalfEdge;
270  }
271 
272  static HalfEdge &GetHalfEdge(Face &face)
273  {
274  check(face.HalfEdge != nullptr);
275  return *face.HalfEdge;
276  }
277 
278  static const HalfEdge &GetHalfEdge(const Face &face)
279  {
280  check(face.HalfEdge != nullptr);
281  return *face.HalfEdge;
282  }
283 
284  // -- Secondary pointers ---------------------------------------------------
285 
286  static HalfEdge &GetNextInFace(HalfEdge &halfEdge)
287  {
288  check(halfEdge.Next != nullptr);
289  return *halfEdge.Next;
290  }
291 
292  static const HalfEdge &GetNextInFace(const HalfEdge &halfEdge)
293  {
294  check(halfEdge.Next != nullptr);
295  return *halfEdge.Next;
296  }
297 
298  static HalfEdge &GetNextInNode(HalfEdge &halfEdge)
299  {
300  return GetNextInFace(GetPair(halfEdge));
301  }
302 
303  static const HalfEdge &GetNextInNode(const HalfEdge &halfEdge)
304  {
305  return GetNextInFace(GetPair(halfEdge));
306  }
307 
308  /// @}
309  // =========================================================================
310  /// @name Other member functions -------------------------------------------
311  // =========================================================================
312  /// @{
313  public:
314 
315  /// Return the angle [-pi, pi] of the half-edge.
316  static float GetAngle(const HalfEdge &halfEdge);
317 
318 #ifdef CARLA_ROAD_GENERATOR_EXTRA_LOG
319  void PrintToLog() const;
320  #endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
321 
322  /// @}
323  // =========================================================================
324  // -- Private members ------------------------------------------------------
325  // =========================================================================
326 
327  private:
328 
330 
332 
334  };
335 
336 } // namespace MapGen
static Face & GetFace(HalfEdge &halfEdge)
typename FaceContainer::iterator FaceIterator
static HalfEdge & GetHalfEdge(Face &face)
static const Node & GetSource(const HalfEdge &halfEdge)
typename NodeContainer::const_iterator ConstNodeIterator
DoublyConnectedEdgeList(const std::array< Position, N > &Cycle)
Create a DoublyConnectedEdgeList consisting of a cycle of N nodes.
Simple doubly-connected edge list structure.
ListView< NodeIterator > GetNodes()
static Node & GetSource(HalfEdge &halfEdge)
ListView< ConstHalfEdgeIterator > GetHalfEdges() const
static HalfEdge & GetPair(HalfEdge &halfEdge)
typename FaceContainer::const_iterator ConstFaceIterator
DoublyConnectedEdgeList::Position Position
ListView< HalfEdgeIterator > GetHalfEdges()
static const HalfEdge & GetLeavingHalfEdge(const Node &node)
typename HalfEdgeContainer::const_iterator ConstHalfEdgeIterator
const DoublyConnectedEdgeList::Position & GetPosition() const
static const Face & GetFace(const HalfEdge &halfEdge)
static const HalfEdge & GetHalfEdge(const Face &face)
static HalfEdge & GetLeavingHalfEdge(Node &node)
ListView< ConstFaceIterator > GetFaces() const
static HalfEdge & GetNextInFace(HalfEdge &halfEdge)
static const HalfEdge & GetPair(const HalfEdge &halfEdge)
static Node & GetTarget(HalfEdge &halfEdge)
static const Node & GetTarget(const HalfEdge &halfEdge)
static HalfEdge & GetNextInNode(HalfEdge &halfEdge)
typename NodeContainer::iterator NodeIterator
ListView< ConstNodeIterator > GetNodes() const
static const HalfEdge & GetNextInNode(const HalfEdge &halfEdge)
ListView< FaceIterator > GetFaces()
typename HalfEdgeContainer::iterator HalfEdgeIterator
static const HalfEdge & GetNextInFace(const HalfEdge &halfEdge)