Extracting the layer table from an external Rhino file


(Paul Poinet) #1

Hi all,

I am retrieving an external 3dm file in Grasshopper (using c#).
I would like to access the layer table, with its nested information.

So far, I only managed to extract the layers as an IList.

This function seems limited since it is not possible to access the FullPath of each layer (the layers are defined here only by their name). Even by looping through those and calling the FullPath property, it only returns the name.
Then I tried to call the GetChildren() function and it returns an error.

Is there an alternative way to achieve what I try to do, or is the nested information lost if one attempts to read the layers from an external rhino file?


(Menno Deij - van Rijswijk) #2

The code below seems to work here:

string fn = RhinoGet.GetFileName(GetFileNameMode.Open, "file.3dm", "Open 3dm", RhinoApp.MainWindow());

using (var f = File3dm.Read(fn))
{
    // make a lookup dictionary for guid-to-layer lookup
    IDictionary<Guid, Layer> layers = f.Layers.ToDictionary(l => l.Id, l => l);

    for (int i = 0; i < f.Layers.Count; i++)
    {
        Layer l = f.Layers[i];
        // make a list of the parents
        List<Layer> parents = new List<Layer>();
        parents.Add(l);
        while (l.ParentLayerId != Guid.Empty)
        {
            var parent = layers[l.ParentLayerId];
            parents.Add(parent);
            l = parent;
        }

        RhinoApp.WriteLine(String.Join("::", parents.Select(ln => ln.Name)));
    }
}

This outputs the following:

Default
Layer 01
Layer 02::Layer 01
Layer 03::Layer 02::Layer 01
Layer 04::Layer 03::Layer 02::Layer 01

for the following layer structure


(Paul Poinet) #3

Thanks menno for your answer!
It is helpful but to a certain extent. Unfortunately the outputs are strings, and not layers, where I can’t operate any methods from rhino common. I will try to see if I can set new FullPaths to the layers based on those strings, but I doubt that this will work :confused:

If any mcNeel person comes across this thread, I think it would be great to integrate in Rhino6 the full access to the layer table from an external file, since it is possible to already access the object table.


(Dale Fugier) #4

See this in Menno’s source code:

    for (int i = 0; i < f.Layers.Count; i++)
    {
        Layer l = f.Layers[i];

(Paul Poinet) #5

But those layers don’t contain the nested information (or hierarchy). What menno is doing is nice and hacky but superficial because it is impossible to run any Layer Method onto either the f.Layers or the output string.
GetChildren() do not work anywhere here…


(Dale Fugier) #6

Hi Paul,

This is true because, Rhino’s layer table is a flag array of layer objects. The only think that makes layer hierarchical is the fact that they know of their parent layer. Root layers, of course, do not have a parent.[quote=“PaulPoinet, post:5, topic:44352”]

GetChildren() do not work anywhere here…
[/quote]

The code behind layer.GetChildren resides in Rhino, not RhinoCommon. Thus it does not work in the standalone RhinoCommon. But you should be able to code up an equivalent function - just look for layers with the same parent id.

– Dale


(Paul Poinet) #7

Hi Dale,

So you mean that GetChildren() relies on the active doc (i.e. Rhino)? So there is no way to import the “complete” LayerTable with hierarchy from an external file? Basically I got quite a bit of code that relies on a bunch of methods from the LayerClass, and after reading your last explanation it seems I will have to rewrite a lot of it just to make things work, looking at an external file. It’s fine anyway, but before diving into that i just wanted to make sure if there was really no way to do all these things “as usual”.


(Dale Fugier) #8

You have complete access to an array of Layer objects from an external file. The LayerTable object is provided by a Rhino document, which is something you only get when you open a document with Rhino.

– Dale


(Paul Poinet) #9

ok, thank you for the explanations


(Radovan Grmusa) #10

Hi Paul

Here is short code that creates hierarchical representation of Layers (LayerTree).
To create LayerTree call static method LayerNode.CreateLayerTree(doc), to print out layers(names) call static method WriteLayerTree(0, layerTree).
One Warning - there is no control in code if layer is deleted or not.

//creation of LayerTree
var layerTree = LayerNode.CreateLayerTree(doc);

//usage of LayerTree
LayerNode.WriteLayerTree(0, layerTree)

public class LayerNode
{
    public Layer LayerX { get; private set; }
    public IEnumerable<LayerNode> ChildNodes { get; private set; }

    private LayerNode(Layer layer, IEnumerable<LayerNode> layerNodes)
    {
        LayerX = layer;
        ChildNodes = layerNodes;
    }

    public static IEnumerable<LayerNode> CreateChildNodes(Guid parentLayerID, ILookup<Guid, Layer> LookupSource)
    {
        var LayerNodes = from L in LookupSource[parentLayerID]
                  select new LayerNode(L, CreateChildNodes(L.Id, LookupSource));
        return LayerNodes;
    }

    public static IEnumerable<LayerNode> CreateLayerTree(RhinoDoc doc)
    {
        var layersLookup = doc.Layers.ToLookup(layer => layer.ParentLayerId);
        var LayerTree = LayerNode.CreateChildNodes(Guid.Empty, layersLookup);
        return LayerTree;
    }

    public static void WriteLayerTree(int depth, IEnumerable<LayerNode> LayerTree)
    {
        if (LayerTree.Count() < 1)
        {
            return;
        }
        depth++;
        string tab = new string('>', depth - 1);
        foreach (var item in LayerTree)
        {
            RhinoApp.WriteLine(tab + "{0}", item.LayerX.Name);
            WriteLayerTree(depth, item.ChildNodes);
        }
    }

}

Regards
Radovan