subroutine aptqexc (qc, qu, qv, quv, quu, qvv, tol,
     &                    np, eu, ev, adir, nerr)

ccbeg.
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c                             SUBROUTINE APTQEXC
c
c     call aptqexc (qc, qu, qv, quv, quu, qvv, tol,
c                   np, eu, ev, adir, nerr)
c
c     Version:  aptqexc  Updated    1994 April 11 11:10.
c               aptqexc  Originated 1994 April 7 15:00
c
c     Author:   Arthur L. Edwards, LLNL, L-298, Telephone (925) 422-4123.
c
c
c     Purpose:  To find the coordinates (eu, ev), type adir, and number np, of
c               any points on a quadric curve in the uv plane with extreme
c               values of u or v, or at an intersection of two straight lines.
c               Up to four extreme points may exist.
c 
c               The implicit equation of the quadric curve is:
c
c                 f(u, v) = qc + qu  * u    + qv  * v     + quv * u * v +
c                                quu * u**2 + qvv * v**2  = 0  .
c
c               Results may be unpredictable if the coefficients differ by
c               many orders of magnitude.
c
c     Method:
c
c               The components of the normal vector to the curve, N, are the
c                 partial derivatives of f with respect to u and v:
c
c                 N = (df/du, df/dv)                      (partial derivatives)
c                 fu = df/du = qu + quv * v + 2 * quu * u (partial derivative)
c                 fv = df/dv = qv + quv * u + 2 * qvv * v (partial derivative)
c
c               The complete first derivatives, u' and v', are:
c
c                 u' = du/dv = -fv / fu
c                 v' = dv/du = -fu / fv
c
c               From zero to two extreme values of u occur where fv = 0, fu is
c               not zero, and u' = 0.  The extreme value is a minimum if u'' is
c               positive, and a maximum if u'' is negative at the extreme point:
c
c                  u'' = d(u')/dv =  -2.0 * qvv / fu, when u' = 0.
c
c               From zero to two extreme values of v occur where fu = 0, fv is
c               not zero, and v' = 0.  The extreme value is a minimum if v'' is
c               positive, and a maximum if v'' is negative at the extreme point:
c
c                  v'' = d(v')/du =  -2.0 * quu / fv, when v' = 0.
c
c               An intersection of two straight lines occurs where fu = fv = 0.
c
c               General cases:
c
c               Null curves (all coefficients zero):  no extreme points.
c               Skew straight lines (simple, coincident or parallel):
c                 no extreme points.
c               Horizontal straight lines (simple or coincident):
c                 one constant value of v.
c               Horizontal parallel lines:  minimum and maximum values of v.
c               Vertical straight lines (simple or coincident):
c                 one constant value of u.
c               Vertical parallel lines:  minimum and maximum values of u.
c               Intersecting straight lines:  one intersection point.
c               Hyperbolas: zero, one or two extreme points.  With two extreme
c                 points, the minimum of one curve will be larger than the
c                 maximum of the other curve.
c               Parabolas:  one extreme point if aligned with an axis, and two
c                 extreme points (one u, one v), if not.
c               Circles or ellipses:  four extreme points (two u, two v).
c
c     Input:    qc, qu, qv, quv, quu, qvv, tol.
c
c     Output:   np, eu, ev, adir, nerr.
c
c     Calls: aptqrts 
c
c     Glossary:
c
c     adir      Output   The type of extreme point:
c                          Minima:  "umin" or "vmin".
c                          Maxima:  "umax" or "vmax".
c                          Horizontal or vertical lines:  "ucon" or "vcon".
c                          Intersection of two straight lines:
c                            "uint" or "vint".
c                          If none, return "unknown".
c                          Size = 4.
c
c     eu, ev    Output   The u and v coordinates of an extreme point or an
c                          intersection of two straight lines.
c                          If none, return (-1.e99,-1.e99).
c                          Size = 4.
c
c     nerr      Output   Indicates an input error, if not zero:
c                          1 if all coefficients, except possible qc, are zero.
c
c     np        Output   Number of extreme or intersection points found.
c
c     qc        In       Constant term in the equation of the quadric curve.
c
c     qu,qv     In       Coefficients of u and v, respectively, in the equation
c                          of the quadric curve.
c
c     qxx       In       Coefficient of x**2 in the equation of the quadric
c                          curve.
c
c     qxy       In       Coefficient of x * y in the equation of the quadric
c                          curve.
c
c     qyy       In       Coefficient of y**2 in the equation of the quadric
c                          curve.
c
c     tol       Input    Numerical tolerance limit.
c                          On Cray computers, recommend 1.e-11.
c                          On 32-bit computers, recommend 1.e-6.
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
ccend.

c.... Dimensioned arguments.

      dimension eu(4)                 ! Coordinate u of extreme point.
      dimension ev(4)                 ! Coordinate v of extreme point.
      dimension adir(4)               ! Normal direction of extreme point.
      character*8 adir                ! Normal direction of extreme point.

c.... Local variables.

cbugc***DEBUG begins.
cbug 9901 format (/ 'aptqexc finding the extrema of quadric curve.' /
cbug     &  '  tol=',1pe13.5 )
cbug 9902 format (
cbug     &  '  qc=         ',1pe22.14 /
cbug     &  '  qu, qv=     ',1p2e22.14 /
cbug     &  '  quv=        ',1pe22.14 /
cbug     &  '  quu, qvv=   ',1p2e22.14)
cbug      write ( 3, 9901) tol
cbug      write ( 3, 9902) qc, qu, qv, quv, quu, qvv
cbugc***DEBUG ends.

c.... Initialize.

      nerr  = 0
      np    = 0
      do 110 n = 1, 4
        eu(n)   = -1.e99
        ev(n)   = -1.e99
        adir(n) = 'unknown'
  110 continue

c.... Test for input errors.

      if ((qu  .eq. 0.0)  .and.
     &    (qv  .eq. 0.0)  .and.
     &    (quv .eq. 0.0)  .and.
     &    (quu .eq. 0.0)  .and.
     &    (qvv .eq. 0.0)) then
        nerr = 1
        go to 210
      endif

c.... Test for simple straight lines.

      if ((quv .eq. 0.0)  .and.
     &    (quu .eq. 0.0)  .and.
     &    (qvv .eq. 0.0)) then
cbugc***DEBUG begins.
cbug 9903 format ('aptqexc DEBUG.  Simple straight line.')
cbug      write (   3, 9903)
cbugc***DEBUG ends.

        if (qv .eq. 0.0) then         ! Straight line u = -qc / qu.
cbugc***DEBUG begins.
cbug 9904 format ('aptqexc DEBUG.  Vertical straight line.')
cbug      write (   3, 9904)
cbugc***DEBUG ends.

          np = np + 1
          eu(np) = -qc / qu
          ev(np) = 0.0
          vnormu = qu
          adir(np) = 'ucon'

          go to 210
 
        endif

        if (qu .eq. 0.0) then         ! Straight line v = -qc / qv.
cbugc***DEBUG begins.
cbug 9905 format ('aptqexc DEBUG.  Horizontal straight line.')
cbug      write (   3, 9905)
cbugc***DEBUG ends.

          np = np + 1
          eu(np) = 0.0
          ev(np) = -qc / qv
          unormv = qv
          adir(np) = 'vcon'

          go to 210

        endif

        go to 210

      endif

c.... Test for horizontal and vertical parallel lines.

      if ((qv  .eq. 0.0)  .and.
     &    (quv .eq. 0.0)  .and.
     &    (qvv .eq. 0.0)) then
cbugc***DEBUG begins.
cbug 9906 format ('aptqexc DEBUG.  Vertical parallel lines.')
cbug      write (   3, 9906)
cbugc***DEBUG ends.

        call aptqrts (0, quu, qu, qc, qq, tol, nrootu, uroot1, uroot2,
     &                itrun)

        if (nrootu .ge. 1) then
          np     = np + 1
          eu(np) = uroot1
          ev(np) = 0.0
          unormu = qu + 2.0 * quu * eu(np)
          adir(np) = 'ucon'
        endif

        if (nrootu .eq. 2) then
          np     = np + 1
          eu(np) = uroot2
          ev(np) = 0.0
          unormu = qu + 2.0 * quu * eu(np)
          if (eu(np) .ge. eu(np-1)) then
            adir(np)   = 'umax'
            adir(np-1) = 'umin'
          else
            adir(np)   = 'umin'
            adir(np-1) = 'umax'
          endif
        endif

        go to 210

      endif

      if ((qu  .eq. 0.0)  .and.
     &    (quv .eq. 0.0)  .and.
     &    (quu .eq. 0.0)) then
cbugc***DEBUG begins.
cbug 9907 format ('aptqexc DEBUG.  Horizontal parallel lines.')
cbug      write (   3, 9907)
cbugc***DEBUG ends.
        call aptqrts (0, qvv, qv, qc, qq, tol, nrootv, vroot1, vroot2,
     &                itrun)

        if (nrootv .ge. 1) then
          np     = np + 1
          eu(np) = 0.0
          ev(np) = vroot1
          vnormv = qv + 2.0 * qvv * ev(np)
          adir(np) = 'vcon'
        endif

        if (nrootv .eq. 2) then
          np     = np + 1
          eu(np) = 0.0
          ev(np) = vroot2
          vnormv = qv + 2.0 * qvv * ev(np)
          if (ev(np) .ge. ev(np-1)) then
            adir(np)   = 'vmax'
            adir(np-1) = 'vmin'
          else
            adir(np)   = 'vmin'
            adir(np-1) = 'vmax'
          endif
        endif

        go to 210

      endif

c.... Test for a quadric curve aligned with the axes.

      if (quv .eq. 0.0) then          ! Aligned quadric curve.
cbugc***DEBUG begins.
cbug 9908 format ('aptqexc DEBUG.  Quadric aligned with axes.')
cbug      write (   3, 9908)
cbugc***DEBUG ends.

c....   Find points with extreme values of u, for aligned quadric.

        if (qvv .ne. 0.0) then

          v  = -0.5 * qv / qvv
          aa = quu
          bb = qu
          cc = qc + qv * v + qvv * v**2

          call aptqrts (0, aa, bb, cc, qq, tol, nrootu, uroot1, uroot2,
     &                  itrun)

          if (nrootu .ge. 1) then
            np     = np + 1
            eu(np) = uroot1
            ev(np) = v
            vnormu = qu + 2.0 * quu * eu(np)
            if     (qvv * vnormu .gt. 0.0) then
              adir(np) = 'umax'
            elseif (qvv * vnormu .lt. 0.0) then
              adir(np) = 'umin'
            else
              adir(np) = 'uint'
            endif
          endif

          if (nrootu .eq. 2) then
            np     = np + 1
            eu(np) = uroot2
            ev(np) = v
            vnormu = qu + 2.0 * quu * eu(np)
            if     (qvv * vnormu .gt. 0.0) then
              adir(np) = 'umax'
            elseif (qvv * vnormu .lt. 0.0) then  ! Exchange two extrema.
              adir(np)   = adir(np-1)
              adir(np-1) = 'umin'
              eu(np)     = uroot1
              eu(np-1)   = uroot2
            else
              adir(np) = 'uint'
            endif
          endif

        endif

c....   Find points with extreme values of v, for aligned quadric.

        if (quu .ne. 0.0) then

          u  = -0.5 * qu / quu
          aa = qvv
          bb = qv
          cc = qc + qu * u + quu * u**2

          call aptqrts (0, aa, bb, cc, qq, tol, nrootv, vroot1, vroot2,
     &                  itrun)

          if (nrootv .ge. 1) then
            np     = np + 1
            eu(np) = u
            ev(np) = vroot1
            vnormv = qv + 2.0 * qvv * ev(np)
            if     (quu * vnormv .gt. 0.0) then
              adir(np) = 'vmax'
            elseif (quu * vnormv .lt. 0.0) then
              adir(np) = 'vmin'
            else
              adir(np) = 'vint'
            endif
          endif

          if (nrootv .eq. 2) then
            np     = np + 1
            eu(np) = u
            ev(np) = vroot2
            vnormv = qv + 2.0 * qvv * ev(np)
            if     (quu * vnormv .gt. 0.0) then
              adir(np) = 'vmax'
            elseif (quu * vnormv .lt. 0.0) then  ! Exchange two extrema.
              adir(np)   = adir(np-1)
              adir(np-1) = 'vmin'
              ev(np)     = vroot1
              ev(np-1)   = vroot2
            else
              adir(np) = 'vint'
            endif
          endif

        endif

        go to 210

      endif                           ! Tested for aligned quadric curve.

c.... Test for an unaligned quadric curve.

      if (quv .ne. 0.0) then          ! Unaligned quadric curve.
cbugc***DEBUG begins.
cbug 9909 format ('aptqexc DEBUG.  Unaligned quadric.')
cbug      write (   3, 9909)
cbugc***DEBUG ends.

c....   Find points with extreme values of u, for unaligned quadric.

        if (qvv .ne. 0.0) then

          aa = qvv * (4.0 * qvv * quu - quv**2)
          bb = 2.0 * qvv * (2.0 * qv * quu  - qu * quv)
          cc = qv**2 * quu - qv * qu * quv + qc * quv**2

          call aptqrts (0, aa, bb, cc, qq, tol, nrootv, vroot1, vroot2,
     &                  itrun)

          if (nrootv .ge. 1) then
            np     = np + 1
            eu(np) = -(qv + 2.0 * qvv * vroot1) / quv
            ev(np) = vroot1
            vnormu = qu + quv * ev(np) + 2.0 * quu * eu(np)
            if     (qvv * vnormu .gt. 0.0) then
              adir(np) = 'umax'
            elseif (qvv * vnormu .lt. 0.0) then
              adir(np) = 'umin'
            else
              adir(np) = 'uint'
            endif
          endif

          if (nrootv .eq. 2) then
            np     = np + 1
            eu(np) = -(qv + 2.0 * qvv * vroot2) / quv
            ev(np) = vroot2
            vnormu = qu + quv * ev(np) + 2.0 * quu * eu(np)
            if     (qvv * vnormu .gt. 0.0) then
              adir(np) = 'umax'
            elseif (qvv * vnormu .lt. 0.0) then  ! Exchange two extrema.
              adir(np)   = adir(np-1)
              adir(np-1) = 'umin'
              eux        = eu(np)
              eu(np)     = eu(np-1)
              eu(np-1)   = eux
              ev(np)     = vroot1
              ev(np-1)   = vroot2
            else
              adir(np) = 'uint'
            endif
          endif
        endif

c....   Find points with extreme values of v, for unaligned quadric.

        if (quu .ne. 0.0) then

          aa = quu * (4.0 * quu * qvv - quv**2)
          bb = 2.0 * quu * (2.0 * qu * qvv  - qv * quv)
          cc = qu**2 * qvv - qu * qv * quv + qc * quv**2

          call aptqrts (0, aa, bb, cc, qq, tol, nrootu, uroot1, uroot2,
     &                  itrun)

          if (nrootu .ge. 1) then
            np     = np + 1
            eu(np) = uroot1
            ev(np) = -(qu + 2.0 * quu * uroot1) / quv
            vnormv = qv + quv * eu(np) + 2.0 * qvv * ev(np)
            if     (quu * vnormv .gt. 0.0) then
              adir(np) = 'vmax'
            elseif (quu * vnormv .lt. 0.0) then
              adir(np) = 'vmin'
            else
              adir(np) = 'vint'
            endif
          endif

          if (nrootu .eq. 2) then
            np     = np + 1
            eu(np) = uroot2
            ev(np) = -(qu + 2.0 * quu * uroot2) / quv
            vnormv = qv + quv * eu(np) + 2.0 * qvv * ev(np)
            if     (quu * vnormv .gt. 0.0) then
              adir(np) = 'vmax'
            elseif (quu * vnormv .lt. 0.0) then  ! Exchange two extrema.
              adir(np)   = adir(np-1)
              adir(np-1) = 'vmin'
              eu(np)     = uroot1
              eu(np-1)   = uroot2
              evx        = ev(np)
              ev(np)     = ev(np-1)
              ev(np-1)   = evx
            else
              adir(np) = 'vint'
            endif
          endif
        endif

        go to 210

      endif                           ! Tested for unaligned quadric curve.

  210 continue
cbugc***DEBUG begins.
cbug 9910 format (/ 'aptqexc results:  np=',i2,' nerr=',i2)
cbug 9911 format (i3,'  eu, ev=  ',1p2e22.14,2x,a8 )
cbug      write ( 3, 9910) np, nerr
cbug      do 991 n = 1, np
cbug        write ( 3, 9911) n, eu(n), ev(n), adir(n)
cbug  991 continue
cbugc***DEBUG ends.

      return

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

UCRL-WEB-209832