2

I have a canvas with lines. On click I want to check if the click was on my line to highlight it.

I also have some rectangles where it's easy by just using start and end point of the square. But for a diagonal line I cannot use the same technique as of course a line does not fill a rectangle.

But how can I else achieve this? Moreover I'd like to also have some "offset" so that if a click was near enought to the line it is also marked, as thin lines may be hard to click otherwise.

Probably I'm missing the right keywords as I'm for sure not the first one wanting to do this. Hope you could help.

Jarrod
  • 9,349
  • 5
  • 58
  • 73
membersound
  • 81,582
  • 193
  • 585
  • 1,120

2 Answers2

4

Write the equation for the line:

a*x + b*y + c = 0

Then put your clicked coordinates into this equation:

distance = a*x1 + b*y1 + c 

where (x1, y1) is the point you clicked. If distance < threshold you clicked on the line.

gaborsch
  • 15,408
  • 6
  • 37
  • 48
  • I have a line that is terminated on both ends, not infinite. Wouldn't this give me also a positive result on clicks where the line would imaginary continue? – membersound Mar 25 '13 at 14:09
3

Gabor is right, it is pretty easy to compute distance between two points and use that. Based on Roger's suggested link, here is some extracted code from the AWT source code that measures the distance between two points. http://developer.classpath.org/doc/java/awt/geom/Line2D-source.html

so, you code would be something like

if (ptLineDist(lineX1,lineY1,lineX2,lineY2,clickX,clickY) < someLimit) 
   clicked=true; 
else clicked=false;

Here's the AWT code (check the link above for the licence)

 521:   /**
 522:    * Measures the square of the shortest distance from the reference point
 523:    * to a point on the infinite line extended from the segment. If the point
 524:    * is on the segment, the result will be 0. If the segment is length 0,
 525:    * the distance is to the common endpoint.
 526:    *
 527:    * @param x1 the first x coordinate of the segment
 528:    * @param y1 the first y coordinate of the segment
 529:    * @param x2 the second x coordinate of the segment
 530:    * @param y2 the second y coordinate of the segment
 531:    * @param px the x coordinate of the point
 532:    * @param py the y coordinate of the point
 533:    * @return the square of the distance from the point to the extended line
 534:    * @see #ptLineDist(double, double, double, double, double, double)
 535:    * @see #ptSegDistSq(double, double, double, double, double, double)
 536:    */
 537:   public static double ptLineDistSq(double x1, double y1, double x2, double y2,
 538:                                     double px, double py)
 539:   {
 540:     double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
 541: 
 542:     double x, y;
 543:     if (pd2 == 0)
 544:       {
 545:         // Points are coincident.
 546:         x = x1;
 547:         y = y2;
 548:       }
 549:     else
 550:       {
 551:         double u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2;
 552:         x = x1 + u * (x2 - x1);
 553:         y = y1 + u * (y2 - y1);
 554:       }
 555: 
 556:     return (x - px) * (x - px) + (y - py) * (y - py);
 557:   }
 558: 
 559:   /**
 560:    * Measures the shortest distance from the reference point to a point on
 561:    * the infinite line extended from the segment. If the point is on the
 562:    * segment, the result will be 0. If the segment is length 0, the distance
 563:    * is to the common endpoint.
 564:    *
 565:    * @param x1 the first x coordinate of the segment
 566:    * @param y1 the first y coordinate of the segment
 567:    * @param x2 the second x coordinate of the segment
 568:    * @param y2 the second y coordinate of the segment
 569:    * @param px the x coordinate of the point
 570:    * @param py the y coordinate of the point
 571:    * @return the distance from the point to the extended line
 572:    * @see #ptLineDistSq(double, double, double, double, double, double)
 573:    * @see #ptSegDist(double, double, double, double, double, double)
 574:    */
 575:   public static double ptLineDist(double x1, double y1,
 576:                                    double x2, double y2,
 577:                                    double px, double py)
 578:   {
 579:     return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py));
 580:   }
 581: 
Tom Carchrae
  • 6,398
  • 2
  • 37
  • 36
  • +1, Thanks for digging the code, I was too lazy to write all the equations with the line coordinates. Actually you can express `a` and `b` with the differences of x and y coordinates of the 1 endpoints as shown in the example code. – gaborsch Mar 25 '13 at 14:06