// File: hzeller[P]gcode-multi-shell-extrude/polygon-offset.cc
// Function: PolygonOffset(std::vector<Vector2D, std::allocator<Vector2D>> const&, double, OffsetType)
Polygon PolygonOffset(const Polygon &polygon, double offset,
                      OffsetType type) {
  // Converting float to clipper integer values. Make sure
  // to stay within limits.
  const float kResolution = 1e4;
  const float kAccuracy = 0.01; // mm : cutting corners with this accuracy

  ClipperLib::Path path;
  Vector2D centroid;
  for (const Vector2D &p : polygon) {
    Vector2D clipper_point = p * kResolution;
    path.push_back(ClipperLib::IntPoint(clipper_point.x, clipper_point.y));
    centroid = centroid + clipper_point;
  }
  centroid = centroid / polygon.size();

  ClipperLib::Paths solutions;
  ClipperLib::ClipperOffset co(2.0, kAccuracy * kResolution);
  ClipperLib::JoinType join = ClipperLib::jtRound;
  switch (type) {
  case kOffsetRound:  join = ClipperLib::jtRound; break;
  case kOffsetSquare: join = ClipperLib::jtSquare; break;
  case kOffsetMiter:  join = ClipperLib::jtMiter; break;
  }
  co.AddPath(path, join, ClipperLib::etClosedPolygon);
  co.Execute(solutions, kResolution * offset);

  if (solutions.size() == 0)  // Nothing left.
    return Polygon();

  // A polygon might become pieces when offset. Use the one that is centered.
  ClipperLib::Path &centered_polygon = solutions[0];
  for (const ClipperLib::Path &solution : solutions) {
    if (is_centered(centroid, solution)) {
      centered_polygon = solution;
      break;
    }
  }

  Polygon tmp;
  for (const ClipperLib::IntPoint &p : centered_polygon) {
    tmp.push_back(Vector2D(p.X / kResolution, p.Y / kResolution));
  }

  // The way the clipper library works, the offset polygon might start at a
  // different point - after all, it is a different polygon.
  // Let's try to find the one that is closest to the start of the input polygon
  // by looking for the closest point to the line represented by the start-vector,
  // i.e. closest point in the same direction.
  const Vector2D &reference = polygon[0];
  double smallest = -1;
  std::size_t offset_index = 0;
  for (std::size_t i = 0; i < tmp.size(); ++i) {
    const Vector2D &p = tmp[i];
#if 0
    // TODO: find center and make line relative to that.
    // Then use http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points
    const double dist = abs(reference.y * p.x - reference.x * p.y);
    const bool same_side = (reference.x * p.x >= 0) && (reference.y * p.y >= 0);
#else
    const double dist = distance(p.x - reference.x, p.y - reference.y, 0);
    const bool same_side = true;
#endif
    if (i == 0 || (dist < smallest && same_side)) {
      offset_index = i;
      smallest = dist;
    }
  }

  // .. then create the result by shifting that.
  Polygon result;
  for (std::size_t i = 0; i < tmp.size(); ++i) {
    result.push_back(tmp[(i + offset_index) % tmp.size()]);
  }
  return result;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x300, %rsp            # imm = 0x300
movq %rdi, -0x298(%rbp)
movq %rdi, %rax
movq %rax, -0x290(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movsd %xmm0, -0x18(%rbp)
movl %edx, -0x1c(%rbp)
movl $0x461c4000, -0x20(%rbp) # imm = 0x461C4000
movl $0x3c23d70a, -0x24(%rbp) # imm = 0x3C23D70A
leaq -0x40(%rbp), %rdi
callq 0xca90
leaq -0x50(%rbp), %rdi
callq 0x8520
jmp 0xc1fe
movq -0x10(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rdi
callq 0x8380
movq %rax, -0x70(%rbp)
movq -0x68(%rbp), %rdi
callq 0x83b0
movq %rax, -0x78(%rbp)
leaq -0x70(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x83e0
testb $0x1, %al
jne 0xc236
jmp 0xc32f
leaq -0x70(%rbp), %rdi
callq 0x8420
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rdi
movss 0x1fd11(%rip), %xmm0    # 0x2bf60
callq 0x8bf0
movsd %xmm1, -0x2a8(%rbp)
movsd %xmm0, -0x2a0(%rbp)
jmp 0xc266
movsd -0x2a8(%rbp), %xmm0
movsd -0x2a0(%rbp), %xmm1
movsd %xmm1, -0x90(%rbp)
movsd %xmm0, -0x88(%rbp)
cvttsd2si -0x90(%rbp), %rsi
cvttsd2si -0x88(%rbp), %rdx
leaq -0xa0(%rbp), %rdi
callq 0xcae0
jmp 0xc2a6
leaq -0x40(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0xcab0
jmp 0xc2b8
leaq -0x50(%rbp), %rdi
leaq -0x90(%rbp), %rsi
callq 0x8c40
movsd %xmm1, -0x2b8(%rbp)
movsd %xmm0, -0x2b0(%rbp)
jmp 0xc2da
movsd -0x2b8(%rbp), %xmm0
movsd -0x2b0(%rbp), %xmm1
movsd %xmm1, -0xb0(%rbp)
movsd %xmm0, -0xa8(%rbp)
movq -0xb0(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0xa8(%rbp), %rax
movq %rax, -0x48(%rbp)
leaq -0x70(%rbp), %rdi
callq 0x84a0
jmp 0xc220
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
jmp 0xc916
movq -0x10(%rbp), %rdi
callq 0x82d0
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, -0x2c0(%rbp)
testq %rax, %rax
movss %xmm0, -0x2bc(%rbp)
js 0xc379
movss -0x2c0(%rbp), %xmm0
movss %xmm0, -0x2bc(%rbp)
movss -0x2bc(%rbp), %xmm0
leaq -0x50(%rbp), %rdi
callq 0x8cb0
movsd %xmm1, -0x2d0(%rbp)
movsd %xmm0, -0x2c8(%rbp)
jmp 0xc39c
movsd -0x2d0(%rbp), %xmm0
movsd -0x2c8(%rbp), %xmm1
movsd %xmm1, -0xc0(%rbp)
movsd %xmm0, -0xb8(%rbp)
movups -0xc0(%rbp), %xmm0
movaps %xmm0, -0x50(%rbp)
leaq -0xd8(%rbp), %rdi
callq 0xcb10
leaq -0x1d0(%rbp), %rdi
movsd 0x1ec5e(%rip), %xmm0    # 0x2b040
movsd 0x1fb66(%rip), %xmm1    # 0x2bf50
callq 0x1bae0
jmp 0xc3f1
movl $0x1, -0x1d4(%rbp)
movl -0x1c(%rbp), %eax
movl %eax, -0x2d4(%rbp)
testl %eax, %eax
je 0xc435
jmp 0xc40a
movl -0x2d4(%rbp), %eax
subl $0x1, %eax
je 0xc441
jmp 0xc417
movl -0x2d4(%rbp), %eax
subl $0x2, %eax
je 0xc44d
jmp 0xc457
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
jmp 0xc90a
movl $0x1, -0x1d4(%rbp)
jmp 0xc457
movl $0x0, -0x1d4(%rbp)
jmp 0xc457
movl $0x2, -0x1d4(%rbp)
movl -0x1d4(%rbp), %edx
leaq -0x1d0(%rbp), %rdi
leaq -0x40(%rbp), %rsi
xorl %ecx, %ecx
callq 0x1bcf0
jmp 0xc471
movsd -0x18(%rbp), %xmm0
movsd 0x1fada(%rip), %xmm1    # 0x2bf58
mulsd %xmm1, %xmm0
leaq -0x1d0(%rbp), %rdi
leaq -0xd8(%rbp), %rsi
callq 0x1c300
jmp 0xc497
leaq -0xd8(%rbp), %rdi
callq 0xcb30
cmpq $0x0, %rax
jne 0xc4e8
movq -0x298(%rbp), %rdi
xorl %esi, %esi
movl $0x18, %edx
callq 0x3140
movq -0x298(%rbp), %rdi
callq 0x8360
movl $0x1, -0x1d8(%rbp)
jmp 0xc8cd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
jmp 0xc8fe
leaq -0xd8(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0xcb60
movq %rax, -0x1e0(%rbp)
leaq -0xd8(%rbp), %rax
movq %rax, -0x1e8(%rbp)
movq -0x1e8(%rbp), %rdi
callq 0xcb80
movq %rax, -0x1f0(%rbp)
movq -0x1e8(%rbp), %rdi
callq 0xcbb0
movq %rax, -0x1f8(%rbp)
leaq -0x1f0(%rbp), %rdi
leaq -0x1f8(%rbp), %rsi
callq 0xcbe0
testb $0x1, %al
jne 0xc54c
jmp 0xc5aa
leaq -0x1f0(%rbp), %rdi
callq 0xcc20
movq %rax, -0x200(%rbp)
movq -0x200(%rbp), %rsi
leaq -0x50(%rbp), %rdi
callq 0xc930
movb %al, -0x2d5(%rbp)
jmp 0xc577
movb -0x2d5(%rbp), %al
testb $0x1, %al
jne 0xc583
jmp 0xc59a
movq -0x200(%rbp), %rsi
movq -0x1e0(%rbp), %rdi
callq 0xcc40
jmp 0xc598
jmp 0xc5aa
jmp 0xc59c
leaq -0x1f0(%rbp), %rdi
callq 0xce90
jmp 0xc533
leaq -0x218(%rbp), %rdi
callq 0x8360
movq -0x1e0(%rbp), %rax
movq %rax, -0x220(%rbp)
movq -0x220(%rbp), %rdi
callq 0xceb0
movq %rax, -0x228(%rbp)
movq -0x220(%rbp), %rdi
callq 0xcee0
movq %rax, -0x230(%rbp)
leaq -0x228(%rbp), %rdi
leaq -0x230(%rbp), %rsi
callq 0xcf10
testb $0x1, %al
jne 0xc606
jmp 0xc68a
leaq -0x228(%rbp), %rdi
callq 0xcf50
movq %rax, -0x238(%rbp)
movq -0x238(%rbp), %rax
cvtsi2ssq (%rax), %xmm0
movss 0x1f933(%rip), %xmm2    # 0x2bf60
divss %xmm2, %xmm0
cvtss2sd %xmm0, %xmm0
cvtsi2ssq 0x8(%rax), %xmm1
divss %xmm2, %xmm1
cvtss2sd %xmm1, %xmm1
leaq -0x248(%rbp), %rdi
callq 0x8470
jmp 0xc651
leaq -0x218(%rbp), %rdi
leaq -0x248(%rbp), %rsi
callq 0x8440
jmp 0xc666
jmp 0xc668
leaq -0x228(%rbp), %rdi
callq 0xcf70
jmp 0xc5ea
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
jmp 0xc8bf
movq -0x10(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x8340
movq %rax, -0x250(%rbp)
movsd 0x1e962(%rip), %xmm0    # 0x2b008
movsd %xmm0, -0x258(%rbp)
movq $0x0, -0x260(%rbp)
movq $0x0, -0x268(%rbp)
movq -0x268(%rbp), %rax
movq %rax, -0x2e0(%rbp)
leaq -0x218(%rbp), %rdi
callq 0x82d0
movq %rax, %rcx
movq -0x2e0(%rbp), %rax
cmpq %rcx, %rax
jae 0xc7b3
movq -0x268(%rbp), %rsi
leaq -0x218(%rbp), %rdi
callq 0x8ff0
movq %rax, -0x270(%rbp)
movq -0x270(%rbp), %rcx
movq -0x250(%rbp), %rax
movsd (%rcx), %xmm0
movsd 0x8(%rcx), %xmm1
movsd (%rax), %xmm3
movsd 0x8(%rax), %xmm2
subsd %xmm3, %xmm0
subsd %xmm2, %xmm1
xorps %xmm2, %xmm2
callq 0x82f0
movsd %xmm0, -0x2e8(%rbp)
jmp 0xc745
movsd -0x2e8(%rbp), %xmm0
movsd %xmm0, -0x278(%rbp)
movb $0x1, -0x279(%rbp)
cmpq $0x0, -0x268(%rbp)
je 0xc77c
movsd -0x278(%rbp), %xmm1
movsd -0x258(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0xc79a
movq -0x268(%rbp), %rax
movq %rax, -0x260(%rbp)
movsd -0x278(%rbp), %xmm0
movsd %xmm0, -0x258(%rbp)
jmp 0xc79c
movq -0x268(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x268(%rbp)
jmp 0xc6c4
movq -0x298(%rbp), %rdi
movb $0x0, -0x27a(%rbp)
callq 0x8360
movq $0x0, -0x288(%rbp)
movq -0x288(%rbp), %rax
movq %rax, -0x2f0(%rbp)
leaq -0x218(%rbp), %rdi
callq 0x82d0
movq %rax, %rcx
movq -0x2f0(%rbp), %rax
cmpq %rcx, %rax
jae 0xc88b
movq -0x288(%rbp), %rax
movq -0x260(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0x2f8(%rbp)
leaq -0x218(%rbp), %rdi
movq %rdi, -0x300(%rbp)
callq 0x82d0
movq -0x300(%rbp), %rdi
movq %rax, %rcx
movq -0x2f8(%rbp), %rax
xorl %edx, %edx
divq %rcx
movq %rdx, %rsi
callq 0x8ff0
movq -0x298(%rbp), %rdi
movq %rax, %rsi
callq 0x8540
jmp 0xc858
jmp 0xc85a
movq -0x288(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x288(%rbp)
jmp 0xc7d1
movq -0x298(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
callq 0x84c0
jmp 0xc8bf
movb $0x1, -0x27a(%rbp)
movl $0x1, -0x1d8(%rbp)
testb $0x1, -0x27a(%rbp)
jne 0xc8b1
movq -0x298(%rbp), %rdi
callq 0x84c0
leaq -0x218(%rbp), %rdi
callq 0x84c0
jmp 0xc8cd
leaq -0x218(%rbp), %rdi
callq 0x84c0
jmp 0xc8fe
leaq -0x1d0(%rbp), %rdi
callq 0x1bbd0
leaq -0xd8(%rbp), %rdi
callq 0xcf90
leaq -0x40(%rbp), %rdi
callq 0xcff0
movq -0x290(%rbp), %rax
addq $0x300, %rsp            # imm = 0x300
popq %rbp
retq
leaq -0x1d0(%rbp), %rdi
callq 0x1bbd0
leaq -0xd8(%rbp), %rdi
callq 0xcf90
leaq -0x40(%rbp), %rdi
callq 0xcff0
movq -0x58(%rbp), %rdi
callq 0x3440
nopl (%rax,%rax)