subroutine aptspcy (qc1, qx1, qy1, qz1, qxy1, qyz1, qzx1,
     &                    qxx1, qyy1, qzz1,
     &                    qc2, qx2, qy2, qz2, qxy2, qyz2, qzx2,
     &                    qxx2, qyy2, qzz2, tol,
     &                    rsph, rcyl, ax1, ay1, az1, ax2, ay2, az2,
     &                    bx, by, bz, daxis,
     &                    cx1, cy1, cz1, cx2, cy2, cz2,
     &                    dx, dy, dz, dsurf, nerr)

ccbeg.
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c                             SUBROUTINE APTSPCY
c
c     call aptspcy (qc1, qx1, qy1, qz1, qxy1, qyz1, qzx1,
c                   qxx1, qyy1, qzz1,
c                   qc2, qx2, qy2, qz2, qxy2, qyz2, qzx2,
c                   qxx2, qyy2, qzz2, tol,
c                   rsph, rcyl, ax1, ay1, az1, ax2, ay2, az2,
c                   bx, by, bz, daxis,
c                   cx1, cy1, cz1, cx2, cy2, cz2,
c                   dx, dy, dz, dsurf, nerr)
c
c     Version:  aptspcy  Updated    1995 January 5 12:00.
c               aptspcy  Originated 1995 January 5 12:00.
c
c     Author:   Arthur L. Edwards, LLNL, L-298, Telephone (925) 422-4123.
c
c
c     Purpose:  For the sphere specified by the coefficients qc1, ..., qzz1
c               and the circular cylinder specified by the coefficients
c               qc2, ..., qzz2, to find the radii rsph of the sphere and
c               rcyl of the cylinder; to find the  center of the sphere
c               a1 = (ax1, ay1, az1) and the proximal point a2 = (ax2, ay2, az2)
c               on the axis of the cylinder, and the vector b = (bx, by, bz) and
c               distance daxis between them; to find the proximal points
c               c1 = (cx1, cy1, cz1) on the sphere and c2 = (cx2, cy2, cz2) on
c               the circular cylinder of minimum separation or maximum overlap
c               of their surfaces, and the vector d = (dx, dy, dz) and distance
c               dsurf between them.
c               Three other larger distances of separation or overlap, all in
c               direction d, may be constructed from rsph, rcyl and daxis:
c               daxis - rsph - rcyl = dsurf (min dist to external tangency)
c               daxis + rsph + rcyl         (max dist to external tangency)
c               daxis - rsph + rcyl         (distance to internal tangency)
c               daxis + rsph - rcyl         (distance to internal tangency)
c
c               The sphere is defined by the implicit quadric equation:
c
c               fs(x,y,z) = qc1 + qx1  * x   + qy1  * y     + qz1  * z     +
c                                 qxy1 * x * y + qyz1 * y * z + qzx1 * z * x +
c                                 qxx1 * x**2  + qyy1 * y**2  + qzz1 * z**2 = 0,
c
c               which in standard form, with the center at the origin, is
c               fs = -rsph**2 + x**2 + y**2 + z**2 = 0,
c               where rsph is the radius.
c
c               If the sphere is centered at point a1 = (ax1, ay1, az1), with
c               radius rsph, the coefficients of the implicit quadric equation
c               are:
c               qc1 = -rsph**2 + ax1**2 + ay1**2 + az1**2
c               qx1 = -2.0 * ax1      qxy1 = 0.0      qxx1 = 1.0
c               qy1 = -2.0 * ay1      qyz1 = 0.0      qyy1 = 1.0
c               qz1 = -2.0 * az1      qzx1 = 0.0      qzz1 = 1.0
c
c               The circular cylinder is defined by the equation:
c
c               fc(x,y,z) = qc2 + qx2  * x   + qy2  * y     + qz2  * z     +
c                                 qxy2 * x * y + qyz2 * y * z + qzx2 * z * x +
c                                 qxx2 * x**2  + qyy2 * y**2  + qzz2 * z**2 = 0,
c
c               which in standard form, with the axis through the origin and
c               in the direction of the z axis, is
c               fc = -rcyl**2 + x**2 + y**2 = 0,
c               where rcyl is the radius.
c
c               Use APT subroutine aptclis to find the coefficients of the
c               implicit quadric equation, if the circular cylinder is
c               defined only by a point on the axis, the axis vector, and the
c               radius.
c
c               Flag nerr indicates any input error.
c
c     Input:    qc1, qx1, qy1, qz1, qxy1, qyz1, qzx1, qxx1, qyy1, qzz1,
c               qc2, qx2, qy2, qz2, qxy2, qyz2, qzx2, qxx2, qyy2, qzz2, tol.
c
c     Output:   rsph, rcyl, ax1, ay1, az1, ax2, ay2, az2, bx, by, bz, daxis,
c               cx1, cy1, cz1, cx2, cy2, cz2, dx, dy, dz, dsurf, nerr.
c
c     Calls: aptaxis, aptptln, aptvdis, aptvxun 
c               
c
c     Glossary:
c
c     ax1, ...  Output   The x, y, z coordinates of the center of the sphere.
c
c     ax2, ...  Output   The x, y, z coordinates of the point on the axis of
c                          the cylinder nearest the center of the sphere.
c
c     bx,by,bz  Output   The x, y, z components of the vector from point
c                          a1 = (ax1, ay1, az1) to point a2 = (ax2, ay2, az2).
c                          The length of vector b is daxis.  Moving the sphere
c                          by this amount would put its center on the axis of
c                          the cylinder.  Vector b is parallel to vector d.
c
c     cx1, ...  Output   The x, y, z coordinates of the point of minimum
c                          distance or maximum overlap on the sphere,
c                          c1 = (cx1, cy1, cz1).
c
c     cx2, ...  Output   The x, y, z coordinates of the point of minimum
c                          distance or maximum overlap on the cylinder,
c                          c2 = (cx2, cy2, cz2).
c
c     daxis     Output   Minimum distance between the center of the sphere and
c                          the axis of the cylinder.
c
c     dsurf     Output   Distance of minimum separation or maximum overlap
c                          of the surfaces of the sphere and the surface of the
c                          cylinder:  dsurf = daxis - rsph - rcyl.
c                          Negative if the sphere and the cylinder overlap.
c                          Zero if the sphere and the cylinder are externally
c                          tangent.
c                          Positive if the sphere and the cylinder do not
c                          overlap.
c                          Moving the sphere and the cylinder toward each other
c                          in the direction of vector d by distance dsurf would
c                          make them externally tangent.  So would the larger
c                          distance daxis + rsph + rcyl.  Movement by the
c                          following distances would make the sphere and the
c                          cylinder internally tangent:  daxis - rsph + rcyl
c                          and daxis + rsph - rcyl.
c
c     dx,dy,dz  Output   The x, y, z components of the vector from point
c                          c1 = (cx1, cy1, cz1) to point c2 = (cx2, cy2, cz2).
c                          The length of vector d is dsurf.  Moving the sphere
c                          by this amount would make it externally tangent to
c                          the cylinder.  Vector d is parallel to vector b.
c
c     nerr      Output   Indicates an input error, if not zero.
c                          1 if the first quadric surface is not a sphere.
c                          2 if the second quadric surface is not a circular
c                          cylinder.
c
c     qc1, ...  Input    Coefficients of the quadric equation for the sphere:
c                          qc1 + qx1 * x + qy1 * y + qz1 * z +
c                          qxy1 * x * y + qyz1 * y * z + qzx1 * z * x +
c                          qxx1 * x**2 + qyy1 * y**2 + qxx1 * z**2 = 0
c                          Given the center a1 = (ax1, ay1, az1) and the
c                          radius rsph:
c                          qc1 = -rsph**2 + ax1**2 + ay1**2 + az1**2
c                          qx1 = -2.0 * ax1      qxy1 = 0.0      qxx1 = 1.0
c                          qy1 = -2.0 * ay1      qyz1 = 0.0      qyy1 = 1.0
c                          qz1 = -2.0 * az1      qzx1 = 0.0      qzz1 = 1.0
c
c     qc2, ...  Input    Coefficients of the quadric equation for the cylinder:
c                          qc2 + qx2 * x + qy2 * y + qz2 * z +
c                          qxy2 * x * y + qyz2 * y * z + qzx2 * z * x +
c                          qxx2 * x**2 + qyy2 * y**2 + qxx2 * z**2 = 0
c
c     rcyl      Output   The radius of the circular cylinder.
c
c     rsph      Output   The radius of the sphere.
c
c     tol       Input    Numerical tolerance limit.  With 64-bit floating point
c                          numbers, 1.e-5 to 1.e-11 is recommended.
c
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
ccend.

c.... Local variables.

      common /laptspcy/ rotq(3,3)     ! Rotation matrix to align cylinder.
cbugc***DEBUG begins.
cbug 9901 format (/ 'aptspcy finding distance between sphere and',
cbug     &  ' cylinder.',
cbug     &  '  tol=',1pe13.5)
cbug 9902 format (
cbug     &  '  Sphere   qc=',1pe22.14 /
cbug     &  '  qx,qy,qz=   ',1p3e22.14 /
cbug     &  '  qxy,qyz,qzx=',1p3e22.14 /
cbug     &  '  qxx,qyy,qzz=',1p3e22.14)
cbug 9903 format (
cbug     &  '  Cylinder qc=',1pe22.14 /
cbug     &  '  qx,qy,qz=   ',1p3e22.14 /
cbug     &  '  qxy,qyz,qzx=',1p3e22.14 /
cbug     &  '  qxx,qyy,qzz=',1p3e22.14)
cbug      write ( 3, 9901) tol
cbug      write ( 3, 9902) qc1, qx1, qy1, qz1, qxy1, qyz1, qzx1,
cbug     &  qxx1, qyy1, qzz1
cbug      write ( 3, 9903) qc1, qx1, qy1, qz1, qxy1, qyz1, qzx1,
cbug     &  qxx1, qyy1, qzz1
cbugc***DEBUG ends.

c.... Initialize.

      nerr  = 0

      daxis = -1.e99
      ax1   = -1.e99
      ay1   = -1.e99
      az1   = -1.e99
      ax2   = -1.e99
      ay2   = -1.e99
      az2   = -1.e99

      bx    = -1.e99
      by    = -1.e99
      bz    = -1.e99

      dsurf = -1.e99
      cx1   = -1.e99
      cy1   = -1.e99
      cz1   = -1.e99
      cx2   = -1.e99
      cy2   = -1.e99
      cz2   = -1.e99

      dx    = -1.e99
      dy    = -1.e99
      dz    = -1.e99

c.... Find the center and radius of the sphere.

      ac  = qc1
      ax  = qx1
      ay  = qy1
      az  = qz1
      axy = qxy1
      ayz = qyz1
      azx = qzx1
      axx = qxx1
      ayy = qyy1
      azz = qzz1

      tolx = tol
      if (tolx .le. 0.0) tolx = 1.e-11

      call aptaxis (ac, ax, ay, az, axy, ayz, azx, axx, ayy, azz, tolx,
     &              xcen1, ycen1, zcen1, rotq, ntype, nerraxis)

      if ((ntype .ne. 16)     .or.
     &    (nerraxis .ne. 0)) then
        nerr = 1
        go to 710
      endif

      ax1 = xcen1
      ay1 = ycen1
      az1 = zcen1

      rsph = sqrt (-ac / axx)

c.... Find the radius of the cylinder, and a line on the axis.

      ac  = qc2
      ax  = qx2
      ay  = qy2
      az  = qz2
      axy = qxy2
      ayz = qyz2
      azx = qzx2
      axx = qxx2
      ayy = qyy2
      azz = qzz2

      tolx = tol
      if (tolx .le. 0.0) tolx = 1.e-11

      call aptaxis (ac, ax, ay, az, axy, ayz, azx, axx, ayy, azz, tolx,
     &              xcen2, ycen2, zcen2, rotq, ntype, nerraxis)

      if ((ntype .ne. 7)    .or.
     &    (nerraxis .ne. 0)) then
        nerr = 2
        go to 710
      endif

      vx2 = rotq(3,1)
      vy2 = rotq(3,2)
      vz2 = rotq(3,3)

      xend2 = xcen2 + vx2
      yend2 = ycen2 + vy2
      zend2 = zcen2 + vz2

      rcyl = sqrt (-ac / axx)

c.... Find the proximal point on the axis of the cylinder, and the distance
c....   from the center of the sphere to the axis of the cylinder.

      call aptptln (ax1, ay1, az1,
     &              xcen2, ycen2, zcen2, xend2, yend2, zend2,
     &              1, tol, 0,
     &              dpmin, fdmin, ax2, ay2, az2, nlim, itrun, nerra)

      call aptvdis (ax1, ay1, az1, ax2, ay2, az2, 1, tol,
     &              bx, by, bz, daxis, nerra)

c.... Find the distance of minimum separation or maximum overlap of the
c....   sphere and the cylinder.

      dsurf = daxis - rsph - rcyl
      disterr  = tol * (abs (daxis) + abs (rsph) + abs (rcyl))
      if (abs (dsurf) .le. disterr) dsurf = 0.0

      if (daxis .eq. 0.0) then        ! Center of sphere on cylinder axis.

c....   The direction of proximity is arbitrary.  Any vector perpendicular to
c....     the axis of the cylinder will do.  Find the unit vector perpendicular
c         to the z axis and the axis of the cylinder.  If none, use x vector.

        call aptvxun (0., 0., 1., vx2, vy2, vz2, 1, tol,
     &                vx12, vy12, vz12, vlen, nerra)

        if (vlen .eq. 0.0) then       ! Cylinder on z axis, use x vector.
          vx12 = 1.0
          vy12 = 0.0
          vz12 = 0.0
        endif

        cx1 = ax1 + rsph * vx12
        cy1 = ay1 + rsph * vy12
        cz1 = az1 + rsph * vz12

        cx2 = ax2 - rcyl * vx12
        cy2 = ay2 - rcyl * vy12
        cz2 = az2 - rcyl * vz12

c....   Find the vector "d" between the proximal surface points.

        call aptvdis (cx1, cy1, cz1, cx2, cy2, cz2, 1, tol,
     &                dx, dy, dz, dist, nerra)

        go to 710

      else                            ! Center of sphere not on cylinder axis.

        cx1 = ax1 + rsph * bx / daxis
        cy1 = ay1 + rsph * by / daxis
        cz1 = az1 + rsph * bz / daxis

        cx2 = ax2 - rcyl * bx / daxis
        cy2 = ay2 - rcyl * by / daxis
        cz2 = az2 - rcyl * bz / daxis

c....   Find the vector "d" between the proximal points.

        call aptvdis (cx1, cy1, cz1, cx2, cy2, cz2, 1, tol,
     &                dx, dy, dz, dist, nerra)

      endif                           ! Tested whether axes intersect or not.

  710 continue
cbugc***DEBUG begins.
cbug 9908 format (/ 'aptspcy results:  nerr=',i3 /
cbug     &  '  rsph,rcyl=  ',1p2e22.14 /
cbug     &  '  ax1,ay1,az1=',1p3e22.14 /
cbug     &  '  ax2,ay2,az2=',1p3e22.14 /
cbug     &  '  bx,by,bz=   ',1p3e22.14 /
cbug     &  '  daxis=      ',1pe22.14 /
cbug     &  '  cx1,cy1,cz1=',1p3e22.14 /
cbug     &  '  cx2,cy2,cz2=',1p3e22.14 /
cbug     &  '  dx,dy,dz=   ',1p3e22.14 /
cbug     &  '  dsurf=      ',1pe22.14 )
cbug      write ( 3, 9908) nerr, rsph, rcyl,
cbug     &  ax1, ay1, az1, ax2, ay2, az2, bx, by, bz, daxis,
cbug     &  cx1, cy1, cz1, cx2, cy2, cz2, dx, dy, dz, dsurf
cbug      dpp  = daxis + rsph + rcyl
cbug      errd = tol * dpp
cbug      dmp  = daxis - rsph + rcyl
cbug      if (abs (dmp) .le. errd) dmp = 0.0
cbug      dpm  = daxis + rsph - rcyl
cbug      if (abs (dpm) .le. errd) dpm = 0.0
cbug 9909 format ('  dpp,dmp,dpm=',1p3e22.14 )
cbug      write ( 3, 9909) dpp, dmp, dpm
cbugc***DEBUG ends.
      return

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

UCRL-WEB-209832