// File: /workspace/github_cpp_makefile_star2_O3/tomfunkhouser[P]gaps/pkgs/R3Shapes/R3MeshSearchTree.cpp
// Function: gaps::R3MeshSearchTree::FindClosest(gaps::R3Point const&, gaps::R3Vector const&, gaps::R3MeshIntersection&, double, double, int (*)(gaps::R3Point const&, gaps::R3Vector const&, gaps::R3Mesh*, gaps::R3MeshFace*, void*), void*)
void R3MeshSearchTree::
FindClosest(const R3Point& query_position, const R3Vector& query_normal, R3MeshIntersection& closest,
  RNScalar min_distance, RNScalar max_distance, 
  int (*IsCompatible)(const R3Point&, const R3Vector&, R3Mesh *, R3MeshFace *, void *), void *compatible_data)
{
  // Initialize result
  closest.type = R3_MESH_NULL_TYPE;
  closest.vertex = NULL;
  closest.edge = NULL;
  closest.face = NULL;
  closest.point = R3zero_point;
  closest.t = 0;

  // Check root
  if (!root) return;

  // Update mark (used to avoid checking same face twice)
  mark++;

  // Use squared distances for efficiency
  RNScalar min_distance_squared = min_distance * min_distance;
  RNScalar closest_distance_squared = max_distance * max_distance;

  // Search nodes recursively
  FindClosest(query_position, query_normal, closest, 
    min_distance_squared, closest_distance_squared, 
    IsCompatible, compatible_data, 
    root, BBox());

  // Update result
  closest.t = sqrt(closest_distance_squared);
  if (closest.type == R3_MESH_VERTEX_TYPE) { 
    closest.face = mesh->FaceOnVertex(closest.vertex);
    closest.edge = mesh->EdgeOnVertex(closest.vertex, closest.face, RN_CCW); 
  }
  else if (closest.type == R3_MESH_EDGE_TYPE) { 
    R3MeshVertex *v0 = mesh->VertexOnEdge(closest.edge, 0);
    R3MeshVertex *v1 = mesh->VertexOnEdge(closest.edge, 1);
    const R3Point& p0 = mesh->VertexPosition(v0);
    const R3Point& p1 = mesh->VertexPosition(v1);
    RNScalar dd0 = R3SquaredDistance(query_position, p0);
    RNScalar dd1 = R3SquaredDistance(query_position, p1);
    closest.vertex = (dd0 < dd1) ? v0 : v1;
    closest.face = mesh->FaceOnEdge(closest.edge);
  }
  else if (closest.type == R3_MESH_FACE_TYPE) { 
    R3MeshVertex *v0 = mesh->VertexOnFace(closest.face, 0);
    R3MeshVertex *v1 = mesh->VertexOnFace(closest.face, 1);
    R3MeshVertex *v2 = mesh->VertexOnFace(closest.face, 2);
    const R3Point& p0 = mesh->VertexPosition(v0);
    const R3Point& p1 = mesh->VertexPosition(v1);
    const R3Point& p2 = mesh->VertexPosition(v2);
    RNScalar dd0 = R3SquaredDistance(query_position, p0);
    RNScalar dd1 = R3SquaredDistance(query_position, p1);
    RNScalar dd2 = R3SquaredDistance(query_position, p2);
    if (dd0 < dd1) closest.vertex = (dd0 < dd2) ? v0 : v2;
    else closest.vertex = (dd1 < dd2) ? v1 : v2;
  }

  // Just checking
  assert((closest.type == R3_MESH_NULL_TYPE) || (RNIsZero(R3SquaredDistance(closest.point, mesh->ClosestPointOnFace(closest.face, closest.point)), RN_SMALL_EPSILON)));
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %r9, (%rsp)
movq %r8, %r13
movsd %xmm1, 0x8(%rsp)
movsd %xmm0, 0x10(%rsp)
movq %rcx, %rbx
movq %rdx, %rbp
movq %rsi, %r12
movq %rdi, %r14
movl $0x0, (%rcx)
leaq 0x20(%rcx), %rdi
xorpd %xmm0, %xmm0
movupd %xmm0, 0x8(%rcx)
xorl %r15d, %r15d
movq %r15, 0x18(%rcx)
leaq 0x4d9786(%rip), %rsi    # 0x4f0d60
callq 0x500a6
movq %r15, 0x38(%rbx)
movq 0x8(%r14), %rax
testq %rax, %rax
je 0x17798
incl 0x14(%r14)
movsd 0x10(%rsp), %xmm0
mulsd %xmm0, %xmm0
movsd 0x8(%rsp), %xmm1
mulsd %xmm1, %xmm1
leaq 0x20(%rsp), %r15
movsd %xmm1, (%r15)
movl $0xf8, %r10d
addq (%r14), %r10
subq $0x8, %rsp
movq %r14, %rdi
movq %r12, 0x18(%rsp)
movq %r12, %rsi
movq %rbp, %rdx
movq %rbx, %rcx
movq %r15, %r8
movq %r13, %r9
pushq %r10
pushq %rax
pushq 0x18(%rsp)
callq 0x17240
addq $0x20, %rsp
movsd (%r15), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jb 0x1765b
sqrtsd %xmm0, %xmm0
jmp 0x17660
callq 0xe340
movsd %xmm0, 0x38(%rbx)
movl (%rbx), %eax
cmpl $0x3, %eax
movq 0x10(%rsp), %r13
je 0x17721
cmpl $0x2, %eax
je 0x176d0
cmpl $0x1, %eax
jne 0x17798
leaq 0x8(%rbx), %rax
movq (%rax), %rsi
movslq 0x14(%rsi), %rax
testq %rax, %rax
jle 0x176b7
movq 0x8(%rsi), %rcx
xorl %edi, %edi
movq (%rcx,%rdi,8), %r8
movq 0x20(%r8), %rdx
testq %rdx, %rdx
jne 0x176b9
movq 0x18(%r8), %rdx
testq %rdx, %rdx
jne 0x176b9
incq %rdi
cmpq %rdi, %rax
jne 0x17699
xorl %edx, %edx
movq %rdx, 0x18(%rbx)
movq (%r14), %rdi
xorl %ecx, %ecx
callq 0x258b8
movq %rax, 0x10(%rbx)
jmp 0x17798
movq 0x10(%rbx), %rax
movq 0x8(%rax), %r15
movq 0x10(%rax), %r12
leaq 0x18(%r15), %rsi
leaq 0x18(%r12), %r14
movq %r13, %rdi
callq 0x2070f
movsd %xmm0, (%rsp)
movq %r13, %rdi
movq %r14, %rsi
callq 0x2070f
ucomisd (%rsp), %xmm0
cmovaq %r15, %r12
movq %r12, 0x8(%rbx)
movq 0x10(%rbx), %rcx
movq 0x20(%rcx), %rax
testq %rax, %rax
jne 0x1771b
movq 0x18(%rcx), %rax
movq %rax, 0x18(%rbx)
jmp 0x17798
movq 0x18(%rbx), %rax
movq 0x8(%rax), %rbp
movq 0x10(%rax), %r12
movq %r13, %r15
movq 0x18(%rax), %r13
leaq 0x18(%rbp), %rsi
leaq 0x18(%r12), %r14
leaq 0x18(%r13), %rax
movq %rax, 0x8(%rsp)
movq %r15, %rdi
callq 0x2070f
movsd %xmm0, (%rsp)
movq %r15, %rdi
movq %r14, %rsi
callq 0x2070f
movsd %xmm0, 0x18(%rsp)
movq %r15, %rdi
movq 0x8(%rsp), %rsi
callq 0x2070f
movsd 0x18(%rsp), %xmm2
ucomisd %xmm2, %xmm0
cmovbeq %r13, %r12
movsd (%rsp), %xmm1
ucomisd %xmm1, %xmm0
cmovaq %rbp, %r13
ucomisd %xmm1, %xmm2
cmovbeq %r12, %r13
movq %r13, 0x8(%rbx)
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop