// File: tomfunkhouser[P]gaps/apps/msh2pts/msh2pts.cpp
// Function: SelectPropertyExtrema(gaps::R3Mesh*, gaps::R3MeshProperty*, int, double, int)
static RNArray<Point *> *
SelectPropertyExtrema(R3Mesh *mesh, R3MeshProperty *prp,
  int npoints, double min_spacing, int extrema_type)
{
  // Copy property 
  R3MeshProperty property(*prp);

  // Normalize property
  property.Normalize();

  // Select points from successively blurred property until number of extrema is npoints
  int max_blurs = 0;
  RNScalar epsilon = 0;
  RNScalar sigma = 0.01 * sqrt(mesh->Area());
  RNArray<R3MeshVertex *> selected_vertices;
  for (int blur = 0; blur <= max_blurs; blur++) { 
    // Find extremum vertices
    RNArray<R3MeshVertex *> extremum_vertices;
    for (int i = 0; i < mesh->NVertices(); i++) {
      R3MeshVertex *vertex = mesh->Vertex(i);
      if (!IsLocalExtremum(mesh, vertex, &property, extrema_type, epsilon)) continue; 
      extremum_vertices.Insert(vertex);
    }

    // Sort extremum vertices by property value
    for (int i = 0; i < extremum_vertices.NEntries(); i++) {
      for (int j = i+1; j < extremum_vertices.NEntries(); j++) {
        RNScalar value_i = property.VertexValue(extremum_vertices[i]);
        RNScalar value_j = property.VertexValue(extremum_vertices[j]);
        if (extrema_type == PROPERTY_MINIMA) { if (value_i > value_j) extremum_vertices.Swap(i, j); }
        else if (extrema_type == PROPERTY_MAXIMA) { if (value_i < value_j) extremum_vertices.Swap(i, j); }
        else { if (fabs(value_i) < fabs(value_j)) extremum_vertices.Swap(i, j); }
      }
    }

    // Select amongst extremum vertices taking into account min_spacing
    R3mesh_mark++;
    selected_vertices.Empty();
    for (int i = 0; i < extremum_vertices.NEntries(); i++) {
      R3MeshVertex *vertex = extremum_vertices.Kth(i);

      // Check if vertex is marked (i.e., too close to vertex previously selected)
      if (mesh->VertexMark(vertex) == R3mesh_mark) continue;

      // Check if vertex is disconnected completely
      if (mesh->VertexValence(vertex) == 0) continue;
    
      // Select vertex
      selected_vertices.Insert(vertex);

      // Mark nearby vertices
      mesh->SetVertexMark(vertex, R3mesh_mark);
      if (min_spacing > 0) {
        RNLength *distances = mesh->DijkstraDistances(vertex, min_spacing);
        for (int j = 0; j < mesh->NVertices(); j++) {
          R3MeshVertex *nearby_vertex = mesh->Vertex(j);
          if (mesh->VertexMark(nearby_vertex) != R3mesh_mark) {
            if (distances[j] <= min_spacing) {
              mesh->SetVertexMark(nearby_vertex, R3mesh_mark);
            }
          }
        } 
        delete [] distances;
      }
    }

    // Print debug statement
    if (print_debug) printf("  %d : %d %g %g\n", blur, selected_vertices.NEntries(), sigma, property.StandardDeviation());

    // Check if found correct number of points
    if ((npoints <= 0) || (selected_vertices.NEntries() <= npoints)) break;

    // Blur the property and iterate
    if (blur < max_blurs) {
      property.Blur(sigma);
      sigma *= 1.1;
    }
  }

  // For debugging purposes
  if (print_debug) property.Write("foo.val");

  // Allocate array of points
  RNArray<Point *> *points = new RNArray<Point *>();
  if (!points) {
    RNFail("Unable to allocate array of points\n");
    return NULL;
  }

  // Create points
  for (int i = 0; (i < selected_vertices.NEntries()) && (i < npoints); i++) {
    R3MeshVertex *vertex = selected_vertices[i];
    Point *point = new Point(mesh, vertex);
    points->Insert(point);
  }

  // Return points
  return points;
}

// Assembly:
subq $0x5e8, %rsp            # imm = 0x5E8
movq %rdi, 0x5d8(%rsp)
movq %rsi, 0x5d0(%rsp)
movl %edx, 0x5cc(%rsp)
movsd %xmm0, 0x5c0(%rsp)
movl %ecx, 0x5bc(%rsp)
movq 0x5d0(%rsp), %rsi
leaq 0x170(%rsp), %rdi
movq %rdi, 0xa8(%rsp)
callq 0x26500
movq 0xa8(%rsp), %rdi
callq 0x29580
jmp 0x1792a
movl $0x0, 0x160(%rsp)
movq $0x0, 0x158(%rsp)
movq 0x5d8(%rsp), %rdi
callq 0x41930
movsd %xmm0, 0xa0(%rsp)
jmp 0x17959
movsd 0xa0(%rsp), %xmm0
callq 0xf390
movsd 0x1326d1(%rip), %xmm1   # 0x14a040
mulsd %xmm1, %xmm0
movsd %xmm0, 0x150(%rsp)
leaq 0x140(%rsp), %rdi
callq 0x1e540
jmp 0x1798b
movl $0x0, 0x13c(%rsp)
movl 0x13c(%rsp), %eax
cmpl 0x160(%rsp), %eax
jg 0x1804a
leaq 0x128(%rsp), %rdi
callq 0x1e540
jmp 0x179b9
movl $0x0, 0x124(%rsp)
movl 0x124(%rsp), %eax
movl %eax, 0x9c(%rsp)
movq 0x5d8(%rsp), %rdi
callq 0x1b460
movl %eax, %ecx
movl 0x9c(%rsp), %eax
cmpl %ecx, %eax
jge 0x17ae9
movq 0x5d8(%rsp), %rdi
movl 0x124(%rsp), %esi
callq 0x1b5b0
movq %rax, 0x90(%rsp)
jmp 0x17a0e
movq 0x90(%rsp), %rax
movq %rax, 0x118(%rsp)
movq 0x5d8(%rsp), %rdi
movq 0x118(%rsp), %rsi
movl 0x5bc(%rsp), %ecx
movsd 0x158(%rsp), %xmm0
leaq 0x170(%rsp), %rdx
callq 0x1a500
movl %eax, 0x8c(%rsp)
jmp 0x17a54
movl 0x8c(%rsp), %eax
cmpl $0x0, %eax
jne 0x17aba
jmp 0x17ad3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x168(%rsp)
movl %eax, 0x164(%rsp)
jmp 0x18250
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x168(%rsp)
movl %eax, 0x164(%rsp)
jmp 0x18243
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x168(%rsp)
movl %eax, 0x164(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x1e550
jmp 0x18243
movq 0x118(%rsp), %rsi
leaq 0x128(%rsp), %rdi
callq 0x1e5b0
jmp 0x17ad1
jmp 0x17ad3
movl 0x124(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x124(%rsp)
jmp 0x179c4
movl $0x0, 0x114(%rsp)
movl 0x114(%rsp), %eax
movl %eax, 0x88(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x1b2f0
movl %eax, %ecx
movl 0x88(%rsp), %eax
cmpl %ecx, %eax
jge 0x17cf1
movl 0x114(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x110(%rsp)
movl 0x110(%rsp), %eax
movl %eax, 0x84(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x1b2f0
movl %eax, %ecx
movl 0x84(%rsp), %eax
cmpl %ecx, %eax
jge 0x17cd9
movl 0x114(%rsp), %esi
leaq 0x128(%rsp), %rdi
callq 0x1f300
movq %rax, 0x78(%rsp)
jmp 0x17b78
movq 0x78(%rsp), %rax
movq (%rax), %rsi
leaq 0x170(%rsp), %rdi
callq 0x1b9a0
movsd %xmm0, 0x70(%rsp)
jmp 0x17b95
movsd 0x70(%rsp), %xmm0
movsd %xmm0, 0x108(%rsp)
movl 0x110(%rsp), %esi
leaq 0x128(%rsp), %rdi
callq 0x1f300
movq %rax, 0x68(%rsp)
jmp 0x17bbf
movq 0x68(%rsp), %rax
movq (%rax), %rsi
leaq 0x170(%rsp), %rdi
callq 0x1b9a0
movsd %xmm0, 0x60(%rsp)
jmp 0x17bdc
movsd 0x60(%rsp), %xmm0
movsd %xmm0, 0x100(%rsp)
cmpl $0xb, 0x5bc(%rsp)
jne 0x17c2d
movsd 0x108(%rsp), %xmm0
ucomisd 0x100(%rsp), %xmm0
jbe 0x17c28
movl 0x114(%rsp), %esi
movl 0x110(%rsp), %edx
leaq 0x128(%rsp), %rdi
callq 0xe8d90
jmp 0x17c26
jmp 0x17c28
jmp 0x17cc1
cmpl $0xa, 0x5bc(%rsp)
jne 0x17c70
movsd 0x108(%rsp), %xmm1
movsd 0x100(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x17c6e
movl 0x114(%rsp), %esi
movl 0x110(%rsp), %edx
leaq 0x128(%rsp), %rdi
callq 0xe8d90
jmp 0x17c6c
jmp 0x17c6e
jmp 0x17cbf
movsd 0x108(%rsp), %xmm1
movaps 0x1323f0(%rip), %xmm0   # 0x14a070
pand %xmm0, %xmm1
movsd 0x100(%rsp), %xmm0
movaps 0x1323dc(%rip), %xmm2   # 0x14a070
pand %xmm2, %xmm0
ucomisd %xmm1, %xmm0
jbe 0x17cbd
movl 0x114(%rsp), %esi
movl 0x110(%rsp), %edx
leaq 0x128(%rsp), %rdi
callq 0xe8d90
jmp 0x17cbb
jmp 0x17cbd
jmp 0x17cbf
jmp 0x17cc1
jmp 0x17cc3
movl 0x110(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x110(%rsp)
jmp 0x17b31
jmp 0x17cdb
movl 0x114(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x114(%rsp)
jmp 0x17af4
leaq 0x170858(%rip), %rax    # 0x188550
movl (%rax), %ecx
incl %ecx
movl %ecx, (%rax)
leaq 0x140(%rsp), %rdi
xorl %esi, %esi
callq 0xe8c00
jmp 0x17d0f
movl $0x0, 0xfc(%rsp)
movl 0xfc(%rsp), %eax
movl %eax, 0x5c(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x1b2f0
movl %eax, %ecx
movl 0x5c(%rsp), %eax
cmpl %ecx, %eax
jge 0x17f2d
movl 0xfc(%rsp), %esi
leaq 0x128(%rsp), %rdi
callq 0x1e590
movq %rax, 0xf0(%rsp)
movq 0x5d8(%rsp), %rdi
movq 0xf0(%rsp), %rsi
callq 0x1b610
leaq 0x1707d8(%rip), %rcx    # 0x188550
cmpl (%rcx), %eax
jne 0x17d81
jmp 0x17f17
movq 0x5d8(%rsp), %rdi
movq 0xf0(%rsp), %rsi
callq 0x1e5e0
cmpl $0x0, %eax
jne 0x17da0
jmp 0x17f17
movq 0xf0(%rsp), %rsi
leaq 0x140(%rsp), %rdi
callq 0x1e5b0
jmp 0x17db7
movq 0x5d8(%rsp), %rdi
movq 0xf0(%rsp), %rsi
leaq 0x170782(%rip), %rax    # 0x188550
movl (%rax), %edx
callq 0x1b6e0
movsd 0x5c0(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x17f15
movq 0x5d8(%rsp), %rdi
movq 0xf0(%rsp), %rsi
movsd 0x5c0(%rsp), %xmm0
xorl %eax, %eax
movl %eax, %edx
callq 0x54770
movq %rax, 0x50(%rsp)
jmp 0x17e14
movq 0x50(%rsp), %rax
movq %rax, 0xe8(%rsp)
movl $0x0, 0xe4(%rsp)
movl 0xe4(%rsp), %eax
movl %eax, 0x4c(%rsp)
movq 0x5d8(%rsp), %rdi
callq 0x1b460
movl %eax, %ecx
movl 0x4c(%rsp), %eax
cmpl %ecx, %eax
jge 0x17ef6
movq 0x5d8(%rsp), %rdi
movl 0xe4(%rsp), %esi
callq 0x1b5b0
movq %rax, 0x40(%rsp)
jmp 0x17e6d
movq 0x40(%rsp), %rax
movq %rax, 0xd8(%rsp)
movq 0x5d8(%rsp), %rdi
movq 0xd8(%rsp), %rsi
callq 0x1b610
leaq 0x1706ba(%rip), %rcx    # 0x188550
cmpl (%rcx), %eax
je 0x17ede
movq 0xe8(%rsp), %rax
movslq 0xe4(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm1
movsd 0x5c0(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jb 0x17edc
movq 0x5d8(%rsp), %rdi
movq 0xd8(%rsp), %rsi
leaq 0x17067b(%rip), %rax    # 0x188550
movl (%rax), %edx
callq 0x1b6e0
jmp 0x17ede
jmp 0x17ee0
movl 0xe4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xe4(%rsp)
jmp 0x17e2c
movq 0xe8(%rsp), %rax
movq %rax, 0x38(%rsp)
cmpq $0x0, %rax
je 0x17f13
movq 0x38(%rsp), %rdi
callq 0xf680
jmp 0x17f15
jmp 0x17f17
movl 0xfc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xfc(%rsp)
jmp 0x17d1a
cmpl $0x0, 0x1796c8(%rip)    # 0x1915fc
je 0x17f9c
movl 0x13c(%rsp), %eax
movl %eax, 0x20(%rsp)
leaq 0x140(%rsp), %rdi
callq 0x1b2f0
movl %eax, 0x24(%rsp)
movsd 0x150(%rsp), %xmm0
movsd %xmm0, 0x28(%rsp)
leaq 0x170(%rsp), %rdi
callq 0x273b0
movsd %xmm0, 0x30(%rsp)
jmp 0x17f76
movsd 0x30(%rsp), %xmm1
movsd 0x28(%rsp), %xmm0
movl 0x24(%rsp), %edx
movl 0x20(%rsp), %esi
leaq 0x1326ff(%rip), %rdi    # 0x14a690
movb $0x2, %al
callq 0xf070
jmp 0x17f9a
jmp 0x17f9c
cmpl $0x0, 0x5cc(%rsp)
jle 0x17fbc
leaq 0x140(%rsp), %rdi
callq 0x1b2f0
cmpl 0x5cc(%rsp), %eax
jg 0x17fc9
movl $0x2, 0xd4(%rsp)
jmp 0x18016
movl 0x13c(%rsp), %eax
cmpl 0x160(%rsp), %eax
jge 0x1800b
movsd 0x150(%rsp), %xmm0
leaq 0x170(%rsp), %rdi
callq 0x29e30
jmp 0x17ff1
movsd 0x13204f(%rip), %xmm0   # 0x14a048
mulsd 0x150(%rsp), %xmm0
movsd %xmm0, 0x150(%rsp)
movl $0x0, 0xd4(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x1e550
movl 0xd4(%rsp), %eax
testl %eax, %eax
je 0x18032
jmp 0x18030
jmp 0x1804a
jmp 0x18034
movl 0x13c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x13c(%rsp)
jmp 0x17996
cmpl $0x0, 0x1795ab(%rip)    # 0x1915fc
je 0x1806b
leaq 0x132647(%rip), %rsi    # 0x14a6a1
leaq 0x170(%rsp), %rdi
callq 0x2af60
jmp 0x18069
jmp 0x1806b
movl $0x10, %edi
callq 0xf4d0
movq %rax, 0x18(%rsp)
jmp 0x1807c
movq 0x18(%rsp), %rdi
callq 0x1b5a0
jmp 0x18088
movq 0x18(%rsp), %rax
movq %rax, 0xc8(%rsp)
cmpq $0x0, 0xc8(%rsp)
jne 0x180f4
leaq 0x132568(%rip), %rdi    # 0x14a60f
xorl %eax, %eax
callq 0xebe00
jmp 0x180b0
movq $0x0, 0x5e0(%rsp)
movl $0x1, 0xd4(%rsp)
jmp 0x18219
movq 0x18(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x168(%rsp)
movl %eax, 0x164(%rsp)
movl $0x10, %esi
callq 0xf4e0
jmp 0x18243
movl $0x0, 0xc4(%rsp)
movl 0xc4(%rsp), %eax
movl %eax, 0x10(%rsp)
leaq 0x140(%rsp), %rdi
callq 0x1b2f0
movl 0x10(%rsp), %ecx
movl %eax, %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, 0x17(%rsp)
jge 0x1813c
movl 0xc4(%rsp), %eax
cmpl 0x5cc(%rsp), %eax
setl %al
movb %al, 0x17(%rsp)
movb 0x17(%rsp), %al
testb $0x1, %al
jne 0x18149
jmp 0x181fe
movl 0xc4(%rsp), %esi
leaq 0x140(%rsp), %rdi
callq 0x1f300
movq %rax, 0x8(%rsp)
jmp 0x18164
movq 0x8(%rsp), %rax
movq (%rax), %rax
movq %rax, 0xb8(%rsp)
movl $0x48, %edi
callq 0xf4d0
movq %rax, (%rsp)
jmp 0x18184
movq (%rsp), %rdi
movq 0x5d8(%rsp), %rsi
movq 0xb8(%rsp), %rdx
callq 0x1b650
jmp 0x1819f
movq (%rsp), %rax
movq %rax, 0xb0(%rsp)
movq 0xc8(%rsp), %rdi
movq 0xb0(%rsp), %rsi
callq 0x1b540
jmp 0x181c2
jmp 0x181c4
movl 0xc4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc4(%rsp)
jmp 0x180ff
movq (%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x168(%rsp)
movl %eax, 0x164(%rsp)
movl $0x48, %esi
callq 0xf4e0
jmp 0x18243
movq 0xc8(%rsp), %rax
movq %rax, 0x5e0(%rsp)
movl $0x1, 0xd4(%rsp)
leaq 0x140(%rsp), %rdi
callq 0x1e550
leaq 0x170(%rsp), %rdi
callq 0x26680
movq 0x5e0(%rsp), %rax
addq $0x5e8, %rsp            # imm = 0x5E8
retq
leaq 0x140(%rsp), %rdi
callq 0x1e550
leaq 0x170(%rsp), %rdi
callq 0x26680
movq 0x168(%rsp), %rdi
callq 0xf8a0
nopw (%rax,%rax)