// File: /workspace/github_cpp_makefile_star2_O2/tomfunkhouser[P]gaps/pkgs/R3Shapes/R3Grid.cpp
// Function: gaps::R3Grid::ClusterWithMeanShift()
void R3Grid::
ClusterWithMeanShift(void)
{
  // Determine maximum number of iterations
  int max_iterations = XResolution();
  if (max_iterations < YResolution()) max_iterations = YResolution();
  if (max_iterations < ZResolution()) max_iterations = ZResolution();

  // Create gaussian kernel
  static RNScalar kernel[5][5][5];
  const double sigma = 1;
  const double denom = -2 * sigma * sigma;
  for (int jz = -2; jz <=2; jz++) {
    for (int jy = -2; jy <= 2; jy++) {
      for (int jx = -2; jx <= 2; jx++) {
        double dd = jx*jx + jy*jy + jz*jz;
        kernel[jx+2][jy+2][jz+2] = exp(dd/denom);
      }
    }
  }

  // Create flow
  int index = 0;
  int *flow = new int [ NEntries() ];
  for (int iz = 0; iz < ZResolution(); iz++) {
    for (int iy = 0; iy < YResolution(); iy++) {
      for (int ix = 0; ix < XResolution(); ix++) {
        flow[index] = -1;
        if (GridValue(ix, iy, iz) > 0) {
          R3Point position(ix, iy, iz);
          for (int k = 0; k < max_iterations; k++) {
            // Compute movement vector
            RNScalar weight = 0;
            R3Vector movement(0, 0, 0);
            for (int jz = -2; jz <= 2; jz++) {
              double z = position[2] + jz;
              for (int jy = -2; jy <= 2; jy++) {
                double y = position[1] + jy;
                for (int jx = -2; jx <= 2; jx++) {
                  double x = position[0] + jx;
                  RNScalar neighbor_value = GridValue(x, y, z);
                  if (neighbor_value > 0) {
                    RNScalar w = kernel[jx+2][jy+2][jz+2] * neighbor_value;
                    movement += R3Vector(w*jx, w*jy, w*jz);
                    weight += w;
                  }
                }
              }
            }
            
            // Move to centroid of neighbors
            if (weight == 0) break;
            if (RNIsZero(movement.Dot(movement))) break;
            position += movement / weight;
          }
          
          // Assign flow
          int fx = (int) (position[0] + 0.5);
          int fy = (int) (position[1] + 0.5);
          int fz = (int) (position[2] + 0.5);
          if (fx < 0) fx = 0;
          if (fy < 0) fy = 0;
          if (fz < 0) fz = 0;
          if (fx >= XResolution()) fx = XResolution() - 1;
          if (fy >= YResolution()) fx = YResolution() - 1;
          if (fz >= ZResolution()) fx = ZResolution() - 1;
          IndicesToIndex(fx, fy, fz, flow[index]);
        }
        index++;
      }
    }
  }

  // Compute cluster IDs
  int nclusters = 0;
  for (int i = 0; i < NEntries(); i++) {
    if (flow[i] == i) {
      SetGridValue(i, nclusters + 1);
      nclusters++;
    }
  }

  // Assign grid cells to cluster IDs
  for (int i = 0; i < NEntries(); i++) {
    if (flow[i] >= 0) {
      int index = flow[i];
      for (int j = 0; j < NEntries(); j++) {
        if (index == flow[index]) break;
        index = flow[index];
      }
      
      // Set grid value
      RNScalar cluster = GridValue(index);
      SetGridValue(i, cluster);
    }
  }

  // Delete flow
  delete [] flow;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
movq %rdi, %rbx
movl 0x238(%rdi), %eax
movl %eax, 0x20(%rsp)
movl 0x23c(%rdi), %eax
movl %eax, 0xc(%rsp)
movl 0x240(%rdi), %eax
movl %eax, 0x10(%rsp)
pushq $-0x2
popq %rax
leaq 0xab578(%rip), %r14     # 0xdb270
cmpq $0x3, %rax
je 0x2fd83
movq %rax, 0x28(%rsp)
imulq %rax, %rax
movq %rax, 0x38(%rsp)
movq %r14, 0x30(%rsp)
pushq $-0x2
popq %rbp
cmpq $0x3, %rbp
je 0x2fd6d
movq %rbp, %r15
imulq %rbp, %r15
addq 0x38(%rsp), %r15
movq %r14, %r12
pushq $-0x2
popq %r13
cmpq $0x3, %r13
je 0x2fd64
movl %r13d, %eax
imull %r13d, %eax
addl %r15d, %eax
cvtsi2sd %eax, %xmm0
mulsd 0x63513(%rip), %xmm0    # 0x93260
callq 0xe820
movsd %xmm0, (%r12)
incq %r13
addq $0xc8, %r12
jmp 0x2fd31
incq %rbp
addq $0x28, %r14
jmp 0x2fd18
movq 0x28(%rsp), %rax
incq %rax
movq 0x30(%rsp), %r14
addq $0x8, %r14
jmp 0x2fcf8
movl 0xc(%rsp), %eax
movl 0x20(%rsp), %ecx
cmpl %eax, %ecx
cmovgl %ecx, %eax
movl 0x10(%rsp), %ecx
cmpl %ecx, %eax
cmovlel %ecx, %eax
movl %eax, 0xc(%rsp)
movslq 0x24c(%rbx), %rax
leaq (,%rax,4), %rcx
testq %rax, %rax
pushq $-0x1
popq %rdi
cmovnsq %rcx, %rdi
callq 0xe030
movl 0x240(%rbx), %r10d
leaq 0xc0(%rsp), %r13
xorl %r9d, %r9d
xorl %r11d, %r11d
movq %rax, 0x68(%rsp)
cmpl %r10d, %r9d
jge 0x30151
cvtsi2sd %r9d, %xmm0
movsd %xmm0, 0x70(%rsp)
movl 0x23c(%rbx), %ecx
xorl %edx, %edx
movl %r9d, 0x44(%rsp)
cmpl %ecx, %edx
jge 0x30149
movl %edx, 0x1c(%rsp)
cvtsi2sd %edx, %xmm0
movsd %xmm0, 0x78(%rsp)
movslq %r11d, %r11
movl 0x238(%rbx), %edx
xorl %ebp, %ebp
cmpl %edx, %ebp
jge 0x3013e
orl $-0x1, (%rax,%r11,4)
movq 0x230(%rbx), %rsi
movl 0x248(%rbx), %edi
imull %r9d, %edi
movl 0x244(%rbx), %r8d
imull 0x1c(%rsp), %r8d
addl %ebp, %edi
addl %r8d, %edi
movslq %edi, %rdi
movsd (%rsi,%rdi,8), %xmm0
ucomisd 0x63391(%rip), %xmm0    # 0x931e8
jbe 0x30134
movq %r11, 0x80(%rsp)
movl %ebp, 0x48(%rsp)
cvtsi2sd %ebp, %xmm0
leaq 0x50(%rsp), %rdi
movsd 0x78(%rsp), %xmm1
movsd 0x70(%rsp), %xmm2
callq 0x37b4c
xorl %eax, %eax
cmpl 0xc(%rsp), %eax
jge 0x3006f
movl %eax, 0x4c(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
xorpd %xmm1, %xmm1
xorpd %xmm2, %xmm2
leaq 0xa8(%rsp), %rdi
callq 0x3830c
leaq 0xab3b7(%rip), %rbp     # 0xdb270
pushq $-0x2
popq %rax
cmpq $0x3, %rax
je 0x2fffc
movq %rax, 0x88(%rsp)
cvtsi2sd %eax, %xmm0
movsd 0x60(%rsp), %xmm1
movsd %xmm0, 0x98(%rsp)
addsd %xmm0, %xmm1
movsd %xmm1, 0x28(%rsp)
movq %rbp, 0x90(%rsp)
pushq $-0x2
popq %r14
cmpq $0x3, %r14
je 0x2ffe0
cvtsi2sd %r14d, %xmm0
movsd 0x58(%rsp), %xmm1
movsd %xmm0, 0xa0(%rsp)
addsd %xmm0, %xmm1
movsd %xmm1, 0x30(%rsp)
pushq $-0x2
popq %r15
xorl %r12d, %r12d
cmpq $0x3e8, %r12            # imm = 0x3E8
je 0x2ffd4
cvtsi2sd %r15d, %xmm1
movsd 0x50(%rsp), %xmm0
movsd %xmm1, 0x38(%rsp)
addsd %xmm1, %xmm0
movq %rbx, %rdi
movsd 0x30(%rsp), %xmm1
movsd 0x28(%rsp), %xmm2
callq 0x2be20
ucomisd 0x63284(%rip), %xmm0    # 0x931e8
jbe 0x2ffc5
mulsd (%rbp,%r12), %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0x38(%rsp), %xmm3
mulsd %xmm0, %xmm3
movapd %xmm0, %xmm1
mulsd 0xa0(%rsp), %xmm1
movapd %xmm0, %xmm2
mulsd 0x98(%rsp), %xmm2
movq %r13, %rdi
movapd %xmm3, %xmm0
callq 0x3830c
leaq 0xa8(%rsp), %rdi
movq %r13, %rsi
callq 0x38a24
movsd 0x10(%rsp), %xmm0
addsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
addq $0xc8, %r12
incl %r15d
jmp 0x2ff26
incq %r14
addq $0x28, %rbp
jmp 0x2fef7
movq 0x88(%rsp), %rax
incq %rax
movq 0x90(%rsp), %rbp
addq $0x8, %rbp
jmp 0x2febc
movsd 0x10(%rsp), %xmm0
ucomisd 0x631de(%rip), %xmm0    # 0x931e8
jne 0x3000e
jnp 0x3006f
leaq 0xa8(%rsp), %rdi
movq %rdi, %rsi
callq 0x38586
leaq 0xaab83(%rip), %rax     # 0xdaba8
movsd (%rax), %xmm1
movapd %xmm1, %xmm2
xorpd 0x62ffb(%rip), %xmm2    # 0x93030
ucomisd %xmm2, %xmm0
jb 0x30041
ucomisd %xmm0, %xmm1
jae 0x3006f
movq %r13, %rdi
leaq 0xa8(%rsp), %rsi
movsd 0x10(%rsp), %xmm0
callq 0x38d1e
leaq 0x50(%rsp), %rdi
movq %r13, %rsi
callq 0x37e9c
movl 0x4c(%rsp), %eax
incl %eax
jmp 0x2fe85
movsd 0x60(%rsp), %xmm0
addsd 0x62f93(%rip), %xmm0    # 0x93010
cvttsd2si %xmm0, %esi
testl %esi, %esi
movl $0x0, %eax
cmovlel %eax, %esi
movapd 0x50(%rsp), %xmm0
addpd 0x62fa7(%rip), %xmm0    # 0x93040
cvttpd2dq %xmm0, %xmm1
movapd %xmm1, %xmm0
pcmpgtd 0x63ca7(%rip), %xmm0    # 0x93d50
pand %xmm1, %xmm0
movq 0x238(%rbx), %rdx
movq %rdx, %xmm1
leal -0x1(%rdx), %eax
pcmpgtd %xmm0, %xmm1
pshufd $0x50, %xmm1, %xmm1     # xmm1 = xmm1[0,0,1,1]
movmskpd %xmm1, %edi
movd %xmm0, %r8d
testb $0x1, %dil
cmovel %eax, %r8d
movq %rdx, %rcx
shrq $0x20, %rcx
leal -0x1(%rcx), %r9d
testb $0x2, %dil
cmovnel %r8d, %r9d
movl 0x240(%rbx), %r10d
leal -0x1(%r10), %edi
cmpl %r10d, %esi
cmovll %r9d, %edi
imull 0x248(%rbx), %esi
pshufd $0x55, %xmm0, %xmm0     # xmm0 = xmm0[1,1,1,1]
movd %xmm0, %r8d
imull 0x244(%rbx), %r8d
addl %esi, %r8d
addl %edi, %r8d
movq 0x68(%rsp), %rax
movq 0x80(%rsp), %r11
movl %r8d, (%rax,%r11,4)
movl 0x44(%rsp), %r9d
movl 0x48(%rsp), %ebp
incq %r11
incl %ebp
jmp 0x2fe17
movl 0x1c(%rsp), %edx
incl %edx
jmp 0x2fdf6
incl %r9d
jmp 0x2fdd5
movl 0x24c(%rbx), %r10d
movq 0x230(%rbx), %rdx
xorl %esi, %esi
testl %r10d, %r10d
movl $0x0, %ecx
cmovgl %r10d, %ecx
xorl %edi, %edi
cmpq %rsi, %rcx
je 0x3018d
movl (%rax,%rsi,4), %r8d
cmpq %r8, %rsi
jne 0x30188
incl %edi
cvtsi2sd %edi, %xmm0
movsd %xmm0, (%rdx,%rsi,8)
incq %rsi
jmp 0x3016f
movq 0x230(%rbx), %rdx
incl %r10d
xorl %esi, %esi
cmpq %rcx, %rsi
je 0x301ca
movl (%rax,%rsi,4), %r8d
testl %r8d, %r8d
js 0x301c5
movl %r10d, %edi
movslq %r8d, %r9
decl %edi
je 0x301ba
movl (%rax,%r9,4), %r8d
cmpl %r8d, %r9d
jne 0x301aa
movsd (%rdx,%r9,8), %xmm0
movsd %xmm0, (%rdx,%rsi,8)
incq %rsi
jmp 0x30199
movq %rax, %rdi
callq 0xe5d0
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq