// File: /workspace/github_cpp_makefile_star2_O2/tomfunkhouser[P]gaps/pkgs/GSV/GSVImage.cpp
// Function: gaps::GSVImage::RayThroughUndistortedPosition(gaps::R2Point const&) const
R3Ray GSVImage::
RayThroughUndistortedPosition(const R2Point& undistorted_image_position) const
{
  // Check camera
  if (!Camera()) return R3null_ray;

  // Compute distorted image position
  R2Point distorted_image_position = DistortedPosition(undistorted_image_position);
  if (distorted_image_position == R2Point(-1,-1)) return R3null_ray;
  
  // Get column index
  int column_index = (int) (distorted_image_position.X() + 0.5);
  if (column_index < 0) column_index = 0;
  if (column_index >= Width()) column_index = Width()-1;
      
  // Get camera pose
  GSVPose pose = Pose(column_index);
  const R3Point& viewpoint = pose.Viewpoint();
  const R3Vector& towards = pose.Towards();
  const R3Vector& up = pose.Up();
  R3Vector right = towards % up;

  // Compute point on ray
  RNScalar dx = (RNScalar) (2 * (undistorted_image_position.X() - 0.5 * Width())) / (RNScalar) Width();
  RNScalar dy = (RNScalar) (2 * (undistorted_image_position.Y() - 0.5 * Height())) / (RNScalar) Height();
  R3Point world_point = viewpoint + towards;
  world_point += dx * right * tan(0.5 * Camera()->XFov());
  world_point += dy * up * tan(0.5 * Camera()->YFov());

  // Return ray through undistorted image point
  return R3Ray(viewpoint, world_point);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xf8, %rsp
movq %rdi, %rbx
movq 0x8(%rsi), %rax
testq %rax, %rax
je 0x3b75b
cmpq $0x0, 0x18(%rax)
je 0x3b75b
movq %rdx, %r12
movq %rsi, %r14
leaq 0x90(%rsp), %r15
movq %r15, %rdi
callq 0x3b20a
leaq 0xa0(%rsp), %r13
movsd 0xef928(%rip), %xmm0    # 0x12b068
movq %r13, %rdi
movapd %xmm0, %xmm1
callq 0xdb258
movq %r15, %rdi
movq %r13, %rsi
callq 0xdb528
testl %eax, %eax
je 0x3b77f
leaq 0x58cc5e(%rip), %rsi    # 0x5c83c0
movq %rbx, %rdi
callq 0xc0a08
movq %rbx, %rax
addq $0xf8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movsd 0x90(%rsp), %xmm0
addsd 0xef8a8(%rip), %xmm0    # 0x12b038
cvttsd2si %xmm0, %eax
xorl %ebp, %ebp
testl %eax, %eax
cmovgl %eax, %ebp
movq %r14, %rdi
callq 0x3ac8e
leal -0x1(%rax), %edx
cmpl %eax, %ebp
cmovll %ebp, %edx
leaq 0xa0(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x3acd2
leaq 0x78(%rsp), %rdi
movq %r15, %rsi
callq 0x41e74
leaq 0x60(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
callq 0x41eba
leaq 0xe0(%rsp), %rdi
leaq 0x78(%rsp), %rsi
leaq 0x60(%rsp), %rdx
callq 0xc1c6e
leaq 0xa8(%rsp), %r15
movsd (%r12), %xmm0
movsd %xmm0, 0x10(%rsp)
movq %r14, %rdi
callq 0x3ac8e
movl %eax, %r13d
movsd 0x8(%r12), %xmm0
movsd %xmm0, 0x8(%rsp)
movq %r14, %rdi
callq 0x3acb0
movl %eax, %ebp
leaq 0x48(%rsp), %rdi
leaq 0x78(%rsp), %rdx
movq %r15, %rsi
callq 0xc10c3
cvtsi2sd %r13d, %xmm1
movsd 0xef88f(%rip), %xmm0    # 0x12b0d8
mulsd %xmm1, %xmm0
addsd 0x10(%rsp), %xmm0
addsd %xmm0, %xmm0
divsd %xmm1, %xmm0
leaq 0x18(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0xc1cb2
movq 0x8(%r14), %rax
movq 0x18(%rax), %rdi
callq 0x3ba56
mulsd 0xef7b6(%rip), %xmm0    # 0x12b038
callq 0x274e0
leaq 0x30(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0xc1cb2
leaq 0x48(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0xc114c
cvtsi2sd %ebp, %xmm1
movsd 0xef827(%rip), %xmm0    # 0x12b0d8
mulsd %xmm1, %xmm0
addsd 0x8(%rsp), %xmm0
addsd %xmm0, %xmm0
divsd %xmm1, %xmm0
leaq 0x18(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0xc1cb2
movq 0x8(%r14), %rax
movq 0x18(%rax), %rdi
callq 0x3babc
mulsd 0xef751(%rip), %xmm0    # 0x12b038
callq 0x274e0
leaq 0x30(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0xc1cb2
leaq 0x48(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0xc114c
leaq 0x48(%rsp), %rdx
movq %rbx, %rdi
movq %r15, %rsi
callq 0xc0a14
leaq 0xa0(%rsp), %rdi
callq 0x41e6a
jmp 0x3b76a
jmp 0x3b936
jmp 0x3b936
jmp 0x3b936
jmp 0x3b936
jmp 0x3b936
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
callq 0x41e6a
movq %rbx, %rdi
callq 0x28170