docs: def cartesian_to_barycentric_2D(tri, xy):
      '''
      cartesian_to_barycentric_2D(tri, xy) yields a (2 x n) barycentric coordinate matrix 
      (or just a tuple if xy is a single (x, y) coordinate) of the first two barycentric coordinates
      for the triangle coordinate array tri. The array tri should be 3 (vertices) x 2 (coordinates) x
      n (triangles) unless xy is a tuple, in which case it should be a (3 x 2) matrix.
      '''
      xy = np.asarray(xy)
      tri = np.asarray(tri)
      if len(xy.shape) == 1:
          return cartesian_to_barycentric_2D(np.transpose(np.asarray([tri]), (1,2,0)),
                                             np.asarray([xy]).T)[:,0]
      xy = xy if xy.shape[0] == 2 else xy.T
      if tri.shape[0] == 3:
          tri = tri if tri.shape[1] == 2 else np.transpose(tri, (0,2,1))
      elif tri.shape[1] == 3:
          tri = tri.T if tri.shape[0] == 2 else np.transpose(tri, (1,2,0))
      elif tri.shape[2] == 3:
          tri = np.transpose(tri, (2,1,0) if tri.shape[1] == 2 else (2,0,1))
      if tri.shape[0] != 3 or tri.shape[1] != 2:
          raise ValueError('Triangle array did not have dimensions of sizes 3 and 2')
      if xy.shape[0] != 2:
          raise ValueError('coordinate matrix did not have a dimension of size 2')
      if tri.shape[2] != xy.shape[1]:
          raise ValueError('number of triangles and coordinates must match')
      # Okay, everything's the right shape...
      (x,y) = xy
      ((x1,y1), (x2,y2), (x3,y3)) = tri
      x_x3  = x  - x3
      x1_x3 = x1 - x3
      x3_x2 = x3 - x2
      y_y3  = y  - y3
      y1_y3 = y1 - y3
      y2_y3 = y2 - y3
      num1 = (y2_y3*x_x3  + x3_x2*y_y3)
      num2 = (-y1_y3*x_x3 + x1_x3*y_y3)
      den  = (y2_y3*x1_x3 + x3_x2*y1_y3)
      zero = np.isclose(den, 0)
      den += zero
      unit = 1 - zero
      l1 = unit * num1 / den
      l2 = unit * num2 / den
      return np.asarray((l1, l2))