What am I doing wrong with my PShape contour?

I'm having trouble making cutout contours using PShapes. The beginContour()/endContour() functions seem to work just fine when I'm drawing directly to the screen, but when I attempt to do it within a PShape definition it comes out like this:

pshape contour

The box on the left is drawn directly to the screen, the box on the right is drawn using a defined PShape. This is the code:

PShape s;

void setup()
{
  frameRate(50);
  size(500,300);

  s = createShape();

  s.beginShape();
  s.fill(255,0,0);
  s.vertex(100,100);
  s.vertex(200,100);
  s.vertex(200,200);
  s.vertex(100,200);
  s.beginContour();
  s.vertex(125,125);
  s.vertex(125,175);
  s.vertex(175,175);
  s.vertex(175,125);
  s.endContour();
  s.endShape(CLOSE);
}

void draw()
{
  beginShape();
  fill(255,0,0);
  vertex(100,100);
  vertex(200,100);
  vertex(200,200);
  vertex(100,200);
  beginContour();
  vertex(125,125);
  vertex(125,175);
  vertex(175,175);
  vertex(175,125);
  endContour();
  endShape(CLOSE);

  shape(s, 200, 0);
}

As you can see, I'm defining both boxes in exactly the same way, yet the PShape seems to ignore my call to beginContour()/endContour(). Is this happening to anyone else? Am I doing something wrong?

Edit: In fact, even when I copy the code from https://processing.org/reference/PShape_beginContour_.html, it gets screwed up in the same way.

Answers

  • I added this right before endContour: s.vertex(125, 125); it helps bu you get an artifact and I am guessing this is cause by the actual stroke color.

    Kf

  • Read the reference on contour

    Outer and inner ring must be opposite direction iirc

    Eg one clockwise, the other amti-clockwise

  • edited April 2017 Answer ✓

    @Dullahan -- re:

    In fact, even when I copy the code from https://processing.org/reference/PShape_beginContour_.html, it gets screwed up in the same way.

    You are right -- it looks like there is a bug in PShape.beginContour() in recent versions of Processing. This can be seen by the canonical reference example (which contains correct clockwise / counterclockwise vertex order) no longer rendering correctly, as you point out.

    The bug report is here:

  • @kfrajer

    I added this right before endContour: s.vertex(125, 125); it helps bu you get an artifact and I am guessing this is cause by the actual stroke color.

    Actually, that's a clever solution! If you also put a s.vertex(100,100); just before beginContour, it closes the shape up with a stroke line connecting (100,100) and (125,125). If you then put in a noStroke(); then the two shapes look identical! It even seems to hold up to various transformations with no visual artifacts. Unfortunately, if you want an outline, there will always be a stroke line connecting the outside outline and the contour outline.


    @Chrisir

    Read the reference on contour

    Outer and inner ring must be opposite direction iirc

    Don't worry, I did. ;) And my vertices do wind in opposite directions.


    @jeremydouglass

    The bug report is here:

    https://github.com/processing/processing/issues/4978

    Thanks for pointing that out. Guess I'll just have to use kfrajer's solution for the time being.

  • @Dullahan

    If you do s.noStroke() then you won't have an artifact but you won't have an outline of the shape. You could the outline manually if you needed. Or even better, you could create a class that will do it for you. It really depends how complex your geometry shape will be. Of course, this is a temporal solution while the bug gets resolved.

    Kf

  • Bug resolved as error in documentation -- use CLOSE twice for inner Contour and outer Shape.

    https://github.com/processing/processing/issues/4978

  • I don't get it. Twice? This is what I have:

    PShape s;
    
    void setup()
    {
      frameRate(50);
      size(500, 300);
    
      s = createShape();
    
      s.beginShape();
      s.fill(255, 0, 0);
      s.vertex(100, 100);
      s.vertex(200, 100);
      s.vertex(200, 200);
      s.vertex(100, 200);
      s.vertex(100, 100);  //Added
      s.beginContour();
      s.vertex(125, 125);
      s.vertex(125, 175);
      s.vertex(175, 175);
      s.vertex(175, 125);
      s.vertex(125, 125);   //Added
      s.endContour();
      s.endShape(CLOSE);
    }
    
    void draw()
    {
      beginShape();
      fill(255, 0, 0);
      vertex(100, 100);
      vertex(200, 100);
      vertex(200, 200);
      vertex(100, 200);
      beginContour();
      vertex(125, 125);
      vertex(125, 175);
      vertex(175, 175);
      vertex(175, 125);
      endContour();
      endShape(CLOSE);
    
      shape(s, 200, 0);
    }
    

    Kf

  • @kfrajer -- hmm. Yeah, I'm not sure.

    Perhaps respond on the issue 4978 I linked above with that example and a brief explanation? The issue might have been closed for the wrong reasons.

  • @jeremydouglass I will do a follow up. Stay tune!

    Kf

  • edited May 2017

    @kfrajer -- Two things I've noticed:

    1. the important thing to communicate is that the beginContour() code sequence in draw() and the PShape.beginContour() code are identical other than being the function / PShape method -- but they give different results.
    2. The reference example uses endShape(CLOSE) twice, for both the outer shape and the contour -- they are in two different begin/end blocks. This behaves the same in draw() or in a specified PShape. However, your test example uses one begin/end block (which I find more intuitive). This is what may expose the surprising behavior that using beginContour inside and outside a shape behaves differently.

    Here is a new illustration:

    BugBeginContour

    And here is a new test code:

    // beginContour() and endContour doesnt work on shape
    // github.com/processing/processing/issues/4978
    // forum.processing.org/two/discussion/comment/97902
    
    PShape s;
    
    void setup()
    {
      frameRate(50);
      size(600, 200);
      fill(255, 0, 0);
      noLoop();
    }
    
    void draw()
    {
      translate(50, 50);
      text("contour shape", 0, -10);
      fill(255, 0, 0);
      beginShape();
      vertex(  0, 0);
      vertex(100, 0);
      vertex(100, 100);
      vertex(  0, 100);
      beginContour();
      vertex( 25, 25);
      vertex( 25, 75);
      vertex( 75, 75);
      vertex( 75, 25);
      endContour();
      endShape(CLOSE);
    
      translate(200, 0);
    
      text("PShape, identical", 0, -10);
      s = createShape();
      s.beginShape();
      s.fill(255, 0, 0);
      s.vertex(  0, 0);
      s.vertex(100, 0);
      s.vertex(100, 100);
      s.vertex(  0, 100);
      s.beginContour();
      s.vertex( 25, 25);
      s.vertex( 25, 75);
      s.vertex( 75, 75);
      s.vertex( 75, 25);
      s.endContour();
      s.endShape(CLOSE);
      shape(s, 0, 0);
    
      translate(200, 0);
    
      text("PShape, two added", 0, -10);
      s = createShape();
      s.beginShape();
      s.fill(255, 0, 0);
      s.vertex(  0, 0);
      s.vertex(100, 0);
      s.vertex(100, 100);
      s.vertex(  0, 100);
      s.vertex(  0, 0); // added
      s.beginContour();
      s.vertex( 25, 25);
      s.vertex( 25, 75);
      s.vertex( 75, 75);
      s.vertex( 75, 25);
      s.vertex( 25, 25); // added
      s.endContour();
      s.endShape(CLOSE);
      shape(s, 0, 0);
    }
    
  • edited May 2017

    Here is a second example: Two identical PShape sequences except that one contains "beginContour / endContour" and one does not. One should contain a contour, but instead both render the same end shape.

    PShape s;
    void setup() {
      size(400, 200);
      fill(255, 0, 0);
      noLoop();
    }
    void draw() {
      translate(50, 50);
      text("PShape w contour", 0, -10);
      s = createShape();
      s.beginShape();
      s.fill(255, 0, 0);
      s.vertex(  0, 0);
      s.vertex(100, 0);
      s.vertex(100, 100);
      s.vertex(  0, 100);
      s.beginContour();
      s.vertex( 25, 25);
      s.vertex( 25, 75);
      s.vertex( 75, 75);
      s.vertex( 75, 25);
      s.endContour();
      s.endShape(CLOSE);
      shape(s, 0, 0);
    
      translate(200, 0);
      text("PShape w/out contour", 0, -10);
      s = createShape();
      s.beginShape();
      s.fill(255, 0, 0);
      s.vertex(  0, 0);
      s.vertex(100, 0);
      s.vertex(100, 100);
      s.vertex(  0, 100);
      s.vertex( 25, 25);
      s.vertex( 25, 75);
      s.vertex( 75, 75);
      s.vertex( 75, 25);
      s.endShape(CLOSE);
      shape(s, 0, 0);
    }
    

    BugBeginContour2

  • edited May 2017

    Now let's do it again, but take those commands out of PShape methods and use the draw functions instead. Again, two identical sequences of vertices, with the only difference being that one uses "beginContour / endContour", and one does not.

    PShape s;
    void setup() {
      size(400, 200);
      fill(255, 0, 0);
      noLoop();
    }
    void draw() {
      translate(50, 50);
      text("shape w contour", 0, -10);
      beginShape();
      fill(255, 0, 0);
      vertex(  0, 0);
      vertex(100, 0);
      vertex(100, 100);
      vertex(  0, 100);
      beginContour(); // begin contour
      vertex( 25, 25);
      vertex( 25, 75);
      vertex( 75, 75);
      vertex( 75, 25);
      endContour(); // end begin contour
      endShape(CLOSE);
    
      translate(200, 0);
      text("shape w contour", 0, -10);
      beginShape();
      fill(255, 0, 0);
      vertex(  0, 0);
      vertex(100, 0);
      vertex(100, 100);
      vertex(  0, 100);
      vertex( 25, 25); // no begin
      vertex( 25, 75);
      vertex( 75, 75);
      vertex( 75, 25);
      endShape(CLOSE); // no end
    } 
    

    BugBeginContour3

Sign In or Register to comment.