// File: tomfunkhouser[P]gaps/pkgs/R3Shapes/R3Mesh.cpp
// Function: gaps::R3Mesh::FillHole(gaps::R3MeshEdge*, double, double)
void R3Mesh::
FillHole(R3MeshEdge *seed_edge, RNLength max_perimeter, RNLength max_planar_deviation)
{
  // Check if seed edge is on boundary
  R3MeshFace *seed_face = FaceOnEdge(seed_edge);
  if (!seed_face) return; 
  if (FaceAcrossEdge(seed_edge, seed_face)) return;
  R3MeshVertex *seed_vertex = VertexOnEdge(seed_edge, seed_face, RN_CCW);

  // Create counterclockwise linked list of boundary vertices
  R3mesh_mark++;
  R3MeshBoundaryVertexData *head = NULL;
  R3MeshBoundaryVertexData *tail = NULL;
  R3MeshEdge *edge = seed_edge;
  R3MeshVertex *vertex = seed_vertex;
  // R3MeshFace *face = seed_face;
  do {
    // Create boundary vertex 
    R3MeshBoundaryVertexData *vdata = new R3MeshBoundaryVertexData();
    vdata->vertex = vertex;
    vdata->edge = edge;
    vdata->prev = NULL;
    vdata->next = NULL;
    vdata->heappointer = NULL;
    vdata->error = 0;

    // Mark vertex (so can detect figure 8)
    SetVertexMark(vertex, R3mesh_mark);

    // Add boundary vertex to list
    if (!head) head = vdata;
    if (tail) tail->next = vdata;
    vdata->prev = tail;
    tail = vdata;

    // Update vdata error 
    if (vdata->prev) {
      R3MeshVertex *prev_vertex = vdata->prev->vertex;
      R3MeshVertex *next_vertex = VertexAcrossEdge(vdata->edge, vdata->vertex);
      const R3Point& position = VertexPosition(vertex);
      const R3Point& prev_position = VertexPosition(prev_vertex);
      const R3Point& next_position = VertexPosition(next_vertex);
      const R3Vector& prev_normal = VertexNormal(prev_vertex);
      const R3Vector& next_normal = VertexNormal(next_vertex);
      R3Vector prev_vector = prev_position - position;
      R3Vector next_vector = next_position - position;
      R3Vector cross = prev_vector % next_vector;
      RNAngle interior_angle = R3InteriorAngle(prev_vector, next_vector);
      if (cross.Dot(VertexNormal(vdata->vertex)) > 0) interior_angle = RN_TWO_PI - interior_angle;
      RNAngle normal_angle = R3InteriorAngle(prev_normal, next_normal);
      vdata->error = interior_angle + normal_angle;
    }

    // Find next vertex
    vertex = VertexAcrossEdge(edge, vertex);

    // Check for repeated vertex (figure 8)
    if (VertexMark(vertex) == R3mesh_mark) {
      if (vertex != seed_vertex) {
        // Find previous instance of repeated vertex
        R3MeshBoundaryVertexData *vdata = tail->prev;
        while (vdata->vertex != vertex) vdata = vdata->prev;

        // Remove part of list before repeated vertex
        head = vdata;
        vdata = head->prev;
        head->prev = NULL;
        while (vdata) { 
          R3MeshBoundaryVertexData *prev = vdata->prev; 
          delete vdata; 
          vdata = prev; 
        }

        // Now have a complete loop
        break;
      }
    }

    // Find next edge
    R3MeshEdge *e = edge;
    while (e) {
      R3MeshFace *f = FaceOnVertex(vertex, e, RN_CCW);
      if (!f) { assert(e != edge); edge = e; break; }
      e = EdgeOnFace(f, vertex, RN_CW);
      if (!e || (e == edge)) return; 
    } 

    // Find next face
    // face = FaceOnVertex(vertex, edge, RN_CW);
  } while (vertex != seed_vertex);

  // Complete loop
  if (head && tail) {
    // Add link between head and tail
    head->prev = tail;
    tail->next = head;

    // Update head error 
    if (head) {
      R3MeshBoundaryVertexData *vdata = head;
      R3MeshVertex *prev_vertex = vdata->prev->vertex;
      R3MeshVertex *next_vertex = vdata->next->vertex;
      const R3Point& position = VertexPosition(vertex);
      const R3Point& prev_position = VertexPosition(prev_vertex);
      const R3Point& next_position = VertexPosition(next_vertex);
      const R3Vector& prev_normal = VertexNormal(prev_vertex);
      const R3Vector& next_normal = VertexNormal(next_vertex);
      R3Vector prev_vector = prev_position - position;
      R3Vector next_vector = next_position - position;
      R3Vector cross = prev_vector % next_vector;
      RNAngle interior_angle = R3InteriorAngle(prev_vector, next_vector);
      if (cross.Dot(VertexNormal(vdata->vertex)) > 0) interior_angle = RN_TWO_PI - interior_angle;
      RNAngle normal_angle = R3InteriorAngle(prev_normal, next_normal);
      vdata->error = interior_angle + normal_angle;
    }
  }

  // Split any edges spanning (back side of) boundary
  R3MeshBoundaryVertexData *vdata = head;
  do {
    R3MeshVertex *vertex = vdata->vertex;
    for (int i = 0; i < VertexValence(vertex); i++) {
      R3MeshEdge *edge = EdgeOnVertex(vertex, i);
      if (edge == vdata->edge) continue;
      if (edge == vdata->prev->edge) continue;
      R3MeshVertex *neighbor = VertexAcrossEdge(edge, vertex);
      if (VertexMark(neighbor)) SubdivideEdge(edge);
    }
    vdata = vdata->next;
  } while (vdata != head);

  // Mark hole boundary
  UnmarkHoleBoundary(this, head);

  // Check hole boundary
  if (!CheckHoleBoundary(this, head, max_perimeter, max_planar_deviation)) return;

  // Fill hole boundary
  FillHoleBoundary(this, head);
}

// Assembly:
subq $0x1e8, %rsp            # imm = 0x1E8
movq %rdi, 0x1e0(%rsp)
movq %rsi, 0x1d8(%rsp)
movsd %xmm0, 0x1d0(%rsp)
movsd %xmm1, 0x1c8(%rsp)
movq 0x1e0(%rsp), %rdi
movq %rdi, 0x18(%rsp)
movq 0x1d8(%rsp), %rsi
callq 0x38aa0
movq %rax, 0x1c0(%rsp)
cmpq $0x0, 0x1c0(%rsp)
jne 0x2033b
jmp 0x20bca
movq 0x18(%rsp), %rdi
movq 0x1d8(%rsp), %rsi
movq 0x1c0(%rsp), %rdx
callq 0x373c0
cmpq $0x0, %rax
je 0x20360
jmp 0x20bca
movq 0x18(%rsp), %rdi
movq 0x1d8(%rsp), %rsi
movq 0x1c0(%rsp), %rdx
xorl %ecx, %ecx
callq 0x38ae0
movq %rax, 0x1b8(%rsp)
movl 0x14f196(%rip), %eax    # 0x16f520
addl $0x1, %eax
movl %eax, 0x14f18d(%rip)    # 0x16f520
movq $0x0, 0x1b0(%rsp)
movq $0x0, 0x1a8(%rsp)
movq 0x1d8(%rsp), %rax
movq %rax, 0x1a0(%rsp)
movq 0x1b8(%rsp), %rax
movq %rax, 0x198(%rsp)
movl $0x30, %edi
callq 0xf4c0
movq %rax, %rdi
movq %rdi, 0x10(%rsp)
xorl %esi, %esi
movl $0x30, %edx
callq 0xf280
movq 0x10(%rsp), %rax
movq 0x18(%rsp), %rdi
movq %rax, 0x190(%rsp)
movq 0x198(%rsp), %rcx
movq 0x190(%rsp), %rax
movq %rcx, (%rax)
movq 0x1a0(%rsp), %rcx
movq 0x190(%rsp), %rax
movq %rcx, 0x8(%rax)
movq 0x190(%rsp), %rax
movq $0x0, 0x10(%rax)
movq 0x190(%rsp), %rax
movq $0x0, 0x18(%rax)
movq 0x190(%rsp), %rax
movq $0x0, 0x20(%rax)
movq 0x190(%rsp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, 0x28(%rax)
movq 0x198(%rsp), %rsi
movl 0x14f0b0(%rip), %edx    # 0x16f520
callq 0x37440
cmpq $0x0, 0x1b0(%rsp)
jne 0x20490
movq 0x190(%rsp), %rax
movq %rax, 0x1b0(%rsp)
cmpq $0x0, 0x1a8(%rsp)
je 0x204af
movq 0x190(%rsp), %rcx
movq 0x1a8(%rsp), %rax
movq %rcx, 0x18(%rax)
movq 0x1a8(%rsp), %rcx
movq 0x190(%rsp), %rax
movq %rcx, 0x10(%rax)
movq 0x190(%rsp), %rax
movq %rax, 0x1a8(%rsp)
movq 0x190(%rsp), %rax
cmpq $0x0, 0x10(%rax)
je 0x206a5
movq 0x18(%rsp), %rdi
movq 0x190(%rsp), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movq %rax, 0x188(%rsp)
movq 0x190(%rsp), %rax
movq 0x8(%rax), %rsi
movq 0x190(%rsp), %rax
movq (%rax), %rdx
callq 0x36f50
movq 0x18(%rsp), %rdi
movq %rax, 0x180(%rsp)
movq 0x198(%rsp), %rsi
callq 0x13660
movq 0x18(%rsp), %rdi
movq %rax, 0x178(%rsp)
movq 0x188(%rsp), %rsi
callq 0x13660
movq 0x18(%rsp), %rdi
movq %rax, 0x170(%rsp)
movq 0x180(%rsp), %rsi
callq 0x13660
movq 0x18(%rsp), %rdi
movq %rax, 0x168(%rsp)
movq 0x188(%rsp), %rsi
callq 0x36860
movq 0x18(%rsp), %rdi
movq %rax, 0x160(%rsp)
movq 0x180(%rsp), %rsi
callq 0x36860
movq %rax, 0x158(%rsp)
movq 0x170(%rsp), %rsi
movq 0x178(%rsp), %rdx
leaq 0x140(%rsp), %rdi
callq 0x6eeb0
movq 0x168(%rsp), %rsi
movq 0x178(%rsp), %rdx
leaq 0x128(%rsp), %rdi
callq 0x6eeb0
leaq 0x110(%rsp), %rdi
leaq 0x140(%rsp), %rsi
leaq 0x128(%rsp), %rdx
callq 0x70af0
leaq 0x140(%rsp), %rdi
leaq 0x128(%rsp), %rsi
callq 0x8c230
movq 0x18(%rsp), %rdi
movsd %xmm0, 0x108(%rsp)
movq 0x190(%rsp), %rax
movq (%rax), %rsi
callq 0x36860
movq %rax, %rsi
leaq 0x110(%rsp), %rdi
callq 0x702c0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x20668
leaq 0x1162a6(%rip), %rax    # 0x1368f8
movsd (%rax), %xmm0
subsd 0x108(%rsp), %xmm0
movsd %xmm0, 0x108(%rsp)
movq 0x160(%rsp), %rdi
movq 0x158(%rsp), %rsi
callq 0x8c230
movsd %xmm0, 0x100(%rsp)
movsd 0x108(%rsp), %xmm0
addsd 0x100(%rsp), %xmm0
movq 0x190(%rsp), %rax
movsd %xmm0, 0x28(%rax)
movq 0x18(%rsp), %rdi
movq 0x1a0(%rsp), %rsi
movq 0x198(%rsp), %rdx
callq 0x36f50
movq 0x18(%rsp), %rdi
movq %rax, 0x198(%rsp)
movq 0x198(%rsp), %rsi
callq 0x37470
cmpl 0x14ee41(%rip), %eax    # 0x16f520
jne 0x207c8
movq 0x198(%rsp), %rax
cmpq 0x1b8(%rsp), %rax
je 0x207c6
movq 0x1a8(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0xf8(%rsp)
movq 0xf8(%rsp), %rax
movq (%rax), %rax
cmpq 0x198(%rsp), %rax
je 0x2073a
movq 0xf8(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0xf8(%rsp)
jmp 0x2070f
movq 0xf8(%rsp), %rax
movq %rax, 0x1b0(%rsp)
movq 0x1b0(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0xf8(%rsp)
movq 0x1b0(%rsp), %rax
movq $0x0, 0x10(%rax)
cmpq $0x0, 0xf8(%rsp)
je 0x207c1
movq 0xf8(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0xf0(%rsp)
movq 0xf8(%rsp), %rax
movq %rax, 0x8(%rsp)
cmpq $0x0, %rax
je 0x207af
movq 0x8(%rsp), %rdi
movl $0x30, %esi
callq 0xf4d0
movq 0xf0(%rsp), %rax
movq %rax, 0xf8(%rsp)
jmp 0x2076e
jmp 0x2088e
jmp 0x207c8
movq 0x1a0(%rsp), %rax
movq %rax, 0xe8(%rsp)
cmpq $0x0, 0xe8(%rsp)
je 0x20876
movq 0x18(%rsp), %rdi
movq 0x198(%rsp), %rsi
movq 0xe8(%rsp), %rdx
xorl %ecx, %ecx
callq 0x37010
movq %rax, 0xe0(%rsp)
cmpq $0x0, 0xe0(%rsp)
jne 0x20828
movq 0xe8(%rsp), %rax
movq %rax, 0x1a0(%rsp)
jmp 0x20876
movq 0x18(%rsp), %rdi
movq 0xe0(%rsp), %rsi
movq 0x198(%rsp), %rdx
movl $0x1, %ecx
callq 0x37a60
movq %rax, 0xe8(%rsp)
cmpq $0x0, 0xe8(%rsp)
je 0x2086c
movq 0xe8(%rsp), %rax
cmpq 0x1a0(%rsp), %rax
jne 0x20871
jmp 0x20bca
jmp 0x207d8
jmp 0x20878
movq 0x198(%rsp), %rax
cmpq 0x1b8(%rsp), %rax
jne 0x203cb
cmpq $0x0, 0x1b0(%rsp)
je 0x20a81
cmpq $0x0, 0x1a8(%rsp)
je 0x20a81
movq 0x1a8(%rsp), %rcx
movq 0x1b0(%rsp), %rax
movq %rcx, 0x10(%rax)
movq 0x1b0(%rsp), %rcx
movq 0x1a8(%rsp), %rax
movq %rcx, 0x18(%rax)
cmpq $0x0, 0x1b0(%rsp)
je 0x20a7f
movq 0x18(%rsp), %rdi
movq 0x1b0(%rsp), %rax
movq %rax, 0xd8(%rsp)
movq 0xd8(%rsp), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movq %rax, 0xd0(%rsp)
movq 0xd8(%rsp), %rax
movq 0x18(%rax), %rax
movq (%rax), %rax
movq %rax, 0xc8(%rsp)
movq 0x198(%rsp), %rsi
callq 0x13660
movq 0x18(%rsp), %rdi
movq %rax, 0xc0(%rsp)
movq 0xd0(%rsp), %rsi
callq 0x13660
movq 0x18(%rsp), %rdi
movq %rax, 0xb8(%rsp)
movq 0xc8(%rsp), %rsi
callq 0x13660
movq 0x18(%rsp), %rdi
movq %rax, 0xb0(%rsp)
movq 0xd0(%rsp), %rsi
callq 0x36860
movq 0x18(%rsp), %rdi
movq %rax, 0xa8(%rsp)
movq 0xc8(%rsp), %rsi
callq 0x36860
movq %rax, 0xa0(%rsp)
movq 0xb8(%rsp), %rsi
movq 0xc0(%rsp), %rdx
leaq 0x88(%rsp), %rdi
callq 0x6eeb0
movq 0xb0(%rsp), %rsi
movq 0xc0(%rsp), %rdx
leaq 0x70(%rsp), %rdi
callq 0x6eeb0
leaq 0x58(%rsp), %rdi
leaq 0x88(%rsp), %rsi
leaq 0x70(%rsp), %rdx
callq 0x70af0
leaq 0x88(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x8c230
movq 0x18(%rsp), %rdi
movsd %xmm0, 0x50(%rsp)
movq 0xd8(%rsp), %rax
movq (%rax), %rsi
callq 0x36860
movq %rax, %rsi
leaq 0x58(%rsp), %rdi
callq 0x702c0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x20a4b
leaq 0x115ebd(%rip), %rax    # 0x1368f8
movsd (%rax), %xmm0
subsd 0x50(%rsp), %xmm0
movsd %xmm0, 0x50(%rsp)
movq 0xa8(%rsp), %rdi
movq 0xa0(%rsp), %rsi
callq 0x8c230
movsd %xmm0, 0x48(%rsp)
movsd 0x50(%rsp), %xmm0
addsd 0x48(%rsp), %xmm0
movq 0xd8(%rsp), %rax
movsd %xmm0, 0x28(%rax)
jmp 0x20a81
movq 0x1b0(%rsp), %rax
movq %rax, 0x40(%rsp)
movq 0x40(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x38(%rsp)
movl $0x0, 0x34(%rsp)
movq 0x18(%rsp), %rdi
movl 0x34(%rsp), %eax
movl %eax, 0x4(%rsp)
movq 0x38(%rsp), %rsi
callq 0x36b50
movl %eax, %ecx
movl 0x4(%rsp), %eax
cmpl %ecx, %eax
jge 0x20b5a
movq 0x18(%rsp), %rdi
movq 0x38(%rsp), %rsi
movl 0x34(%rsp), %edx
callq 0x36ec0
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rax
movq 0x40(%rsp), %rcx
cmpq 0x8(%rcx), %rax
jne 0x20af2
jmp 0x20b4a
movq 0x28(%rsp), %rax
movq 0x40(%rsp), %rcx
movq 0x10(%rcx), %rcx
cmpq 0x8(%rcx), %rax
jne 0x20b08
jmp 0x20b4a
movq 0x18(%rsp), %rdi
movq 0x28(%rsp), %rsi
movq 0x38(%rsp), %rdx
callq 0x36f50
movq 0x18(%rsp), %rdi
movq %rax, 0x20(%rsp)
movq 0x20(%rsp), %rsi
callq 0x37470
cmpl $0x0, %eax
je 0x20b48
movq 0x18(%rsp), %rdi
movq 0x28(%rsp), %rsi
movq (%rdi), %rax
callq *0xc8(%rax)
jmp 0x20b4a
movl 0x34(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x34(%rsp)
jmp 0x20aa3
movq 0x40(%rsp), %rax
movq 0x18(%rax), %rax
movq %rax, 0x40(%rsp)
movq 0x40(%rsp), %rax
cmpq 0x1b0(%rsp), %rax
jne 0x20a8e
movq 0x18(%rsp), %rdi
movq 0x1b0(%rsp), %rsi
callq 0x20be0
movq 0x18(%rsp), %rdi
movq 0x1b0(%rsp), %rsi
movsd 0x1d0(%rsp), %xmm0
movsd 0x1c8(%rsp), %xmm1
callq 0x20c40
cmpl $0x0, %eax
jne 0x20bb8
jmp 0x20bca
movq 0x18(%rsp), %rdi
movq 0x1b0(%rsp), %rsi
callq 0x20ec0
addq $0x1e8, %rsp            # imm = 0x1E8
retq
nopw %cs:(%rax,%rax)