docs: def faster_minimum_distance2(hull_a, center_a, hull_b, center_b):
      '''Do the minimum distance using the bimodal property of hull ordering
      
      '''
      #
      # Find the farthest vertex in b from some point within A. Find the
      # vertices within A visible from this point in B. If the point in A
      # is within B or the farthest vertex in B is within A, then the objects
      # intersect.
      #
      if within_hull(center_a, hull_b):
          return 0
      farthest_b = find_farthest(center_a, hull_b)
      if within_hull(hull_b[farthest_b,:], hull_a):
          return 0
      visible_b = find_visible(hull_b, center_a, farthest_b)
      #
      # Do the same for B
      if within_hull(center_b, hull_a):
          return 0
      farthest_a = find_farthest(center_b, hull_a)
      if within_hull(hull_a[farthest_a,:], hull_b):
          return 0
      visible_a = find_visible(hull_a, center_b, farthest_a)
      #
      # Now go from the first in A and last in B measuring distances
      # which should decrease as we move toward the best
      #
      i = visible_a[0]
      i_next = (i+1) % hull_a.shape[0]
      j = visible_b[1]
      j_next = (j+hull_b.shape[0]-1) % hull_b.shape[0]
      a = hull_a[i,:]
      a_next = hull_a[i_next,:]
      b = hull_b[j,:]
      b_next = hull_b[j_next,:]
      d2_min = np.sum((a-b)**2)
      
      while i != visible_a[1] and j != visible_b[0]:
          if lines_intersect(a, a_next, b, b_next):
              return 0
          if (np.dot(b-b_next,a-b_next) > 0 and
              np.dot(b_next-b,a-b) > 0):
              # do the edge if better than the vertex
              d2a = distance2_to_line(b, a, a_next)
          else:
              # try the next vertex of a
              d2a = np.sum((a_next-b)**2)
          if (np.dot(a-a_next,b-a_next) > 0 and
              np.dot(a_next-a,b-a) > 0):
              d2b = distance2_to_line(a, b, b_next)
          else:
              d2b = np.sum((b_next-a)**2)
          if d2a < d2_min and d2a < d2b:
              # The edge of A is closer than the best or the b-edge
              # Take it and advance A
              d2_min = d2a
              a = a_next
              i = i_next
              i_next = (i+1) % hull_a.shape[0]
              a_next = hull_a[i_next,:]
          elif d2b < d2_min:
              # B is better. Take it and advance
              d2_min = d2b
              b = b_next
              j = j_next
              j_next = (j+hull_b.shape[0]-1) % hull_b.shape[0]
              b_next = hull_b[j_next,:]
          else:
              return d2_min
      #
      # Some more to do... either one more i or one more j
      #
      while i != visible_a[1]:
          d2_min = min(d2_min, np.sum((a_next-b)**2))
          a = a_next
          i = i_next
          i_next = (i+1) % hull_a.shape[0]
          a_next = hull_a[i_next,:]
          
      while j != visible_b[0]:
          d2_min = min(d2_min, np.sum((b_next-a)**2))
          b = b_next
          j = j_next
          j_next = (j+ hull_b.shape[0]-1) % hull_b.shape[0]
          b_next = hull_b[j_next,:]
      return d2_min