// File: tomfunkhouser[P]gaps/apps/msh2prp/msh2prp.cpp
// Function: ComputeLaplacianProperties(gaps::R3Mesh*)
static R3MeshPropertySet *
ComputeLaplacianProperties(R3Mesh *mesh)
{
  // Start statistics
  RNTime start_time;
  start_time.Read();
  if (print_verbose) {
    printf("Computing laplacian properties ...\n");
    fflush(stdout);
  }

  // Allocate property set
  R3MeshPropertySet *properties = new R3MeshPropertySet(mesh);
  if (!properties) {
    RNFail("Unable to allocate property set.\n");
    return NULL;
  }

  // Allocate/initialize laplacian matrix
  int n = mesh->NVertices();
  RNScalar *laplacian_matrix = new RNScalar [ n * n ];
  for (int i = 0; i < n * n; i++) laplacian_matrix[i] = 0;
  for (int i = 0; i < n; i++) laplacian_matrix[i*n+i] = -1;

  // Compute laplacian matrix entries
  for (int i1 = 0; i1 < n; i1++) {
    RNScalar total_weight = 0;
    R3MeshVertex *v1 = mesh->Vertex(i1);
    const R3Point& p1 = mesh->VertexPosition(v1);
    for (int j = 0; j < mesh->VertexValence(v1); j++) {
      R3MeshEdge *e = mesh->EdgeOnVertex(v1, j);
      R3MeshVertex *v2 = mesh->VertexAcrossEdge(e, v1);
      const R3Point& p2 = mesh->VertexPosition(v2);
      int i2 = mesh->VertexID(v2);

      // Compute cotan weight
      double weight = 0;
      for (int k = 0; k < 2; k++) {
        R3MeshFace *f = mesh->FaceOnEdge(e, k);
        if (!f) continue;
        R3MeshVertex *v3 = mesh->VertexAcrossFace(f, e);
        const R3Point& p3 = mesh->VertexPosition(v3);
        R3Vector vec1 = p1 - p3; vec1.Normalize();
        R3Vector vec2 = p2 - p3; vec2.Normalize();
        RNAngle angle = R3InteriorAngle(vec1, vec2);
        if (angle == 0) continue;
        double tan_angle = tan(angle);
        if (tan_angle == 0) continue;
        weight += 1.0 / tan_angle;
      }

      // Add weighted position
      laplacian_matrix[i1*n + i2] = weight;
      total_weight += weight;
    }

    // Normalize weights
    if (total_weight > 0) {
      for (int j = 0; j < mesh->VertexValence(v1); j++) {
        R3MeshEdge *e = mesh->EdgeOnVertex(v1, j);
        R3MeshVertex *v2 = mesh->VertexAcrossEdge(e, v1);
        int i2 = mesh->VertexID(v2);
        laplacian_matrix[i1*n + i2] /= total_weight;
      }
    }
  }

  // Compute eigenvectors of laplacian
  RNScalar *u = new RNScalar [ n * n ];
  RNScalar *eigenvalues = new RNScalar [ n  ];
  RNScalar *eigenvectors = new RNScalar [ n * n ];
  RNSvdDecompose(n, n, laplacian_matrix, u, eigenvalues, eigenvectors);

  // Determine time scale factor -- from [de Goes 2008] and [Rustimov 2010]
  RNScalar time_scale = 1;
  RNScalar lambda1 = eigenvalues[n-2];
  if (lambda1 > 0) time_scale = 1 / (2 * lambda1);

  // Compute HKS at several times
  RNScalar *hks = new RNScalar [ n ];
  RNScalar t = 0.01 * time_scale;
  for (int k = 0; k < 8; k++) {
    char name[256];
    sprintf(name, "HeatKernelSignature%d", k+1);
    R3MeshProperty *property = new R3MeshProperty(mesh, name);
    for (int i = 0; i < n; i++) {
      RNScalar hks = 0;
      for (int j = 0; j < n; j++) {
        RNScalar lambda = eigenvalues[j];
        RNScalar phi = eigenvectors[j*n+i];
        hks += exp(-t * lambda) * phi * phi;
      }
      property->SetVertexValue(i, hks);
    }
    InsertProperty(properties, property);
    t *= 2;
  }
  delete [] hks;

  // Create/insert properties
  int num_eigenvalues = 10;
  for (int i = 0; i < num_eigenvalues; i++) {
    char name[256];
    sprintf(name, "LaplacianEigenvector%d", i+1);
    R3MeshProperty *property = new R3MeshProperty(mesh, name);
    for (int j = 0; j < n; j++) property->SetVertexValue(j, eigenvectors[(n-i-1)*n+j]);
    InsertProperty(properties, property);
  }

  // Delete stuff
  delete [] laplacian_matrix;
  delete [] u;
  delete [] eigenvalues;
  delete [] eigenvectors;

  // Print statistics
  if (print_verbose) {
    printf("  Time = %.2f seconds\n", start_time.Elapsed());
    printf("  # Properties = %d\n", properties->NProperties());
    fflush(stdout);
  }

  // Return property set
  return properties;
}

// Assembly:
subq $0x418, %rsp            # imm = 0x418
movq %rdi, 0x408(%rsp)
leaq 0x3f8(%rsp), %rdi
callq 0xe98e0
leaq 0x3f8(%rsp), %rdi
callq 0x1f280
cmpl $0x0, 0x1b2030(%rip)    # 0x1ca740
je 0x1872f
leaq 0x15bc69(%rip), %rdi    # 0x174382
movb $0x0, %al
callq 0x11090
movq 0x1a8869(%rip), %rax    # 0x1c0f90
movq (%rax), %rdi
callq 0x117f0
movl $0x18, %edi
callq 0x11680
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x68(%rsp)
movq 0x408(%rsp), %rsi
callq 0x24ce0
jmp 0x18753
movq 0x68(%rsp), %rax
movq %rax, 0x3f0(%rsp)
cmpq $0x0, 0x3f0(%rsp)
jne 0x187b2
leaq 0x15bae4(%rip), %rdi    # 0x174256
movb $0x0, %al
callq 0xedb00
movq $0x0, 0x410(%rsp)
jmp 0x192b0
movq 0x68(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3e8(%rsp)
movl %eax, 0x3e4(%rsp)
movl $0x18, %esi
callq 0x11690
jmp 0x192c0
movq 0x408(%rsp), %rdi
callq 0x1f2e0
movl %eax, 0x3e0(%rsp)
movl 0x3e0(%rsp), %eax
imull 0x3e0(%rsp), %eax
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x11040
movq %rax, 0x3d8(%rsp)
movl $0x0, 0x3d4(%rsp)
movl 0x3d4(%rsp), %eax
movl 0x3e0(%rsp), %ecx
imull 0x3e0(%rsp), %ecx
cmpl %ecx, %eax
jge 0x18850
movq 0x3d8(%rsp), %rax
movslq 0x3d4(%rsp), %rcx
xorps %xmm0, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl 0x3d4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x3d4(%rsp)
jmp 0x1880b
movl $0x0, 0x3d0(%rsp)
movl 0x3d0(%rsp), %eax
cmpl 0x3e0(%rsp), %eax
jge 0x188ac
movq 0x3d8(%rsp), %rax
movl 0x3d0(%rsp), %ecx
imull 0x3e0(%rsp), %ecx
addl 0x3d0(%rsp), %ecx
movslq %ecx, %rcx
movsd 0x15b7a4(%rip), %xmm0   # 0x174038
movsd %xmm0, (%rax,%rcx,8)
movl 0x3d0(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x3d0(%rsp)
jmp 0x1885b
movl $0x0, 0x3cc(%rsp)
movl 0x3cc(%rsp), %eax
cmpl 0x3e0(%rsp), %eax
jge 0x18cd0
xorps %xmm0, %xmm0
movsd %xmm0, 0x3c0(%rsp)
movq 0x408(%rsp), %rdi
movl 0x3cc(%rsp), %esi
callq 0x1f380
movq %rax, 0x3b8(%rsp)
movq 0x408(%rsp), %rdi
movq 0x3b8(%rsp), %rsi
callq 0x1f4b0
movq %rax, 0x3b0(%rsp)
movl $0x0, 0x3ac(%rsp)
movl 0x3ac(%rsp), %eax
movl %eax, 0x64(%rsp)
movq 0x408(%rsp), %rdi
movq 0x3b8(%rsp), %rsi
callq 0x1f3d0
movl %eax, %ecx
movl 0x64(%rsp), %eax
cmpl %ecx, %eax
jge 0x18bb4
movq 0x408(%rsp), %rdi
movq 0x3b8(%rsp), %rsi
movl 0x3ac(%rsp), %edx
callq 0x1f850
movq %rax, 0x3a0(%rsp)
movq 0x408(%rsp), %rdi
movq 0x3a0(%rsp), %rsi
movq 0x3b8(%rsp), %rdx
callq 0x1f880
movq %rax, 0x398(%rsp)
movq 0x408(%rsp), %rdi
movq 0x398(%rsp), %rsi
callq 0x1f4b0
movq %rax, 0x390(%rsp)
movq 0x408(%rsp), %rdi
movq 0x398(%rsp), %rsi
callq 0x1f3b0
movl %eax, 0x38c(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x380(%rsp)
movl $0x0, 0x37c(%rsp)
cmpl $0x2, 0x37c(%rsp)
jge 0x18b54
movq 0x408(%rsp), %rdi
movq 0x3a0(%rsp), %rsi
movl 0x37c(%rsp), %edx
callq 0x1f8d0
movq %rax, 0x370(%rsp)
cmpq $0x0, 0x370(%rsp)
jne 0x18a24
jmp 0x18b3e
movq 0x408(%rsp), %rdi
movq 0x370(%rsp), %rsi
movq 0x3a0(%rsp), %rdx
callq 0x1f8f0
movq %rax, 0x368(%rsp)
movq 0x408(%rsp), %rdi
movq 0x368(%rsp), %rsi
callq 0x1f4b0
movq %rax, 0x360(%rsp)
movq 0x3b0(%rsp), %rsi
movq 0x360(%rsp), %rdx
leaq 0x348(%rsp), %rdi
callq 0x88640
leaq 0x348(%rsp), %rdi
callq 0x89ba0
movq 0x390(%rsp), %rsi
movq 0x360(%rsp), %rdx
leaq 0x330(%rsp), %rdi
callq 0x88640
leaq 0x330(%rsp), %rdi
callq 0x89ba0
leaq 0x348(%rsp), %rdi
leaq 0x330(%rsp), %rsi
callq 0x2dad0
movsd %xmm0, 0x328(%rsp)
movsd 0x328(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x18aee
jp 0x18aee
jmp 0x18b3e
movsd 0x328(%rsp), %xmm0
callq 0x11390
movsd %xmm0, 0x320(%rsp)
movsd 0x320(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x18b1b
jp 0x18b1b
jmp 0x18b3e
movsd 0x15b4f5(%rip), %xmm0   # 0x174018
divsd 0x320(%rsp), %xmm0
addsd 0x380(%rsp), %xmm0
movsd %xmm0, 0x380(%rsp)
movl 0x37c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x37c(%rsp)
jmp 0x189e2
movsd 0x380(%rsp), %xmm0
movq 0x3d8(%rsp), %rax
movl 0x3cc(%rsp), %ecx
imull 0x3e0(%rsp), %ecx
addl 0x38c(%rsp), %ecx
movslq %ecx, %rcx
movsd %xmm0, (%rax,%rcx,8)
movsd 0x380(%rsp), %xmm0
addsd 0x3c0(%rsp), %xmm0
movsd %xmm0, 0x3c0(%rsp)
movl 0x3ac(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x3ac(%rsp)
jmp 0x1891b
movsd 0x3c0(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x18cb8
movl $0x0, 0x31c(%rsp)
movl 0x31c(%rsp), %eax
movl %eax, 0x60(%rsp)
movq 0x408(%rsp), %rdi
movq 0x3b8(%rsp), %rsi
callq 0x1f3d0
movl %eax, %ecx
movl 0x60(%rsp), %eax
cmpl %ecx, %eax
jge 0x18cb6
movq 0x408(%rsp), %rdi
movq 0x3b8(%rsp), %rsi
movl 0x31c(%rsp), %edx
callq 0x1f850
movq %rax, 0x310(%rsp)
movq 0x408(%rsp), %rdi
movq 0x310(%rsp), %rsi
movq 0x3b8(%rsp), %rdx
callq 0x1f880
movq %rax, 0x308(%rsp)
movq 0x408(%rsp), %rdi
movq 0x308(%rsp), %rsi
callq 0x1f3b0
movl %eax, 0x304(%rsp)
movsd 0x3c0(%rsp), %xmm1
movq 0x3d8(%rsp), %rax
movl 0x3cc(%rsp), %ecx
imull 0x3e0(%rsp), %ecx
addl 0x304(%rsp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl 0x31c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x31c(%rsp)
jmp 0x18bd5
jmp 0x18cb8
jmp 0x18cba
movl 0x3cc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x3cc(%rsp)
jmp 0x188b7
movl 0x3e0(%rsp), %eax
imull 0x3e0(%rsp), %eax
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x11040
movq %rax, 0x2f8(%rsp)
movslq 0x3e0(%rsp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x11040
movq %rax, 0x2f0(%rsp)
movl 0x3e0(%rsp), %eax
imull 0x3e0(%rsp), %eax
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x11040
movq %rax, 0x2e8(%rsp)
movl 0x3e0(%rsp), %edi
movl 0x3e0(%rsp), %esi
movq 0x3d8(%rsp), %rdx
movq 0x2f8(%rsp), %rcx
movq 0x2f0(%rsp), %r8
movq 0x2e8(%rsp), %r9
callq 0xec990
movsd 0x15b268(%rip), %xmm0   # 0x174018
movsd %xmm0, 0x2e0(%rsp)
movq 0x2f0(%rsp), %rax
movl 0x3e0(%rsp), %ecx
subl $0x2, %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x2d8(%rsp)
movsd 0x2d8(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x18e14
movsd 0x15b21a(%rip), %xmm1   # 0x174010
mulsd 0x2d8(%rsp), %xmm1
movsd 0x15b211(%rip), %xmm0   # 0x174018
divsd %xmm1, %xmm0
movsd %xmm0, 0x2e0(%rsp)
movslq 0x3e0(%rsp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x11040
movq %rax, 0x2d0(%rsp)
movsd 0x15b1e3(%rip), %xmm0   # 0x174030
mulsd 0x2e0(%rsp), %xmm0
movsd %xmm0, 0x2c8(%rsp)
movl $0x0, 0x2c4(%rsp)
cmpl $0x8, 0x2c4(%rsp)
jge 0x19085
movl 0x2c4(%rsp), %edx
incl %edx
leaq 0x15b51e(%rip), %rsi    # 0x1743a6
xorl %eax, %eax
movl %eax, 0x54(%rsp)
leaq 0x1c0(%rsp), %rdi
movq %rdi, 0x48(%rsp)
callq 0x11120
movl $0x448, %edi            # imm = 0x448
callq 0x11680
movq 0x48(%rsp), %rdx
movq %rax, %rdi
movl 0x54(%rsp), %eax
movq %rdi, %rcx
movq %rcx, 0x58(%rsp)
movq 0x408(%rsp), %rsi
movl %eax, %ecx
callq 0x27ef0
jmp 0x18ecf
movq 0x58(%rsp), %rax
movq %rax, 0x1b8(%rsp)
movl $0x0, 0x1b4(%rsp)
movl 0x1b4(%rsp), %eax
cmpl 0x3e0(%rsp), %eax
jge 0x1903e
xorps %xmm0, %xmm0
movsd %xmm0, 0x1a8(%rsp)
movl $0x0, 0x1a4(%rsp)
movl 0x1a4(%rsp), %eax
cmpl 0x3e0(%rsp), %eax
jge 0x1900b
movq 0x2f0(%rsp), %rax
movslq 0x1a4(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x198(%rsp)
movq 0x2e8(%rsp), %rax
movl 0x1a4(%rsp), %ecx
imull 0x3e0(%rsp), %ecx
addl 0x1b4(%rsp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x190(%rsp)
movsd 0x2c8(%rsp), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
mulsd 0x198(%rsp), %xmm0
callq 0x11bf0
mulsd 0x190(%rsp), %xmm0
movsd 0x190(%rsp), %xmm2
movsd 0x1a8(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x1a8(%rsp)
movl 0x1a4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1a4(%rsp)
jmp 0x18f12
movq 0x58(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3e8(%rsp)
movl %eax, 0x3e4(%rsp)
movl $0x448, %esi            # imm = 0x448
callq 0x11690
jmp 0x192c0
movq 0x1b8(%rsp), %rdi
movl 0x1b4(%rsp), %esi
movsd 0x1a8(%rsp), %xmm0
callq 0x2ae50
movl 0x1b4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1b4(%rsp)
jmp 0x18ee7
movq 0x3f0(%rsp), %rdi
movq 0x1b8(%rsp), %rsi
xorl %edx, %edx
callq 0x148a0
movsd 0x15afb3(%rip), %xmm0   # 0x174010
mulsd 0x2c8(%rsp), %xmm0
movsd %xmm0, 0x2c8(%rsp)
movl 0x2c4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x2c4(%rsp)
jmp 0x18e6a
movq 0x2d0(%rsp), %rax
movq %rax, 0x40(%rsp)
cmpq $0x0, %rax
je 0x190a2
movq 0x40(%rsp), %rdi
callq 0x118b0
movl $0xa, 0x18c(%rsp)
movl $0x0, 0x188(%rsp)
movl 0x188(%rsp), %eax
cmpl 0x18c(%rsp), %eax
jge 0x191dc
movl 0x188(%rsp), %edx
incl %edx
leaq 0x15b2e0(%rip), %rsi    # 0x1743bc
xorl %eax, %eax
movl %eax, 0x34(%rsp)
leaq 0x80(%rsp), %rdi
movq %rdi, 0x28(%rsp)
callq 0x11120
movl $0x448, %edi            # imm = 0x448
callq 0x11680
movq 0x28(%rsp), %rdx
movq %rax, %rdi
movl 0x34(%rsp), %eax
movq %rdi, %rcx
movq %rcx, 0x38(%rsp)
movq 0x408(%rsp), %rsi
movl %eax, %ecx
callq 0x27ef0
jmp 0x19123
movq 0x38(%rsp), %rax
movq %rax, 0x78(%rsp)
movl $0x0, 0x74(%rsp)
movl 0x74(%rsp), %eax
cmpl 0x3e0(%rsp), %eax
jge 0x191b2
movq 0x78(%rsp), %rdi
movl 0x74(%rsp), %esi
movq 0x2e8(%rsp), %rax
movl 0x3e0(%rsp), %ecx
subl 0x188(%rsp), %ecx
subl $0x1, %ecx
imull 0x3e0(%rsp), %ecx
addl 0x74(%rsp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
callq 0x2ae50
movl 0x74(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x74(%rsp)
jmp 0x19135
movq 0x38(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3e8(%rsp)
movl %eax, 0x3e4(%rsp)
movl $0x448, %esi            # imm = 0x448
callq 0x11690
jmp 0x192c0
movq 0x3f0(%rsp), %rdi
movq 0x78(%rsp), %rsi
xorl %edx, %edx
callq 0x148a0
movl 0x188(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x188(%rsp)
jmp 0x190b8
movq 0x3d8(%rsp), %rax
movq %rax, 0x20(%rsp)
cmpq $0x0, %rax
je 0x191f9
movq 0x20(%rsp), %rdi
callq 0x118b0
movq 0x2f8(%rsp), %rax
movq %rax, 0x18(%rsp)
cmpq $0x0, %rax
je 0x19216
movq 0x18(%rsp), %rdi
callq 0x118b0
movq 0x2f0(%rsp), %rax
movq %rax, 0x10(%rsp)
cmpq $0x0, %rax
je 0x19233
movq 0x10(%rsp), %rdi
callq 0x118b0
movq 0x2e8(%rsp), %rax
movq %rax, 0x8(%rsp)
cmpq $0x0, %rax
je 0x19250
movq 0x8(%rsp), %rdi
callq 0x118b0
cmpl $0x0, 0x1b14e9(%rip)    # 0x1ca740
je 0x192a0
leaq 0x3f8(%rsp), %rdi
callq 0xe99a0
leaq 0x15af9f(%rip), %rdi    # 0x17420c
movb $0x1, %al
callq 0x11090
movq 0x3f0(%rsp), %rdi
callq 0x1f400
movl %eax, %esi
leaq 0x15b02d(%rip), %rdi    # 0x1742b7
movb $0x0, %al
callq 0x11090
movq 0x1a7cf8(%rip), %rax    # 0x1c0f90
movq (%rax), %rdi
callq 0x117f0
movq 0x3f0(%rsp), %rax
movq %rax, 0x410(%rsp)
movq 0x410(%rsp), %rax
addq $0x418, %rsp            # imm = 0x418
retq
movq 0x3e8(%rsp), %rdi
callq 0x11bb0
nopl (%rax)