// File: tomfunkhouser[P]gaps/pkgs/R3Surfels/R3SurfelUtils.cpp
// Function: gaps::EstimateOrientedBBox(gaps::R3SurfelPointSet*)
R3OrientedBox 
EstimateOrientedBBox(R3SurfelPointSet *pointset)
{
  // Check pointset
  if (pointset->NPoints() == 0) return R3null_oriented_box;
    
  // Get centroid 
  R3Point centroid = pointset->Centroid();

  // Search for best axes
  int nxsteps = 1;
  int nysteps = 1;
  int nzsteps = 16;
  RNVolume best_volume = FLT_MAX;
  R3OrientedBox best_obb = R3null_oriented_box;
  for (int ix = 0; ix < nxsteps; ix++) {
    for (int iy = 0; iy < nysteps; iy++) {
      for (int iz = 0; iz < nzsteps; iz++) {
        R3Triad axes = R3xyz_triad;
        axes.Rotate(RN_X, ix*0.5*RN_PI/nxsteps);
        axes.Rotate(RN_Y, iy*0.5*RN_PI/nysteps);
        axes.Rotate(RN_Z, iz*0.5*RN_PI/nzsteps);

        // Compute oriented bbox
        R3OrientedBox obb = EstimateOrientedBBox(pointset, centroid, axes);
        RNVolume volume = obb.Volume();
        if (volume < best_volume) {
          best_volume = volume;
          best_obb = obb;
        }
      }
    }
  }
      
  // Check if should rotate around Z by 90 degrees to make axis0 the longer axis
  if (best_obb.Radius(0) < best_obb.Radius(1)) {
    best_obb.Reset(best_obb.Center(), best_obb.Axis(1), -(best_obb.Axis(0)),
      best_obb.Radius(1), best_obb.Radius(0), best_obb.Radius(2));
  }

  // Return best oriented box
  return best_obb;
}

// Assembly:
subq $0x1a8, %rsp            # imm = 0x1A8
movq %rdi, 0x50(%rsp)
movq %rdi, %rax
movq %rax, 0x58(%rsp)
movq %rdi, 0x1a0(%rsp)
movq %rsi, 0x198(%rsp)
movq 0x198(%rsp), %rdi
callq 0x18700
cmpl $0x0, %eax
jne 0x3dc6c
movq 0x50(%rsp), %rdi
leaq 0x1bf46e(%rip), %rsi    # 0x1fd0d0
callq 0xc7980
jmp 0x3e046
movq 0x198(%rsp), %rsi
leaq 0x180(%rsp), %rdi
callq 0x560c0
movq 0x50(%rsp), %rdi
movl $0x1, 0x17c(%rsp)
movl $0x1, 0x178(%rsp)
movl $0x10, 0x174(%rsp)
movsd 0x1664e1(%rip), %xmm0   # 0x1a4190
movsd %xmm0, 0x168(%rsp)
movb $0x0, 0x167(%rsp)
leaq 0x1bf409(%rip), %rsi    # 0x1fd0d0
callq 0xc7980
movl $0x0, 0x160(%rsp)
movl 0x160(%rsp), %eax
cmpl 0x17c(%rsp), %eax
jge 0x3df1f
movl $0x0, 0x15c(%rsp)
movl 0x15c(%rsp), %eax
cmpl 0x178(%rsp), %eax
jge 0x3df07
movl $0x0, 0x158(%rsp)
movl 0x158(%rsp), %eax
cmpl 0x174(%rsp), %eax
jge 0x3deef
leaq 0x1bf8f8(%rip), %rsi    # 0x1fd628
leaq 0x110(%rsp), %rdi
callq 0xd5be0
jmp 0x3dd3f
cvtsi2sdl 0x160(%rsp), %xmm0
movsd 0x166408(%rip), %xmm1   # 0x1a4158
mulsd %xmm1, %xmm0
leaq 0x16b5a5(%rip), %rax    # 0x1a9300
movsd (%rax), %xmm1
mulsd %xmm1, %xmm0
cvtsi2sdl 0x17c(%rsp), %xmm1
divsd %xmm1, %xmm0
leaq 0x110(%rsp), %rdi
xorl %esi, %esi
callq 0xd61a0
jmp 0x3dd81
cvtsi2sdl 0x15c(%rsp), %xmm0
movsd 0x1663c6(%rip), %xmm1   # 0x1a4158
mulsd %xmm1, %xmm0
leaq 0x16b563(%rip), %rax    # 0x1a9300
movsd (%rax), %xmm1
mulsd %xmm1, %xmm0
cvtsi2sdl 0x178(%rsp), %xmm1
divsd %xmm1, %xmm0
leaq 0x110(%rsp), %rdi
movl $0x1, %esi
callq 0xd61a0
jmp 0x3ddc6
cvtsi2sdl 0x158(%rsp), %xmm0
movsd 0x166381(%rip), %xmm1   # 0x1a4158
mulsd %xmm1, %xmm0
leaq 0x16b51e(%rip), %rax    # 0x1a9300
movsd (%rax), %xmm1
mulsd %xmm1, %xmm0
cvtsi2sdl 0x174(%rsp), %xmm1
divsd %xmm1, %xmm0
leaq 0x110(%rsp), %rdi
movl $0x2, %esi
callq 0xd61a0
jmp 0x3de0b
movq 0x198(%rsp), %rsi
leaq 0x80(%rsp), %rdi
leaq 0x180(%rsp), %rdx
leaq 0x110(%rsp), %rcx
callq 0x3d740
jmp 0x3de32
leaq 0x80(%rsp), %rdi
callq 0xc8cf0
movsd %xmm0, 0x48(%rsp)
jmp 0x3de47
movsd 0x48(%rsp), %xmm0
movsd %xmm0, 0x78(%rsp)
movsd 0x78(%rsp), %xmm1
movsd 0x168(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x3decc
movq 0x50(%rsp), %rdi
movsd 0x78(%rsp), %xmm0
movsd %xmm0, 0x168(%rsp)
leaq 0x80(%rsp), %rsi
callq 0x443b0
jmp 0x3de8b
jmp 0x3decc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
jmp 0x3e03a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
leaq 0x80(%rsp), %rdi
callq 0x1bd00
jmp 0x3e03a
leaq 0x80(%rsp), %rdi
callq 0x1bd00
movl 0x158(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x158(%rsp)
jmp 0x3dd15
jmp 0x3def1
movl 0x15c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x15c(%rsp)
jmp 0x3dcf6
jmp 0x3df09
movl 0x160(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x160(%rsp)
jmp 0x3dcd7
movq 0x50(%rsp), %rdi
xorl %esi, %esi
callq 0x1c270
movsd %xmm0, 0x40(%rsp)
jmp 0x3df33
movq 0x50(%rsp), %rdi
movl $0x1, %esi
callq 0x1c270
movsd %xmm0, 0x38(%rsp)
jmp 0x3df4a
movsd 0x38(%rsp), %xmm0
movsd 0x40(%rsp), %xmm1
ucomisd %xmm1, %xmm0
jbe 0x3e01c
movq 0x50(%rsp), %rdi
callq 0x43aa0
movq %rax, 0x30(%rsp)
jmp 0x3df71
movq 0x50(%rsp), %rdi
movl $0x1, %esi
callq 0x43ac0
movq %rax, 0x28(%rsp)
jmp 0x3df87
movq 0x50(%rsp), %rdi
xorl %esi, %esi
callq 0x43ac0
movq %rax, 0x20(%rsp)
jmp 0x3df9a
movq 0x20(%rsp), %rsi
leaq 0x60(%rsp), %rdi
callq 0xfa7a0
jmp 0x3dfab
movq 0x50(%rsp), %rdi
movl $0x1, %esi
callq 0x1c270
movsd %xmm0, 0x18(%rsp)
jmp 0x3dfc2
movq 0x50(%rsp), %rdi
xorl %esi, %esi
callq 0x1c270
movsd %xmm0, 0x10(%rsp)
jmp 0x3dfd6
movq 0x50(%rsp), %rdi
movl $0x2, %esi
callq 0x1c270
movsd %xmm0, 0x8(%rsp)
jmp 0x3dfed
movsd 0x8(%rsp), %xmm2
movsd 0x10(%rsp), %xmm1
movsd 0x18(%rsp), %xmm0
movq 0x28(%rsp), %rdx
movq 0x30(%rsp), %rsi
movq 0x50(%rsp), %rdi
leaq 0x60(%rsp), %rcx
callq 0xc98d0
jmp 0x3e01a
jmp 0x3e01c
movb $0x1, 0x167(%rsp)
testb $0x1, 0x167(%rsp)
jne 0x3e038
movq 0x50(%rsp), %rdi
callq 0x1bd00
jmp 0x3e046
movq 0x50(%rsp), %rdi
callq 0x1bd00
jmp 0x3e053
movq 0x58(%rsp), %rax
addq $0x1a8, %rsp            # imm = 0x1A8
retq
movq 0x108(%rsp), %rdi
callq 0x13970