We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSyntax Questions › Recognizing a line when mouse over
Page Index Toggle Pages: 1
Recognizing a line when mouse over (Read 2245 times)
Recognizing a line when mouse over
Jul 18th, 2009, 5:40am
 
Hi!

I am a Processing newbie and I would like to ask you for your advice.
I have written a program that emulates one of the early computer art drawings, basically drawing bundles lines with different lengths and orientations using random numbers. Now I would like to make this static drawing interactive, in a way that every time that the user passes over a certain line with the mouse it will play a sound.

The problem is that I can not figure out how to recognize a single line with the mouse, since what I use to draw lines is the only the line() function.

Thanks a lot!
Re: Recognizing a line when mouse over
Reply #1 - Jul 18th, 2009, 8:30am
 
This is one of those design problems where it's easy to describe aloud or on paper, but it's actually quite complicated in terms of the methods required to accomplish it. Let me try and point you in the right direction.

First of all, you'll need to design a class to accomplish this stuff, especially if you're going to be using hundreds of lines. You'll need to take the current mouse coordinates and test them against the locations of all the parts of all your lines. This is where it gets a little bit tricky. Lines are only one pixel thick (at least the defaults are). So in order to detect rollover on a particular line, the mouse would have to come to rest on one particular pixel. It gets even tougher here because when you're using the line() function, you have no way of easily knowing the exact location of all your points in the line. So how will you test for them? This stuff could all be done, but you can see it gets rather complicated rather quickly.

If this were my project, I think I would put little ellipses on the ends of all the lines, and have those be the parts you point at with your mouse. Checking rollover for an ellipse is much simpler, and it may actually give a cool look to the project. Then you also don't have to worry about detecting mouse intersections with parts of lines. I think I'm going to go mock up some code real quick to show you what I mean. Check back and I'll post it. Meanwhile, if you have any questions about classes or rollover in general, ask away and we'll help point you to the right references.
Re: Recognizing a line when mouse over
Reply #2 - Jul 18th, 2009, 8:58am
 
First of all, thanks a lot for the detailed explanation. You are right, it sounds like an easy task but actually is rather complex... I am trying to create, along with each line, a rectangle with the same starting point, same length, angle and minimum width, so I expect I can check the mouse rollover. Anyway, I would really like to see more of your idea, I'm sure it'll be more then helpful.

This is the basic code that creates the lines, no mouse interaction considered:

void setup()
{  
 size(600, 700);
 background(250);
 
 // Variables initialization
 float i = 0, x0 = 0, y0 = 0, alfa0 = 0, L0 = 0, t = 0,
 n = 0, j = 0, x = 0, y = 0,
 beta = 0, alfa = 0, a = 0, b = 0, Dt = 0, Da = 0, Db = 0, Dbeta = 0,
 Px = 0, Py = 0, Qx = 0, Qy = 0;
 int c = 0;
 // Collection of Brushes
 int[][] brushes = {{0, 0, 0, 1}, // Black Thin Stroke
                   {0, 0, 0, 2}, // Black Thick Stroke
                   {207, 118, 38, 2}}; // Orange Thick Stroke
 
 for (i = 1; i <= random(5, 20); i++){ // Control of the number of carriers i
   c = int(random(0, 3)); // Random index for the brushes matrix
   // Initial parameters of one carrier (a straight line)
   x0 = random(0.4 * width, 0.8 * width); // Origin point A0(x0, y0)
   y0 = random(0.5 * height, 0.7 * height);
   alfa0 = random(-PI, PI); // Angle(in radians)
   L0 = random(0.4 * width, 0.6 * width); // Length
   // Lenghts "a" and "b" of the first line (divided in two segments) of the bundle over the carrier.
   // They have the same angle "beta".
   a = random(0.2 * L0, 0.7 * L0);
   b = random(0.2 * L0, 0.7 * L0);
   beta = random(-PI, PI);
   n = random(5, 30); // Number of lines in the bundle
   t = 0; // First point in the carrier
   
   for (j = 0; j <= n ; j += 1){ // Bundle of lines
     t = t + Dt; // Next point in the carrier
     x = x0 + t * L0 * cos(alfa0); // Point (x,y)
     y = y0 + t * L0 * sin(alfa0);
     // Calculation of the parameters of the lines "a" and "b"
     a = a + Da;
     b = b + Db;
     beta = beta + Dbeta; // Next angle of "a" and "b" over the carrier
     alfa = PI - alfa0 - beta; // Next angle of "a" and "b" over the coordinates origin
     // P: ending point of "a"
     Px = x0 + t * L0 * cos(alfa0) + b * (- cos(alfa));
     Py = y0 + t * L0 * sin(alfa0) + b * (sin(alfa));
     // Q: ending point of "b"
     Qx = x0 + t * L0 * cos(alfa0) + a * (cos(alfa));
     Qy = y0 + t * L0 * sin(alfa0) + a * (- sin(alfa));
     
     smooth();
     strokeWeight(brushes[c][3]);
     stroke(brushes[c][0], brushes[c][1], brushes[c][2]);
     line(x, y, Px, Py); // Paint line a
     line(x, y, Qx, Qy); // Paint line b
     // Random diferentials -> Next point
     Dt = random(0, 0.04);
     Dbeta = random(-0.05 * PI, 0.05 * PI);
     Da = random(- 0.2 * a, 0.2 * a);
     Db = random (- 0.2 * b, 0.2 * b);
   }
 }
}
Re: Recognizing a line when mouse over
Reply #3 - Jul 18th, 2009, 9:13am
 
Here's what I came up with that describes what I was talking about. Point to one of the circles at the ends of the lines to show the rollover.

Code:

int LINES_NUM = 50;
SoundLine[] lines;

void setup(){
size(600, 600);
smooth();
cursor(CROSS);

lines = new SoundLine[LINES_NUM];
for(int i=0; i<LINES_NUM; i++){
  lines[i] = new SoundLine();
}
}

void draw(){
 background(255, 255, 255);
 for(int i=0; i<LINES_NUM; i++){
   lines[i].checkRollover();
   lines[i].drawLine();
 }
}

class SoundLine{
 float x1, y1;
 float x2, y2;
 int diameter;
 color ellipse_col;
 
 SoundLine(){
   x1 = width/2;
   y1 = height/2;
   x2 = random(width*0.125, width*0.875);
   y2 = random(height*0.125, height*0.875);
   diameter = 5;
   ellipse_col = color(230, 230, 230);
 }
 
 void drawLine(){
   stroke(0);
   line(x1, y1, x2, y2);
   fill(ellipse_col, 128);
   ellipse(x2, y2, diameter, diameter);
 }
 
 void checkRollover(){
   float disX = x2 - mouseX;
   float disY = y2 - mouseY;
   if(sqrt(sq(disX) + sq(disY)) < diameter/2){
     diameter = 15;
     ellipse_col = color(255, 0, 0);
   } else {
     diameter = 5;
     ellipse_col = color(230, 230, 230);
   }
 }  
}


I'll take a look at your code and get back with you...
Re: Recognizing a line when mouse over
Reply #4 - Jul 18th, 2009, 9:23pm
 
maybe this helps. pointInsideLine

Quote:
PVector p1;
PVector p2;

PVector mouse;

void setup() {
  size(400,400);
  mouse = new PVector();
  p1 = new PVector(100,100);
  p2 = new PVector(200,200);
}


void draw() {
  background(0);
  stroke(255);
  mouse.set(mouseX, mouseY,0);
  if(pointInsideLine(mouse, p1, p2, 4)==true) {
    stroke(0,255,0);
  }
  line(p1.x, p1.y,p2.x,p2.y);
}


/**
  * PVector thePoint 
  * the point we will check if it is close to our line.
  *
  * PVector theLineEndPoint1 
  * one end of the line.
  *
  * PVector theLineEndPoint2
  * the second end of the line.
  *
  * int theTolerance 
  * how close thePoint must be to our line to be recogized.
  */
boolean pointInsideLine(PVector thePoint,
                        PVector theLineEndPoint1,
                        PVector theLineEndPoint2,
                        int theTolerance) {
                          
  PVector dir = new PVector(theLineEndPoint2.x,
                            theLineEndPoint2.y,
                            theLineEndPoint2.z);
  dir.sub(theLineEndPoint1);
  PVector diff = new PVector(thePoint.x, thePoint.y, 0);
  diff.sub(theLineEndPoint1);

  // inside distance determines the weighting
  // between linePoint1 and linePoint2
  float insideDistance = diff.dot(dir) / dir.dot(dir);

  if(insideDistance>0 && insideDistance<1) {
    // thePoint is inside/close to
    // the line if insideDistance>0 or <1
    println( ((insideDistance<0.5) ?
            "closer to p1":"closer to p2" ) +
            "\t p1:"+nf((1-insideDistance),1,2)+
            " / p2:"+nf(insideDistance,1,2) );
            
    PVector closest = new PVector(theLineEndPoint1.x,
                                  theLineEndPoint1.y,
                                  theLineEndPoint1.z);
    dir.mult(insideDistance);
    closest.add(dir);
    PVector d = new PVector(thePoint.x, thePoint.y, 0);
    d.sub(closest);
     // println((insideDistance>0.5) ? "b":"a");
    float distsqr = d.dot(d);
    
    // check the distance of thePoint to the line against our tolerance.
    return (distsqr < pow(theTolerance,2));
  }
  return false;
}




Re: Recognizing a line when mouse over
Reply #5 - Jul 29th, 2009, 7:28am
 
Thanks a lot for the help!

The pointsInsideLine worked perfectly Smiley
Page Index Toggle Pages: 1