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

ccbeg.
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
c
c                             SUBROUTINE APTCYCY
c
c     call aptcycy (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                   rcyl1, rcyl2, ax1, ay1, az1, ax2, ay2, az2,
c                   bx, by, bz, daxis,
c                   cx1, cy1, cz1, cx2, cy2, cz2,
c                   dx, dy, dz, dsurf, ipar, nerr)
c
c     Version:  aptcycy  Updated    1995 December 9 16:35.
c               aptcycy  Originated 1995 January 3 13:40.
c
c     Author:   Arthur L. Edwards, LLNL, L-298, Telephone (925) 422-4123.
c
c
c     Purpose:  For the two circular cylinders specified by the coefficients
c               qc1, ..., qzz1 and qc2, ..., qzz2, to find the radii rcyl1 and
c               rcyl2 of the two cylinders; to find the proximal points
c               a1 = (ax1, ay1, az1) and a2 = (ax2, ay2, az2) on the two axes,
c               and the vector b = (bx, by, bz) and distance daxis between them;
c               to find the points c1 = (cx1, cy1, cz1) and c2 = (cx2, cy2, cz2)
c               of minimum separation or maximum overlap of the two cylinders,
c               and the vector d = (dx, dy, dz) and distance dsurf between them;
c               and to find (indicator ipar) if the two axes are parallel or
c               not, and if the two cylinders are coincident or not.  Three
c               other larger distances of separation or overlap, all in
c               direction d, may be constructed from rcyl1, rcyl2 and daxis:
c               daxis - rcyl1 - rcyl2 = dsurf (min dist to external tangency)
c               daxis + rcyl1 + rcyl2         (max dist to external tangency)
c               daxis - rcyl1 + rcyl2         (distance to internal tangency)
c               daxis + rcyl1 - rcyl2         (distance to internal tangency)
c
c               The circular cylinders are defined by the implicit quadric
c               equations:
c
c               f1(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               f2(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 f = -r**2 + x**2 + y**2 = 0,
c               where r is the radius.
c
c               Use APT subroutine aptclis to find the coefficients of the
c               implicit quadric equation, if either 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:   rcyl1, rcyl2, ax1, ay1, az1, ax2, ay2, az2, bx, by, bz, daxis,
c               cx1, cy1, cz1, cx2, cy2, cz2, dx, dy, dz, dsurf, ipar, nerr.
c
c     Calls: aptaxis, aptlnln, aptmopv, apttran, aptvdis, aptvxun 
c               
c
c     Glossary:
c
c     ax1, ...  Output   The x, y, z coordinates of the point on the axis of
c                          the first cylinder nearest the axis of the second
c                          cylinder.
c
c     ax2, ...  Output   The x, y, z coordinates of the point on the axis of
c                          the second cylinder nearest the axis of the first
c                          cylinder.
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 first
c                          cylinder by this amount would make its axis
c                          intersect the axis of the second cylinder.
c                          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 first cylinder,
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 second cylinder,
c                          c2 = (cx2, cy2, cz2).
c
c     daxis     Output   Minimum distance between the axes of the two cylinders.
c                          Zero if they intersect.  If daxis = 0 and ipar = 1,
c                          the two axes coincide, so the two cylinders are
c                          concentric.  If daxis = 0 and ipar = 2, the two
c                          cylinders coincide.
c
c     dsurf     Output   Distance of minimum separation or maximum overlap
c                          of the surfaces of the two cylinders.
c                            dsurf = daxis - rcyl1 - rcyl2
c                          Negative if the two cylinders overlap.
c                          Zero if the two cylinders are externally tangent.
c                          Positive if the two cylinders do not overlap.
c                          Moving the cylinders toward each other in the
c                          direction of vector d by distance dsurf would make
c                          them externally tangent.  So would the larger
c                          distance daxis + rcyl1 + rcyl2.  Movement by the
c                          following distances would make the two circular
c                          cylinders internally tangent:  daxis - rcyl1 + rcyl2
c                          and daxis + rcyl1 - rcyl2.
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 first
c                          cylinder by this amount would make it externally
c                          tangent to the second cylinder.
c                          Vector d is parallel to vector b.
c
c     ipar      Output   Zero if the axes of the two cylinders are not parallel.
c                          1 if the axes of the two cylinders are parallel.
c                          If ipar = 1 and daxis = 0, the two axes coincide,
c                          so the cylinders are concentric.
c                          2 if the two cylinders coincide.
c
c     nerr      Output   Indicates an input error, if not zero.
c                          1 if either of the quadric surfaces is not a circular
c                          cylinder.
c
c     qc1, ...  Input    Coefficients of the quadric equation for the first
c                          cylinder:
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
c     qc2, ...  Input    Coefficients of the quadric equation for the second
c                          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     rcyl1     Output   The radius of the first circular cylinder.
c
c     rcyl2     Output   The radius of the second circular cylinder.
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 /laptcycy/ rotq(3,3)     ! Rotation matrix to align cylinder.
cbugc***DEBUG begins.
cbug 9901 format (/ 'aptcycy finding distance between two cylinders.',
cbug     &  '  tol=',1pe13.5)
cbug 9902 format (
cbug     &  '  Cyl 1:  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     &  '  Cyl 2:  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 radius of the first cylinder, and a line on the axis.

      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. 7)     .or.
     &    (nerraxis .ne. 0)) then
        nerr = 1
        go to 710
      endif

      vx1 = rotq(3,1)
      vy1 = rotq(3,2)
      vz1 = rotq(3,3)

      xend1 = xcen1 + vx1
      yend1 = ycen1 + vy1
      zend1 = zcen1 + vz1

      rcyl1 = sqrt (-ac / axx)

c.... Find the radius of the second 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 = 1
        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

      rcyl2 = sqrt (-ac / axx)

c.... Find the proximal points on each axis, and the distance of separation.

      call aptlnln (xcen1, ycen1, zcen1, xend1, yend1, zend1,
     &              xcen2, ycen2, zcen2, xend2, yend2, zend2,
     &              1, tol, dpmin, fracab, fraccd,
     &              ax1, ay1, az1, ax2, ay2, az2, itrun, ipar, 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....   circular cylinders.

      dsurf = daxis - rcyl1 - rcyl2
      disterr  = tol * (abs (daxis) + abs (rcyl1) + abs (rcyl2))
      if (abs (dsurf) .le. disterr) dsurf = 0.0

      if (daxis .eq. 0.0) then        ! Cylinder axes intersect or coincide.

        if (ipar .eq. 1) then         ! Cylinder axes coincide.

          rcylerr = tol * (rcyl1 + rcyl2)
          if (abs (rcyl2 - rcyl1) .le. rcylerr) then  ! Cylinders coincide.
            ipar = 2
          endif

c....     Find two arbitrary proximal points on the circle of proximity.

          cx1 = rcyl1
          cy1 = 0.0
          cz1 = 0.0

          cx2 = -rcyl2
          cy2 = 0.0
          cz2 = 0.0

          call aptmopv (rotq, 1, 0., 0., 0., cx1, cy1, cz1, 1, tol,
     &                  nerr)

          call aptmopv (rotq, 1, 0., 0., 0., cx2, cy2, cz2, 1, tol,
     &                  nerr)

          dcenx1 = -xcen1
          dceny1 = -ycen1
          dcenz1 = -zcen1

          call apttran (dcenx1, dceny1, dcenz1, cx1, cy1, cz1, 1, tol,
     &                  nerr)

          call apttran (dcenx1, dceny1, dcenz1, cx2, cy2, cz2, 1, tol,
     &                  nerr)

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

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

          go to 710
        endif

c....   Find the unit vector perpendicular to both axes.

        call aptvxun (vx1, vy1, vz1, vx2, vy2, vz2, 1, tol,
     &                vx12, vy12, vz12, vlen, nerra)

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

        cx2 = ax2 - rcyl2 * vx12
        cy2 = ay2 - rcyl2 * vy12
        cz2 = az2 - rcyl2 * 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                            ! Cylinder axes do not intersect.

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

        cx2 = ax2 - rcyl2 * bx / daxis
        cy2 = ay2 - rcyl2 * by / daxis
        cz2 = az2 - rcyl2 * 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 (/ 'aptcycy results:  ipar=',i3,13x,' nerr=',i3 /
cbug     &  '  rcyl1,rcyl2=',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) ipar, nerr, rcyl1, rcyl2,
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 aptcycy.      (+1 line)
      end

UCRL-WEB-209832