CARLA
 
载入中...
搜索中...
未找到
GraphGenerator.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"
8#include "GraphGenerator.h"
9
10#include <vector>
11
12// 定义一个名为MapGen的命名空间,以下所有的函数、类型定义等都在这个命名空间内
13namespace MapGen {
14
15 // 使用Graph作为DoublyConnectedEdgeList的别名,方便后续使用
17
18 // 定义一个常量表达式,用于表示一个边距值,这里设置为6
19 constexpr static int32 MARGIN = 6;
20
21 // ===========================================================================
22 // -- Static local methods ---------------------------------------------------
23 // ===========================================================================
24
25 // 定义一个静态函数signOf,它接受一个int32类型的参数val
26 // 根据val的值返回其符号,若val大于0则返回1,若val小于0则返回-1,若val等于0则返回0
27 static int32 signOf(int32 val) {
28 return (0 < val) - (val < 0);
29 }
30
31 // 定义一个静态函数getSourcePosition,它接受一个Graph::HalfEdge类型的参数edge
32 // 返回该边的源节点的位置信息,通过调用Graph::GetSource函数获取源节点,再获取其位置
34 return Graph::GetSource(edge).GetPosition();
35 }
36
37 // 定义一个静态函数getTargetPosition,它接受一个Graph::HalfEdge类型的参数edge
38 // 返回该边的目标节点的位置信息,通过调用Graph::GetTarget函数获取目标节点,再获取其位置
40 return Graph::GetTarget(edge).GetPosition();
41 }
42
43 // 定义一个静态函数getDirection,它接受一个Graph::HalfEdge类型的参数edge
44 // 通过目标节点位置减去源节点位置,计算并返回该边的方向向量
46 return getTargetPosition(edge) - getSourcePosition(edge);
47 }
48
49 // 定义一个静态函数getRandomOpposingEdges,它接受一个Graph::Face类型的参数face和一个FRandomStream类型的参数random
50 // 该函数的目的是从给定的面(face)中随机获取一对相对的边
51 static std::pair<Graph::HalfEdge *, Graph::HalfEdge *> getRandomOpposingEdges(
52 Graph::Face &face,
53 FRandomStream &random) {
54 // 创建一个向量用于存储面中的所有边
55 std::vector<Graph::HalfEdge *> edges;
56 // 获取面的第一条半边(half-edge),这是遍历面的边的起始点
57 edges.reserve(4u);
58 // 将第一条半边赋值给临时指针edge,用于后续遍历
59 auto &firstEdge = Graph::GetHalfEdge(face);
60 // 开始遍历面的所有边,直到回到起始边
61 auto *edge = &firstEdge;
62 do {
63 // 将当前边添加到边向量中
64 edges.emplace_back(edge);
65 // 获取下一条在面中的半边,继续遍历
66 edge = &Graph::GetNextInFace(*edge);
67 } while (edge != &firstEdge);
68 // 检查边向量的大小是否为4u,如果不是则可能存在错误
69 check(edges.size() == 4u);
70 // 在0到边向量大小减1的范围内随机生成一个索引值
71 auto randomIndex = random.RandRange(0, edges.size() - 1);
72 // 返回随机选择的一对相对边,其中一条是随机索引对应的边,另一条是相隔两条边的相对边
73 return {edges[randomIndex], edges[(randomIndex + 2u) % edges.size()]};
74 }
75
76 // 定义一个静态函数splitFace,它接受一个Graph类型的参数graph、一个Graph::Face类型的参数face和一个FRandomStream类型的参数random
77 // 该函数的目的是将给定的面(face)进行分割
78 static Graph::Face *splitFace(Graph &graph, Graph::Face &face, FRandomStream &random) {
79 // 获取面中的一对随机相对边
80 auto edgePair = getRandomOpposingEdges(face, random);
81 // 计算第一条随机边的方向向量
82 auto dir = getDirection(*edgePair.first);
83 // 假设两条随机边是矩形相对的面,计算第二条随机边的方向向量
84 auto otherDir = getDirection(*edgePair.second);
85 // 检查两条边的方向向量在x和y方向上是否互为相反数,以此验证是否是相对边的假设成立
86 check((dir.x == -1 * otherDir.x) && (dir.y == -1 * otherDir.y));
87 // 如果矩形的边长小于一定的阈值,则不进行分割
88 if ((std::abs(dir.x) < 2*MARGIN+1) && (std::abs(dir.y) < 2*MARGIN+1))
89 return nullptr;
90 // 沿着边获取一个随机点
91 auto randX = (dir.x != 0 ? signOf(dir.x) * random.RandRange(MARGIN, std::abs(dir.x) - MARGIN) : 0);
92 // 根据第一条随机边的方向向量,在其边上随机生成一个y坐标值
93 auto randY = (dir.y != 0 ? signOf(dir.y) * random.RandRange(MARGIN, std::abs(dir.y) - MARGIN) : 0);
94 // 计算在第一条随机边的源节点位置基础上,根据随机生成的坐标偏移得到的新位置
95 auto position0 = getSourcePosition(*edgePair.first) + Graph::Position{randX, randY};
96 // 计算在第二条随机边的目标节点位置基础上,根据随机生成的坐标偏移得到的新位置
97 auto position1 = getTargetPosition(*edgePair.second) + Graph::Position{randX, randY};
98 // 拆分这些边并连接起来
99 Graph::Node &node0 = graph.SplitEdge(position0, *edgePair.first);
100 // 在图中根据新位置分割第二条随机边,并获取分割后产生的新节点node1
101 Graph::Node &node1 = graph.SplitEdge(position1, *edgePair.second);
102 // 连接两个新节点,并返回新生成的面的指针
103 return &graph.ConnectNodes(node0, node1);
104 }
105
106 // 定义一个静态函数randomize,它接受一个Graph类型的参数graph和一个int32类型的参数seed
107 // 该函数的目的是对给定的图(graph)进行随机化操作
108 static void randomize(Graph &graph, const int32 seed)
109 {
110 // 检查图中的节点数量是否为4u,如果不是则可能存在错误
111 check(graph.CountNodes() == 4u);
112 // 检查图中的半边数量是否为8u,如果不是则可能存在错误
113 check(graph.CountHalfEdges() == 8u);
114 // 检查图中的面数量是否为2u,如果不是则可能存在错误
115 check(graph.CountFaces() == 2u);
116 // 创建一个随机数生成流,使用传入的seed作为种子
117 FRandomStream random(seed);
118 /// @todo 我们跳过第一个面,因为它是环绕面。
119 /// 但情况并非总是如此,如果以不同的方式生成图,那可能就会是
120 /// 另一个(面需要被处理)了。
121 // 获取图中除了第一个面之外的第一个面的指针,这里假设第一个面是周围的面,可能需要根据实际情况调整
122 Graph::Face *face = &*(++graph.GetFaces().begin());
123 do {
124 face = splitFace(graph, *face, random);
125#ifdef CARLA_ROAD_GENERATOR_EXTRA_LOG
126 graph.PrintToLog();
127#endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
128 } while (face != nullptr);
129 }
130
131 // =============================================================================
132 // -- GraphGenerator -----------------------------------------------------------
133 // =============================================================================
134
135 // 定义GraphGenerator类的Generate函数,它接受三个参数:SizeX(无符号32位整数)、SizeY(无符号32位整数)和Seed(int32类型)
136 // 该函数的目的是生成一个特定的图结构(DoublyConnectedEdgeList类型)
137 TUniquePtr<DoublyConnectedEdgeList> GraphGenerator::Generate(
138 const uint32 SizeX,
139 const uint32 SizeY,
140 const int32 Seed)
141 {
142 // 使用DoublyConnectedEdgeList中的Position类型定义一个别名Position,方便后续使用
144 // 创建一个包含4个Position类型元素的数组box,用于表示一个矩形的四个顶点位置
145 std::array<Position, 4u> box;
146 box[0u] = Position(0, 0);
147 box[1u] = Position(0, SizeY);
148 box[2u] = Position(SizeX, SizeY);
149 box[3u] = Position(SizeX, 0);
150 // 创建一个唯一指针指向新生成的DoublyConnectedEdgeList对象,传入矩形的顶点位置数组作为初始化参数
151 auto Dcel = MakeUnique<DoublyConnectedEdgeList>(box);
152 // 对生成的图结构进行随机化操作,传入随机数种子
153 randomize(*Dcel, Seed);
154 // 返回生成并随机化后的图结构的唯一指针
155 return Dcel;
156 }
157
158} // namespace MapGen
简单的双连通边链表结构。它只允许添加元素,不允许删除元素。
Face & ConnectNodes(Node &Node0, Node &Node1)
用一对边连接两个节点。
static HalfEdge & GetHalfEdge(Face &face)
static Node & GetTarget(HalfEdge &halfEdge)
static Node & GetSource(HalfEdge &halfEdge)
static HalfEdge & GetNextInFace(HalfEdge &halfEdge)
Node & SplitEdge(const Position &Position, HalfEdge &HalfEdge)
在 位置分割 HalfEdge (和它的配对)
static TUniquePtr< DoublyConnectedEdgeList > Generate(uint32 SizeX, uint32 SizeY, int32 Seed)
创建一个大小为 SizeX 乘以 SizeY 的平方双连通边链表 DoublyConnectedEdgeList, 并使用固定的随机数生成种子 Seed 在内部生成随机连接。
static void randomize(Graph &graph, const int32 seed)
static std::pair< Graph::HalfEdge *, Graph::HalfEdge * > getRandomOpposingEdges(Graph::Face &face, FRandomStream &random)
static constexpr int32 MARGIN
static Graph::Face * splitFace(Graph &graph, Graph::Face &face, FRandomStream &random)
static const Graph::Position & getTargetPosition(const Graph::HalfEdge &edge)
static const Graph::Position & getSourcePosition(const Graph::HalfEdge &edge)
static int32 signOf(int32 val)
static Graph::Position getDirection(const Graph::HalfEdge &edge)
const DoublyConnectedEdgeList::Position & GetPosition() const