Node Cloning

I noticed that Node includes duplicateNode(), but not cloneNode() or cloneTree(). Now, the javadocs for Node.duplicateNode read:

But clearly the cloneTree and cloneNode methods don’t exist in Node. As I recall from Java3D, the correct behavior was for the user to call cloneTree(), which would in turn call cloneNode() on the current node and cloneTree() on all children nodes. According to the Java3D API docs, duplicateNode() is called by cloneNode(), cloneNode() is called by cloneTree(), and users should only ever call cloneTree() directly.

Was an intentional diversion from this method made in Xith3D, are these methods simply not yet completed, or was this just overlooked?

Paul

approaching it from a different perspective - what is your requirement?

Will the Node.sharedCopy method suffice?

E.g., if you have a TransformGroup to duplicate - this may be suitable:
TransformGroup copy = (TransformGroup) meshTG.sharedCopy();

Search the forum for “sharedCopy” if you want more info.

Note: Make sure you have Xith3D from CVS, the Node class was very recently updated.

Will.

I suspect that duplicateNode() would not suffice, as per the javadoc:

What I am duplicating is an animated model, in which the geometry is modified by the child animation nodes thorughout its life. Therefore, when I duplicate it, I will need a true deep copy, otherwise multiple copies of the model that happen to be at different points in the animation (or worse yet, have different animations set) would cause the geometries of all models to get quite screwed up.

It strikes me that if duplicateNode() was included, the intention was to include the cloning methods as well, as they are mentioned right in the javadoc. I’d really like to know from one of the developers if this is simply a case of not-yet-implemented, or if something else is going on here. It seems to me that the hard work (duplicateNode()) is done, and it’s just a matter of writing the correct wrappers, ie:


public Node cloneNode(boolean forceDuplicate) {
  Node node = new Node();
  node.duplicateNode(this, forceDuplicate);
  return node;
}

public Node cloneTree(boolean forceDuplicate) {
  Node node = cloneNode(forceDuplicate);
  if ((this instanceof Group) && (node instanceof Group)) {
    Group group = (Group)this;
    for (int i=0;i<group.numChildren();i++) {
       Node child = (Node)group.getChild(i);
       Node childClone = child.cloneNode(forceDuplicate);
       ((Group)node).addChild(childClone);
     }
  }
  return node;
}

Of course, I haven’t looked in the Java3D source code of these methods, so maybe there’s more that’s supposed to be going on here than what I just posted. But the above looks like a deep copy to me. Of course, any child class of Node would have to override cloneNode() to return an object of the correct type, but from Java3D’s javadocs, this looks to be expected:

Am I missing something here? I have to suspect that the developers of Xith just overlooked this one, but someone please correct me if I’m wrong.

Paul

Ok, I took a look at the Xith3d source code, and noticed the following in Node.java:


public void duplicateNode(Node originalNode, boolean forceDuplicate) {
}

And not a single child class of Node overrides this method. So perhaps I was assuming a bit much that this method was indeed fully fleshed out. However, I also noticed that NodeComponent has implemented the methods cloneNodeComponent(boolean forceDuplicate) and duplicateNodeComponent(NodeComponent originalNodeComponent, boolean forceDuplicate). So perhaps really all that’s missing is NodeComponent’s duplicateNode() method, ala:


public void duplicateNode(originalNode, boolean forceDuplicate) {
  if (originalNode instanceof NodeComponent) {
    duplicateNodeComponent((NodeComponent)originalNode, forceDuplicate);
  }
}

Again, mostly trolling here for some feedback from David or someone else who actually worked on this code. If I’m totally off base here, I’d like to be set straight.

Paul

Rereading my own post, this looks a bit whiney to me. I thought I’d clarify that I wasn’t looking for a work-around (as I’ve already got a servicable one), but wanted info on what the intentions were, and some expectations on where we’ll see the code go in future around this kind of thing.

Paul

yeah, these unimplemented methods need to be flagged better - this is currently a major weakness of the javadoc.

sharedCopy works well for me as I’m not altering the actual geometry like you will be. Yuri might be able to shed some light on that code, otherwise you might just have to have a crack at implementing it yourself.

Will.

Ok, it’s pretty clear this change isn’t going to happen unless I do it myself. I’m not at all against that either. So I must ask: what are the official channels for submitting such a change?

Paul

create an Issue the project page (apply for a BetaTester role) raising the topic. Then submit your unified diff patch files or just the modified files in their entirety (along with the date and version of Xith3D you made your changes against).

This recently happened in this thread: http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=xith3d;action=display;num=1090680774

Then the changes are reviewed and incorporated into the core.

Thanks - this would be a useful contribution.

Will.

Looks like this is a bigger can of worms than I first thought. :slight_smile:

Looking at NodeComponent (which I had previously foolishy assumed was a child of Node – not so) I see that the main use of this class is to be a super class of objects such as Appearance, Material, etc. in order to stream-line node cloning. It sets up the base abstract method of duplicateNodeComponent that children must override, and the children classes do indeed override it. Looking through the code of NodeComponent itself, it really doesn’t do much else.

However, this is where the clone support ends. There is no place where the Node class keeps any kind of list of registered NodeComponents. Node children such as Shape3D seem to simply have member instances of NodeComponent children, and nowhere do I ever see such an object being referred to by its base class of NodeComponent.

So for example, in Shape3D I see:

 
    private Appearance appearance = null;

...

    public final Appearance getAppearance() {
        return appearance;
    }

    public final void setAppearance(Appearance appearance) {
        this.appearance = appearance;
    }

What I would recommend is having NodeComponent actually maintain a HashTable (or HashMap depending on which version of the JVM we require) of registered NodeComponents. It would have private members to get/set node components based on class name. Thus, the above code would actually look like this:

 
    public final Appearance getAppearance() {
        // Actually, probably ought to have some checking here in
        // case the appearance node component is not set at all.
        return (Appearance)getNodeComponent(Appearance.class.getName());
    }

    public final void setAppearance(Appearance appearance) {
        setNodeComponent(Appearance.class.getName(), appearance);
    }

I have no problem making such changes, but I wanted to make sure it was ok to do, as it’s going to be a much larger change than previously thought and widespread throughout the scenegraph package.

Paul

go for it!

Having a register of NodeComponents makes sense. Definitally use HashMap - Xith3D can’t run on anything less than 1.4.2 (a restriction of JOGL).

Any reason for Appearance.class.getName() instead of just “Appearance” - just a bit obfuscated that’s all? Perhaps some constants in NodeComponent so it’s NodeComponent.APPEARANCE would be a good idea (that way we can say that the keys of the HashMap should be constants of NodeComponent).

Regarding the getAppearance method - it should return null if there isn’t one so your code is fine.

These changes have my +1

Will.

I figured it would be best to use class.getName() just in case there is ever an overlap of NodeComponent class names. You never know, it could happen. By using the fully qualified class name, we should be able to gaurentee uniqueness for any given NodeComponent.

A series of constants in the NodeComponent class would do the trick as well, but then when creating a new NodeComponent child class you’d have to touch the NodeComponent class as well. With the above, a newly created NodeComponent can be fully self-contained.

Paul

Having constants in NodeComponent is probably bad I agree.

If you really think it could be possible to have two NodeComponents with the same name (I do not believe anyone would ever want to do that) - what about specifying the fully quantified class name as a string, e.g. “com.xith3d.scenegraph.Appearance”? I just think Appearance.class.getName() is needlessly complicated when a simple String would do.

Or you could even change the method setNodeComponent so it only takes one argument - the NodeComponent and calls getClass().getName() on it (the call to getNodeComponent would still need the string but). I’m not convinced this would help however.

Will.

Couldn’t you simply use Appearance.getClass() and avoid the extra conversion to String?

As an added bonus, getClass() is a member function of Object, while getName() is not. This allows simplified goodness.

public final void setAppearance(Appearance appearance) {
  setNodeComponent(appearance);
}

... setNodeComponent(NodeComponent x)
{
  // Register the component
  key=x.getClass();
}

Please ignore me if I missed something obvious.

Well, Appearance.class.getName() actually does return the string “com.xith3d.scenegraph.Appearance”. Of course, since setNodeComponent(String key, NodeComponent component) takes a String as a key, there’s nothing stopping a user from supplying any string he so desires.

In general, I think class.getName() is cleaner than hard-coding the string: it will cause compile errors if you mistype it, and it need not be changed if the class is ever refactored into a different package (not that I expect that to ever happen, but you never know).

I suppose I could, though personally I’m a bit happier using Strings as keys rather than Class objects as keys. I sort of feel that String equality testing behaves in a somewhat more predictable way than Class equality testing. Plus I think having strings as keys is more adaptable to strange cases. For example, suppose I were to write a Node object that had two separate Appearance member variables. With strings as keys, I could just do this:


public void setAppearance1(Appearance appearance) {
  setNodeComponent(Appearance.class.getName() + "_1", appearance);
}

public void setAppearance2(Appearance appearance) {
  setNodeComponent(Appearance.class.getName() + "_2", appearance);
}

In fact, Appearance itself contains an arbitrarily sized array of TextureUnitState objects. I’m still trying to figure out the best way to approach this one, but something similar to the above is certainly possible. I’m also contemplating creating a NodeComponentArray wrapper class that is itself a child of NodeComponent, and simply contains an aribtrarily sized array of other NodeComponent objects.

I have to say, I think having setNodeComponent() only take a single argument is a patently bad idea. The problem is, if I’m writing a child class of Node and I want to use this functionality to set node components, how do I know what to supply as the key for relevant getter? I don’t. By forcing the user to supply the key in the setter, I can gaurentee that said user will know exactly what to supply in the getter. It’s best to keep the definition of the key localized in a single class.

Paul

Isn’t this what the common pattern of returning a value from the set method is for? You return the key that the set method automatically used…

The general ideas is used quite a bit in java Collections, e.g. remove( key ) methods return the value of key that has been removed, and set( key, value ) methods return the OLD value of that key, if the key was already mapped. It’s a return value that is often unused, but gives the invoker the option of preserving valuable information if they need it.