Very basic question on a line and a point

Hi

I am looking at https://processing.org/discourse/beta/num_1276644884.html.

Shame on me, but I miss to understand the geometry (and/or algebra) which justifies the line of code
float mX = (-x1+x)*ca + (-y1+y)*sa;.
How is it that that works fine?
Thanks

1 Like

reposting the snippet as a reference:

/**
 * Returns a point on the line (x1,y1) -> (x2,y2) 
 * that is closest to the point (x,y)
 * 
 * The result is a PVector. 
 * result.x and result.y are points on the line. 
 * The result.z variable contains the distance from (x,y) to the line, 
 * just in case you need it :) 
 */
PVector getDistance( float x1, float y1, float x2, float y2, float x, float y ){
  PVector result = new PVector(); 
  
  float dx = x2 - x1; 
  float dy = y2 - y1; 
  float d = sqrt( dx*dx + dy*dy ); 
  float ca = dx/d; // cosine
  float sa = dy/d; // sine 
  
  float mX = (-x1+x)*ca + (-y1+y)*sa; 
  
  if( mX <= 0 ){
    result.x = x1; 
    result.y = y1; 
  }
  else if( mX >= d ){
    result.x = x2; 
    result.y = y2; 
  }
  else{
    result.x = x1 + mX*ca; 
    result.y = y1 + mX*sa; 
  }
  
  dx = x - result.x; 
  dy = y - result.y; 
  result.z = sqrt( dx*dx + dy*dy ); 
  
  return result;   
}

let’s say we use the figure from wikipedia
image

this code (I flipped inside the parenthesis)

  float mX = (x-x1)*ca + (y-y1)*sa; 

is a dot product of (x-x1, y-y1) and (ca, sa). The former is a vector from (x1, y1) to (x, y), corresponding to a in the figure. The latter is a vector from (x1, y1) to (x2, y2) but normalized (as divided by d): b in the figure. The dot product can be thought as a projection, and since (ca, sa) is normalized and is a unit vector, the result mX is the length of (x-x1, y-y1) or a projected on b (in the figure, mX corresponds to the length of a1).

4 Likes

Thanks for the reply. Yes, I understand I miss some basic linear algebra, I’ll try to check out a book.

Still, I miss to see how it is that you may define result.x = x1 + (-x1+x)*ca + (-y1+y)*sa)*ca. Where does it come from?

I appreciate your help

again (-x1+x)*ca + (-y1+y)*sa is the dot product explained above. Say the dot product is a, then x = x1 + a * ca is basically moving from the point (x, y) along the line… but I guess you should look for some material instead of someone explaining this here… I studied math in Japan so I don’t know any good material in English but if anyone suggestions that would be great.

Yes, you are correct. Need some spare time.

the initial link doesn’t work

here is link

and Sketch (from link)



//https://forum.processing.org/beta/num_1276644884.html


// press space to reset
// click for randomness
// drag to move

Line myLine;

void setup() {
  size( 600, 600 );
  smooth();
  textFont( createFont( "SansSerif-12.vlw", 12 ) );

  myLine = new Line( width/2 - 100, height/2, width/2 + 100, height/2 );
}


void draw() {
  background( 0 );

  stroke( 255 );
  myLine.draw();

  fill( 255, 255, 0 );
  noStroke();
  ellipse( mouseX, mouseY, 10, 10 );

  PVector result = myLine.getDistance( mouseX, mouseY );
  stroke( 150 );
  line( mouseX, mouseY, result.x, result.y );

  fill( 255 );
  text( "The distance to the line is: " + result.z, 10, 10 );
}


void mousePressed() {
  myLine.x1 = 100+random(width-200);
  myLine.y1 = 100+random(height-200);
  myLine.update();
}

void mouseDragged() {
  myLine.x1 = mouseX;
  myLine.y1 = mouseY;
  myLine.update();
}

void keyPressed() {
  myLine.x1 = width/2-100;
  myLine.y1 = height/2;
  myLine.update();
}

//////////////////////////////////////////////

class Line {
  // where does the line start/end?
  public float x1, x2, y1, y2;

  // some happy math variables
  private float dx, dy, d, ca, sa, mx, dx2, dy2;

  // we use this to store the result,
  // so if you want to store the result and calculate again
  // you should do
  // PVector mine = new PVector();
  // mine.set( line.getDistance( mouseX, mouseY ) );
  private PVector result;

  public Line( float x1, float y1, float x2, float y2 ) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    result = new PVector();
    update();
  }

  /**
   * Call this after changing the coordinates!!!
   */
  public void update() {
    dx = x2 - x1;
    dy = y2 - y1;
    d = sqrt( dx*dx + dy*dy );
    ca = dx/d; // cosine
    sa = dy/d; // sine
  }

  /**
   * Returns a point on this line
   * that is closest to the point (x,y)
   *
   * The result is a PVector.
   * result.x and result.y are points on the line.
   * The result.z variable contains the distance from (x,y) to the line, just in case you need it :)
   */
  PVector getDistance( float x, float y ) {
    mx = (-x1+x)*ca + (-y1+y)*sa;

    if ( mx <= 0 ) {
      result.x = x1;
      result.y = y1;
    } else if ( mx >= d ) {
      result.x = x2;
      result.y = y2;
    } else {
      result.x = x1 + mx*ca;
      result.y = y1 + mx*sa;
    }

    dx2 = x - result.x;
    dy2 = y - result.y;
    result.z = sqrt( dx2*dx2 + dy2*dy2 );

    return result;
  }

  /**
   * Draw it!
   */
  public void draw() {
    line( x1, y1, x2, y2 );
  }
}