Spaces:
Running
Running
# Copyright 2016 The TensorFlow Authors All Rights Reserved. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
# ============================================================================== | |
"""Utilities for generating and applying rotation matrices. | |
""" | |
import numpy as np | |
ANGLE_EPS = 0.001 | |
def normalize(v): | |
return v / np.linalg.norm(v) | |
def get_r_matrix(ax_, angle): | |
ax = normalize(ax_) | |
if np.abs(angle) > ANGLE_EPS: | |
S_hat = np.array( | |
[[0.0, -ax[2], ax[1]], [ax[2], 0.0, -ax[0]], [-ax[1], ax[0], 0.0]], | |
dtype=np.float32) | |
R = np.eye(3) + np.sin(angle)*S_hat + \ | |
(1-np.cos(angle))*(np.linalg.matrix_power(S_hat, 2)) | |
else: | |
R = np.eye(3) | |
return R | |
def r_between(v_from_, v_to_): | |
v_from = normalize(v_from_) | |
v_to = normalize(v_to_) | |
ax = normalize(np.cross(v_from, v_to)) | |
angle = np.arccos(np.dot(v_from, v_to)) | |
return get_r_matrix(ax, angle) | |
def rotate_camera_to_point_at(up_from, lookat_from, up_to, lookat_to): | |
inputs = [up_from, lookat_from, up_to, lookat_to] | |
for i in range(4): | |
inputs[i] = normalize(np.array(inputs[i]).reshape((-1,))) | |
up_from, lookat_from, up_to, lookat_to = inputs | |
r1 = r_between(lookat_from, lookat_to) | |
new_x = np.dot(r1, np.array([1, 0, 0]).reshape((-1, 1))).reshape((-1)) | |
to_x = normalize(np.cross(lookat_to, up_to)) | |
angle = np.arccos(np.dot(new_x, to_x)) | |
if angle > ANGLE_EPS: | |
if angle < np.pi - ANGLE_EPS: | |
ax = normalize(np.cross(new_x, to_x)) | |
flip = np.dot(lookat_to, ax) | |
if flip > 0: | |
r2 = get_r_matrix(lookat_to, angle) | |
elif flip < 0: | |
r2 = get_r_matrix(lookat_to, -1. * angle) | |
else: | |
# Angle of rotation is too close to 180 degrees, direction of rotation | |
# does not matter. | |
r2 = get_r_matrix(lookat_to, angle) | |
else: | |
r2 = np.eye(3) | |
return np.dot(r2, r1) | |