| 206 | } |
| 207 | |
| 208 | NodeAttributes::Ptr getMergedAttributes(const DynamicSceneGraph& graph, |
| 209 | const std::vector<NodeId>& nodes) { |
| 210 | if (nodes.empty()) { |
| 211 | return nullptr; |
| 212 | } |
| 213 | |
| 214 | auto iter = nodes.begin(); |
| 215 | CHECK(graph.hasNode(*iter)); |
| 216 | const auto& node = graph.getNode(*iter); |
| 217 | ++iter; |
| 218 | |
| 219 | auto attrs_ptr = node.attributes().clone(); |
| 220 | auto& attrs = *CHECK_NOTNULL(dynamic_cast<KhronosObjectAttributes*>(attrs_ptr.get())); |
| 221 | attrs.semantic_feature = attrs.semantic_feature.rowwise().mean().eval(); |
| 222 | |
| 223 | while (iter != nodes.end()) { |
| 224 | const auto& other = graph.getNode(*iter); |
| 225 | const auto& other_attrs = other.attributes<KhronosObjectAttributes>(); |
| 226 | attrs.position += other_attrs.position; |
| 227 | attrs.semantic_feature += other_attrs.semantic_feature.rowwise().mean(); |
| 228 | // TODO(nathan) update khronos to add the attribute merging somewhere convenient |
| 229 | mergeObjectAttributes(other_attrs, attrs); |
| 230 | ++iter; |
| 231 | } |
| 232 | |
| 233 | attrs.position /= nodes.size(); |
| 234 | attrs.semantic_feature /= nodes.size(); |
| 235 | return attrs_ptr; |
| 236 | } |
| 237 | |
| 238 | std::optional<std::pair<NodeId, bool>> getBestParent(const DynamicSceneGraph& graph, |
| 239 | const std::vector<NodeId>& nodes) { |
no test coverage detected