Making an independent copy of an object

I have created a fairly complicated program and so far it's been a fun journey. Recently I got the idea to add a node based editor to the program which until now worked quite nice. Basically I have Points which are contained in an ArrayList in a Frame object (before you ask, so far no problems with Java's own Frame). These Points and Frames are manipulated through the program.

Have a look at the following image.

https://www.dropbox.com/s/wh2v6c23u1od5sk/CopyBug.png

This is what's happening here:

-The Source element has an ArrayList of Frames. It sends out one at a time to the Output node depending on an internal variable, which is passed on as well to the Sync node

-The Translate Input node accepts the Frame and performs a translation to the Points in it. The y-value of the translation is connected to the Sync output of the Source element so it shifts down gradually according to which Frame is sent out.

-The Output element accepts the Frame from the Translate element and displays it in its preview window. It stores all Frames it receives in an ArrayList which is passed on to the main program once you click "Import in IldaViewer".

As you can see the Frame (the red globe) is translated down as expected in the Output element (the Points are not supposed to leave the preview window but that's easily corrected). But the Frames in the Source element are also translated! This is not supposed to happen.

I believe the problem is caused by a shallow vs a deep copy of the Frame, when it's passed on to the next element. I tried searching the internet for solutions but couldn't find a working one. One of the things I tried is an in-between element:

      if (inputFrame != null) //inputFrame is passed on by the Connection to the input
      {
        startFrame.points.clear();  //startFrame is the Frame in the Translate element, points is an arrayList<Point>
        Frame temp = new Frame(inputFrame);
        for (Point point : temp.points)
        {
          startFrame.points.add(new Point(point));
        }
      }

I created new constructors for both the Frame and Point class to easify creating new objects. No luck. The internet also told me to serialize my objects and create an input/outputstream, but that's not a route I want to take.

I can't share code as the program is pretty large. The node editor code itself is over 2000 lines and heavily spaghettified.

Any help? Suggestions?

Thanks!

Answers

  • edited May 2014

    An expert programmer made from pure awesomeness descended from the clouds of Code and Led Controllers has told me the solution.

    My error was that my constructor was wrong. I did this:

    Frame(Frame frame)
    {
      this.points = frame.points;
      //etc.
    }
    

    instead of this:

      Frame(Frame frame)
      {
        this.points = new ArrayList<Point>(frame.points.size());
        for (Point point : frame.points)
        {
          this.points.add(new Point(point.clone()));
        }
      //etc.
     }
    

    So the trick is to create a new ArrayList and fill it with new clones of each Point. Otherwise, you're storing pointers to the original Points again.

    Also there needs to be a clone() method in the Point class:

    Point clone()
      {
        Point point = new Point(this);
        return point;
      }
    

    where it calls the Point(Point point) constructor:

    Point(Point point)
      {
        this.position = new PVector(point.position.x, point.position.y, point.position.z);
        this.colour = point.colour;
        //etc.
      }
    

    Notice that you need to create a new PVector, because it's an object, but not a new color because it's a primitive type (a Processing color is actually an int).

  • Accepted your post so it's no longer an unanswered question.

    I never worked with interfaces before, I'll make sure to check your examples out!

  • Gonna leave the relevant clone() part below for faster access! ;)

    class Vertex implements Cloneable, Comparable<Vertex> {
      ArrayList<PVector> subs = new ArrayList();
      float x, y;
    
      Vertex get() {
        try {
          return clone();
        }
    
        catch (CloneNotSupportedException ex) {
          throw new AssertionError(ex);
        }
      }
    
      protected Vertex clone() throws CloneNotSupportedException {
        final Vertex v = (Vertex) super.clone();
        final ArrayList<PVector> vsubs = 
          v.subs = (ArrayList<PVector>) subs.clone();
    
        for ( int i = vsubs.size(); i-- != 0;
          vsubs.set(i, subs.get(i).get()) );
    
        return v;
      }
    }
    
Sign In or Register to comment.