// File: tomfunkhouser[P]gaps/apps/msh2df/msh2df.cpp
// Function: SmoothDistanceAtRefinementBoundary(gaps::R3Grid*, int)
static int
SmoothDistanceAtRefinementBoundary(R3Grid *grid, int refinement_radius)
{
  // Start statistics
  RNTime start_time;
  start_time.Read();
  int count = 0;

  // Copy original grid values
  R3Grid copy_grid(*grid);
  
  // Smooth distance at grid cells near boundary between kdtree and grid estimation
  RNLength grid_spacing = grid->GridToWorldScaleFactor();
  RNScalar min_distance = (refinement_radius-2) * grid_spacing;
  RNScalar max_distance = (refinement_radius+2) * grid_spacing;
  if (min_distance < 2*grid_spacing) min_distance = 2*grid_spacing;
  for (int iz = 0; iz < grid->ZResolution(); iz++) {
    for (int iy = 0; iy < grid->YResolution(); iy++) {
      for (int ix = 0; ix < grid->XResolution(); ix++) {
        // Check if on refinement boundary
        RNScalar grid_value = copy_grid.GridValue(ix, iy, iz);
        if (fabs(grid_value) > max_distance) continue;
        if (fabs(grid_value) < min_distance) continue;

        // Compute weighted sum of distances for neighbor cells
        RNScalar sum_weight = 0;
        RNScalar sum_distance = 0;
        for (int dz = -1; dz <= 1; dz++) {
          int gz = iz + dz;
          if ((gz < 0) || (gz >= grid->ZResolution())) continue;
          for (int dy = -1; dy <= 1; dy++) {
            int gy = iy + dy;
            if ((gy < 0) || (gy >= grid->YResolution())) continue;
            for (int dx = -1; dx <= 1; dx++) {
              int gx = ix + dx;
              if ((gx < 0) || (gx >= grid->XResolution())) continue;
              RNScalar weight = pow(2, -(dx + dy + dz));
              RNScalar distance = copy_grid.GridValue(gx, gy, gz);
              sum_distance += weight * distance;
              sum_weight += weight;
            }
          }
        }
        
        // Set smoothed distance
        if (RNIsZero(sum_weight)) continue;
        RNScalar distance = sum_distance / sum_weight;
        grid->SetGridValue(ix, iy, iz, distance);
        count++;
      }
    }
  }

  // Print statistics
  if (print_verbose) {
    printf("Smoothed refinement boundary ...\n");
    printf("  Time = %.2f seconds\n", start_time.Elapsed());
    printf("  Resolution = %d %d %d\n", grid->XResolution(), grid->YResolution(), grid->ZResolution());
    printf("  Spacing = %g\n", grid->GridToWorldScaleFactor());
    printf("  Cardinality = %d\n", grid->Cardinality());
    printf("  Volume = %g\n", grid->Volume());
    RNInterval grid_range = grid->Range();
    printf("  Minimum = %g\n", grid_range.Min());
    printf("  Maximum = %g\n", grid_range.Max());
    printf("  L1Norm = %g\n", grid->L1Norm());
    printf("  L2Norm = %g\n", grid->L2Norm());
    printf("  Count = %d\n", count);
    fflush(stdout);
  }

  // Return success
  return 1;
}

// Assembly:
subq $0x368, %rsp            # imm = 0x368
movq %rdi, 0x360(%rsp)
movl %esi, 0x35c(%rsp)
leaq 0x348(%rsp), %rdi
callq 0xddf30
leaq 0x348(%rsp), %rdi
callq 0x17860
movl $0x0, 0x344(%rsp)
movq 0x360(%rsp), %rsi
leaq 0xf0(%rsp), %rdi
callq 0x7acf0
movq 0x360(%rsp), %rdi
callq 0x17b20
movsd %xmm0, 0xe8(%rsp)
movl 0x35c(%rsp), %eax
subl $0x2, %eax
cvtsi2sd %eax, %xmm0
mulsd 0xe8(%rsp), %xmm0
movsd %xmm0, 0xe0(%rsp)
movl 0x35c(%rsp), %eax
addl $0x2, %eax
cvtsi2sd %eax, %xmm0
mulsd 0xe8(%rsp), %xmm0
movsd %xmm0, 0xd8(%rsp)
movsd 0xe0(%rsp), %xmm1
movsd 0x12aaf1(%rip), %xmm0   # 0x140038
mulsd 0xe8(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x15570
movsd 0x12aada(%rip), %xmm0   # 0x140038
mulsd 0xe8(%rsp), %xmm0
movsd %xmm0, 0xe0(%rsp)
movl $0x0, 0xd4(%rsp)
movl 0xd4(%rsp), %eax
movl %eax, 0x5c(%rsp)
movq 0x360(%rsp), %rdi
callq 0x17b80
movl %eax, %ecx
movl 0x5c(%rsp), %eax
cmpl %ecx, %eax
jge 0x1598a
movl $0x0, 0xd0(%rsp)
movl 0xd0(%rsp), %eax
movl %eax, 0x58(%rsp)
movq 0x360(%rsp), %rdi
callq 0x17b60
movl %eax, %ecx
movl 0x58(%rsp), %eax
cmpl %ecx, %eax
jge 0x15972
movl $0x0, 0xcc(%rsp)
movl 0xcc(%rsp), %eax
movl %eax, 0x54(%rsp)
movq 0x360(%rsp), %rdi
callq 0x17b40
movl %eax, %ecx
movl 0x54(%rsp), %eax
cmpl %ecx, %eax
jge 0x1595a
movl 0xcc(%rsp), %esi
movl 0xd0(%rsp), %edx
movl 0xd4(%rsp), %ecx
leaq 0xf0(%rsp), %rdi
callq 0x17e80
movsd %xmm0, 0xc0(%rsp)
movsd 0xc0(%rsp), %xmm0
movaps 0x12aa22(%rip), %xmm1   # 0x140060
pand %xmm1, %xmm0
ucomisd 0xd8(%rsp), %xmm0
jbe 0x15652
jmp 0x15944
movsd 0xc0(%rsp), %xmm1
movaps 0x12a9fe(%rip), %xmm0   # 0x140060
pand %xmm0, %xmm1
movsd 0xe0(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1567a
jmp 0x15944
xorps %xmm0, %xmm0
movsd %xmm0, 0xb8(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0xb0(%rsp)
movl $0xffffffff, 0xac(%rsp) # imm = 0xFFFFFFFF
cmpl $0x1, 0xac(%rsp)
jg 0x158c3
movl 0xd4(%rsp), %eax
addl 0xac(%rsp), %eax
movl %eax, 0xa8(%rsp)
cmpl $0x0, 0xa8(%rsp)
jl 0x156ec
movl 0xa8(%rsp), %eax
movl %eax, 0x50(%rsp)
movq 0x360(%rsp), %rdi
callq 0x17b80
movl %eax, %ecx
movl 0x50(%rsp), %eax
cmpl %ecx, %eax
jl 0x156f1
jmp 0x158ad
movl $0xffffffff, 0xa4(%rsp) # imm = 0xFFFFFFFF
cmpl $0x1, 0xa4(%rsp)
jg 0x158ab
movl 0xd0(%rsp), %eax
addl 0xa4(%rsp), %eax
movl %eax, 0xa0(%rsp)
cmpl $0x0, 0xa0(%rsp)
jl 0x1574b
movl 0xa0(%rsp), %eax
movl %eax, 0x4c(%rsp)
movq 0x360(%rsp), %rdi
callq 0x17b60
movl %eax, %ecx
movl 0x4c(%rsp), %eax
cmpl %ecx, %eax
jl 0x15750
jmp 0x15895
movl $0xffffffff, 0x9c(%rsp) # imm = 0xFFFFFFFF
cmpl $0x1, 0x9c(%rsp)
jg 0x15893
movl 0xcc(%rsp), %eax
addl 0x9c(%rsp), %eax
movl %eax, 0x98(%rsp)
cmpl $0x0, 0x98(%rsp)
jl 0x157aa
movl 0x98(%rsp), %eax
movl %eax, 0x48(%rsp)
movq 0x360(%rsp), %rdi
callq 0x17b40
movl %eax, %ecx
movl 0x48(%rsp), %eax
cmpl %ecx, %eax
jl 0x157af
jmp 0x15857
movl 0x9c(%rsp), %esi
movl 0xa4(%rsp), %eax
addl %eax, %esi
movl 0xac(%rsp), %eax
addl %eax, %esi
negl %esi
movl $0x2, %edi
callq 0x1b060
movsd %xmm0, 0x40(%rsp)
jmp 0x157dc
movsd 0x40(%rsp), %xmm0
movsd %xmm0, 0x90(%rsp)
movl 0x98(%rsp), %esi
movl 0xa0(%rsp), %edx
movl 0xa8(%rsp), %ecx
leaq 0xf0(%rsp), %rdi
callq 0x17e80
movsd %xmm0, 0x78(%rsp)
movsd 0x90(%rsp), %xmm0
movsd 0x78(%rsp), %xmm2
movsd 0xb0(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0xb0(%rsp)
movsd 0x90(%rsp), %xmm0
addsd 0xb8(%rsp), %xmm0
movsd %xmm0, 0xb8(%rsp)
movl 0x9c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x9c(%rsp)
jmp 0x1575b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x88(%rsp)
movl %eax, 0x84(%rsp)
leaq 0xf0(%rsp), %rdi
callq 0x7ad90
jmp 0x15b6c
jmp 0x15895
movl 0xa4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xa4(%rsp)
jmp 0x156fc
jmp 0x158ad
movl 0xac(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xac(%rsp)
jmp 0x1569d
movsd 0xb8(%rsp), %xmm0
leaq 0x170c1d(%rip), %rax    # 0x1864f0
movsd (%rax), %xmm1
callq 0x1b080
movl %eax, 0x3c(%rsp)
jmp 0x158e2
movl 0x3c(%rsp), %eax
cmpl $0x0, %eax
je 0x158ed
jmp 0x15944
movsd 0xb0(%rsp), %xmm0
movsd 0xb8(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x70(%rsp)
movq 0x360(%rsp), %rdi
movl 0xcc(%rsp), %esi
movl 0xd0(%rsp), %edx
movl 0xd4(%rsp), %ecx
movsd 0x70(%rsp), %xmm0
callq 0x17ef0
jmp 0x15933
movl 0x344(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x344(%rsp)
movl 0xcc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xcc(%rsp)
jmp 0x155dd
jmp 0x1595c
movl 0xd0(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xd0(%rsp)
jmp 0x155ac
jmp 0x15974
movl 0xd4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xd4(%rsp)
jmp 0x1557b
cmpl $0x0, 0x170c67(%rip)    # 0x1865f8
je 0x15b52
leaq 0x12ab3a(%rip), %rdi    # 0x1404d8
xorl %eax, %eax
callq 0xf070
jmp 0x159a7
leaq 0x348(%rsp), %rdi
callq 0xddff0
movsd %xmm0, 0x30(%rsp)
jmp 0x159bc
movsd 0x30(%rsp), %xmm0
leaq 0x12a85a(%rip), %rdi    # 0x140223
movb $0x1, %al
callq 0xf070
jmp 0x159d2
movq 0x360(%rsp), %rdi
callq 0x17b40
movl %eax, 0x28(%rsp)
movq 0x360(%rsp), %rdi
callq 0x17b60
movl %eax, 0x2c(%rsp)
movq 0x360(%rsp), %rdi
callq 0x17b80
movl 0x28(%rsp), %esi
movl 0x2c(%rsp), %edx
movl %eax, %ecx
leaq 0x12a87e(%rip), %rdi    # 0x140290
xorl %eax, %eax
callq 0xf070
jmp 0x15a1b
movq 0x360(%rsp), %rdi
callq 0x17b20
leaq 0x12a87a(%rip), %rdi    # 0x1402a9
movb $0x1, %al
callq 0xf070
jmp 0x15a38
movq 0x360(%rsp), %rdi
callq 0x7b1f0
movl %eax, 0x24(%rsp)
jmp 0x15a4b
movl 0x24(%rsp), %esi
leaq 0x12a863(%rip), %rdi    # 0x1402b9
xorl %eax, %eax
callq 0xf070
jmp 0x15a5f
movq 0x360(%rsp), %rdi
callq 0x17ba0
movsd %xmm0, 0x18(%rsp)
jmp 0x15a74
movsd 0x18(%rsp), %xmm0
leaq 0x12a84c(%rip), %rdi    # 0x1402cd
movb $0x1, %al
callq 0xf070
jmp 0x15a8a
movq 0x360(%rsp), %rsi
leaq 0x60(%rsp), %rdi
callq 0x7aff0
jmp 0x15a9e
leaq 0x60(%rsp), %rdi
callq 0x17be0
leaq 0x12a82d(%rip), %rdi    # 0x1402dc
movb $0x1, %al
callq 0xf070
jmp 0x15ab8
leaq 0x60(%rsp), %rdi
callq 0x17bf0
leaq 0x12a823(%rip), %rdi    # 0x1402ec
movb $0x1, %al
callq 0xf070
jmp 0x15ad2
movq 0x360(%rsp), %rdi
callq 0x7b0e0
movsd %xmm0, 0x10(%rsp)
jmp 0x15ae7
movsd 0x10(%rsp), %xmm0
leaq 0x12a808(%rip), %rdi    # 0x1402fc
movb $0x1, %al
callq 0xf070
jmp 0x15afd
movq 0x360(%rsp), %rdi
callq 0x17c00
movsd %xmm0, 0x8(%rsp)
jmp 0x15b12
movsd 0x8(%rsp), %xmm0
leaq 0x12a7ec(%rip), %rdi    # 0x14030b
movb $0x1, %al
callq 0xf070
jmp 0x15b28
movl 0x344(%rsp), %esi
leaq 0x12a9c4(%rip), %rdi    # 0x1404fa
xorl %eax, %eax
callq 0xf070
jmp 0x15b3f
movq 0x16744a(%rip), %rax    # 0x17cf90
movq (%rax), %rdi
callq 0xf5d0
jmp 0x15b50
jmp 0x15b52
leaq 0xf0(%rsp), %rdi
callq 0x7ad90
movl $0x1, %eax
addq $0x368, %rsp            # imm = 0x368
retq
movq 0x88(%rsp), %rdi
callq 0xf890
nopl (%rax)