/*
 * MLGEOM.C - geometry routines for PML
 *
 * Source Version: 2.0
 * Software Release #92-0043
 *
 */

#include "cpyright.h"

#include "pml.h"

#define INSERT_POINT(_i, _ln, _lx, _d, _n)                                  \
    {int _l;                                                                \
     _lx++;                                                                 \
     if (_n >= _lx)                                                         \
        {_n += 10;                                                          \
	 REMAKE_N(_d, int, _n);};                                           \
     for (_l = _lx-1; _l > _ln; _l--)                                       \
         _d[_l] = _d[_l-1];                                                 \
     _d[_l] = _i;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PM_CROSS - test for the intersection of lines or parts of lines
 *           - LINEx has value 0, 1, 2 for segment, ray, or line
 *           - the lines are defined by the vectors: X1 and X2
 *           - and vectors: X3 and X4
 *           - for rays X1 and X3 are the terminations of the ray
 *           - (i.e. tail of vector)
 *           - and X2 and X4 are X1 - dXa and X3 - dXb (dXa and dXb define
 *           - the direction of the rays)
 *           - here vectors are defined as X = (x, y)
 *           -
 *           - the algorithm is as follows:
 *           -
 *           - (1) X1 + (X2-X1)t = X3 + (X4-X3)s   is the equation for the
 *           -                                     intersection
 *           -
 *           - if 0 <= t <= 1 and  0 <= s <= 1 then the segments intersect
 *           - the determinant of these two equations is
 *           - d = (X1-X2)x(X3-X4)
 *           -
 *           - if d = 0 then the lines are parallel and further tests
 *           - are:
 *           -
 *           - if the following condition is true:
 *           -
 *           - (2) (X2-X1)x(X3-X1) # 0
 *           -
 *           - then the lines do not intersect
 *           - otherwise, the intersection is the point given by the
 *           - smallest positive value for either t1 and t2 less than
 *           - unity. t1 and t2 satify the following:
 *           -
 *           - (3) X3 + (X4-X3)t1 = X1   and    X3 + (X4-X3)t2 = X2
 */

static int _PM_cross(x1, y1, x2, y2, x3, y3, x4, y4,
		     px0, py0, line1, line2)
   double x1, y1, x2, y2, x3, y3, x4, y4, *px0, *py0;
   int line1, line2;
   {int cross_flag;
    double a, b, dx21, dy21, dx43, dy43, dx13, dy13, idx, idy;
    double d, t1, t2;

/* assume they don't intersect */
    cross_flag = FALSE;

    t1 = -HUGE;
    t2 = -HUGE;

/* start far away */
    *px0 = HUGE;
    *py0 = HUGE;

    dx21 = x2 - x1;
    dy21 = y2 - y1;
    dx43 = x4 - x3;
    dy43 = y4 - y3;
    dx13 = x1 - x3;
    dy13 = y1 - y3;

/* find determinant for equation (1) */
    a = dx21*dy43;
    b = dy21*dx43;

/* check for parallel lines (i.e. d = 0 or a = b) */
    if (PM_CLOSETO_REL(a, b))

/* check the cross product (2) (i.e. cp = 0 or a = b) */
       {a = dx13*dy21;
	b = dx21*dy13;
	if (PM_CLOSETO_REL(a, b))

/* compute and test t1 and t2 */
           {if (x2 == x1)
               {idy = 1.0/dy43;
		t1  = dy13*idy;
                t2  = (y2 - y3)*idy;}
            else
               {idx = 1.0/dx43;
		t1  = dx13*idx;
                t2  = (x2 - x3)*idx;};

	    *px0 = x3 + dx43*min(t1, t2);
	    *py0 = y3 + dy43*min(t1, t2);}}

/* compute the point of intersection of the segment and ray */
    else
       {d  = 1.0/(a - b);
        t1 = (dy13*dx43 - dx13*dy43)*d;
        t2 = (dy13*dx21 - dx13*dy21)*d;

	*px0 = x1 + dx21*t1;
	*py0 = y1 + dy21*t1;};

    switch (line1)
       {case 0 :
	     switch (line2)
	         {case 0 :
		       cross_flag = ((-TOLERANCE <= t1) &&
				     (t1 <= 1.0000000001) &&
				     (-TOLERANCE <= t2) &&
				     (t2 <= 1.0000000001));
		       break;
		  case 1 :
		       cross_flag = ((-TOLERANCE <= t1) &&
				     (t1 <= 1.0000000001) &&
				     (-TOLERANCE <= t2));
		       break;
		  case 2 :
		       cross_flag = ((-TOLERANCE <= t1) &&
				     (t1 <= 1.0000000001));
		       break;};
	     break;
	case 1 :
	     switch (line2)
	        {case 0 :
		      cross_flag = ((-TOLERANCE <= t1) &&
				    (-TOLERANCE <= t2) &&
					(t2 <= 1.0000000001));
		      break;
		 case 1 :
		      cross_flag = ((-TOLERANCE <= t1) &&
				    (-TOLERANCE <= t2));
		      break;
		 case 2 :
		      cross_flag = (-TOLERANCE <= t1);
		      break;};
	     break;
        case 2 :
	     switch (line2)
	        {case 0 :
		      cross_flag = ((-TOLERANCE <= t2) &&
				    (t2 <= 1.0000000001));
		      break;
		 case 1 :
		      cross_flag = (-TOLERANCE <= t2);
		      break;
		 case 2 :
		      cross_flag = TRUE;
		      break;};
	     break;};

    return(cross_flag);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
#if 0
/* PM_CROSS - this function tests for the intersection of a line segment
 *          - defined by the vectors: X1 and X2, and a ray defined by the
 *          - vectors: X3 and X4
 *          - where X3 is the termination of the ray (i.e. head of vector)
 *          - and X4 is X3 - dX (dX defines the direction of the ray)
 *          - here vectors are defined as X = (x, y)
 *          -
 *          - the algorithm is as follows:
 *          -
 *          - (1) X1 + (X2-X1)t = X3 + (X4-X3)s   is the equation for the
 *          -                                     intersection
 *          -
 *          - if 0 <= t <= 1 and  0 <= s then the segment intersects the ray
 *          - the determinant of these two equations is d = (X1-X2)x(X3-X4)
 *          -
 *          - if d = 0 then the lines are parallel and further tests
 *          - are:
 *          -
 *          - if the following condition is true:
 *          -
 *          - (2) (X2-X1)x(X3-X1) # 0
 *          -
 *          - then the lines do not intersect at all,
 *          - otherwise, the intersection is the point given by the smallest
 *          - positive value for either t1 and t2.  If both are negative then
 *          - the ray does NOT intersect the segment. t1 and t2 satify the
 *          - following:
 *          -
 *          - (3) X3 + (X4-X3)t1 = X1   and    X3 + (X4-X3)t2 = X2
 */

int PM_cross(x1, y1, x2, y2, x3, y3, x4, y4, px0, py0)
   double x1, y1, x2, y2, x3, y3, x4, y4, *px0, *py0;
   {int cross_flag;
    double d, dx43, dy43, cp, t1, t2;

/* assume they don't intersect */
    cross_flag = FALSE;

/* start far away */
    *px0 = HUGE;
    *py0 = HUGE;

    dx43 = x4 - x3;
    dy43 = y4 - y3;

/* find determinant for equation (1) */
    d = (x2 - x1)*dy43 - (y2 - y1)*dx43;

/* check for parallel lines (i.e. d = 0) */
    if (d == 0.0)

/* compute the cross product (2) */
       {cp = PM_DELTA_CROSS_2D(x1, y1, x2, y2, x3, y3);
        if (cp == 0.0)

/* compute and test t1 and t2 */
           {if (x2 == x1)
               {t1 = (y1 - y3)/dy43;
                t2 = (y2 - y3)/dy43;}
            else
               {t1 = (x1 - x3)/dx43;
                t2 = (x2 - x3)/dx43;};

	    if ((t1 >= -TOLERANCE) && (t2 >= -TOLERANCE))
	       {cross_flag = TRUE;
		*px0 = x3 + dx43*min(t1, t2);
		*py0 = y3 + dy43*min(t1, t2);}
	    else if ((t1 >= -TOLERANCE) && (t2 < -TOLERANCE))
	       {cross_flag = TRUE;
		*px0 = x1;
		*py0 = y1;}
	    else if ((t1 < -TOLERANCE) && (t2 >= -TOLERANCE))
	       {cross_flag = TRUE;
		*px0 = x2;
		*py0 = y2;};};}

/* compute the point of intersection of the segment and ray */
    else
       {t1 = ((y1 - y3)*dx43 - (x1 - x3)*dy43)/d;
        t2 = ((y1 - y2)*(x1 - x3) - (x1 - x2)*(y1 - y3))/d;
        if ((-TOLERANCE <= t1) && (t1 <= 1.0000000001) &&
            (-TOLERANCE <= t2))
           {cross_flag = TRUE;
            *px0 = x1 + (x2 - x1)*t1;
            *py0 = y1 + (y2 - y1)*t1;};};

    return(cross_flag);}
#endif
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_CROSS - test for the intersection of a line segment and a ray */

int PM_cross(x1, y1, x2, y2, x3, y3, x4, y4, px0, py0)
   double x1, y1, x2, y2, x3, y3, x4, y4, *px0, *py0;
   {return(_PM_cross(x1, y1, x2, y2, x3, y3, x4, y4, px0, py0, 0, 1));}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_CROSS_SEG - test for the intersection of a two line segments */

int PM_cross_seg(x1, y1, x2, y2, x3, y3, x4, y4, px0, py0)
   double x1, y1, x2, y2, x3, y3, x4, y4, *px0, *py0;
   {return(_PM_cross(x1, y1, x2, y2, x3, y3, x4, y4, px0, py0, 0, 0));}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_CROSS_LINE_PLANE - test for the intersection of lines and a plane
 *                     - LINE has value 0, 1, 2 for segment, ray, or line
 *                     - the line is defined by the vectors: X1 and X2
 *                     - the plane is defined by the vectors: X3, X4, X5
 *                     - for rays X1 is the terminations of the ray
 *                     - (i.e. tail of vector)
 *                     - and X2 is X1 - dX (dX defines the direction of
 *                     - the ray)
 *                     - here vectors are defined as X = (x, y)
 *                     -
 *                     - the algorithm is as follows:
 *                     -
 *                     - (1) (X1 + t*(X2-X1) - X4).((X5-X4)x(X3-X4)) = 0
 *                     -     is the equation for the intersection
 *                     -     of a line and plane
 *                     -
 */

int PM_cross_line_plane(x1, y1, z1, x2, y2, z2, px, py, pz,
			px0, py0, pz0,
			line)
   double x1, y1, z1, x2, y2, z2;
   REAL *px, *py, *pz, *px0, *py0, *pz0;
   int line;
   {int cross_flag;
    double a, b, t;
    double nx, ny, nz;
    double x0, y0, z0;
    double dx54, dy54, dz54, dx34, dy34, dz34;
    double dx14, dy14, dz14, dx21, dy21, dz21;

/* assume they don't intersect */
    cross_flag = FALSE;

    dx54 = px[0] - px[1];
    dy54 = py[0] - py[1];
    dz54 = pz[0] - pz[1];

    dx34 = px[2] - px[1];
    dy34 = py[2] - py[1];
    dz34 = pz[2] - pz[1];

    dx14 = x1 - px[1];
    dy14 = y1 - py[1];
    dz14 = z1 - pz[1];

    dx21 = x2 - x1;
    dy21 = y2 - y1;
    dz21 = z2 - z1;

    nx = dy54*dz34 - dz54*dy34;
    ny = dz54*dx34 - dx54*dz34;
    nz = dx54*dy34 - dy54*dx34;

    a = dx21*nx + dy21*ny + dz21*nz;
    b = dx14*nx + dy14*ny + dz14*nz;
    t = (a == 0.0) ? HUGE : -b/a;

    if (t == HUGE)
       {x0 = HUGE;
	y0 = HUGE;
	z0 = HUGE;
        cross_flag = FALSE;}
    else
       {x0 = x1 + dx21*t;
	y0 = y1 + dy21*t;
	z0 = z1 + dz21*t;
        cross_flag = TRUE;};

    switch (line)
       {case 0 :
	     cross_flag &= ((-TOLERANCE <= t) && (t <= 1.0000000001));
	     break;
	case 1 :
	     cross_flag &= (-TOLERANCE <= t);
	     break;
        case 2 :
	     cross_flag &= TRUE;
	     break;};

    *px0 = x0;
    *py0 = y0;
    *pz0 = z0;

    return(cross_flag);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_CONVEX_HULL - create the polygon which is the convex hull of the
 *                - given set of points
 */

void PM_convex_hull(p1, p2, nh, ppx, ppy, pnp)
   REAL *p1, *p2;
   int nh;
   REAL **ppx, **ppy;
   int *pnp;
   {int i, i0, i1, i2, i3;
    int j, j0, j1, j2, j3;
    int np, nd, l, c1, c2, c3;
    int *di;
    REAL *px, *py;
    REAL x0, y0, x1, y1, x2, y2, x3, y3, xn, yn;

    nd = nh;
    di = FMAKE_N(int, nd, "PM_CONVEX_HULL:di");
    
    np    = 2;
    di[0] = 0;
    di[1] = 1;
    for (i = 0; i < nh; i++)

/* NOTE: 1->np crucial for getting the handedness right */
        {for (j = 1; j <= np; j++)
             {j0 = (j - 2 + np) % np;
              j1 = (j - 1 + np) % np;
              j2 = j % np;
              j3 = (j + 1) % np;

	      i0 = di[j0];
              i1 = di[j1];
              i2 = di[j2];
              i3 = di[j3];

              x0 = p1[i0];
              y0 = p2[i0];
              x1 = p1[i1];
              y1 = p2[i1];
              x2 = p1[i2];
              y2 = p2[i2];
              x3 = p1[i3];
              y3 = p2[i3];
              xn = p1[i];
              yn = p2[i];

              c1 = (PM_DELTA_CROSS_2D(x0, y0, x1, y1, xn, yn) < 0.0);
              c2 = (PM_DELTA_CROSS_2D(x1, y1, x2, y2, xn, yn) < 0.0);
              c3 = (PM_DELTA_CROSS_2D(x2, y2, x3, y3, xn, yn) < 0.0);

/* replace j1 by i and splice out j2 */
              if (c1 && c2 && c3)
                 {di[j1] = i;
                  for (l = j2; l < np; l++)
                      di[l] = di[l+1];
                  np--;}

/* replace j1 by i*/
              else if (c1 && c2)
		 di[j1] = i;

/* replace j2 by i*/
              else if (c2 && c3)
		 di[j2] = i;

/* insert the third point - crucial to get this right */
              else if ((np == 2) && (c1 || c3))
		 {INSERT_POINT(i, 0, np, di, nd);}

/* break the (j1,j2) segment and splice in the current point */
              else if (c2)
		 {INSERT_POINT(i, j, np, di, nd);};};};

    px = FMAKE_N(REAL, np+1, "PM_CONVEX_HULL:px");
    py = FMAKE_N(REAL, np+1, "PM_CONVEX_HULL:py");

/* copy the points to the output arrays */
    for (i = 0; i < np; i++)
        {j = di[i];
         px[i] = p1[j];
         py[i] = p2[j];};

    px[np] = px[0];
    py[np] = py[0];

    *ppx = px;
    *ppy = py;
    *pnp = np + 1;

    SFREE(di);

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_COLINEAR_2D - return TRUE iff the n points are colinear */

int PM_colinear_2d(px, py, n)
   REAL *px, *py;
   int n;
   {int i, col;
    int ifx0, ify0, ifxi0, ifyi0;
    double x1, y1, dx, dy, dxi, dyi;
    double rx, ry;

    x1 = px[0];
    y1 = py[0];

    dx = px[1] - x1;
    dy = py[1] - y1;

    ifx0  = (ABS(dx) < TOLERANCE);
    ify0  = (ABS(dy) < TOLERANCE);

    for (i = 2, col = TRUE; (i < n) && col; i++)
        {dxi = px[i] - x1;
         dyi = py[i] - y1;

	 ifxi0 = (ABS(dxi) < TOLERANCE);
	 ifyi0 = (ABS(dyi) < TOLERANCE);

         if ((ifx0 && ifxi0) || (ify0 && ifyi0))
	    col = TRUE;
         else
            {rx  = (ifx0 ? HUGE : dxi/dx);
             ry  = (ify0 ? HUGE : dyi/dy);
             col = PM_CLOSETO_REL(rx, ry);};};

    return(col);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_COLINEAR_3D - return TRUE iff the n points are colinear */

int PM_colinear_3d(px, py, pz, n)
   REAL *px, *py, *pz;
   int n;
   {int i, col;
    int ifx0, ify0, ifz0, ifxi0, ifyi0, ifzi0;
    double rx, ry, rz;
    double x1, y1, z1, dx, dy, dz, dxi, dyi, dzi;

    x1 = px[0];
    y1 = py[0];
    z1 = pz[0];

    if (PM_CLOSETO_REL(x1, px[1]))
       dx = 0.0;
    else
       dx = px[1] - x1;

    if (PM_CLOSETO_REL(y1, py[1]))
       dy = 0.0;
    else
       dy = py[1] - y1;

    if (PM_CLOSETO_REL(z1, pz[1]))
       dz = 0.0;
    else
       dz = pz[1] - z1;

    ifx0  = (ABS(dx) < TOLERANCE);
    ify0  = (ABS(dy) < TOLERANCE);
    ifz0  = (ABS(dz) < TOLERANCE);

    for (i = 2, col = TRUE; (i < n) && col; i++)
        {ifxi0 = PM_CLOSETO_REL(x1, px[i]);
	 dxi   = ifxi0 ? 0.0 : px[i] - x1;
	 rx    = ifx0 ? HUGE : dxi/dx;

         ifyi0 = PM_CLOSETO_REL(y1, py[i]);
         dyi   = ifyi0 ? 0.0 : py[i] - y1;
	 ry    = ify0 ? HUGE : dyi/dy;

         ifzi0 = PM_CLOSETO_REL(z1, pz[i]);
         dzi   = ifzi0 ? 0.0 : pz[i] - z1;
	 rz    = ifz0 ? HUGE : dzi/dz;

         if (ifx0 && ifxi0)
            {if ((ify0 && ifyi0) || (ifz0 && ifzi0))
	        col = TRUE;
             else
	        col = PM_CLOSETO_REL(ry, rz);}
         else if (ify0 && ifyi0)
	    {if (ifz0 && ifzi0)
	        col = TRUE;
             else
	        col = PM_CLOSETO_REL(rz, rx);}
         else if (ifz0 && ifzi0)
	    col = PM_CLOSETO_REL(rx, ry);
         else
	    col = PM_CLOSETO_REL(rx, ry) && PM_CLOSETO_REL(ry, rz);};

    return(col);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_CONTAINS_2D - check whether the point is contained in the polygon
 *                - return TRUE iff the point is on the boundary or in
 *                - the interior
 */

int PM_contains_2d(x, y, px, py, n)
   double x, y;
   REAL *px, *py;
   int n;
   {int i;

    for (i = 1; i < n; i++)
        if (PM_DELTA_CROSS_2D(px[i-1], py[i-1], px[i], py[i], x, y) < 0.0)
           return(FALSE);

    return(TRUE);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_CONTAINS_3D - check whether the point is contained in the triangle
 *                - if BND is TRUE return TRUE iff the point is in the
 *                - interior
 *                - otherwise return TRUE iff the point is on the boundary
 *                - or in the interior
 */

int PM_contains_3d(x, y, z, px, py, pz, bnd)
   double x, y, z;
   REAL *px, *py, *pz;
   int bnd;
   {int i, if1, if2, if3;
    double x1, y1, z1, x2, y2, z2;
    double dx1, dy1, dz1, dx2, dy2, dz2;
    double nx[3], ny[3], nz[3];
    double d1, d2, d3;

    x1 = px[2];
    y1 = py[2];
    z1 = pz[2];
    for (i = 0; i < 3; i++)
        {x2 = px[i];
	 y2 = py[i];
	 z2 = pz[i];

	 dx1 = x2 - x1;
	 dy1 = y2 - y1;
	 dz1 = z2 - z1;

         dx2 = x - x1;
         dy2 = y - y1;
         dz2 = z - z1;

         nx[i] = dy1*dz2 - dz1*dy2;
         ny[i] = dz1*dx2 - dx1*dz2;
         nz[i] = dx1*dy2 - dy1*dx2;

	 x1 = x2;
	 y1 = y2;
	 z1 = z2;};

    d1 = nx[0]*nx[1] + ny[0]*ny[1] + nz[0]*nz[1];
    d2 = nx[1]*nx[2] + ny[1]*ny[2] + nz[1]*nz[2];
    d3 = nx[2]*nx[0] + ny[2]*ny[0] + nz[2]*nz[0];

    if (bnd)
       {if1 = (d1 > -TOLERANCE);
	if2 = (d2 > -TOLERANCE);
	if3 = (d3 > -TOLERANCE);
	return(if1 && if2 && if3);}
    else
       {if1 = (d1 > TOLERANCE);
	if2 = (d2 > TOLERANCE);
	if3 = (d3 > TOLERANCE);
	return(if1 && if2 && if3);};}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_INTERSECT_LINE_POLYGON - compute the intersection points of the
 *                           - given line with the given polygon
 *                           - return the number of intersection points PIC
 *                           - actually does clip to polygon
 *                           - return FALSE if the line segment is completely
 *                           - outside the polygon
 */

int PM_intersect_line_polygon(pxmn, pymn, pxmx, pymx, ppx, ppy, np, pic)
   REAL *pxmn, *pymn, *pxmx, *pymx, *ppx, *ppy;
   int np, *pic;
   {int i, ic, p1, p2;
    double x0, y0, x1, x2, x3, x4, y1, y2, y3, y4;
    double xr1, xr2, yr1, yr2;

    x1  = *pxmn;
    y1  = *pymn;
    x2  = *pxmx;
    y2  = *pymx;

    xr1 = 0.0;
    yr1 = 0.0;
    xr2 = 0.0;
    yr2 = 0.0;

    ic  = 0;
    for (i = 1; i < np; i++)
        {x3 = ppx[i];
         y3 = ppy[i];
         x4 = ppx[i-1];
         y4 = ppy[i-1];
         if (PM_cross_seg(x1, y1, x2, y2, x3, y3, x4, y4, &x0, &y0))
            {if (ic == 0)
                {xr1 = x0;
                 yr1 = y0;}
             else
                {xr2 = x0;
                 yr2 = y0;};

	     ic++;};};

    *pic = ic;

    p1 = 0;
    p2 = 0;
    if (ic < 2)
       {p1 = PM_contains_2d(x1, y1, ppx, ppy, np);
        p2 = PM_contains_2d(x2, y2, ppx, ppy, np);
        if (ic == 1)
	   {if (p1)
	       {xr2 = x1;
                yr2 = y1;}
	    else
	       {xr2 = x2;
                yr2 = y2;};}

	else if (p1 && p2)
	   {xr1 = x1;
	    yr2 = y1;
	    xr2 = x2;
	    yr2 = y2;};};

/* order the points from left to right */
    if (xr1 < xr2)
       {*pxmn = xr1;
	*pxmx = xr2;
	*pymn = yr1;
	*pymx = yr2;}
    else
       {*pxmx = xr1;
	*pxmn = xr2;
	*pymx = yr1;
	*pymn = yr2;};

    return((ic > 1) || p1 || p2);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PM_NEAREST_POINT - find the point in an array of points neares
 *                  - a specified point
 */

void PM_nearest_point(px, py, n, xs, ys, pxt, pyt, pi)
   REAL *px, *py;
   int n;
   double xs, ys;
   REAL *pxt, *pyt;
   int *pi;
   {int i, indx;
    double s, smn, dx, dy;

    smn  = HUGE;
    indx = -1;
    for (i = 0; i < n; i++)
        {dx  = px[i] - xs;
         dy  = py[i] - ys;
         s   = HYPOT(dx, dy);
         smn = min(smn, s);
         if (s == smn)
            indx = i;};

    if (indx > -1)
       {*pi = indx;
        *pxt = px[indx];
        *pyt = py[indx];};

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
