def zoom_in_on_pixel_coords(p, zoom_factor, x_size = 1000):
  """p is pixel coordinate point, return SL(2,C) matrix zooming in on p by a factor of scale"""
  # Note that the zoom factor is only accurate at the point p itself. As we move away from p, we zoom less and less.
  # We zoom with the inverse zoom_factor towards/away from the antipodal point to p.
  M_rot = rotate_pixel_coords_p_to_q( p, (0,0), x_size = x_size)
  M_scl = [[zoom_factor,0],[0,1]] ### zoom in on zero in CP^1
  return matrix_mult( matrix_mult(matrix2_inv(M_rot), M_scl), M_rot )
def zoom_in_on_pixel_coords(p, zoom_factor, x_size=1000):
    """p is pixel coordinate point, return SL(2,C) matrix zooming in on p by a factor of scale"""
    # Note that the zoom factor is only accurate at the point p itself. As we move away from p, we zoom less and less.
    # We zoom with the inverse zoom_factor towards/away from the antipodal point to p.
    M_rot = rotate_pixel_coords_p_to_q(p, (0, 0), x_size=x_size)
    M_scl = [[zoom_factor, 0], [0, 1]]  ### zoom in on zero in CP^1
    return matrix_mult(matrix_mult(matrix2_inv(M_rot), M_scl), M_rot)
def zoom_along_axis_sphere_points_p_q(p, q, zoom_factor):
  """p and q are points on sphere, return SL(2,C) matrix zooming along axis from p to q"""
  p, q = vector(p), vector(q)
  CP1p, CP1q = CP1_from_sphere(p), CP1_from_sphere(q)
  assert dot(p,q) < 0.9999   #points should not be in the same place
  r = get_vector_perp_to_p_and_q(p, q)
  CP1r = CP1_from_sphere(r)
  M_standardise = two_triples_to_SL(CP1p, CP1q, CP1r, [0,1], [1,0], [1,1])
  M_theta = [[zoom_factor,0],[0,1]] 
  return matrix_mult( matrix_mult(matrix2_inv(M_standardise), M_theta), M_standardise )
def rotate_around_axis_sphere_points_p_q(p,q,theta):
  """p and q are points on sphere, return SL(2,C) matrix rotating by angle theta around the axis from p to q"""
  p, q = vector(p), vector(q)
  CP1p, CP1q = CP1_from_sphere(p), CP1_from_sphere(q)
  assert dot(p,q) < 0.9999, "axis points should not be in the same place!"
  r = get_vector_perp_to_p_and_q(p, q)
  CP1r = CP1_from_sphere(r)
  M_standardise = two_triples_to_SL(CP1p, CP1q, CP1r, [0,1], [1,0], [1,1])
  M_theta = [[complex(cos(theta),sin(theta)),0],[0,1]] #rotate on axis through 0, infty by theta
  return matrix_mult( matrix_mult(matrix2_inv(M_standardise), M_theta), M_standardise )
def zoom_along_axis_sphere_points_p_q(p, q, zoom_factor):
    """p and q are points on sphere, return SL(2,C) matrix zooming along axis from p to q"""
    p, q = vector(p), vector(q)
    CP1p, CP1q = CP1_from_sphere(p), CP1_from_sphere(q)
    assert dot(p, q) < 0.9999  #points should not be in the same place
    r = get_vector_perp_to_p_and_q(p, q)
    CP1r = CP1_from_sphere(r)
    M_standardise = two_triples_to_SL(CP1p, CP1q, CP1r, [0, 1], [1, 0], [1, 1])
    M_theta = [[zoom_factor, 0], [0, 1]]
    return matrix_mult(matrix_mult(matrix2_inv(M_standardise), M_theta),
                       M_standardise)
def rotate_around_axis_sphere_points_p_q(p, q, theta):
    """p and q are points on sphere, return SL(2,C) matrix rotating by angle theta around the axis from p to q"""
    p, q = vector(p), vector(q)
    CP1p, CP1q = CP1_from_sphere(p), CP1_from_sphere(q)
    assert dot(p, q) < 0.9999, "axis points should not be in the same place!"
    r = get_vector_perp_to_p_and_q(p, q)
    CP1r = CP1_from_sphere(r)
    M_standardise = two_triples_to_SL(CP1p, CP1q, CP1r, [0, 1], [1, 0], [1, 1])
    M_theta = [[complex(cos(theta), sin(theta)), 0],
               [0, 1]]  #rotate on axis through 0, infty by theta
    return matrix_mult(matrix_mult(matrix2_inv(M_standardise), M_theta),
                       M_standardise)
def two_triples_to_SL(a1, b1, c1, a2, b2, c2):
    """returns SL(2,C) matrix that sends the three CP^1 points a1,b1,c1 to a2,b2,c2"""
    return matrix_mult(inf_zero_one_to_triple(a2, b2, c2),
                       matrix2_inv(inf_zero_one_to_triple(a1, b1, c1)))
def two_triples_to_SL(a1,b1,c1,a2,b2,c2):
  """returns SL(2,C) matrix that sends the three CP^1 points a1,b1,c1 to a2,b2,c2"""
  return matrix_mult( inf_zero_one_to_triple(a2,b2,c2), matrix2_inv(inf_zero_one_to_triple(a1,b1,c1) ) )