// File: tomfunkhouser[P]gaps/pkgs/R3Shapes/R3Mesh.cpp
// Function: gaps::R3Mesh::MergeCoincidentVertices(double)
void R3Mesh::
MergeCoincidentVertices(RNLength epsilon)
{
  // Compute epsilon
  if (epsilon < 0.0) epsilon = 0.0001 * bbox.DiagonalLength();

  // Allocate grid 
  const int NUM_GRID_CELLS = 32;
  RNArray<R3MeshVertex *> ***grid = new RNArray<R3MeshVertex *> **[NUM_GRID_CELLS];
  for (int i = 0; i < NUM_GRID_CELLS; i++) {
    grid[i] = new RNArray<R3MeshVertex *> *[NUM_GRID_CELLS];
    for (int j = 0; j < NUM_GRID_CELLS; j++) {
      grid[i][j] = new RNArray<R3MeshVertex *> [NUM_GRID_CELLS];
    }
  }
  
  // Load all vertices into a regular grid
  for (int i = 0; i < vertices.NEntries(); i++) {
    R3MeshVertex *v = vertices[i];
    const R3Point& p = v->position;
    int ix = (int) (NUM_GRID_CELLS * (p.X() - bbox.XMin()) / bbox.XLength());
    int iy = (int) (NUM_GRID_CELLS * (p.Y() - bbox.YMin()) / bbox.YLength());
    int iz = (int) (NUM_GRID_CELLS * (p.Z() - bbox.ZMin()) / bbox.ZLength());
    if (ix < 0) ix = 0; else if (ix > NUM_GRID_CELLS-1) ix = NUM_GRID_CELLS-1;
    if (iy < 0) iy = 0; else if (iy > NUM_GRID_CELLS-1) iy = NUM_GRID_CELLS-1;
    if (iz < 0) iz = 0; else if (iz > NUM_GRID_CELLS-1) iz = NUM_GRID_CELLS-1;
    grid[ix][iy][iz].Insert(v);
  }

  // Merge coincident vertices in same grid cell
  for (int ix = 0; ix < NUM_GRID_CELLS; ix++) {
    for (int iy = 0; iy < NUM_GRID_CELLS; iy++) {
      for (int iz = 0; iz < NUM_GRID_CELLS; iz++) {
        // Consider all pairs of vertices in same cell
        for (int j = 0; j < grid[ix][iy][iz].NEntries(); j++) {
          R3MeshVertex *v1 = grid[ix][iy][iz].Kth(j);
          for (int k = j+1; k < grid[ix][iy][iz].NEntries(); k++) {
            R3MeshVertex *v2 = grid[ix][iy][iz].Kth(k);
            // Check if vertices are coincident
            if (R3Contains(v1->position, v2->position)) {
              // Merge coincident vertices
              MergeVertex(v1, v2);
            }
          }
        }
      }
    }
  }

  // Delete grid
  for (int i = 0; i < NUM_GRID_CELLS; i++) {
    for (int j = 0; j < NUM_GRID_CELLS; j++) {
      delete [] grid[i][j];
    }
    delete [] grid[i];
  }
  delete [] grid;
}

// Assembly:
subq $0x148, %rsp            # imm = 0x148
movq %rdi, 0x140(%rsp)
movsd %xmm0, 0x138(%rsp)
movq 0x140(%rsp), %rax
movq %rax, 0xb8(%rsp)
xorps %xmm0, %xmm0
ucomisd 0x138(%rsp), %xmm0
jbe 0x1b782
movq 0xb8(%rsp), %rdi
addq $0xf8, %rdi
callq 0x43d60
movaps %xmm0, %xmm1
movsd 0x117a9b(%rip), %xmm0   # 0x133210
mulsd %xmm1, %xmm0
movsd %xmm0, 0x138(%rsp)
movl $0x20, 0x134(%rsp)
movl $0x100, %edi            # imm = 0x100
callq 0xf030
movq %rax, 0x128(%rsp)
movl $0x0, 0x124(%rsp)
cmpl $0x20, 0x124(%rsp)
jge 0x1b93b
movl $0x100, %edi            # imm = 0x100
callq 0xf030
movq %rax, %rdx
movq 0x128(%rsp), %rax
movslq 0x124(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
movl $0x0, 0x120(%rsp)
cmpl $0x20, 0x120(%rsp)
jge 0x1b923
movl $0x208, %edi            # imm = 0x208
callq 0xf030
movq %rax, 0x98(%rsp)
movq $0x20, (%rax)
addq $0x8, %rax
movq %rax, 0xa0(%rsp)
movq %rax, %rcx
addq $0x200, %rcx            # imm = 0x200
movq %rcx, 0xa8(%rsp)
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rdi
movq %rdi, 0x90(%rsp)
callq 0x36800
jmp 0x1b848
movq 0xa8(%rsp), %rcx
movq 0x90(%rsp), %rax
addq $0x10, %rax
cmpq %rcx, %rax
movq %rax, 0xb0(%rsp)
jne 0x1b831
movq 0xa0(%rsp), %rdx
movq 0x128(%rsp), %rax
movslq 0x124(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0x120(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
movl 0x120(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x120(%rsp)
jmp 0x1b7e4
movq 0xa0(%rsp), %rcx
movq %rax, %rsi
movq 0x90(%rsp), %rax
movq %rsi, 0x118(%rsp)
movl %edx, 0x114(%rsp)
cmpq %rax, %rcx
movq %rax, 0x88(%rsp)
je 0x1b90c
movq 0x88(%rsp), %rdi
addq $-0x10, %rdi
movq %rdi, 0x80(%rsp)
callq 0x36850
movq 0xa0(%rsp), %rcx
movq 0x80(%rsp), %rax
cmpq %rcx, %rax
movq %rax, 0x88(%rsp)
jne 0x1b8d6
movq 0x98(%rsp), %rdi
movl $0x208, %esi            # imm = 0x208
callq 0xf990
jmp 0x1bf59
jmp 0x1b925
movl 0x124(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x124(%rsp)
jmp 0x1b7aa
movl $0x0, 0x110(%rsp)
movq 0xb8(%rsp), %rdi
movl 0x110(%rsp), %eax
movl %eax, 0x7c(%rsp)
addq $0x8, %rdi
callq 0x13600
movl %eax, %ecx
movl 0x7c(%rsp), %eax
cmpl %ecx, %eax
jge 0x1bbd0
movq 0xb8(%rsp), %rdi
addq $0x8, %rdi
movl 0x110(%rsp), %esi
callq 0x37800
movq (%rax), %rax
movq %rax, 0x108(%rsp)
movq 0x108(%rsp), %rax
addq $0x18, %rax
movq %rax, 0x100(%rsp)
movq 0x100(%rsp), %rdi
callq 0x37820
movq 0xb8(%rsp), %rdi
movsd %xmm0, 0x48(%rsp)
addq $0xf8, %rdi
callq 0x37830
movsd 0x48(%rsp), %xmm1
movq 0xb8(%rsp), %rdi
subsd %xmm0, %xmm1
movsd 0x117830(%rip), %xmm0   # 0x133218
mulsd %xmm1, %xmm0
movsd %xmm0, 0x50(%rsp)
addq $0xf8, %rdi
callq 0x37850
movaps %xmm0, %xmm1
movsd 0x50(%rsp), %xmm0
divsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, 0xfc(%rsp)
movq 0x100(%rsp), %rdi
callq 0x37870
movq 0xb8(%rsp), %rdi
movsd %xmm0, 0x58(%rsp)
addq $0xf8, %rdi
callq 0x37880
movsd 0x58(%rsp), %xmm1
movq 0xb8(%rsp), %rdi
subsd %xmm0, %xmm1
movsd 0x1177c1(%rip), %xmm0   # 0x133218
mulsd %xmm1, %xmm0
movsd %xmm0, 0x60(%rsp)
addq $0xf8, %rdi
callq 0x378a0
movaps %xmm0, %xmm1
movsd 0x60(%rsp), %xmm0
divsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, 0xf8(%rsp)
movq 0x100(%rsp), %rdi
callq 0x378c0
movq 0xb8(%rsp), %rdi
movsd %xmm0, 0x68(%rsp)
addq $0xf8, %rdi
callq 0x378d0
movsd 0x68(%rsp), %xmm1
movq 0xb8(%rsp), %rdi
subsd %xmm0, %xmm1
movsd 0x117752(%rip), %xmm0   # 0x133218
mulsd %xmm1, %xmm0
movsd %xmm0, 0x70(%rsp)
addq $0xf8, %rdi
callq 0x378f0
movaps %xmm0, %xmm1
movsd 0x70(%rsp), %xmm0
divsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, 0xf4(%rsp)
cmpl $0x0, 0xfc(%rsp)
jge 0x1bb0b
movl $0x0, 0xfc(%rsp)
jmp 0x1bb22
cmpl $0x1f, 0xfc(%rsp)
jle 0x1bb20
movl $0x1f, 0xfc(%rsp)
jmp 0x1bb22
cmpl $0x0, 0xf8(%rsp)
jge 0x1bb39
movl $0x0, 0xf8(%rsp)
jmp 0x1bb50
cmpl $0x1f, 0xf8(%rsp)
jle 0x1bb4e
movl $0x1f, 0xf8(%rsp)
jmp 0x1bb50
cmpl $0x0, 0xf4(%rsp)
jge 0x1bb67
movl $0x0, 0xf4(%rsp)
jmp 0x1bb7e
cmpl $0x1f, 0xf4(%rsp)
jle 0x1bb7c
movl $0x1f, 0xf4(%rsp)
jmp 0x1bb7e
movq 0x128(%rsp), %rax
movslq 0xfc(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0xf8(%rsp), %rcx
movq (%rax,%rcx,8), %rdi
movslq 0xf4(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
movq 0x108(%rsp), %rsi
callq 0x37410
movl 0x110(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x110(%rsp)
jmp 0x1b946
movl $0x0, 0xf0(%rsp)
cmpl $0x20, 0xf0(%rsp)
jge 0x1be12
movl $0x0, 0xec(%rsp)
cmpl $0x20, 0xec(%rsp)
jge 0x1bdfa
movl $0x0, 0xe8(%rsp)
cmpl $0x20, 0xe8(%rsp)
jge 0x1bde2
movl $0x0, 0xe4(%rsp)
movl 0xe4(%rsp), %eax
movl %eax, 0x44(%rsp)
movq 0x128(%rsp), %rax
movslq 0xf0(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0xec(%rsp), %rcx
movq (%rax,%rcx,8), %rdi
movslq 0xe8(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
callq 0x13600
movl %eax, %ecx
movl 0x44(%rsp), %eax
cmpl %ecx, %eax
jge 0x1bdca
movq 0x128(%rsp), %rax
movslq 0xf0(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0xec(%rsp), %rcx
movq (%rax,%rcx,8), %rdi
movslq 0xe8(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
movl 0xe4(%rsp), %esi
callq 0x377e0
movq %rax, 0xd8(%rsp)
movl 0xe4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xd4(%rsp)
movl 0xd4(%rsp), %eax
movl %eax, 0x40(%rsp)
movq 0x128(%rsp), %rax
movslq 0xf0(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0xec(%rsp), %rcx
movq (%rax,%rcx,8), %rdi
movslq 0xe8(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
callq 0x13600
movl %eax, %ecx
movl 0x40(%rsp), %eax
cmpl %ecx, %eax
jge 0x1bdb2
movq 0x128(%rsp), %rax
movslq 0xf0(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0xec(%rsp), %rcx
movq (%rax,%rcx,8), %rdi
movslq 0xe8(%rsp), %rax
shlq $0x4, %rax
addq %rax, %rdi
movl 0xd4(%rsp), %esi
callq 0x377e0
movq %rax, 0xc8(%rsp)
movq 0xd8(%rsp), %rdi
addq $0x18, %rdi
movq 0xc8(%rsp), %rsi
addq $0x18, %rsi
callq 0x82180
cmpl $0x0, %eax
je 0x1bd9a
movq 0xb8(%rsp), %rdi
movq 0xd8(%rsp), %rsi
movq 0xc8(%rsp), %rdx
movq (%rdi), %rax
callq *0x88(%rax)
jmp 0x1bd9c
movl 0xd4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xd4(%rsp)
jmp 0x1bcc7
jmp 0x1bdb4
movl 0xe4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xe4(%rsp)
jmp 0x1bc26
jmp 0x1bdcc
movl 0xe8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xe8(%rsp)
jmp 0x1bc0d
jmp 0x1bde4
movl 0xec(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xec(%rsp)
jmp 0x1bbf4
jmp 0x1bdfc
movl 0xf0(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xf0(%rsp)
jmp 0x1bbdb
movl $0x0, 0xc4(%rsp)
cmpl $0x20, 0xc4(%rsp)
jge 0x1bf34
movl $0x0, 0xc0(%rsp)
cmpl $0x20, 0xc0(%rsp)
jge 0x1bef3
movq 0x128(%rsp), %rax
movslq 0xc4(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0xc0(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x38(%rsp)
cmpq $0x0, %rax
je 0x1bedb
movq 0x38(%rsp), %rcx
movq %rcx, %rax
addq $-0x8, %rax
movq %rax, 0x20(%rsp)
movq -0x8(%rcx), %rdx
movq %rdx, 0x28(%rsp)
shlq $0x4, %rdx
movq %rcx, %rax
addq %rdx, %rax
cmpq %rax, %rcx
movq %rax, 0x30(%rsp)
je 0x1bec4
movq 0x30(%rsp), %rdi
addq $-0x10, %rdi
movq %rdi, 0x18(%rsp)
callq 0x36850
movq 0x38(%rsp), %rcx
movq 0x18(%rsp), %rax
cmpq %rcx, %rax
movq %rax, 0x30(%rsp)
jne 0x1be9d
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %rsi
shlq $0x4, %rsi
addq $0x8, %rsi
callq 0xf990
jmp 0x1bedd
movl 0xc0(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc0(%rsp)
jmp 0x1be36
movq 0x128(%rsp), %rax
movslq 0xc4(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x10(%rsp)
cmpq $0x0, %rax
je 0x1bf1c
movq 0x10(%rsp), %rdi
callq 0xf670
jmp 0x1bf1e
movl 0xc4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc4(%rsp)
jmp 0x1be1d
movq 0x128(%rsp), %rax
movq %rax, 0x8(%rsp)
cmpq $0x0, %rax
je 0x1bf51
movq 0x8(%rsp), %rdi
callq 0xf670
addq $0x148, %rsp            # imm = 0x148
retq
movq 0x118(%rsp), %rdi
callq 0xf890
nopw %cs:(%rax,%rax)