subroutine apttrip (px, py, pz, ax, ay, az, bx, by, bz,
     &                    cx, cy, cz, noptfd, tol,
     &                    dpmin, wa, wb, wc, qx, qy, qz,
     &                    nlima, nlimb, nlimc, itrun, nside, nerr)

ccbeg.
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c                             SUBROUTINE APTTRIP
c
c     call apttrip (px, py, pz, ax, ay, az, bx, by, bz,
c    &              cx, cy, cz, noptfd, tol,
c    &              dpmin, wa, wb, wc, qx, qy, qz,
c    &              nlima, nlimb, nlimc, itrun, nside, nerr)
c
c     Version:  apttrip  Updated    1990 October 23 15:30.
c               apttrip  Originated 1989 November 2 14:10.
c
c     Author:   Arthur L. Edwards, LLNL, L-298, Telephone (925) 422-4123.
c
c
c     Purpose:  To find the distance dpmin from a point p = (px, py, pz)
c               to a plane defined by the three points a = (ax, ay, az),
c               b = (bx, by, bz), and c = (cx, cy, cz), and the point
c               q = (qx, qy, qz) nearest to point p, and in the plane,
c               subject to constraints that may be imposed by option noptfd
c               and the value of tol.
c
c               Optionally, to find the fractional distances wa, wb and wc
c               of point "q" along the triangle's altitudes:
c
c                 q = wa * a + wb * b + wc * c.
c
c               Flags nlima, nlimb, nlimc indicate when wa, wb and wc have been
c               restrained.  Flag itrun indicates when dpmin has been truncated
c               to zero.  Flag nside indicates when the minimum point is inside
c               the triangle.  Flag nerr indicates any input error.
c
c     Input:    px, py, pz, ax, ay, az, bx, by, bz, cx, cy, cz, noptfd, tol.
c
c     Output:   dpmin, wa, wb, wc, qx, qy, qz,
c               nlima, nlimb, nlimc, itrun, nside, nerr.
c
c     Calls: aptfdad, aptptln, aptvdis, aptvpln 
c               
c
c     Glossary:
c
c     ax,ay,az  Input    The x, y, z coordinates of point "a".
c
c     bx,by,bz  Input    The x, y, z coordinates of point "b".
c
c     cx,cy,cz  Input    The x, y, z coordinates of point "c".
c
c     dpmin     Output   Distance from point "p" to the nearest (constrained)
c                          point in the plane defined by points "a", "b", "c".
c                          a value less than the estimated error in its
c                          calculation is truncated to zero (itrun = 1).
c                          dpmin is positive when the external point is on the
c                          side of the plane for which the three points are in
c                          counterclockwise order.  See noptfd.
c
c     itrun     Output   0 if no change is made in the calculated value of
c                          dpmin, 1 if dpmin is changed to zero, when less than
c                          the estimated error in its calculation.
c
c     nerr      Output   Indicates an input error, if not 0.
c                          1 is added if noptfd is not between 0 and 2.
c                          2 is added if 3 points representing triangle are
c                          colinear or congruent.
c
c     nlima     Output   0 if no limit imposed on wa, 1 if the limit of
c                          noptfd = 1 is imposed, 2 if the limit of noptfd = 2
c                          is imposed.
c
c     nlimb,c   Output   Like nlima, but for wb, wc, respectively.
c
c     noptfd    Input    Option to limit range of wa, wb, wc:
c                          -1 for no limit, no calculation of wa, wb, wc,
c                           0 for no limit,
c                           1 to increase to tol, if in the range from -tol
c                             to tol, and decrease to 1.0 - tol, if in the
c                             range from 1.0 - tol to 1.0 + tol (move a point
c                             near an edge slightly inside the triangle), and
c                           2 to limit to the range from 0.0 to 1.0 (move a
c                             point outside the triangle to an edge).
c
c     nside     Output   0 if minimum point outside the triangle, 1 if inside.
c                          0 if moved to edge, when noptfd = 2.
c
c     px,py,pz  Input    The x, y, z coordinates of point "p".
c
c     qx,qy,qz  Output   The x, y, z coordinate of the point in the plane
c                          nearest point "p".  May be constrained by option
c                          noptfd.
c
c     tol       Input    Numerical tolerance limit for dpmin, wa, wb, wc.
c                          On Cray computers, recommend 1.e-5 to 1.e-11.
c
c     wa        Output   Fractional distance of point "q"
c                          from edge "bc" to vertex "a".
c
c     wb        Output   Fractional distance of point "q"
c                          from edge "ca" to vertex "b".
c
c     wc        Output   Fractional distance of point "q"
c                          from edge "ab" to vertex "c".
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
ccend.

c.... Dimensioned arguments.

c.... (None.)

c.... Local variables.

c---- A very big number.
      common /lapttrip/ big

c---- Is dpmin after moving wa, wb, wc.
      common /lapttrip/ dpminx
c---- Is dpmin after moving wa.
      common /lapttrip/ dpmina
c---- Is dpmin after moving wb.
      common /lapttrip/ dpminb
c---- Is dpmin after moving wc.
      common /lapttrip/ dpminc
c---- Sign of dpmin.
      common /lapttrip/ dpsign
c---- Is qx - px.
      common /lapttrip/ dx
c---- Is qy - py.
      common /lapttrip/ dy
c---- Is qz - pz.
      common /lapttrip/ dz
c---- Fractional distance of p along edge.
      common /lapttrip/ fds
c---- Component of vector "ap" along vn.
      common /lapttrip/ fract
c---- 2 if point moved to end of edge.
      common /lapttrip/ nlim
c---- Is qx after moving wa.
      common /lapttrip/ qxa
c---- Is qx after moving wb.
      common /lapttrip/ qxb
c---- Is qx after moving wc.
      common /lapttrip/ qxc
c---- Is qy after moving wa.
      common /lapttrip/ qya
c---- Is qy after moving wb.
      common /lapttrip/ qyb
c---- Is qy after moving wc.
      common /lapttrip/ qyc
c---- Is qz after moving wa.
      common /lapttrip/ qza
c---- Is qz after moving wb.
      common /lapttrip/ qzb
c---- Is qz after moving wc.
      common /lapttrip/ qzc
c---- Sum wa + wb + wc.
      common /lapttrip/ sum
c---- Magnitude of normal vector.
      common /lapttrip/ vlen
c---- Square of length of normal vector.
      common /lapttrip/ vnsq
c---- Component x of normal vector.
      common /lapttrip/ vnx
c---- Component y of normal vector.
      common /lapttrip/ vny
c---- Component z of normal vector.
      common /lapttrip/ vnz
cbugc***DEBUG begins.
cbug 9900 format (/ 'apttrip finding distance from triangle',
cbug     &  ' through points:' /
cbug     &  '  ax,ay,az=',1p3e22.14 /
cbug     &  '  bx,by,bz=',1p3e22.14 /
cbug     &  '  cx,cy,cz=',1p3e22.14 /
cbug     &  '  to point:' /
cbug     &  '  px,py,pz=',1p3e22.14)
cbug      write ( 3, 9900) ax, ay, az, bx, by, bz, cx, cy, cz,
cbug     &  px, py, pz
cbugc***DEBUG ends.

c.... Initialize.

c---- A very big number.
      big = 1.e+99

      itrun = 0
      nerr  = 0
      nlima = 0
      nlimb = 0
      nlimc = 0
      nside = 0

c.... Test for input errors.

c++++ Bad input.
      if ((noptfd .lt. -1) .or. (noptfd .gt. 2)) then
        nerr = nerr + 1
      endif

c.... Find the components of the normal vector, which is upward from the
c....   side of the plane for which points (a, b, c) are counterclockwise.

      call aptvpln (ax, ay, az, bx, by, bz, cx, cy, cz, 1, tol,
     &              vnx, vny, vnz, vlen, nerr)

      vnsq = vlen**2
cbugc***DEBUG begins.
cbug 9901 format (/ 'apttrip' /
cbug     &  'vnx=',1pe13.5,' vny=',1pe13.5,' vnz=',1pe13.5,' vlen=',1pe13.5)
cbug      write ( 3, 9901) vnx, vny, vnz, vlen
cbugc***DEBUG ends.

c---- Null triangle.
      if (vlen .le. tol) then
        nerr = nerr + 2
      endif

c---- An input error was found.
      if (nerr .ne. 0) go to 210

c.... Find the fractional distance along the normal vector from the
c....   plane to the external point.

      fract  = ((px - ax) * vnx + (py - ay) * vny +
     &          (pz - az) * vnz) / vnsq
      dpsign = sign (1.0, fract)

c.... Find the distance from the plane to (px, py, pz).

      dpmin = fract * vlen

      if (abs (fract) .lt. tol) then
        itrun = 1
        dpmin = 0.0
        fract = 0.0
      endif

c.... Find the point in the plane nearest to (px, py, pz).

      qx = px - fract * vnx
      qy = py - fract * vny
      qz = pz - fract * vnz
cbugc***DEBUG begins.
cbug 9902 format ('fract=',1pe13.5 /
cbug     &  '  initial qx=',1pe13.5,' qy=',1pe13.5,' qz=',1pe13.5 /
cbug     &  '  initial dpmin=',1pe22.14,' itrun=',i2)
cbug      write ( 3, 9902) fract, qx, qy, qz, dpmin, itrun
cbugc***DEBUG ends.

c.... See which option is specified for adjusting point "q".

      if (noptfd .eq. -1) go to 210

c.... Find the fractional distances of the point along the altitudes.

      wa = (((cy - by)*(qz - cz) - (cz - bz)*(qy - cy)) * vnx +
     &      ((cz - bz)*(qx - cx) - (cx - bx)*(qz - cz)) * vny +
     &      ((cx - bx)*(qy - cy) - (cy - by)*(qx - cx)) * vnz) /
     &     vnsq
      wb = (((ay - cy)*(qz - az) - (az - cz)*(qy - ay)) * vnx +
     &      ((az - cz)*(qx - ax) - (ax - cx)*(qz - az)) * vny +
     &      ((ax - cx)*(qy - ay) - (ay - cy)*(qx - ax)) * vnz) /
     &     vnsq
      wc = (((by - ay)*(qz - bz) - (bz - az)*(qy - by)) * vnx +
     &      ((bz - az)*(qx - bx) - (bx - ax)*(qz - bz)) * vny +
     &      ((bx - ax)*(qy - by) - (by - ay)*(qx - bx)) * vnz) /
     &     vnsq
cbugc***DEBUG begins.
cbug 9903 format (/ 'apttrip' /
cbug     &  'wa=',1pe13.5,' wb=',1pe13.5,' wc=',1pe13.5,
cbug     &  ' before adjusting' / 'sum=',1pe22.14)
cbug      sum = wa + wb + wc
cbug      write ( 3, 9903) wa, wb, wc, sum
cbugc***DEBUG ends.

c.... Adjust the fractional distances according to noptfd.

c---- No adjustment of wa, wb, wc.
      if (noptfd .eq. 0) then

        nside = 1

        if ((wa .lt. 0.0) .or. (wa .gt. 1.0)) then
          nside = 0
        endif

        if ((wb .lt. 0.0) .or. (wb .gt. 1.0)) then
          nside = 0
        endif

        if ((wc .lt. 0.0) .or. (wc .gt. 1.0)) then
          nside = 0
        endif

c---- Adjust points near triangle edges.
      elseif (noptfd .eq. 1) then

        nside = 1

        call aptfdad (wa, 1, tol, nlima, nerr)

        if ((wa .lt. tol) .or. (wa .gt. (1.0 - tol))) then
          nside = 0
        endif

        call aptfdad (wb, 1, tol, nlimb, nerr)

        if ((wb .lt. tol) .or. (wb .gt. (1.0 - tol))) then
          nside = 0
        endif

        call aptfdad (wc, 1, tol, nlimc, nerr)

        if ((wc .lt. tol) .or. (wc .gt. (1.0 - tol))) then
          nside = 0
        endif

c++++ Adjusted wa, wb, wc.
        if ((nlima + nlimb + nlimc) .gt. 0) then
cbugc***DEBUG begins.
cbug 9904 format (/ 'apttrip' /
cbug     &  'wa=',1pe13.5,' wb=',1pe13.5,' wc=',1pe13.5,' after  adjusting')
cbug      write ( 3, 9904) wa, wb, wc
cbugc***DEBUG ends.

c....     Renormalize wa, wb, wc.

          sum = wa + wb + wc
          wa  = wa / sum
          wb  = wb / sum
          wc  = wc / sum

c....     Recalculate point "q".

          qx = wa * ax + wb * bx + wc * cx
          qy = wa * ay + wb * by + wc * cy
          qz = wa * az + wb * bz + wc * cz

c....     Recalculate dpmin, with correct sign.

          call aptvdis (px, py, pz, qx, qy, qz, 1, tol,
     &                  dx, dy, dz, dpmin, itrun)

          dpmin = dpsign * dpmin
cbugc***DEBUG begins.
cbug 9905 format (/ 'apttrip' /
cbug     &  'wa=',1pe13.5,' wb=',1pe13.5,' wc=',1pe13.5,
cbug     &  ' after  sum = 1.0' /
cbug     &  10x,'qx=',1pe13.5,' qy=',1pe13.5,' qz=',1pe13.5 /
cbug     &  9x,'dpmin=',1pe13.5)
cbug      write ( 3, 9905) wa, wb, wc, qx, qy, qz, dpmin
cbugc***DEBUG ends.
c---- Adjusted wa, wb, wc.
        endif

c---- Move outside point to nearest edge.
      elseif (noptfd .eq. 2) then

        dpminx = big

c---- Impose limit 0.0 .le. wa .le. 1.0.
        if (wa .lt. 0.0) then

          nlima = 2
          call aptptln (px, py, pz, bx, by, bz, cx, cy, cz, 1, tol,
     &                  noptfd, dpmina, fds, qxa, qya, qza,
     &                  nlim, itrun, nerr)

          if (dpmina .lt. dpminx) then
            dpminx = dpmina
            qx     = qxa
            qy     = qya
            qz     = qza
          endif
cbugc***DEBUG begins.
cbug 9906 format (/ 'apttrip' /
cbug     &  '  new wa.  qx=',1pe13.5,' qy=',1pe13.5,' qz=',1pe13.5 /
cbug     &  '  new dpmin=',1pe22.14)
cbug      write ( 3, 9906) qxa, qya, qza, dpmina
cbugc***DEBUG ends.

c---- Imposed limit on wa.
        endif

c---- Impose limit 0.0 .le. wb .le. 1.0.
        if (wb .lt. 0.0) then

          nlimb = 2
          call aptptln (px, py, pz, ax, ay, az, cx, cy, cz, 1, tol,
     &                  noptfd, dpminb, fds, qxb, qyb, qzb,
     &                  nlim, itrun, nerr)

          if (dpminb .lt. dpminx) then
            dpminx = dpminb
            qx     = qxb
            qy     = qyb
            qz     = qzb
          endif
cbugc***DEBUG begins.
cbug 9907 format (/ 'apttrip' /
cbug     &  '  new wb.  qx=',1pe13.5,' qy=',1pe13.5,' qz=',1pe13.5 /
cbug     &  '  new dpmin=',1pe22.14)
cbug      write ( 3, 9907) qxb, qyb, qzb, dpminb
cbugc***DEBUG ends.

c---- Imposed limit on wb.
        endif

c---- Impose limit 0.0 .le. wc .le. 1.0.
        if (wc .lt. 0.0) then

          nlimc = 2
          call aptptln (px, py, pz, ax, ay, az, bx, by, bz, 1, tol,
     &                  noptfd, dpminc, fds, qxc, qyc, qzc,
     &                  nlim, itrun, nerr)

          if (dpminc .lt. dpminx) then
            dpminx = dpminc
            qx     = qxc
            qy     = qyc
            qz     = qzc
          endif
cbugc***DEBUG begins.
cbug 9908 format (/ 'apttrip' /
cbug     &  '  new wc.  qx=',1pe13.5,' qy=',1pe13.5,' qz=',1pe13.5 /
cbug     &  '  new dpmin=',1pe22.14)
cbug      write ( 3, 9908) qxc, qyc, qzc, dpminc
cbugc***DEBUG ends.

c---- Imposed limit on wc.
        endif

c....   Recalculate wa, wb, wc if nearest point moved to a triangle edge.
c....     Adjust as necessary to reduce truncation error.

        nside = 1

c++++ Recalculate wa, wb, wc.
        if ((nlima + nlimb + nlimc) .gt. 0) then

          nside = 0

          wa = (((cy - by)*(qz - cz) - (cz - bz)*(qy - cy)) * vnx +
     &          ((cz - bz)*(qx - cx) - (cx - bx)*(qz - cz)) * vny +
     &          ((cx - bx)*(qy - cy) - (cy - by)*(qx - cx)) * vnz)/
     &         vnsq
          if (wa .lt. tol) wa = 0.0

          wb = (((ay - cy)*(qz - az) - (az - cz)*(qy - ay)) * vnx +
     &          ((az - cz)*(qx - ax) - (ax - cx)*(qz - az)) * vny +
     &          ((ax - cx)*(qy - ay) - (ay - cy)*(qx - ax)) * vnz)/
     &         vnsq
          if (wb .lt. tol) wb = 0.0

          wc = (((by - ay)*(qz - bz) - (bz - az)*(qy - by)) * vnx +
     &          ((bz - az)*(qx - bx) - (bx - ax)*(qz - bz)) * vny +
     &          ((bx - ax)*(qy - by) - (by - ay)*(qx - bx)) * vnz)/
     &         vnsq
          if (wc .lt. tol) wc = 0.0

c....     Renormalize wa, wb, wc.

          sum = wa + wb + wc
          wa  = wa / sum
          wb  = wb / sum
          wc  = wc / sum

c....     Recalculate point "q".

          qx = wa * ax + wb * bx + wc * cx
          qy = wa * ay + wb * by + wc * cy
          qz = wa * az + wb * bz + wc * cz

c....     Recalculate dpmin, with correct sign.

          call aptvdis (px, py, pz, qx, qy, qz, 1, tol,
     &                  dx, dy, dz, dpmin, itrun)

          dpmin = dpsign * dpmin
cbugc***DEBUG begins.
cbug 9909 format (/ 'apttrip' /
cbug     &  'wa=',1pe13.5,' wb=',1pe13.5,' wc=',1pe13.5,' after  moving')
cbug 9910 format (6x,'new qx=',1pe13.5,' qy=',1pe13.5,' qz=',1pe13.5 /
cbug     &  '  new dpmin=',1pe22.14)
cbug      write ( 3, 9909) wa, wb, wc
cbug      write ( 3, 9910) qx, qy, qz, dpmin
cbugc***DEBUG ends.

c---- Recalculated wa, wb, wc.
        endif

c---- Noptfd options.
      endif

  210 return

c.... End of subroutine apttrip.      (+1 line.)
      end

UCRL-WEB-209832