Check if mouse over a curve

edited November 2017 in Questions about Code

How do I check if mouse is near a curve? I have made a function that checks if mouse is over a straight line, but I need a way to somehow check if it's over a curve. For example:

background(255);
stroke(0);
PVector a = new PVector(10, 10);
PVector b = new PVector(width-10, 10);
PVector c = new PVector(width-10, height-10);
PVector d = new PVector(10, height-10);

beginShape();
curveVertex(a.x, a.y);
curveVertex(a.x, a.y);
curveVertex(b.x, b.y);
curveVertex(c.x, c.y);
curveVertex(d.x, d.y);
curveVertex(d.x, d.y);
endShape();

How do I check if the user's mouse is over the line? It would be good if it worked on some kind of an array of PVectors, and used dist() to check if the mouse is at a certain distance from the line.

Answers

  • An easy way is to check the pix color under the mouse. This is not super accurate but fast and I would think it could be sufficient for your case. That is, assuming you have a single line and a non-changing background. Check https://processing.org/reference/get_.html

    Is this curve made of random points or do they follow a specific pattern. Does the curve cross itself? Do you want to highlight the whole curve?

    This old discussion might assist: https://stackoverflow.com/questions/4409491/mouse-over-curve

    A precise solution, as discussed above, requires knowing the function of the curve. You can use dist() to find the closer point in the list of initially provided points and then generate the equation of the line associated with this point and its neighbouring points. Then you will find the distance of the mouse pointer to this equation. This approach could potentially not give you the expected result. You might have to iterate through all the points and fit all the curves. Any attempt of your task would require a more precise definition of your challenge.

    Kf

  • edited October 2017

    Re:

    It would be good if it worked on some kind of an array of PVectors

    What kind of curve? The kind you would define with, bezierPoint(), or curvePoint(), or...

    I agree with @kfrajer -- a robust solution is to draw whatever line you want, then check for a pixel value under the mouse (or for a value in any of the n pixel values near the mouse). This allows you to detect collision with any arbitrary shape(s).

    • If the curve is invisible, draw on a PGraphics buffer and check the value there.
    • If the curve collision area is larger than the line, increase the strokeWidth on the PGraphics buffer.
    • If memory is a problem, e.g. with a very large canvas or many separate collision checks, then draw on and check against a lower resolution scaled PGraphics surface (e.g. 4:1, 400x400 canvas : 100x100 PGraphics). This can also simplify checking only one pixel.
  • @kfrajer @jeremydouglass I am not too fond on using PGraphics, because from my experience they can lag your program quite a bit. Or is it drawing PGraphics that is laggy? In my certain case I have two points connected by a curve, although there is an alternative: because the curve is similar to a sine wave, I could just generate a bunch of points using sin(). I will check the performance of your solutions and tell you if everything went smooth. So the curve I provided in my example isn't really what I want to test.

    Anyways, thank you to both of you.

  • edited November 2017

    Once drawn, a PGraphics or PImage is just a pixel buffer. The question is whether your equation will be faster to solve then looking up a value in the buffer....

    If your curve is a sine wave, you have another option: you can discover whether the mouse is above or below the curve by simply plugging in y = sin(mouseX), then checking whether y is greater or less than mouseY.

    Here is a simple example. It draws a line up if the mouse is above the curve, down if the mouse is below the curve.

    /**
     * CurveHeightDetect
     * 2017-11-01 Jeremy Douglass - Processing 3.3.6 
     * draw a line up if mouse is above the curve, down if below
     * forum.processing.org/two/discussion/24810/check-if-mouse-over-a-curve
     */
    float y;
    void draw(){
      background(255);
      pushMatrix();
      translate(0,height/2);
      y = height/2 * sin(mouseX/(width/4.0));
    
      for(int i = 0; i<width; i++){
        y = height/2 * sin(i/(width/4.0));
        point(i, y);
        if(i == (int)mouseX){
          if(mouseY-height/2 < y){ // adjust by translation
            line(i,y,i,0-height/2);
          }
          else {
            line(i,y,i,height-height/2);
          }
        }
      }
      popMatrix();
      fill(255,0,0,64);
      ellipse(mouseX,mouseY,20,20);
    }
    

    CurveHeightDetect--screenshot1 CurveHeightDetect--screenshot2

  • I actually ended up using curvePoint() and it worked great. I had no idea that this function existed, so thank you for that.

Sign In or Register to comment.