Ok, so for those who would like to do the same thing, here is how I eventually managed. This code looks definately not optimal and it’s not bulletproof but it worked for my specific needs.
First, I created some extensions methods for GH_Path, in a separate class :
public static class GH_PathExtension
{
/// Compare two paths, returns true if the initial path is an immediate child of the parent path (like {0,1,42} being a child of {0,1})
public static bool IsImmediateChild(this GH_Path path, GH_Path parentPath)
{
if(path == null) { return false; }
int generation = 0;
if (!path.IsAncestor(parentPath, ref generation)) { return false; }
if (generation == 1) { return true; }
return false;
}
/// Count the number of ancestors (distance to top node) for a given path into a GH_Structure
public static int NumberOfAncestors<T>(this GH_Path path, GH_Structure<T> structure) where T:IGH_Goo
{
if(structure == null || structure.DataCount == 0) { return 0; }
int i = 0;
foreach(GH_Path structPth in structure.Paths)
{
int j = -1;
if(path.IsAncestor(structPth, ref j)){ i += 1; }
}
return i;
}
}
Then, I created a node that we are going to use into a tree :
public class PathNode
{
public GH_Path Path { get; set; }
public List<PathNode> Children { get; set; }
public PathNode(GH_Path path)
{
Path = path;
Children = new List<PathNode>();
}
/// <summary>
/// Go through the tree and add a new path-node as a child of the correct parent node
/// </summary>
/// <param name="root">root node</param>
/// <param name="path">path to add as a node</param>
/// <returns>true if succesfuly added, false otherwise</returns>
public static bool TraverseAndAdd(PathNode root, GH_Path path)
{
if (path.IsImmediateChild(root.Path))
{
root.Children.Add(new PathNode(path));
return true;
}
else
{
foreach (PathNode child in root.Children)
{
if (TraverseAndAdd(child, path)) { return true; }
}
}
return false;
}
}
At last, you can build the path tree out of any GH_Structure. Keep in mind that we only defined a method for adding nodes as children of existing nodes, never as parents. Therefore, the initial path list should be ordered in a way that ‘parent’ nodes are always inserted into the tree before children. I did that by ordering the list by the ‘number of ancestors’ : paths with the least ancestors go first. I am not sure this will work all the time.
/// Build a path tree from a given GH_Structure.
public static List<PathNode> BuildPathTree<T>(GH_Structure<T> structure) where T:IGH_Goo
{
List<PathNode> root = new List<PathNode>();
foreach (GH_Path path in structure.Paths.OrderBy(x => x.NumberOfAncestors(structure)).ToList()) // order paths by the number of ancestors
{
if (path.NumberOfAncestors(structure) == 0) { root.Add(new PathNode(path)); }
else
{
bool found = false;
foreach(PathNode rootNode in root)
{
if (PathNode.TraverseAndAdd(rootNode, path)){
found = true;
break; }
}
if (!found) { throw new Exception("Something went wrong, you shoudn't have a node with an ancestor with no parent node already in the tree."); }
}
}
return root;
}
Then, you can easily use this ‘PathNode’ Tree to get paths in a logical top-down order --> paths with no parents first, then their childs, then their grand childs, and so on.
Hope this helps 