Grasshopper

algorithmic modeling for Rhino

Hi.

 

I get a DataTree<Point3d> as input to my c# script, and I would like to copy this DataTree to a variable, in order to treat the points and aferwards compare them.

Because of the C# value and reference types (the Class DataTree being the latter), I cannot seem to be able to create a copy of my input class. Hence, all the changes I make affect both the original and "cloned" DataTree.

 

Example:

RunScript(DataTree<Point3d> originalPoints)
  {
    // clone
    DataTree<Point3d> copyTree = originalPoints;

 

    for(int i = 0; i < copyTree.BranchCount; i++)
      {

        //The path for this index
        GH_Path path = copyTree.Path(i);

        //The count of elements in this index
        int elementCount = copyTree.Branch(i).Count;

        if(elementCount > 0)
        {
          for(int k = 0; k < elementCount; k++)
          {
            // The k point in this path
            Point3d kPoint = copyTree[path, k];

            //change

            kPoint.X += 2;

            copyTree.Branch(path).RemoveAt(k);
            copyTree.Branch(path).Insert(k, kPoint);

           }

       }

}

 

Because the my copyTree only is a pointer to the originalPoints, a comparison afterwards shows all points to be the same.

 

Is there a DataTree constructor that clones itself, or a way to create a new Datatree and fill it with the values from the original?

 

Cheers, Peter

Views: 2216

Replies to This Discussion

Hi Peter,

 

not yet. I'll add one. In the meantime you'll have to iterate over all the paths and make a new DataTree with the same layout.

 

I just added two constructors for this:

 

Public Sub New(ByVal other As DataTree(Of T))

Public Sub New(ByVal other As DataTree(Of T), ByVal copyDelegate As DuplicateT)

Public Delegate Function DuplicateT(ByVal original As T) As T

 

This way you can create both shallow and true duplicates in case you have a DataTree with a Reference Type for T.

 

--

David Rutten

david@mcneel.com

Poprad, Slovakia

Thanks David.

 

Do you have the code in C# for using the constructors you added or to copy the ? .. Do I have to reference or download a new library in order to use the constructors you added?

 

Would this code work?

 

    DataTree<Point3d> copyTree = new DataTree<Point3d>();

    for(int i = 0; i < originalTree.BranchCount; i++)
      {

        //The path for this index
        GH_Path path = originalTree.Path(i);

        //The count of elements in this index
        int elementCount = originalTree.Branch(i).Count;

        if(elementCount > 0)
        {
          for(int k = 0; k < elementCount; k++)
          {
            // insert a new item to replicate original
           copyTree.Branch(path).Insert(k, originalTree [path, k]);

           }

       }

Or would it not work because the copyTree does not have a Path/Branches where I want to insert the duplicate?

 

Sorry, I can’t seem to find any documentation on the DataTree class, not here or on the Rhinocommon, so I am sort of lost.

 

..

 

Best, Peter.

Sorry, the new constructors won't be available until the next release. I'm not planning to release very soon as I'm overhauling some pretty widely used interface classes.

 

Since you're working with Point3d Value Types you can get away with the following:

 

DataTree<Point3d> dup = new DataTree<Point3d>();

for(int i = 0; i < originalTree.BranchCount; i++)
{
  GH_Path path = new GH_Path(originalTree.Path(i));
  List<Point3d> list = new List<Point3d>(originalTree.Branch(i));
  dup.AddRange(list, path)

}

 

If you're dealing with ReferenceTypes and you want to duplicate those as well, you'll need to add an extra loop to duplicate all items inside the list.

 

--

David Rutten

david@mcneel.com

Poprad, Slovakia

Thanks David,

 

it finally worked out for me. I`m getting close to finish the script and start with my design.

Thanks a lot for your help,

 

greetz Peter

Hi David,

did you implemented the new copy-constructor for Datatrees to the new Version 20110705b yet ? I got a new issue with that topic,

 

greetz Peter

 

Yup, they're in there.

 

Public Sub New(ByVal other As DataTree(Of T))

 

this constructor will make a shallow copy of another DataTree. If your T is a value type (Int32, Double, Boolean, Point3d, Plane) then you'll get a completely fresh DataTree. If your T is a reference type (Curve, Brep, Mesh) then the data will be shared amongst both trees.

 

If you want to duplicate a tree and duplicate the reference-type data inside, you need to use this constructor:

 

Public Sub New(ByVal other As DataTree(Of T), ByVal copyDelegate As DuplicateT)

 

I don't know how to duplicate a class instance, which is why you need to specify a function I can use to copy your T instances.

 

--

David Rutten

david@mcneel.com

Poprad, Slovakia

Hi David, thanks a lot.

 

the by-value constructor works excellent, however, I don't really understand the last syntax :ByVal copyDelegate As DuplicateT

 

Can you give me a explanation of that line?

 

The T in our case is a PlaneSurface.

 

cheers, Peter

PlaneSurface doesn't have a constructor that takes another PlaneSurface and copies that. It also doesn't have a Duplicate() function that returns a PlaneSurface.

 

Although I can work out for specific types (such as PlaneSurface or Curve) how to make an exact duplicate of the class, I cannot work this out in a way that works for all possible types that exist.

 

If you want to duplicate a DataTree(Of PlaneSurface), you'll need to write a function that duplicates/copies an existing PlaneSurface. This function needs to adhere to the DuplicateT delegate:

 

Public Delegate Function DuplicateT(ByVal original As T) As T

 

Or, in this particular case:

 

Public Function DuplicatePlaneSrf(ByVal original As PlaneSurface) As PlaneSurface

  If (original Is Nothing) Then Return Nothing

  Dim geo As GeometryBase = original.Duplicate()

  If (geo Is Nothing) Then Return Nothing

  Return TryCast(geo, PlaneSurface)

End Function

 

Once you have defined this function, you need to pass it to the constructor, like so:

 

Dim dupTree As New DataTree(Of PlaneSurface)(oldTree, AddressOf DuplicatePlaneSrf)

 

The AddressOf keyword basically allows you to pass a method instead of a value to a function.

 

--

David Rutten

david@mcneel.com

Poprad, Slovakia

Hallo David,

 

thanks for your reply !

I think i got an idea how this constructor will work.

 

Due to the fact that your answer was in VB i tried something like that:

 

additional code:

 

public delegate PlaneSurface DuplicateT(PlaneSurface original);

  public PlaneSurface DuplicatePlaneSrf(PlaneSurface original)
  {
    if(original == null)
      return null;

    Rhino.Geometry.GeometryBase geo = original.Duplicate();

    if(geo == null)
      return null;

    return geo as PlaneSurface;
  }

 

main code:

 

...

DuplicateT delegateDup = DuplicatePlaneSrf;

DataTree < PlaneSurface > allSurfacesDup = new DataTree(allSurfaces, delegateDup);

...

 

I still get the error that the argument delegateDup is wrong.

Is it the right way for C# to construct a delegate when i want to use this duplictate constructor.

 

best wishes, greetings Peter!

 

Hi Peter,

 

this is a C# example of a component that creates a deep copy of a DataTree of Curves object, and then modifies both the original and the copy in two different ways to see the difference.

I hope it helps,

 

- Giulio
____________
giulio@mcneel.com
McNeel Europe

Attachments:

Hi Giulio,


thank you for your reply. I did try the same way but for some reason it did not work.


I will try sometime to edit your code and make it work for the PlaneSurface type.


For rightnow i worked out my own duplicate DataTree function:


additional Code:


public PlaneSurface DuplicatePlaneSurface(PlaneSurface original)
  {
    if(original == null)
      return null;

    Rhino.Geometry.GeometryBase geo = original.Duplicate();

    if(geo == null)
      return null;

    return geo as PlaneSurface;
  }

  private DataTree<PlaneSurface> duplicateDataTree(DataTree < PlaneSurface > originalTree)
  {
    DataTree<PlaneSurface> dupTree = new DataTree<PlaneSurface>();

    for(int i = 0; i < originalTree.BranchCount; i++)
    {
      GH_Path newpath = new GH_Path(originalTree.Path(i));

      for(int k = 0; k < originalTree.Branch(newpath).Count; k++)
      {
        PlaneSurface originalElement = originalTree[newpath, k];

        PlaneSurface dupElement = DuplicatePlaneSurface(originalElement);

        dupTree.Insert(dupElement, newpath, k);
      }
    }
    return dupTree;
  }



Main Code:

...


theDuplicatedTree= duplicateDataTree(original);


...




I assume that this is quiete simillar of what the constructor will do.


I have no a programmer - background that why i have sometimes leaks of a basic ken


Anyway thank your for reply and your efforts to make it work,


greetz Peter

 

PS: i attached a file where i made that code work, and what i have tried so far to make the constructor work; and i attached a file with the entiere script and a corresponding rhinofile.

Attachments:
Hello again Peter,

this is your file, with some small modifications to make it work.
The biggest issue was... a missing "<PlaneSurface>"!

You were close,

- Giulio
_____________
giulio@mcneel.com
McNeel Europe
Attachments:

RSS

About

Translate

Search

Photos

  • Add Photos
  • View All

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service