# Path: ldif/util/geom_util.py
# def ray_sphere_intersect(ray_start, ray_direction, sphere_center, sphere_radius,
#                          max_t):
# def to_homogeneous(t, is_point):
# def transform_points_with_normals(points, tx, normals=None):
# def transform_featured_points(points, tx):
# def rotation_to_tx(rot):
# def extract_points_near_origin(points, count, features=None):
# def local_views_of_shape(global_points,
#                          world2local,
#                          local_point_count,
#                          global_normals=None,
#                          global_features=None,
#                          zeros_invalid=False,
#                          zero_threshold=1e-6,
#                          expand_region=True,
#                          threshold=4.0):
# def chamfer_distance(pred, target):
# def dodeca_parameters(dodeca_idx):
# def get_camera_to_world(viewpoint, center, world_up):
# def get_dodeca_camera_to_worlds():
# def gaps_depth_render_to_xyz(model_config, depth_image, camera_parameters):
# def angle_of_rotation_to_2d_rotation_matrix(angle_of_rotation):
# def fractional_vector_projection(e0, e1, p, falloff=2.0):
# def rotate_about_point(angle_of_rotation, point, to_rotate):
# def interpolate_from_grid(samples, grid):
# def reflect(samples, reflect_x=False, reflect_y=False, reflect_z=False):
# def z_reflect(samples):
# def get_world_to_camera(idx):
# def transform_depth_dodeca_to_xyz_dodeca(depth_dodeca):
# def transform_depth_dodeca_to_xyz_dodeca_np(depth_dodeca):
# def _unbatch(arr):
# def to_homogenous_np(arr, is_point=True):
# def depth_to_cam_np(im, xfov=0.5):
# def apply_tx_np(samples, tx, is_point=True):
# def depth_image_to_sdf_constraints(im, cam2world, xfov=0.5):
# def depth_dodeca_to_sdf_constraints(depth_ims):
# def depth_dodeca_to_samples(dodeca):
# def depth_image_to_class_constraints(im, cam2world, xfov=0.5):
# def depth_image_to_samples(im, cam2world, xfov=0.5):  # pylint:disable=unused-argument
# def apply_4x4(tensor, tx, are_points=True, batch_rank=None, sample_rank=None):
# def depth_image_to_xyz_image(depth_images, world_to_camera, xfov=0.5):
# def interpolate_from_grid_coordinates(samples, grid):
# 
# Path: ldif/util/file_util.py
# def readlines(p):
# def readbin(p):
# def writebin(p, s):
# def writetxt(p, s):
# def write_np(path, arr):
# def read_grd(path):
# def read_sif_v1(path, verbose=False):
# def read_lines(p):
# def read_image(p):
# def read_npz(p):
# def read_np(p):
# def read_txt_to_np(p):
# def read_py2_pkl(p):
# def write_mesh(path, mesh):
# def read_mesh(path):
# def read_csv(path):
# def read_normals(path_to_dir, im_count=20, leading='_depth'):
# def write_points(path_ext_optional, points):
# def write_grd(path, volume, world2grid=None):
# def write_depth_image(path, depth_image):


import importlib
import math
import numpy as np
import tensorflow as tf
from ldif.util import geom_util
from ldif.util.file_util import log
  zero = tf.zeros_like(st)
  one = tf.ones_like(st)
  base_rot = tf.stack([ct, st, zero, -st, ct, zero, zero, zero, one], axis=-1)
  base_rot = tf.reshape(base_rot, [batch_size, 3, 3])
  v_outer = tf.matmul(v[:, :, tf.newaxis], v[:, tf.newaxis, :])
  rotation_3x3 = tf.matmul(v_outer - tf.eye(3, batch_shape=[batch_size]),
                           base_rot)
  return rotation_to_tx(rotation_3x3)


def random_rotation_np():
  """Returns a uniformly random SO(3) rotation as a [3,3] numpy array."""
  vals = np.random.uniform(size=(3,))
  theta = vals[0] * 2.0 * np.pi
  phi = vals[1] * 2.0 * np.pi
  z = 2.0 * vals[2]
  r = np.sqrt(z)
  v = np.stack([r * np.sin(phi), r * np.cos(phi), np.sqrt(2.0 * (1 - vals[2]))])
  st = np.sin(theta)
  ct = np.cos(theta)
  base_rot = np.array([[ct, st, 0], [-st, ct, 0], [0, 0, 1]], dtype=np.float32)
  return (np.outer(v, v) - np.eye(3)).dot(base_rot)


def random_scales(batch_size, minval, maxval):
  scales = tf.random.uniform(
      shape=[batch_size, 3], minval=minval, maxval=maxval)
  hom_coord = tf.ones([batch_size, 1], dtype=tf.float32)
  scales = tf.concat([scales, hom_coord], axis=1)
  s = tf.linalg.diag(scales)

# Path: ldif/util/geom_util.py
# def ray_sphere_intersect(ray_start, ray_direction, sphere_center, sphere_radius,
#                          max_t):
# def to_homogeneous(t, is_point):
# def transform_points_with_normals(points, tx, normals=None):
# def transform_featured_points(points, tx):
# def rotation_to_tx(rot):
# def extract_points_near_origin(points, count, features=None):
# def local_views_of_shape(global_points,
#                          world2local,
#                          local_point_count,
#                          global_normals=None,
#                          global_features=None,
#                          zeros_invalid=False,
#                          zero_threshold=1e-6,
#                          expand_region=True,
#                          threshold=4.0):
# def chamfer_distance(pred, target):
# def dodeca_parameters(dodeca_idx):
# def get_camera_to_world(viewpoint, center, world_up):
# def get_dodeca_camera_to_worlds():
# def gaps_depth_render_to_xyz(model_config, depth_image, camera_parameters):
# def angle_of_rotation_to_2d_rotation_matrix(angle_of_rotation):
# def fractional_vector_projection(e0, e1, p, falloff=2.0):
# def rotate_about_point(angle_of_rotation, point, to_rotate):
# def interpolate_from_grid(samples, grid):
# def reflect(samples, reflect_x=False, reflect_y=False, reflect_z=False):
# def z_reflect(samples):
# def get_world_to_camera(idx):
# def transform_depth_dodeca_to_xyz_dodeca(depth_dodeca):
# def transform_depth_dodeca_to_xyz_dodeca_np(depth_dodeca):
# def _unbatch(arr):
# def to_homogenous_np(arr, is_point=True):
# def depth_to_cam_np(im, xfov=0.5):
# def apply_tx_np(samples, tx, is_point=True):
# def depth_image_to_sdf_constraints(im, cam2world, xfov=0.5):
# def depth_dodeca_to_sdf_constraints(depth_ims):
# def depth_dodeca_to_samples(dodeca):
# def depth_image_to_class_constraints(im, cam2world, xfov=0.5):
# def depth_image_to_samples(im, cam2world, xfov=0.5):  # pylint:disable=unused-argument
# def apply_4x4(tensor, tx, are_points=True, batch_rank=None, sample_rank=None):
# def depth_image_to_xyz_image(depth_images, world_to_camera, xfov=0.5):
# def interpolate_from_grid_coordinates(samples, grid):
# 
# Path: ldif/util/file_util.py
# def readlines(p):
# def readbin(p):
# def writebin(p, s):
# def writetxt(p, s):
# def write_np(path, arr):
# def read_grd(path):
# def read_sif_v1(path, verbose=False):
# def read_lines(p):
# def read_image(p):
# def read_npz(p):
# def read_np(p):
# def read_txt_to_np(p):
# def read_py2_pkl(p):
# def write_mesh(path, mesh):
# def read_mesh(path):
# def read_csv(path):
# def read_normals(path_to_dir, im_count=20, leading='_depth'):
# def write_points(path_ext_optional, points):
# def write_grd(path, volume, world2grid=None):
# def write_depth_image(path, depth_image):


# Path: ldif/util/random_util.py
import importlib
import math
import numpy as np
import tensorflow as tf
from ldif.util import geom_util
from ldif.util.file_util import log

  zero = tf.zeros_like(st)
  one = tf.ones_like(st)
  base_rot = tf.stack([ct, st, zero, -st, ct, zero, zero, zero, one], axis=-1)
  base_rot = tf.reshape(base_rot, [batch_size, 3, 3])
  v_outer = tf.matmul(v[:, :, tf.newaxis], v[:, tf.newaxis, :])
  rotation_3x3 = tf.matmul(v_outer - tf.eye(3, batch_shape=[batch_size]),
                           base_rot)
  return rotation_to_tx(rotation_3x3)


def random_rotation_np():
  """Returns a uniformly random SO(3) rotation as a [3,3] numpy array."""
  vals = np.random.uniform(size=(3,))
  theta = vals[0] * 2.0 * np.pi
  phi = vals[1] * 2.0 * np.pi
  z = 2.0 * vals[2]
  r = np.sqrt(z)
  v = np.stack([r * np.sin(phi), r * np.cos(phi), np.sqrt(2.0 * (1 - vals[2]))])
  st = np.sin(theta)
  ct = np.cos(theta)
  base_rot = np.array([[ct, st, 0], [-st, ct, 0], [0, 0, 1]], dtype=np.float32)
  return (np.outer(v, v) - np.eye(3)).dot(base_rot)


def random_scales(batch_size, minval, maxval):
  scales = tf.random.uniform(
      shape=[batch_size, 3], minval=minval, maxval=maxval)
  hom_coord = tf.ones([batch_size, 1], dtype=tf.float32)
  scales = tf.concat([scales, hom_coord], axis=1)
  s = tf.linalg.diag(scales)

  log.info(s.get_shape().as_list())