GraphBuilder.cpp
Go to the documentation of this file.
1#include "GraphBuilder.h"
2
3#include <algorithm>
4#include <cstddef>
5#include <optional>
6#include <vector>
7
11
13
16#include <armarx/navigation/core/aron/Graph.aron.generated.h>
18
19#include <SemanticObjectRelations/Shapes/Shape.h>
20
22{
23 const core::arondto::Edge ARON_UNSET_EDGE_VALUES = []()
24 {
25 core::arondto::Edge edge;
26 edge.sourceVertexID = -1;
27 edge.targetVertexID = -1;
28 return edge;
29 }();
30
31 void
33 {
34 core::VertexAttribs attribs;
35 attribs.setPose(FramedPose(pose.matrix(), armarx::GlobalFrame, ""));
36
37 const semrel::ShapeID shapeId(++vertexIdCnt);
38 graph.addVertex(shapeId, attribs);
39
40 startVertex = graph.vertex(shapeId);
41
42 // pedantic check
43 ARMARX_CHECK(startVertex->attrib().hasPose()) << "Start vertex must have a pose!";
44
45 activeVertices_ = {shapeId};
46 }
47
48 // const std::vector<core::Graph::VertexDescriptor>&
49 // GraphBuilder::activeVertices() const
50 // {
51 // return activeVertices_;
52 // }
53 void
55 {
57 getGraph(); // FIXME remove
58
59 core::VertexAttribs attribs;
60 attribs.setPose(FramedPose(pose.matrix(), armarx::GlobalFrame, ""));
61
62 const semrel::ShapeID shapeId(++vertexIdCnt); // TODO implement newShapeId()
63 graph.addVertex(shapeId, attribs);
64
65
66 // pedantic check
67 ARMARX_CHECK(graph.vertex(shapeId).attrib().hasPose()) << "Vertex pose must be set!";
68
70 getGraph(); // FIXME remove
71
72
73 for (const semrel::ShapeID& activeVertexId : activeVertices_)
74 {
75 graph.addEdge(activeVertexId,
76 shapeId,
77 core::Graph::EdgeAttrib{.aron = ARON_UNSET_EDGE_VALUES,
78 .strategy = strategy,
79 .trajectory = std::nullopt});
80 }
81
82 activeVertices_ = {shapeId};
83 }
84
85 void
86 GraphBuilder::connect(const std::vector<core::Graph::VertexDescriptor>& routes,
87 const client::GlobalPlanningStrategy& strategy)
88 {
89 // for (const auto& vertex : activeVertices_)
90 // {
91 // graph.addEdge()
92 // }
93 }
94
95 semrel::ShapeID
96 GraphBuilder::addOrGetVertex(const core::Graph::VertexAttrib& attributes)
97 {
98 const auto vertex = getVertexByAttributes(attributes);
99 if (vertex.has_value())
100 {
101 return vertex.value();
102 }
103
104 const semrel::ShapeID shapeId(++vertexIdCnt);
105 graph.addVertex(shapeId, attributes);
106
107 return shapeId;
108 }
109
110 bool
111 operator==(const core::Graph::VertexAttrib& lhs, const core::Graph::VertexAttrib& rhs)
112 {
113 if (lhs.hasLocationName() and rhs.hasLocationName())
114 {
115 return lhs.getLocationName() == rhs.getLocationName();
116 };
117
118 // otherwise:
119 // (1) only one of both has a name => not equal
120 // (2) both are 'anonymous' => not equal (by definition)
121 return false;
122 }
123
124 std::optional<semrel::ShapeID>
125 GraphBuilder::getVertexByAttributes(const core::Graph::VertexAttrib& attributes)
126 {
127 auto vertices = graph.vertices();
128 const auto vIt = std::find_if(vertices.begin(),
129 vertices.end(),
130 [&attributes](const core::Graph::ConstVertex& vertex)
131 { return vertex.attrib() == attributes; });
132
133 if (vIt != vertices.end()) // vertex exists
134 {
135 ARMARX_DEBUG << "Found matching vertex " << QUOTED(vIt->attrib().getLocationName());
136 return vIt->objectID();
137 }
138
139 return std::nullopt;
140 }
141
142 void
143 GraphBuilder::connect(const std::vector<core::GraphPath>& routes,
144 const client::GlobalPlanningStrategy& strategy)
145 {
146 ARMARX_CHECK(not routes.empty())
147 << "Routes must exist. Otherwise, the graph will not have any active connections!";
148
149 // all active vertices will be connected to all routes
150 for (const auto& vertex : activeVertices_)
151 {
152 for (const auto& route : routes)
153 {
154 if (route.empty())
155 {
156 continue;
157 }
158
159 // The shape ids of the routes passed to this function are not meaningful. They will be changed.
160 std::vector<semrel::ShapeID> routeShapeIds;
161
163
164 // add all vertices to the graph
165 for (const auto& vertex : route)
166 {
167 ARMARX_CHECK(vertex.attrib().hasPose())
168 << "Vertex on the route must have a pose!";
169
170 const semrel::ShapeID shapeId = addOrGetVertex(vertex.attrib());
171 routeShapeIds.push_back(shapeId);
172
173 // pedantic check
174 ARMARX_CHECK(graph.vertex(shapeId).attrib().hasPose())
175 << "Vertex pose must be set!";
176 }
177
179
180 // add all edges to the graph (between consecutive vertices)
181 for (size_t i = 0; i < route.size() - 1; i++)
182 {
183 graph.addEdge(routeShapeIds.at(i),
184 routeShapeIds.at(i + 1),
185 core::Graph::EdgeAttrib{
186 .aron = ARON_UNSET_EDGE_VALUES,
187 .strategy = client::GlobalPlanningStrategy::Point2Point,
188 .trajectory = std::nullopt});
189 }
190
192 // connect `vertex` an this path
193 graph.addEdge(graph.vertex(vertex).objectID(),
194 routeShapeIds.front(),
195 core::Graph::EdgeAttrib{.aron = ARON_UNSET_EDGE_VALUES,
196 .strategy = strategy,
197 .trajectory = std::nullopt});
198 }
199 }
200
201 // By definition, all routes share the same final vertex, which is the new active vertex ...
202 const auto targetDescriptor = routes.front().back().descriptor();
203 // ... this is ensured by the following check ...
204 ARMARX_CHECK(std::none_of(routes.begin(),
205 routes.end(),
206 [&targetDescriptor](const auto& route) -> bool
207 { return route.back().descriptor() != targetDescriptor; }));
208
209 // ... and will be the new active vertex.
210 const std::optional<semrel::ShapeID> shapeId =
211 getVertexByAttributes(routes.front().back().attrib());
212 ARMARX_CHECK(shapeId.has_value()) << "Vertex exists. This should not have happened";
213
214
215 activeVertices_ = {shapeId.value()};
216 }
217
218 inline void
219 GraphBuilder::validate(auto&& vertices) const
220 {
222 std::for_each(vertices.begin(),
223 vertices.end(),
224 [](const core::Graph::ConstVertex& vertex)
225 {
226 // ARMARX_CHECK(graph.vertex(vertex.objectID()).attrib().hasPose())
227 // << "Check 1: Vertex " << QUOTED(vertex.attrib().getName())
228 // << " with ID " << vertex.attrib().objectID
229 // << " does not have pose attribute!";
230
231 ARMARX_CHECK(vertex.attrib().hasPose())
232 << "Check 2: Vertex " << QUOTED(vertex.attrib().getLocationName())
233 << " with ID " << vertex.attrib().objectID
234 << " does not have pose attribute!";
235 });
236 }
237
238 const core::Graph&
240 {
241 validate(graph.vertices());
242 return graph;
243 }
244
245 core::Graph::VertexDescriptor
247 {
248 ARMARX_CHECK(activeVertices_.size() == 1) << "There should be only one goal vertex.";
249 return activeVertices_.front();
250 }
251
254 {
255 return getGraph().vertex(goalVertex()).attrib().requireGlobal();
256 }
257
258 // void
259 // GraphBuilder::addEdge(const std::vector<core::Graph::VertexDescriptor>& sources,
260 // const std::vector<core::Graph::VertexDescriptor>& targets)
261 // {
262
263 // for (const core::Graph::VertexDescriptor& source : sources)
264 // {
265 // for (const core::Graph::VertexDescriptor& target : targets)
266 // {
267 // // connect source and target
268 // // FIXME implement graph.addEdge(source.)
269 // }
270 // }
271 // }
272} // namespace armarx::navigation::server
#define QUOTED(x)
The FramedPose class.
Definition FramedPose.h:281
void connect(const core::Pose &pose, const client::GlobalPlanningStrategy &strategy)
std::optional< core::Graph::ConstVertex > startVertex
const core::Graph & getGraph() const
void initialize(const core::Pose &pose)
core::Graph::VertexDescriptor goalVertex() const
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
std::string const GlobalFrame
Variable of the global coordinate system.
Definition FramedPose.h:65
Eigen::Isometry3f Pose
Definition basic_types.h:31
This file is part of ArmarX.
Definition Visu.h:48
This file is part of ArmarX.
bool operator==(const core::Graph::VertexAttrib &lhs, const core::Graph::VertexAttrib &rhs)
const core::arondto::Edge ARON_UNSET_EDGE_VALUES
void setPose(const FramedPose &pose)
Definition Graph.cpp:89
#define ARMARX_TRACE
Definition trace.h:77