/*
* $Id: line_dist.c,v 1.8 2003/09/11 16:12:48 markus Exp $
*
****************************************************************************
*
* MODULE:       Vector library 
*   	    	
* AUTHOR(S):    Original author CERL, probably Dave Gerdes.
*               Update to GRASS 5.7 Radim Blazek.
*
* PURPOSE:      Lower level functions for reading/writing/manipulating vectors.
*
* COPYRIGHT:    (C) 2001 by the GRASS Development Team
*
*               This program is free software under the GNU General Public
*   	    	License (>=v2). Read the file COPYING that comes with GRASS
*   	    	for details.
*
*****************************************************************************/
#include    <math.h>

#define ZERO(x) ((x) < tolerance && (x) > -tolerance)
#define TOLERANCE 1.0e-10
static double tolerance = TOLERANCE;

int 
dig_set_distance_to_line_tolerance (double t)
{
  if (t <= 0.0)
    t = TOLERANCE;
  tolerance = t;

  return 0;
}

/*
*   dig_distance2_point_to_line ()
*   compute square of distance of point (x,y) to line segment (x1,y1 - x2,y2)
*   ( works correctly for  x1==x2 && y1==y2 )
*
*   returns: square distance
*   sets (if not NULL): *px, *py - nearest point on segment
*                       *pdist - distance of px,py from segment start
*                       *status = 0 if ok, -1 if t < 0  and 1 if t > 1
*                                 (tells if point is w/in segment space, or past ends)
*/

double 
dig_distance2_point_to_line ( 
	double x, double y, double z,       /* point */
	double x1, double y1, double z1,    /* line segment */
	double x2, double y2, double z2,	
	int with_z, /* use z coordinate, (3D calculation) */ 
	double *px, double *py, double *pz, /* point on segment */
	double *pdist, /* distance of point on segment from the first point of segment */
        int *status)
{
    register double dx, dy, dz;
    register double dpx, dpy, dpz;
    register double tpx, tpy, tpz;
    double t;
    int    st;

    st = 0;

    if ( !with_z ) {
       z = 0;
       z1 = 0;
       z2 = 0;
    }       
    
    dx = x2 - x1;
    dy = y2 - y1;
    dz = z2 - z1;

    if (ZERO (dx) && ZERO (dy) && ZERO (dz) )	{ /* line is degenerate */
      dx = x1 - x;
      dy = y1 - y;
      dz = z1 - z;
      tpx = x1;
      tpy = y1;
      tpz = z1;
    } else {
	t = (dx * (x - x1) + dy * (y - y1) + dz * (z - z1)) / (dx * dx + dy * dy + dz * dz);

	if (t < 0.0) {			/* go to x1,y1,z1 */
	    t = 0.0;
	    st = -1;
	} else if (t > 1.0) {		/* go to x2,y2,z2 */
	    t = 1.0;
	    st = 1;
	}
    
	/* go t from x1,y1,z1 towards x2,y2,z2 */
	tpx = dx * t + x1;
	tpy = dy * t + y1;
	tpz = dz * t + z1;
	dx = tpx - x;
	dy = tpy - y;
	dz = tpz - z;
    }

    if ( px ) *px = tpx;
    if ( py ) *py = tpy;
    if ( pz ) *pz = tpz;
    if ( status ) *status = st;

    if ( pdist ) {
	dpx = tpx - x1;
	dpy = tpy - y1;
	dpz = tpz - z1;
	*pdist = sqrt ( dpx * dpx + dpy * dpy + dpz * dpz ); 
    }
   
    return (dx * dx + dy * dy + dz * dz);
}

