How to copy a PShape object??

edited November 2015 in Questions about Code

Hello

anyone know how I can clone an object PShape?

PShape s1;
PShape s2;

void setup() 
{
  size(1000, 500, P2D);
  s1 = createShape();
  s1.beginShape();
  s1.fill(0, 0, 255);
  s1.noStroke();
  s1.vertex(0, 0);
  s1.vertex(0, 50);
  s1.vertex(50, 50);
  s1.vertex(50, 0);
  s1.endShape(CLOSE);

  s2 = createShape(s1);
}

void draw()
{
  shape(s2, 25, 25);

}

Answers

  • edited October 2013
        void setup() { 
          size(1000, 500, P2D); 
          s1 = createShape(); 
          s1.beginShape(); 
          s1.fill(0, 0, 255); 
          s1.noStroke(); 
          s1.vertex(0, 0); 
          s1.vertex(0, 50); 
          s1.vertex(50, 50); 
          s1.vertex(50, 0); 
          s1.endShape(CLOSE);
          //s2 = createShape(s1);
        }
    
        void draw() {
          shape(s1, width/2, height/2); 
          shape(s1, 25, 25);  
        }
    

    Are you sure you need to clone shape, doesn't seem to make sense when you can do above. For something a bit more radical check this out

  • I've got the same problem, I really need to copy a PShape. When you check the current version of Processing on Github, you can see that somebody already put some efford into it: https://github.com/processing/processing/blob/master/core/src/processing/core/PShape.java

    Though this functionality, isn't tested yet and for some reason not in the newest version of the officially downloadable version of processing.

    Plus, there's an issue on github rotting around, which adresses exactly this problem: https://github.com/processing/processing/issues/1710

    If anybody is making any progress on this, please let us know here, I will do the same.

  • edited July 2015

    I came here looking for the same thing, unfortunately it seems impossible to copy a PShape instead of referencing it. I looked and looked to no end. The only thing I can think of is actually loading it one more time from file if it's an "svg" we're talking about. Posting this in the hopes that it gets bumped up and some of the wise elders might help.

  • I've been working on a method for copying shapes. I don't quite understood if this solution is going to be implemented on the future or not, but the thing is i need that functionality for a project i must finish this month, so i decided to work on an simple method that i could just paste and use.

    Basically what it does is read the vertexes of a PShape argument, then read the vertexes codes (0 for normal vertex and 1 for bezierVertexes) and recreates this shape on a copy_shape variable. Then return it. It's been working perfectly for some time now. But right know it only works with vertex() and bezierVertex(). Someone should probably make it work with other kinds of vertexes (curveVertex for example)

    PShape copyShape(PShape original){
    
      PShape copy_shape = createShape();
      int nOfVertexes = original.getVertexCount();      
      int nOfVertexesCodes = original.getVertexCodeCount();      
      int code_index = 0; // which vertex i'm reading?
      PVector pos[] = new PVector[nOfVertexes];
      int codes[] = new int[nOfVertexes];
    
      println("nOfVertexes: "+nOfVertexes);
      println("nOfVertexesCodes: "+nOfVertexesCodes);
    
      // creates the shape to be manipulated
      // and initiate the codes array
      beginShape();
        for (int i=0; i< nOfVertexes; i++){
          copy_shape.vertex(0,0);
          codes[i] = 666; //random number, different than 0 or 1
        }
      endShape();
    
      // GET THE CODES
      for (int i=0; i< nOfVertexesCodes; i++){
        int code = original.getVertexCode(i);
        codes[code_index] = code;
        if (code == 0) {
          code_index++;
        } else if( code == 1){
          code_index +=3;
        }
      }
      // GET THE POSITIONS
      for (int i=0; i< nOfVertexes; i++){
        pos[i] = original.getVertex(i);
      }
      //for debugging purposes
      println("==============POS==============");
      printArray(pos);
      println("==============CODES==============");
      printArray(codes);
    
      copy_shape = createShape();
      copy_shape.beginShape();
      for (int i=0; i< nOfVertexes; i++){
        if ( codes[i] == 0) {
          //if a regular vertex
          copy_shape.vertex(pos[i].x, pos[i].y);
    
        } else if ( codes[i]==1 ){
           //if a bezier vertex
           copy_shape.bezierVertex(pos[i].x, pos[i].y,
                                   pos[i+1].x, pos[i+1].y,
                                   pos[i+2].x, pos[i+2].y);
    
        } else {
         //this vertex will be used inside the bezierVertex, wich uses 3 vertexes at once
         println("skipping vertex "+i);
        }
      }
      copy_shape.endShape();
      return copy_shape;
    }
    
  • If you can't copy the whole PShape, what you can do get its children.
    Creating a new PShape and adding these children could work.

    PShape shp1, shp2;
    
    void setup() {
      size(950, 620);  
      shp1 = loadShape("https://upload.wikimedia.org/wikipedia/commons/8/80/World_map_-_low_resolution.svg");
      PShape[] children = shp1.getChildren();
    
      shp2 = createShape(GROUP);
      for (int i =0; i< children.length; i++) {
        shp2.addChild(children[i]);
      }
    
      background(255);
      shape(shp2, 0, 0);
    }
    
    void draw() {
    }
    
  • edited November 2015

    Never mind, it doesn't work this way. Children are still the same, so no real copy.
    Does it has to be PShape? Or is a library an option?
    Geomerative is great for working with SVGs.

  • Here is an example with geomerative:

    import geomerative.*;
    
    void setup(){
      size(300, 150);
      RG.init(this);
    
      // load shape
      RShape shp1 = RG.loadShape("https://upload.wikimedia.org/wikipedia/commons/8/88/Blue_oval.svg");
      // copy shape
      RShape shp2 = new RShape(shp1);
    
      // manipulate first shape
      // so we see, if the are different
      for( RShape child : shp1.children )
        child.setFill(0xffff0000);
    
      RG.shape(shp1, 25, 50);
      RG.shape(shp2, 175, 50);
    }
    
  • edited November 2015

    I've just realized we were missing a really simple solution. Just use a function that returns the desired Shape. You will gave to type to lines to initialize the shape anyway. This works with absolutely every kind of shape.

    PShape my_shape = shapeConstructor();
    
    PShape shapeConstructor(){
      int size = 9;
      PShape output = createShape(RECT, -size/2, -size/2, size, size);
      output.setFill( color(6, 6, 6, 1) );
      output.setStrokeWeight( 2 );
      output.rotate(QUARTER_PI);
      return output;
    }
    

    If you already know how you're going to manipulate that shape you could even use this function inside a class along with it's specific methods and variables.

    So simple! Can't believe i didn't thought about it before haha

  • edited April 2016

    Or an even simpler way to make a copy of a PShape s that you already have:

      PShape d; // d will be the duplicate of s
      d = createShape();
      d.beginShape();
      for(int i = 0; i < s.getVertexCount(); i++){
        float x = s.getVertexX(i);
        float y = s.getVertexY(i);
        d.vertex(x,y);
      }
      d.endShape();
    
  • that doesn't copy the fill or the noStroke state set in the original post. or any of the 100 other fields in the PShape object: https://github.com/processing/processing/blob/master/core/src/processing/core/PShape.java

Sign In or Register to comment.