CARLA
 
载入中...
搜索中...
未找到
DoublyConnectedEdgeList.cpp
浏览该文件的文档.
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#include "Carla.h"
9
10#include <cmath>
11#include <map>
12
13#ifdef CARLA_ROAD_GENERATOR_EXTRA_LOG
14#include <sstream>
15#endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
16
17namespace MapGen {
18
19 // ===========================================================================
20 // -- Local static methods ---------------------------------------------------
21 // ===========================================================================
22
23#ifdef CARLA_ROAD_GENERATOR_EXTRA_LOG
24
25 static void ResetIndices() {
26 GraphNode::ResetIndex();
27 GraphHalfEdge::ResetIndex();
28 GraphFace::ResetIndex();
29 }
30
31#endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
32
33 /// Return the pair {prev, next}, where prev/next is the previous/next edge
34 /// counterclockwise around edge's source node. I.e., edge's position is in
35 /// between prev and next.
36 ///
37 /// Note: Always returns the half-edge pointing out from node.
38 ///
39 /// The time complexity is O(n*log(n)) where n is the number of edges of
40 /// edge's source.
41 static std::pair<DoublyConnectedEdgeList::HalfEdge *, DoublyConnectedEdgeList::HalfEdge *>
43 {
44 using Dcel = DoublyConnectedEdgeList;
45 // from [-pi, pi] to [0, 1].
46 auto normalize = [](auto a) {
47 constexpr float twoPi = 2.0 * 3.14159265359;
48 a /= twoPi;
49 while (a >= 1.0) a -= 1.0;
50 while (a < 0.0) a += 1.0;
51 return a;
52 };
53 auto angle = Dcel::GetAngle(halfEdge);
54 std::map<decltype(angle), Dcel::HalfEdge *> edgeMap;
55 // Iterate every half-edge in the source node.
56 auto &firstHalfEdge = Dcel::GetLeavingHalfEdge(Dcel::GetSource(halfEdge));
57 auto *edge = &firstHalfEdge;
58 do {
59 if (edge != &halfEdge) {
60 auto alpha = DoublyConnectedEdgeList::GetAngle(*edge);
61 auto a = normalize(alpha - angle);
62 edgeMap.insert({a, edge});
63 }
64 edge = &Dcel::GetNextInNode(*edge);
65 } while (edge != &firstHalfEdge);
66 check(!edgeMap.empty());
67 return {edgeMap.rbegin()->second, edgeMap.begin()->second};
68 }
69
70 // ===========================================================================
71 // -- Constructors and destructor --------------------------------------------
72 // ===========================================================================
73
75 const Position &Position0,
76 const Position &Position1) :
77 Nodes(),
78 HalfEdges(2u),
79 Faces(1u)
80 {
81 Nodes.emplace_back(Position0);
82 Nodes.emplace_back(Position1);
83
84 Faces.front().HalfEdge = &HalfEdges.front();
85
86 HalfEdges.front().Source = &Nodes.front();
87 HalfEdges.front().Target = &Nodes.back();
88 HalfEdges.front().Next = &HalfEdges.back();
89 HalfEdges.front().Pair = &HalfEdges.back();
90 HalfEdges.front().Face = &Faces.front();
91
92 HalfEdges.back().Source = &Nodes.back();
93 HalfEdges.back().Target = &Nodes.front();
94 HalfEdges.back().Next = &HalfEdges.front();
95 HalfEdges.back().Pair = &HalfEdges.front();
96 HalfEdges.back().Face = &Faces.front();
97
98 Nodes.front().LeavingHalfEdge = &HalfEdges.front();
99 Nodes.back().LeavingHalfEdge = &HalfEdges.back();
100 }
101
103 {
104#ifdef CARLA_ROAD_GENERATOR_EXTRA_LOG
105 ResetIndices();
106#endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
107 }
108
109 // ===========================================================================
110 // -- Adding elements to the graph -------------------------------------------
111 // ===========================================================================
112
114 const Position &NodePosition,
115 Node &OtherNode)
116 {
117 Nodes.emplace_back(NodePosition);
118 auto &newNode = Nodes.back();
119 HalfEdges.emplace_back();
120 auto &edge0 = HalfEdges.back();
121 HalfEdges.emplace_back();
122 auto &edge1 = HalfEdges.back();
123
124 edge0.Source = &newNode;
125 edge0.Target = &OtherNode;
126 edge0.Pair = &edge1;
127
128 edge1.Source = &OtherNode;
129 edge1.Target = &newNode;
130 edge1.Pair = &edge0;
131
132 HalfEdge *prev;
133 HalfEdge *next;
134 std::tie(prev, next) = FindPositionInNode(edge1);
135
136 edge0.Next = next;
137 edge0.Face = next->Face;
138
139 edge1.Next = &edge0;
140 edge1.Face = next->Face;
141
142 prev->Pair->Next = &edge1;
143
144 newNode.LeavingHalfEdge = &edge0;
145 return newNode;
146 }
147
149 const Position &Position,
150 HalfEdge &edge)
151 {
152 HalfEdges.emplace_back();
153 auto &edge0 = HalfEdges.back();
154 HalfEdges.emplace_back();
155 auto &edge1 = HalfEdges.back();
156
157 Nodes.emplace_back(Position);
158 auto &newNode = Nodes.back();
159
160 auto &node0 = *edge.Source;
161
162 // Opposite direction of edge.
163 edge0.Source = &newNode;
164 edge0.Target = &node0;
165 edge0.Pair = &edge1;
166 edge0.Face = edge.Pair->Face;
167
168 // Same direction as edge.
169 edge1.Source = &node0;
170 edge1.Target = &newNode;
171 edge1.Pair = &edge0;
172 edge1.Next = &edge;
173 edge1.Face = edge.Face;
174
175 // Fix connections to node0.
176 HalfEdge *prev;
177 HalfEdge *next;
178 std::tie(prev, next) = FindPositionInNode(edge);
179 edge0.Next = next;
180 prev->Pair->Next = &edge1;
181
182 // Fix the pair that was split.
183 edge.Source = &newNode;
184 edge.Pair->Target = &newNode;
185 edge.Pair->Next = &edge0;
186
187 // Fix the node's edges.
188 node0.LeavingHalfEdge = &edge1;
189 newNode.LeavingHalfEdge = &edge0;
190
191 return newNode;
192 }
193
195 Node &Node0,
196 Node &Node1)
197 {
198 Faces.emplace_back();
199 auto &newFace = Faces.back();
200 HalfEdges.emplace_back();
201 auto &edge0 = HalfEdges.back();
202 HalfEdges.emplace_back();
203 auto &edge1 = HalfEdges.back();
204
205 edge0.Source = &Node0;
206 edge0.Target = &Node1;
207 edge0.Pair = &edge1;
208 edge1.Source = &Node1;
209 edge1.Target = &Node0;
210 edge1.Pair = &edge0;
211
212 // Connect edges to node0.
213 HalfEdge *prev0;
214 HalfEdge *next0;
215 std::tie(prev0, next0) = FindPositionInNode(edge0);
216 edge1.Next = next0;
217 prev0->Pair->Next = &edge0;
218
219 // Connect edges to node1.
220 HalfEdge *prev1;
221 HalfEdge *next1;
222 std::tie(prev1, next1) = FindPositionInNode(edge1);
223 edge0.Next = next1;
224 prev1->Pair->Next = &edge1;
225
226 // Attach faces to the newly created edges.
227 auto &oldFace = *next1->Face;
228 oldFace.HalfEdge = &edge0;
229 newFace.HalfEdge = &edge1;
230
231 // Iterate over the edges of each face and correct pointers.
232 auto fixFace = [](Face &face) {
233 auto &firstEdge = GetHalfEdge(face);
234 auto *edge = &firstEdge;
235 do {
236 edge->Face = &face;
237 edge = &GetNextInFace(*edge);
238 } while (edge != &firstEdge);
239 };
240 fixFace(oldFace);
241 fixFace(newFace);
242
243 return newFace;
244 }
245
246 // ===========================================================================
247 // -- Other member functions -------------------------------------------------
248 // ===========================================================================
249
251 auto src = GetSource(halfEdge).GetPosition();
252 auto trg = GetTarget(halfEdge).GetPosition();
253 auto dir = trg - src; // @todo normalize?
254 return std::atan2(static_cast<double>(dir.y), static_cast<double>(dir.x));
255 }
256
257#ifdef CARLA_ROAD_GENERATOR_EXTRA_LOG
258
259 void DoublyConnectedEdgeList::PrintToLog() const
260 {
261 std::wstringstream sout;
262 {
263 sout << "iterate all nodes: ";
264 for (auto &node : GetNodes()) {
265 auto p = node.GetPosition();
266 sout << node << "{" << p.x << "," << p.y << "} ";
267 }
268 sout << "\n";
269 }
270 {
271 sout << "iterate all faces: ";
272 for (auto &face : GetFaces()) {
273 sout << face << " ";
274 }
275 sout << "\n";
276 }
277 {
278 sout << "iterate all edges: ";
279 for (auto &edge : GetHalfEdges()) {
280 auto &src = GetSource(edge);
281 auto &trg = GetTarget(edge);
282 auto &face = GetFace(edge);
283 sout << edge << "{" << src << "->" << trg << "," << face << "} ";
284 }
285 sout << "\n";
286 }
287 {
288 sout << "iterate nodes in face: ";
289 for (auto &face : GetFaces()) {
290 sout << face << "{ ";
291 auto &firstEdge = GetHalfEdge(face);
292 const auto *edge = &firstEdge;
293 do {
294 sout << GetSource(*edge) << " ";
295 edge = &GetNextInFace(*edge);
296 } while (edge != &firstEdge);
297 sout << "} ";
298 }
299 sout << "\n";
300 }
301 {
302 sout << "iterate edges in node: ";
303 for (auto &node : GetNodes()) {
304 sout << node << "{ ";
305 auto &firstEdge = GetLeavingHalfEdge(node);
306 const auto *edge = &firstEdge;
307 do {
308 sout << GetTarget(*edge) << " ";
309 edge = &GetNextInNode(*edge);
310 } while (edge != &firstEdge);
311 sout << "} ";
312 }
313 sout << "\n";
314 }
315 UE_LOG(LogCarla, Log, TEXT("\n%s"), sout.str().c_str());
316 }
317
318#endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
319
320} // namespace MapGen
Simple doubly-connected edge list structure.
Node & AddNode(const Position &NodePosition, Node &OtherNode)
{
Face & ConnectNodes(Node &Node0, Node &Node1)
Connect two nodes by a pair of edges.
ListView< HalfEdgeIterator > GetHalfEdges()
DoublyConnectedEdgeList(const Position &Position0, const Position &Position1)
Create a DoublyConnectedEdgeList with two nodes, two edges and one face.
static float GetAngle(const HalfEdge &halfEdge)
Return the angle [-pi, pi] of the half-edge.
static HalfEdge & GetHalfEdge(Face &face)
static Node & GetTarget(HalfEdge &halfEdge)
static HalfEdge & GetLeavingHalfEdge(Node &node)
static Face & GetFace(HalfEdge &halfEdge)
static Node & GetSource(HalfEdge &halfEdge)
static HalfEdge & GetNextInNode(HalfEdge &halfEdge)
static HalfEdge & GetNextInFace(HalfEdge &halfEdge)
Node & SplitEdge(const Position &Position, HalfEdge &HalfEdge)
Split HalfEdge (and its pair) at Position.
static std::pair< DoublyConnectedEdgeList::HalfEdge *, DoublyConnectedEdgeList::HalfEdge * > FindPositionInNode(DoublyConnectedEdgeList::HalfEdge &halfEdge)
Return the pair {prev, next}, where prev/next is the previous/next edge counterclockwise around edge'...
const DoublyConnectedEdgeList::Position & GetPosition() const