// File: tomfunkhouser[P]gaps/pkgs/R3Shapes/R3MeshProperty.cpp
// Function: gaps::R3MeshProperty::Laplacian(gaps::R3MeshVertex*) const
RNScalar R3MeshProperty::
Laplacian(R3MeshVertex *vertex) const
{
  // Get vertex value
  R3MeshVertex *v1 = vertex;
  RNScalar value1 = VertexValue(v1);
  if (value1 == RN_UNKNOWN) return RN_UNKNOWN;
  const R3Point& p1 = mesh->VertexPosition(v1);

  // Compute vector from vertex to cotan weighted average of neighbors 
  RNScalar total_sum = 0;
  RNScalar total_weight = 0;
  for (int j = 0; j < mesh->VertexValence(v1); j++) {
    R3MeshEdge *e = mesh->EdgeOnVertex(v1, j);
    R3MeshVertex *v2 = mesh->VertexAcrossEdge(e, v1);
    RNScalar value2 = VertexValue(v2);
    if (value2 == RN_UNKNOWN) continue;
    const R3Point& p2 = mesh->VertexPosition(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
    total_sum += weight * value2;
    total_weight += weight;
  }

  // Check total weight
  if (total_weight == 0) return 0;

  // Compute weighted average
  RNScalar weighted_average = total_sum / total_weight;

  // Compute laplacian 
  RNScalar laplacian = value1 - weighted_average;

  // Return laplacian
  return laplacian;
}

// Assembly:
subq $0xf8, %rsp
movq %rdi, 0xe8(%rsp)
movq %rsi, 0xe0(%rsp)
movq 0xe8(%rsp), %rdi
movq %rdi, 0x10(%rsp)
movq 0xe0(%rsp), %rax
movq %rax, 0xd8(%rsp)
movq 0xd8(%rsp), %rsi
callq 0x2b020
movsd %xmm0, 0xd0(%rsp)
movsd 0xd0(%rsp), %xmm0
movsd 0x1295f5(%rip), %xmm1   # 0x196020
ucomisd %xmm1, %xmm0
jne 0x6ca49
jp 0x6ca49
movsd 0x1295e5(%rip), %xmm0   # 0x196020
movsd %xmm0, 0xf0(%rsp)
jmp 0x6cd64
movq 0x10(%rsp), %rax
movq (%rax), %rdi
movq 0xd8(%rsp), %rsi
callq 0x2ab40
movq %rax, 0xc8(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0xc0(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0xb8(%rsp)
movl $0x0, 0xb4(%rsp)
movq 0x10(%rsp), %rax
movl 0xb4(%rsp), %ecx
movl %ecx, 0xc(%rsp)
movq (%rax), %rdi
movq 0xd8(%rsp), %rsi
callq 0x6c0d0
movl %eax, %ecx
movl 0xc(%rsp), %eax
cmpl %ecx, %eax
jge 0x6cd06
movq 0x10(%rsp), %rax
movq (%rax), %rdi
movq 0xd8(%rsp), %rsi
movl 0xb4(%rsp), %edx
callq 0x6c100
movq %rax, %rcx
movq 0x10(%rsp), %rax
movq %rcx, 0xa8(%rsp)
movq (%rax), %rdi
movq 0xa8(%rsp), %rsi
movq 0xd8(%rsp), %rdx
callq 0x712f0
movq 0x10(%rsp), %rdi
movq %rax, 0xa0(%rsp)
movq 0xa0(%rsp), %rsi
callq 0x2b020
movsd %xmm0, 0x98(%rsp)
movsd 0x98(%rsp), %xmm0
movsd 0x1294f1(%rip), %xmm1   # 0x196020
ucomisd %xmm1, %xmm0
jne 0x6cb3c
jp 0x6cb3c
jmp 0x6ccf0
movq 0x10(%rsp), %rax
movq (%rax), %rdi
movq 0xa0(%rsp), %rsi
callq 0x2ab40
movq %rax, 0x90(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x88(%rsp)
movl $0x0, 0x84(%rsp)
cmpl $0x2, 0x84(%rsp)
jge 0x6cca9
movq 0x10(%rsp), %rax
movq (%rax), %rdi
movq 0xa8(%rsp), %rsi
movl 0x84(%rsp), %edx
callq 0x71340
movq %rax, 0x78(%rsp)
cmpq $0x0, 0x78(%rsp)
jne 0x6cbac
jmp 0x6cc93
movq 0x10(%rsp), %rax
movq (%rax), %rdi
movq 0x78(%rsp), %rsi
movq 0xa8(%rsp), %rdx
callq 0x71360
movq %rax, %rcx
movq 0x10(%rsp), %rax
movq %rcx, 0x70(%rsp)
movq (%rax), %rdi
movq 0x70(%rsp), %rsi
callq 0x2ab40
movq %rax, 0x68(%rsp)
movq 0xc8(%rsp), %rsi
movq 0x68(%rsp), %rdx
leaq 0x50(%rsp), %rdi
callq 0xd4d00
leaq 0x50(%rsp), %rdi
callq 0xd6260
movq 0x90(%rsp), %rsi
movq 0x68(%rsp), %rdx
leaq 0x38(%rsp), %rdi
callq 0xd4d00
leaq 0x38(%rsp), %rdi
callq 0xd6260
leaq 0x50(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x85680
movsd %xmm0, 0x30(%rsp)
movsd 0x30(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x6cc4f
jp 0x6cc4f
jmp 0x6cc93
movsd 0x30(%rsp), %xmm0
callq 0x22500
movsd %xmm0, 0x28(%rsp)
movsd 0x28(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x6cc73
jp 0x6cc73
jmp 0x6cc93
movsd 0x1293ed(%rip), %xmm0   # 0x196068
divsd 0x28(%rsp), %xmm0
addsd 0x88(%rsp), %xmm0
movsd %xmm0, 0x88(%rsp)
movl 0x84(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x84(%rsp)
jmp 0x6cb70
movsd 0x88(%rsp), %xmm0
movsd 0x98(%rsp), %xmm2
movsd 0xc0(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0xc0(%rsp)
movsd 0x88(%rsp), %xmm0
addsd 0xb8(%rsp), %xmm0
movsd %xmm0, 0xb8(%rsp)
movl 0xb4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xb4(%rsp)
jmp 0x6ca89
movsd 0xb8(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x6cd28
jp 0x6cd28
xorps %xmm0, %xmm0
movsd %xmm0, 0xf0(%rsp)
jmp 0x6cd64
movsd 0xc0(%rsp), %xmm0
divsd 0xb8(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0xd0(%rsp), %xmm0
subsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x18(%rsp), %xmm0
movsd %xmm0, 0xf0(%rsp)
movsd 0xf0(%rsp), %xmm0
addq $0xf8, %rsp
retq
nopw %cs:(%rax,%rax)