DHART
Loading...
Searching...
No Matches
graph.h
Go to the documentation of this file.
1
8#pragma once
9
10#include <robin_hood.h>
11#include <vector>
12#include <Edge.h>
13#include <Node.h>
14#include <Eigen>
15#include <iostream>
16
17namespace Eigen {
18}
19
20namespace HF::SpatialStructures {
21 using EdgeMatrix = Eigen::SparseMatrix<float, 1>;
22 using TempMatrix = Eigen::Map<const EdgeMatrix>;
23
28 enum class COST_AGGREGATE : int {
30 SUM = 0,
32 AVERAGE = 1,
34 COUNT = 2
35 };
36
39 enum class Direction : int {
40 INCOMING = 0, //< Use the child node's attribute for the cost.
41 OUTGOING = 1, //< Use the parent node's attribute as the cost.
42 BOTH = 2 //< Add the parent and child's attributes for the cost.
43 };
44
45
54 struct CSRPtrs {
55 int nnz;
56 int rows;
57 int cols;
58
59 float* data;
62
69
93 inline bool AreValid() {
94 return (data && outer_indices && inner_indices);
95 }
96
103
105
111 inline float* CSRPtrs::data_begin() const {
112 return data ? data : nullptr;
113 }
114
121
122 // If the data field has not been given an address, and/or the nnz field has not been given
123 // a value, data_end will return nullptr.
124
130 inline float* CSRPtrs::data_end() const {
131 if (nnz > 0) {
132 return data ? data + nnz : nullptr;
133 }
134
135 return nullptr;
136 }
137
144
145 // If the inner_indices field has not been given an address, inner_begin will return nullptr.
146
153 inline int* CSRPtrs::inner_begin() const {
154 return inner_indices ? inner_indices : nullptr;
155 }
156
163
174 inline int* CSRPtrs::inner_end() const {
175 if (nnz > 0) {
176 return inner_indices ? inner_indices + nnz : nullptr;
177 }
178
179 return nullptr;
180 }
181
188
189 // If the outer_indices field has not been given an address, outer_begin will return nullptr.
190
196 inline int* CSRPtrs::outer_begin() const {
197 return outer_indices ? outer_indices : nullptr;
198 }
199
206
207 // If the outer_end field has not been given an address, and/or the rows field has not been
208 // given a value, outer_end will return nullptr.
209
215 inline int* CSRPtrs::outer_end() const {
216 if (rows > 0) {
217 return outer_indices ? outer_indices + rows : nullptr;
218 }
219
220 return nullptr;
221 }
222
232
233 // If the data field has not been given an address, or the rows field has not been given a
234 // value, or row_number >= rows, row_begin will return nullptr.
235
241 inline float* CSRPtrs::row_begin(int row_number) const {
242 float* begin = nullptr;
243
244 if (data && rows > 0) {
245 if (row_number >= 0 && row_number < rows) {
246 begin = data + outer_indices[row_number];
247 }
248 }
249
250 return begin;
251 }
252
265
266 // If the data field has not been given an address, or the rows field has not been given a
267 // value, or row_number >= rows, row_end will return nullptr.
268
274 inline float* CSRPtrs::row_end(int row_number) const {
275 float* end = nullptr;
276 const int next_row = row_number + 1;
277
278 if (data && rows > 0) {
279 if (next_row > 0 && next_row < rows) {
280 end = data + outer_indices[next_row];
281 }
282 else if (next_row > 0 && next_row == rows) {
283 end = data_end();
284 }
285 }
286
287 return end;
288 }
289
302
303 // If the inner_indices and/or outer_indices field have not been given addresses, or
304 // row_number >= rows, col_begin will return nullptr.
305
312 inline int* CSRPtrs::col_begin(int row_number) const {
313 int* begin = nullptr;
314
316 if (row_number >= 0 && row_number < rows) {
317 begin = inner_indices + outer_indices[row_number];
318 }
319 }
320
321 return begin;
322 }
323
335
336 // If the inner_indices and/or outer_indices field have not been given addresses, or
337 // row_number >= rows, col_end will return nullptr.
338
344 inline int* CSRPtrs::col_end(int row_number) const {
345 int* end = nullptr;
346 const int next_row = row_number + 1;
347
349 if (next_row > 0 && next_row < rows) {
350 end = inner_indices + outer_indices[next_row];
351 }
352 else if (next_row > 0 && next_row == rows) {
353 end = inner_end();
354 }
355 }
356 return end;
357 }
358 };
359
364 struct Subgraph {
366 std::vector<Edge> m_edges;
367 };
368
376 private:
377 std::vector<float> costs;
378
379 public:
381 EdgeCostSet() { this->costs.resize(0); };
382
388 inline EdgeCostSet(int size) { this->ResizeIfNeeded(size); }
389
394 inline int size() const { return this->costs.size(); };
395
403 inline void ResizeIfNeeded(int new_size) {
404 const int old_size = this->size();
405 if (this->size() < new_size)
406 {
407 // resize the cost array
408 this->costs.resize(new_size);
409
410 // fill new values with NAN
411 const auto start_offset = costs.begin() + old_size;
412 std::fill(start_offset, costs.end(), NAN);
413 }
414 };
415
417 inline void Clear() { this->costs.clear(); }
418
424 inline float& operator[](int i) {
425 assert(this->bounds_check(i));
426 return this->costs[i];
427 }
428
429 inline bool bounds_check(int i) const {
430 return !(i >= this->size()) || (i < 0);
431 }
432
438 inline float operator[](int i) const {
439 assert(this->bounds_check(i));
440 return this->costs[i];
441 }
442
448 inline float* GetPtr() {
449 assert(this->costs.size() > 0);
450 return this->costs.data();
451 }
452
458 inline const float* GetPtr() const {
459 assert(this->costs.size() > 0);
460 return this->costs.data();
461 }
462
463 };
464
486 class Graph {
487 using NodeAttributeValueMap = robin_hood::unordered_map<int, std::string>;
488
489 private:
490 int next_id = 0;
491 std::vector<Node> ordered_nodes;
492
493 //robin_hood::unordered_map<int, int> id_to_ordered_node; ///< Maps ids to indexes in ordered_nodes.
494 robin_hood::unordered_map<Node, int> idmap;
495
496 std::vector<Eigen::Triplet<float>> triplets;
497 bool needs_compression = true;
498
499 robin_hood::unordered_map<std::string, NodeAttributeValueMap> node_attr_map;
500
501 std::string active_cost_type;
503
504 std::string default_cost = "Distance";
505 std::unordered_map<std::string, EdgeCostSet> edge_cost_maps;
506
513 bool has_cost_arrays = false;
514
522 bool nodes_out_of_order = false;
523
541 int getOrAssignID(const Node & input_node);
542
555 int getOrAssignID(int input_int);
556
570 bool checkForEdge(int parent, int child) const;
571
589 void CSRAddOrUpdateEdge(int parent_id, int child_id, float cost);
590
599 void TripletsAddOrUpdateEdge(int parent_id, int child_id, float cost);
600
612
623 bool hasKey(int id) const;
624
634 bool HasCostArray(const std::string & key) const;
635
650 EdgeCostSet& GetCostArray(const std::string& key);
651
661 EdgeCostSet& GetOrCreateCostType(const std::string& name);
662
672 EdgeCostSet& CreateCostArray(const std::string& name);
673
686 const EdgeCostSet& GetCostArray(const std::string& key) const;
687
701 bool IsDefaultName(const std::string& name) const;
702
725 int FindValueArrayIndex(int parent_id, int child_id) const;
726
738 void InsertEdgeIntoCostSet(int parent_id, int child_id, float score, EdgeCostSet& cost_set);
739
748 void InsertEdgesIntoCostSet(EdgeCostSet& cost_set, const std::vector<EdgeSet>& es);
749
774 void InsertOrUpdateEdge(int parent_id, int child_id, float score, const std::string& cost_type);
775
790 float GetCostForSet(const EdgeCostSet& set, int parent_id, int child_id) const;
791
805 std::vector<Edge> GetEdgesForNode(
806 int parent_id,
807 bool undirected = false,
808 const std::string& cost_type = ""
809 ) const;
810
824 TempMatrix MapCostMatrix(const std::string& cost_type) const;
825
827 bool HasNodeAttribute(const std::string & key) const;
828
829 public:
880 const std::vector<std::vector<int>>& edges,
881 const std::vector<std::vector<float>>& distances,
882 const std::vector<Node>& Nodes,
883 const std::string& default_cost = "Distance"
884 );
885
902 Graph(const std::string& default_cost_name = "Distance");
903
943 const std::array<float, 3>& parent,
944 const std::array<float, 3>& child,
945 bool undirected = false
946 ) const;
947
983 const Node& parent,
984 const Node& child,
985 const bool undirected = false,
986 const std::string cost_type = ""
987 ) const;
988
989 /* \brief Determine if the graph has an edge from parent to child.
990
991 \param parent Parent of the edge to check for.
992 \param child Child of the edge to check for.
993 \param undirected If true, look for an edge from child to parent as well.
994 \returns True if an edge between parentand child exists
995 (also child and parent if undirected is true).
996
997 \exception std::exception if the graph is uncompressed.
998
999 \code
1000 // be sure to #include "graph.h"
1001
1002 // Create the nodes
1003 HF::SpatialStructures::Node node_0(1.0f, 1.0f, 2.0f);
1004 HF::SpatialStructures::Node node_1(2.0f, 3.0f, 4.0f, 5);
1005 HF::SpatialStructures::Node node_2(11.0f, 22.0f, 140.0f);
1006
1007 // Create a container (vector) of nodes
1008 std::vector<HF::SpatialStructures::Node> nodes = { node_0, node_1, node_2 };
1009
1010 // Create matrices for edges and distances, edges.size() == distances().size()
1011 std::vector<std::vector<int>> edges = { { 1, 2 }, { 2 }, { 1 } };
1012 std::vector<std::vector<float>> distances = { { 1.0f, 2.5f }, { 54.0f }, { 39.0f } };
1013
1014 // Now you can create a Graph - note that nodes, edges, and distances are passed by reference
1015 HF::SpatialStructures::Graph graph(edges, distances, nodes);
1016
1017 // last argument can be true/false for undirected/directed graph respectively
1018 bool has_edge = graph.HasEdge(0, 1, true);
1019 \endcode
1020 */
1021 bool HasEdge(int parent, int child, bool undirected = false, const std::string& cost_type = "") const;
1022
1029
1053 std::vector<Node> Nodes() const;
1054
1064
1100 std::vector<Edge> GetUndirectedEdges(const Node& N, const std::string& cost_type = "") const;
1101
1108
1145 std::vector<EdgeSet> GetEdges() const;
1146
1152 std::vector<IntEdge> GetIntEdges(int parent) const;
1153
1166
1204 std::vector<float> AggregateGraph(COST_AGGREGATE agg_type, bool directed = true, const std::string& cost_type = "") const;
1247 const std::vector<Edge> operator[](const Node& n) const;
1248
1261
1303 void addEdge(const Node& parent, const Node& child, float score = 1.0f, const std::string& cost_type = "");
1304
1317
1368 void addEdge(int parent_id, int child_id, float score, const std::string& cost_type = "");
1369
1379
1425 bool hasKey(const Node& n) const;
1426
1433
1471 std::vector<std::array<float, 3>> NodesAsFloat3() const;
1472
1479
1503 int size() const;
1504
1514 int MaxID() const;
1515
1522
1562 int getID(const Node& node) const;
1563
1610 void Compress();
1611
1621
1661 CSRPtrs GetCSRPointers(const std::string& cost_type = "");
1662
1672
1701 Node NodeFromID(int id) const;
1702
1706
1732 void Clear();
1733
1743
1749 std::vector<Node> GetChildren(const Node& n) const;
1750
1760
1766 std::vector<Node> GetChildren(const int parent_id) const;
1767
1777 Subgraph GetSubgraph(const Node& parent_node, const std::string& cost_type = "") const;
1778
1788 Subgraph GetSubgraph(int parent_id, const std::string & cost_type = "") const;
1789
1802
1808 void AddNodeAttribute(int id, const std::string & attribute, const std::string & score);
1809
1823
1832 void AddNodeAttributes(const std::vector<int> & id, const std::string & name, const std::vector<std::string> & scores);
1833
1844
1850 std::vector<std::string> GetNodeAttributes(std::string attribute) const;
1851
1858
1867 void ClearNodeAttributes(std::string name);
1868
1869 bool DumpToJson(const std::string & path);
1870
1889 void AddEdges(const EdgeSet& edges, const std::string& cost_name = "");
1890
1892 void AddEdges(const std::vector<EdgeSet>& edges, const std::string& cost_name = "");
1893
1901 std::vector<EdgeSet> GetEdges(const std::string& cost_name) const;
1902
1908 std::vector<std::string> GetCostTypes() const;
1909
1924 float GetCost(int parent_id, int child_id, const std::string& cost_type = "") const;
1925
1943 void Graph::AddEdges(const std::vector<std::vector<IntEdge>>& edges, const std::string& cost_type);
1944
1955 void ClearCostArrays(const std::string & cost_name = "");
1956
1972 const std::string & node_attribute,
1973 const std::string & cost_to_store_as,
1974 Direction consider = Direction::INCOMING);
1975
1976 };
1977}
Contains definitions for the Edge structure.
Contains definitions for the Node structure.
Contains standard fundamental data structures for representing space used throughout DHARTAPI.
A Subgraph consists of a parent Node m_parent and a container of Edge m_edges such that all Edge in m...
Definition: graph.h:364
Node m_parent
The parent node from which all Edge in m_edges extend.
Definition: graph.h:365
Eigen::SparseMatrix< float, 1 > EdgeMatrix
The type of matrix the graph uses internally.
Definition: graph.h:21
COST_AGGREGATE
Methods of aggregating the costs for edges for each node in the graph.
Definition: graph.h:28
@ AVERAGE
Average the cost of all edges.
@ COUNT
Count how many edges this node has.
@ SUM
Add the cost of all edges.
Eigen::Map< const EdgeMatrix > TempMatrix
A mapped matrix of EdgeMatrix. Only owns pointers to memory.
Definition: graph.h:22
std::vector< Edge > m_edges
The edges that extend from m_parent.
Definition: graph.h:366
Direction
Node to use for calculating the cost of an edge when converting node attributes to edge costs.
Definition: graph.h:39
Eigen a C++ template library for linear algebra: matrices, vectors, numerical solvers,...
Definition: objloader.h:30
A collection of edges and a parent.
Definition: Edge.h:77
A struct to hold all necessary information for a CSR.
Definition: graph.h:54
int * CSRPtrs::col_end(int row_number) const
Returns the address of the element that denotes the end of a 'subarray' within inner_indices
Definition: graph.h:344
float * CSRPtrs::row_begin(int row_number) const
Returns the address of the first non-zero element of row_number within the CSR data buffer
Definition: graph.h:241
int * CSRPtrs::col_begin(int row_number) const
Returns the address of the element that determines the column where the first non-zero value begins w...
Definition: graph.h:312
int * CSRPtrs::inner_end() const
Returns the address of one-past the last element within the inner_indices buffer
Definition: graph.h:174
int * CSRPtrs::inner_begin() const
Returns the address of one-past the last element within the data buffer
Definition: graph.h:153
float * CSRPtrs::data_begin() const
Returns the base address of the data buffer
Definition: graph.h:111
bool AreValid()
Verify the CSR referenced by this instance is valid.
Definition: graph.h:93
int * outer_indices
Stores for each column (resp. row) the index of the first non-zero in the previous two arrays.
Definition: graph.h:60
int cols
Number of columns in this CSR.
Definition: graph.h:57
int nnz
Number of non-zeros contained by the CSR.
Definition: graph.h:55
int * inner_indices
Stores the row (resp. column) indices of the non-zeros.
Definition: graph.h:61
int * CSRPtrs::outer_end() const
Returns the address of one-past the last element within the outer_indices buffer
Definition: graph.h:215
float * data
Stores the coefficient values of the non-zeros.
Definition: graph.h:59
int rows
Number of rows in this CSR.
Definition: graph.h:56
float * CSRPtrs::row_end(int row_number) const
Returns the address of the first non-zero element of row_number + 1, i.e. the base address of the nex...
Definition: graph.h:274
int * CSRPtrs::outer_begin() const
Returns the base address of the outer_indices buffer
Definition: graph.h:196
A set of edge costs for a graph.
Definition: graph.h:375
std::vector< float > costs
Array of costs to be used like eigen's internal indices array.
Definition: graph.h:377
float * GetPtr()
Get the pointer to the start of this array.
Definition: graph.h:448
void ResizeIfNeeded(int new_size)
Resize this edge matrix if needed.
Definition: graph.h:403
EdgeCostSet(int size)
Create an edge cost set and allocate a specific size.
Definition: graph.h:388
float & operator[](int i)
Index internal values array.
Definition: graph.h:424
float operator[](int i) const
Index internal values array.
Definition: graph.h:438
void Clear()
Clear all values from this edge cost set.
Definition: graph.h:417
bool bounds_check(int i) const
Definition: graph.h:429
EdgeCostSet()
Construct an empty edge cost set.
Definition: graph.h:381
int size() const
Get the size of this edge matrix.
Definition: graph.h:394
const float * GetPtr() const
Get the pointer to the start of this array.
Definition: graph.h:458
A Graph of nodes connected by edges that supports both integers and HF::SpatialStructures::Node.
Definition: graph.h:486
void InsertEdgesIntoCostSet(EdgeCostSet &cost_set, const std::vector< EdgeSet > &es)
Insert edges for a specific cost type into a cost set.
void ClearNodeAttributes(std::string name)
Clears the attribute at name and all of its contents from the internal hashmap
void addEdge(int parent_id, int child_id, float score, const std::string &cost_type="")
Add a new edge to the graph from parent to child.
bool DumpToJson(const std::string &path)
EdgeMatrix edge_matrix
The underlying CSR containing edge information.
Definition: graph.h:502
float GetCostForSet(const EdgeCostSet &set, int parent_id, int child_id) const
Get the cost of traversing the edge between parent and child using set.
int getOrAssignID(int input_int)
Add an ID to the graph if it doesn't exist already.
void ResizeIfNeeded()
Resize the CSR to fit all the nodes in ordered_nodes if needed.
void InsertOrUpdateEdge(int parent_id, int child_id, float score, const std::string &cost_type)
Insert an edge into the default cost array or a new cost array.
std::vector< EdgeSet > GetEdges() const
Get every in the given graph as IDs.
void TripletsAddOrUpdateEdge(int parent_id, int child_id, float cost)
Add a new edge to the triplets list.
bool IsDefaultName(const std::string &name) const
Check if this name belongs to the default graph.
bool needs_compression
If true, the CSR is inaccurate and requires compression.
Definition: graph.h:497
std::vector< Eigen::Triplet< float > > triplets
Edges to be converted to a CSR when Graph::Compress() is called.
Definition: graph.h:496
Graph(const std::string &default_cost_name="Distance")
Construct an empty graph.
int size() const
Determine how many nodes are in the graph.
float GetCost(int parent_id, int child_id, const std::string &cost_type="") const
get the cost from parent_id to child_id in the given cost_type.
void AddNodeAttributes(const std::vector< int > &id, const std::string &name, const std::vector< std::string > &scores)
Add an attribute to the node at id. If the node at id already has a score for the attribute at name,...
void addEdge(const Node &parent, const Node &child, float score=1.0f, const std::string &cost_type="")
Add a new edge to the graph from parent to child.
TempMatrix MapCostMatrix(const std::string &cost_type) const
Construct a temp matrix for the specific cost type.
void Compress()
Compress the graph to a CSR and enable the usage of several functions.
bool HasCostArray(const std::string &key) const
Check if we have this edge matrix already defined.
bool HasNodeAttribute(const std::string &key) const
Check if this graph has a specific node attribute.
bool nodes_out_of_order
Determines whether or not the graph is using integer nodes.
Definition: graph.h:522
std::vector< float > AggregateGraph(COST_AGGREGATE agg_type, bool directed=true, const std::string &cost_type="") const
Summarize the costs of every outgoing edge for every node in the graph.
robin_hood::unordered_map< Node, int > idmap
Maps a list of X,Y,Z positions to positions in ordered_nodes.
Definition: graph.h:494
std::unordered_map< std::string, EdgeCostSet > edge_cost_maps
< The default cost type of the graph.
Definition: graph.h:505
bool hasKey(const Node &n) const
Determine if n exists in the graph.
void AddEdges(const std::vector< EdgeSet > &edges, const std::string &cost_name="")
Add an array of edges to the graph.
std::vector< Node > GetChildren(const int parent_id) const
Retrieve node parent_id's child nodes
int MaxID() const
Calculate the maximum ID of any node in the graph.
void AddEdges(const EdgeSet &edges, const std::string &cost_name="")
Add multiple edges to the graph.
Graph(const std::vector< std::vector< int > > &edges, const std::vector< std::vector< float > > &distances, const std::vector< Node > &Nodes, const std::string &default_cost="Distance")
Construct a graph from a list of nodes, edges, and distances.
std::string active_cost_type
The active edge matrix to use for the graph.
Definition: graph.h:501
Node NodeFromID(int id) const
Retrieve the node that corresponds to id.
const std::vector< Edge > operator[](const Node &n) const
CSRPtrs GetCSRPointers(const std::string &cost_type="")
Obtain the size of and pointers to the 3 arrays that comprise this graph's CSR. graph if it isn't com...
void AddNodeAttribute(int id, const std::string &attribute, const std::string &score)
Add an attribute to the node at id
EdgeCostSet & GetOrCreateCostType(const std::string &name)
Get a reference to the edge matrix, or create a new one if it doesn't exist.
std::vector< std::string > GetCostTypes() const
Get an array of all cost names within this graph.
Subgraph GetSubgraph(const Node &parent_node, const std::string &cost_type="") const
Retrieves a Subgraph using a Node.
bool HasEdge(int parent, int child, bool undirected=false, const std::string &cost_type="") const
void ClearCostArrays(const std::string &cost_name="")
Clear one or more cost arrays from the graph.
bool checkForEdge(int parent, int child) const
Determine if an edge between parent and child exists in the graph.
Subgraph GetSubgraph(int parent_id, const std::string &cost_type="") const
Retrieves a Subgraph using a parent node ID.
void Clear()
Clear all nodes and edges from the graph.
bool has_cost_arrays
Indicates that the graph has cost arrays.
Definition: graph.h:513
std::vector< Edge > GetEdgesForNode(int parent_id, bool undirected=false, const std::string &cost_type="") const
Get the edges for the given node.
std::vector< Node > Nodes() const
Get a list of nodes from the graph sorted by ID.
int FindValueArrayIndex(int parent_id, int child_id) const
Get the index of the cost at parent/child.
int next_id
The id for the next unique node.
Definition: graph.h:490
bool HasEdge(const Node &parent, const Node &child, const bool undirected=false, const std::string cost_type="") const
Determine if the graph has an edge from parent to child.
void CSRAddOrUpdateEdge(int parent_id, int child_id, float cost)
Add a new edge cost to the CSR or update if if a cost already exists.
std::string default_cost
Definition: graph.h:504
EdgeCostSet & CreateCostArray(const std::string &name)
Create a new edge matrix.
EdgeCostSet & GetCostArray(const std::string &key)
Get a reference to the edge matrix at the given key.
std::vector< Edge > GetUndirectedEdges(const Node &N, const std::string &cost_type="") const
Get a list of all edges to and from node N.
void AttrToCost(const std::string &node_attribute, const std::string &cost_to_store_as, Direction consider=Direction::INCOMING)
Generate edge costs from a set of node attributes.
robin_hood::unordered_map< int, std::string > NodeAttributeValueMap
Definition: graph.h:487
std::vector< EdgeSet > GetEdges(const std::string &cost_name) const
Get the edges of a specfic cost type.
std::vector< IntEdge > GetIntEdges(int parent) const
Get children of a specific node as integers.
std::vector< Node > ordered_nodes
A list of nodes contained by the graph.
Definition: graph.h:491
void InsertEdgeIntoCostSet(int parent_id, int child_id, float score, EdgeCostSet &cost_set)
Add an edge to a cost set between parent_id and child_id.
std::vector< Node > GetChildren(const Node &n) const
Retrieve n's child nodes - n is a parent node
std::vector< std::string > GetNodeAttributes(std::string attribute) const
Get the score for the given attribute of every node in the graph. Nodes that do not have a score for ...
std::vector< std::array< float, 3 > > NodesAsFloat3() const
Get a list of nodes as float arrays.
robin_hood::unordered_map< std::string, NodeAttributeValueMap > node_attr_map
Node attribute type : Map of node id to node attribute.
Definition: graph.h:499
bool HasEdge(const std::array< float, 3 > &parent, const std::array< float, 3 > &child, bool undirected=false) const
Determine if the graph has an edge from parent to child.
int getID(const Node &node) const
Retrieve the ID for node in this graph.
const EdgeCostSet & GetCostArray(const std::string &key) const
Get a reference to the edge matrix at the given key.
bool hasKey(int id) const
Check if this ID has already been assigned.
int getOrAssignID(const Node &input_node)
Get the unique ID for this x, y, z position and assign it an new one if it doesn't already exist.
A point in space with an ID.
Definition: node.h:38