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
Tags:
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
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.
Welcome to
Grasshopper
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
© 2024 Created by Scott Davidson. Powered by