Ability to select custom shapes (created using vertex())

edited June 2014 in How To...

Hello,

Is there any way to select a custom shape in Processing (using a mouse press). I have created a simple program which outlines an simple irregular shape using vertex(); within beginShape(); and endShape(); which has over 50 vertex() declarations. I want to be able to select within this shape and change it's colour after a mouse click. Is there any possible way of doing this?

So far, I have only been able to do this within shapes such as a rectangle or eclipse.

Thanks

Answers

  • edited July 2014 Answer ✓

    the trick is to get the color on the mouse click pos (get(mouseX,mouseY);)

    check for each shape if its color is == the color of the mouse pos

    (when each shape has another color this approach works

    when not so you can paint the shapes on a 2nd hidden canvas with unique colors and do the check there)

    ;-)

  • edited June 2014 Answer ✓

    here

    //
    // states
    final int stateGame  = 0; // consts
    final int statePause = 1;
    int state = stateGame;    // current 
    
    // ---------------------------------------------------------------
    
    void setup() {
      // init (runs only once)
      size(800, 600);
    } // func 
    
    void draw() { 
      // runs on and on 
    
      switch (state) {
    
      case stateGame: 
        // Game
        handleStateGame();
        break; 
    
      case statePause:
        // Pause
        handleStatePause(); 
        break;
    
      default:
        // error
        println("Error number 939; unknown state : " + state+".");
        exit();
        break;
      } // switch
      //
    } // func 
    
    // functions for states - called from draw() 
    
    void handleStateGame() {
      // Game
      background(11);
      fill(244, 3, 3); // red 
      text ("Game....", 210, 313);    
      //
      noStroke();
      fill(255, 2, 2) ;
      rect(100, 100, 100, 100);
      fill(255, 2, 255) ;
      rect(300, 100, 100, 100);
    } // func 
    
    void handleStatePause() {
      // Pause
      background(255);
      fill(244, 3, 3); // red 
      text ("Pause.... ", 210, 313);    
      text ("Hit p to start Game", 210, 385);
    } // func 
    
    // ----------------------------------------
    // keyboard input 
    
    void keyPressed() {
    
      switch (state) {
    
      case stateGame: 
        // Game
        keyPressedForStateGame();
        break; 
    
      case statePause:
        // Pause
        keyPressedForStatePause(); 
        break;
    
      default:
        // error
        println("Error number 1039; unknown state : " + state+".");
        exit();
        break;
      } // switch
    } // func 
    
    // ----
    
    void keyPressedForStateGame() { 
      if (key == CODED) 
      {
        if (keyCode == UP) {
          //
        } 
        else if (keyCode == DOWN) {
          //
        }
    
        if (keyCode == LEFT) {
          //
        } 
        else if (keyCode == RIGHT) {
          //
        }
        else {
          // do nothing
        } // else
      } //  if (key == CODED) {
      else 
      {
        // not CODED ---------------------- 
        if (key == 'p') {
          // Pause 
          state = statePause;
        }
        else {
          // do nothing
        } // else
      } // else not CODED
    } // func
    
    void keyPressedForStatePause() { 
      if (key == CODED) 
      {
        if (keyCode == UP) {
          //
        } 
        else if (keyCode == DOWN) {
          // none
        }
    
        if (keyCode == LEFT) {
          //
        } 
        else if (keyCode == RIGHT) {
          //
        }
        else {
          // do nothing
        } // else
      } //  if (key == CODED) {
      else 
      {
        // not CODED ---------------------- 
        if (key == 'p') {
          //
          state = stateGame;
        }
        else {
          // do nothing
        } // else
      } // else not CODED
    } // func
    
    // -------------------------------------------------------
    // Mouse input
    
    void mousePressed() {
      //
      switch (state) {
    
      case stateGame: 
        // Game
        mousePressedForStateGame();
        break; 
    
      case statePause:
        // Pause
        mousePressedForStatePause(); 
        break;
    
      default:
        // error
        println("Error number 1139; unknown state : " + state+".");
        exit();
        break;
      } // switch
    } // func 
    
    void mousePressedForStateGame() {
      //
      color c1 = get(mouseX, mouseY);
      if (c1 == color(255, 2, 2)) {
        println ("left");
      }
      else if (c1 == color(255, 2, 255)) {
        println ("right");
      }
      //
    } // func 
    
    void mousePressedForStatePause() {
      //
    } // func 
    // ==================================
    
  • The answer did solve the problem as I asked, but maybe I shouldn't of overcomplicated my question by using the color example, I simply want to identify when the mouse is pressed within the vertex object. Although your example worked perfectly, it depended on the color of the object, whereas my program contains 10s of objects which are the same color, but I would like to identify when each is pressed, changing the interface depending on which is pressed.

    i.e

    beginShape();
    vertex(5,5);
    vertex(10,10);
    vertex(12,21);
    
    ...
    
    vertex(1,3);
    vertex(5,5);
    endShape();
    
  • edited July 2014

    Understood

    Use 2 different colors for each shape:

    • One col to display

    • One col to draw on the 2nd hidden canvas - do get() there

    I still think this is easiest

    • But it won't work with overlapping
  • If you draw a line from the click point to a known point outside the object and count the number of edges crossed you can determine if it is inside or outside. An even count is outside object, odd count is inside.

  • As I do have a limited number of shapes, the colour solution is probably the best anyway and I'll give it a try and let you know how successful I am with it! Thanks!

  • Like so

    InsideOutside2

  • The objects are fairly close and some share edges so theres no way, as far as I can see, I could identify which object the point is within, just that it is within one of them. The color solution seems to work, however the application fails to identify the color underneath the above. i.e I've coloured the visible layer (0,0,255), and the hidden mask behind (0,255,255), yet it is only identified when I define:

      color c = get(mouseX, mouseY);
      if (c == color(0, 0, 255)) {
        println ("inside");
      }
    

    not the ideal:

      color c = get(mouseX, mouseY);
      if (c == color(0, 255, 255)) {
        println ("inside");
      }
    

    feels like I'm missing something fairly obvious.

  • edited July 2014

    For hidden canvas see PGraphics...

    See quarks answer on my last post

    http://forum.processing.org/two/discussion/comment/21248#Comment_21248

  • edited July 2014

    Given the "mouse click to point outside" line you can for each object check to see if the line intersect the edges defined by the vertex, counting the number of edges. If the shapes overlap then the click could be inside multiple shapes. If so, you need to appreciate the stack order, the object on top is the one clicked.

    See http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect for a discussion of detecting line segment intersections.

  • In line 1 you use get alone

    But you must use pg.get....

    To get the right color 0,255,255

  • Pg and your visible canvas must be same size etc.

  • edited July 2014

    If you store the vertices in an array of PVectors then you can use this method to see whether a point is inside or not.

       /**
         * See if the given point [x0, y0] is inside a polygon defined by the 
         * vertices provided. 
         * The vertices form an 'open' contour i.e. it assumes a closure 
         * between the first and last
         * vertex.
         */
        public boolean isInsidePolygon(PVector[] verts, float x0, float y0){
          boolean oddNodes = false;
          for (int i = 0, j = verts.length - 1; i < verts.length; j = i, i++) {
            PVector vi = verts[i];
            PVector vj = verts[j];
            if ((vi.y < y0 && vj.y >= y0 || vj.y < y0 && vi.y >= y0) && (vi.x + (y0 - vi.y) / (vj.y - vi.y) * (vj.x - vi.x) < x0))
              oddNodes = !oddNodes;
          }
          return oddNodes;
        }
    
Sign In or Register to comment.