// File: hzeller[P]gcode-multi-shell-extrude/multi-shell-extrude.cc
// Function: CreateExtrusion(std::vector<Vector2D, std::allocator<Vector2D>> const&, Printer*, Vector2D const&, ExtrusionParams const&)
static void CreateExtrusion(const Polygon &extrusion_polygon, Printer *printer,
                            const Vector2D &center,
                            const ExtrusionParams &params) {
  printer->Comment("Center X=%.1f Y=%.1f\n", center.x, center.y);
  printer->SetColor(0, 0, 0);
  const float z_bottom_offset = params.layer_height / 2;
  const double rotation_per_layer =
      params.layer_height * params.rotation_per_mm * 2 * M_PI;
  bool fan_is_on = false;
  printer->SwitchFan(false);
  double height = 0;
  double angle = 0;
  double run_len = 0;
  const bool do_lock = (params.lock_offset > 0);
  double polygon_len = 0;
  Polygon p; // active polygon.
  static const int kLockOverlap = 3;
  enum State { START, WIDE_LOCK, NORMAL, NARROW_LOCK };
  enum State state = START;
  enum State prev_state;
  for (height = 0, angle = 0; height < params.total_height;
       height += params.layer_height, angle += rotation_per_layer) {
    printer->SetTemperature(GetLayerTemperature(
        params.base_temp, params.temp_variation, height, 30));
    prev_state = state;

    // Experimental. Locking screws do have smaller/larger diameter at their
    // ends. This goes through the state transitions.
    // What to print. For locking screw we're very simple: we just offset the
    // polygon, but don't do any transition for now.
    // TODO: re-arrange polygon to start at same angle.
    switch (state) {
    case START:
      if (do_lock) {
        state = WIDE_LOCK;
        p = PolygonOffset(extrusion_polygon, params.lock_offset);
      } else {
        state = NORMAL;
        p = extrusion_polygon;
      }
      break;

    case WIDE_LOCK:
      if (do_lock && height > kLockOverlap) {
        p = extrusion_polygon;
        state = NORMAL;
      }
      break;

    case NORMAL:
      if (do_lock && height > params.total_height - kLockOverlap) {
        p = PolygonOffset(extrusion_polygon, -params.lock_offset);
        state = NARROW_LOCK;
      }
      break;
    case NARROW_LOCK: /* terminal state */
      break;
    }

    if (state != prev_state) {
      polygon_len = CalcPolygonLen(p);
      // First move slowly, so that we wipe potential nozzle leak extrusion
      printer->SetSpeed(std::min(params.feedrate / 3, 15.0));
      printer->MoveTo(p[0] + center, height + z_bottom_offset);
    }

    for (int i = 0; i < (int)p.size(); ++i) {
      if (i == 0) {
        run_len = 0;
      } else {
        run_len += distance(p[i].x - p[i - 1].x, p[i].y - p[i - 1].y, 0);
      }
      const double fraction = run_len / polygon_len;
      const double a = angle + fraction * rotation_per_layer;
      const Vector2D point = rotate(p[i], a);
      const double z = height + params.layer_height * fraction;
      const bool is_initial_layers = z < 2 * params.layer_height;
      // Speed: keep slow while initial layers, then lerp-ing up to full
      // speed within 4 more layers
      if (is_initial_layers) {
        printer->SetSpeed(params.feedrate *
                          params.first_layer_feedrate_multiplier);
      } else if (z < 4 * params.layer_height) {
        const double range = 1.0 - params.first_layer_feedrate_multiplier;
        const double lerp = (z - 2 *  params.layer_height)
          / ((4 - 2) * params.layer_height);
        printer->SetSpeed(params.feedrate *
                          (params.first_layer_feedrate_multiplier
                           + lerp * range));
      } else {
        printer->SetSpeed(params.feedrate);
      }
      // Start only extruding when min z-offset reached and also stop extruding
      // at the top to wipe off excess
      if (z > z_bottom_offset / 2 &&
          z < params.total_height - 0.30 * params.layer_height) {
        printer->ExtrudeTo(point + center, z,
                           (is_initial_layers)
                           ? params.elephant_foot_multiplier
                           : 1.0);
      } else {
        // In the last layer, we stop extruding to have a smooth finish.
        printer->MoveTo(point + center, z);
      }
    }

    if (height > params.fan_on_height && !fan_is_on) {
      printer->SwitchFan(true); // reached fan-on height: switch on.
      fan_is_on = true;
    }
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x200, %rsp            # imm = 0x200
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rax
movsd (%rax), %xmm0
movq -0x18(%rbp), %rax
movsd 0x8(%rax), %xmm1
movq (%rdi), %rcx
leaq 0x24399(%rip), %rsi     # 0x2bd83
movb $0x2, %al
callq *0x18(%rcx)
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
xorps %xmm2, %xmm2
movaps %xmm2, %xmm0
movaps %xmm2, %xmm1
callq *0x68(%rax)
movq -0x20(%rbp), %rax
movsd 0x8(%rax), %xmm0
movsd 0x2362d(%rip), %xmm1    # 0x2b040
divsd %xmm1, %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, -0x24(%rbp)
movq -0x20(%rbp), %rax
movsd 0x8(%rax), %xmm0
movq -0x20(%rbp), %rax
mulsd 0x18(%rax), %xmm0
movsd 0x23606(%rip), %xmm1    # 0x2b040
mulsd %xmm1, %xmm0
movsd 0x23602(%rip), %xmm1    # 0x2b048
mulsd %xmm1, %xmm0
movsd %xmm0, -0x30(%rbp)
movb $0x0, -0x31(%rbp)
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
xorl %esi, %esi
callq *0x58(%rax)
xorps %xmm0, %xmm0
movsd %xmm0, -0x40(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x48(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x50(%rbp)
movq -0x20(%rbp), %rax
movsd 0x20(%rax), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
seta %al
andb $0x1, %al
movb %al, -0x51(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x60(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x8360
movl $0x0, -0x7c(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x40(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x48(%rbp)
movsd -0x40(%rbp), %xmm1
movq -0x20(%rbp), %rax
movsd 0x10(%rax), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x8234
movq -0x10(%rbp), %rax
movq %rax, -0x158(%rbp)
movq -0x20(%rbp), %rax
movss 0x40(%rax), %xmm0
movss 0x44(%rax), %xmm1
movsd -0x40(%rbp), %xmm2
cvtsd2ss %xmm2, %xmm2
movss 0x2357b(%rip), %xmm3    # 0x2b074
callq 0x8260
movss %xmm0, -0x14c(%rbp)
jmp 0x7b08
movq -0x158(%rbp), %rdi
movss -0x14c(%rbp), %xmm0
cvtss2sd %xmm0, %xmm0
movq (%rdi), %rax
movq 0x20(%rax), %rax
callq *%rax
jmp 0x7b26
movl -0x7c(%rbp), %eax
movl %eax, -0x80(%rbp)
movl -0x7c(%rbp), %eax
movq %rax, -0x160(%rbp)
subq $0x3, %rax
ja 0x7c82
movq -0x160(%rbp), %rax
leaq 0x235a2(%rip), %rcx     # 0x2b0f0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x84c0
jmp 0x8246
testb $0x1, -0x51(%rbp)
je 0x7bbf
movl $0x1, -0x7c(%rbp)
movq -0x8(%rbp), %rsi
movq -0x20(%rbp), %rax
movsd 0x20(%rax), %xmm0
leaq -0xa8(%rbp), %rdi
xorl %edx, %edx
callq 0xc1b0
jmp 0x7ba1
leaq -0x78(%rbp), %rdi
leaq -0xa8(%rbp), %rsi
callq 0x8aa0
leaq -0xa8(%rbp), %rdi
callq 0x84c0
jmp 0x7bd7
movl $0x2, -0x7c(%rbp)
movq -0x8(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0x9050
jmp 0x7bd5
jmp 0x7bd7
jmp 0x7c82
testb $0x1, -0x51(%rbp)
je 0x7c0b
movsd -0x40(%rbp), %xmm0
movsd 0x23461(%rip), %xmm1    # 0x2b050
ucomisd %xmm1, %xmm0
jbe 0x7c0b
movq -0x8(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0x9050
jmp 0x7c04
movl $0x2, -0x7c(%rbp)
jmp 0x7c82
testb $0x1, -0x51(%rbp)
je 0x7c7e
movsd -0x40(%rbp), %xmm0
movq -0x20(%rbp), %rax
movsd 0x10(%rax), %xmm1
movsd 0x23427(%rip), %xmm2    # 0x2b050
subsd %xmm2, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x7c7e
movq -0x8(%rbp), %rsi
movq -0x20(%rbp), %rax
movsd 0x20(%rax), %xmm0
movaps 0x23479(%rip), %xmm1    # 0x2b0c0
pxor %xmm1, %xmm0
leaq -0xc0(%rbp), %rdi
xorl %edx, %edx
callq 0xc1b0
jmp 0x7c5b
leaq -0x78(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x8aa0
leaq -0xc0(%rbp), %rdi
callq 0x84c0
movl $0x3, -0x7c(%rbp)
jmp 0x7c82
jmp 0x7c82
movl -0x7c(%rbp), %eax
cmpl -0x80(%rbp), %eax
je 0x7da2
leaq -0x78(%rbp), %rdi
callq 0x35f0
movsd %xmm0, -0x168(%rbp)
jmp 0x7ca1
movsd -0x168(%rbp), %xmm0
movsd %xmm0, -0x60(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x178(%rbp)
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movsd 0x23387(%rip), %xmm1    # 0x2b050
divsd %xmm1, %xmm0
movsd %xmm0, -0xc8(%rbp)
movabsq $0x402e000000000000, %rax # imm = 0x402E000000000000
movq %rax, -0xd0(%rbp)
leaq -0xc8(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
callq 0x92a0
movq %rax, -0x170(%rbp)
jmp 0x7d02
movq -0x178(%rbp), %rdi
movq -0x170(%rbp), %rax
movsd (%rax), %xmm0
movq (%rdi), %rax
movq 0x28(%rax), %rax
callq *%rax
jmp 0x7d1f
movq -0x10(%rbp), %rax
movq %rax, -0x190(%rbp)
xorl %eax, %eax
movl %eax, %esi
leaq -0x78(%rbp), %rdi
callq 0x8ff0
movq %rax, %rdi
movq -0x18(%rbp), %rsi
callq 0x8c40
movsd %xmm1, -0x188(%rbp)
movsd %xmm0, -0x180(%rbp)
jmp 0x7d55
movq -0x190(%rbp), %rdi
movsd -0x188(%rbp), %xmm0
movsd -0x180(%rbp), %xmm1
movsd %xmm1, -0xe0(%rbp)
movsd %xmm0, -0xd8(%rbp)
movsd -0x40(%rbp), %xmm0
movss -0x24(%rbp), %xmm1
cvtss2sd %xmm1, %xmm1
addsd %xmm1, %xmm0
movq (%rdi), %rax
movq 0x48(%rax), %rax
leaq -0xe0(%rbp), %rsi
callq *%rax
jmp 0x7da0
jmp 0x7da2
movl $0x0, -0xe4(%rbp)
movl -0xe4(%rbp), %eax
movl %eax, -0x194(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x82d0
movq %rax, %rcx
movl -0x194(%rbp), %eax
cmpl %ecx, %eax
jge 0x81dd
cmpl $0x0, -0xe4(%rbp)
jne 0x7de8
xorps %xmm0, %xmm0
movsd %xmm0, -0x50(%rbp)
jmp 0x7e86
movslq -0xe4(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0x8ff0
movsd (%rax), %xmm0
movsd %xmm0, -0x1b0(%rbp)
movl -0xe4(%rbp), %eax
subl $0x1, %eax
movslq %eax, %rsi
leaq -0x78(%rbp), %rdi
callq 0x8ff0
movsd -0x1b0(%rbp), %xmm0
subsd (%rax), %xmm0
movsd %xmm0, -0x1a0(%rbp)
movslq -0xe4(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0x8ff0
movsd 0x8(%rax), %xmm0
movsd %xmm0, -0x1a8(%rbp)
movl -0xe4(%rbp), %eax
subl $0x1, %eax
movslq %eax, %rsi
leaq -0x78(%rbp), %rdi
callq 0x8ff0
movsd -0x1a8(%rbp), %xmm1
movsd -0x1a0(%rbp), %xmm0
subsd 0x8(%rax), %xmm1
xorps %xmm2, %xmm2
callq 0x82f0
addsd -0x50(%rbp), %xmm0
movsd %xmm0, -0x50(%rbp)
movsd -0x50(%rbp), %xmm0
movsd -0x60(%rbp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0xf0(%rbp)
movsd -0x48(%rbp), %xmm1
movsd -0xf0(%rbp), %xmm0
movsd -0x30(%rbp), %xmm2
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0xf8(%rbp)
movslq -0xe4(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0x8ff0
movq %rax, %rdi
movsd -0xf8(%rbp), %xmm0
cvtsd2ss %xmm0, %xmm0
callq 0x92e0
movsd %xmm1, -0x1c0(%rbp)
movsd %xmm0, -0x1b8(%rbp)
jmp 0x7ef4
movsd -0x1c0(%rbp), %xmm0
movsd -0x1b8(%rbp), %xmm1
movsd %xmm1, -0x108(%rbp)
movsd %xmm0, -0x100(%rbp)
movsd -0x40(%rbp), %xmm1
movq -0x20(%rbp), %rax
movsd 0x8(%rax), %xmm0
movsd -0xf0(%rbp), %xmm2
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x110(%rbp)
movsd -0x110(%rbp), %xmm1
movq -0x20(%rbp), %rax
movsd 0x230f2(%rip), %xmm0    # 0x2b040
mulsd 0x8(%rax), %xmm0
ucomisd %xmm1, %xmm0
seta %al
andb $0x1, %al
movb %al, -0x111(%rbp)
testb $0x1, -0x111(%rbp)
je 0x7f90
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movsd 0x38(%rax), %xmm1
mulsd %xmm1, %xmm0
movq (%rdi), %rax
movq 0x28(%rax), %rax
callq *%rax
jmp 0x7f8b
jmp 0x8046
movsd -0x110(%rbp), %xmm1
movq -0x20(%rbp), %rax
movsd 0x230b4(%rip), %xmm0    # 0x2b058
mulsd 0x8(%rax), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x802b
movq -0x20(%rbp), %rax
movsd 0x38(%rax), %xmm1
movsd 0x23070(%rip), %xmm0    # 0x2b030
subsd %xmm1, %xmm0
movsd %xmm0, -0x120(%rbp)
movsd -0x110(%rbp), %xmm0
movq -0x20(%rbp), %rax
movsd 0x8(%rax), %xmm1
addsd %xmm1, %xmm1
subsd %xmm1, %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, -0x128(%rbp)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movsd 0x38(%rax), %xmm2
movsd -0x128(%rbp), %xmm1
movsd -0x120(%rbp), %xmm3
mulsd %xmm3, %xmm1
addsd %xmm2, %xmm1
mulsd %xmm1, %xmm0
movq (%rdi), %rax
movq 0x28(%rax), %rax
callq *%rax
jmp 0x8029
jmp 0x8044
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rax
movsd (%rax), %xmm0
movq (%rdi), %rax
movq 0x28(%rax), %rax
callq *%rax
jmp 0x8042
jmp 0x8044
jmp 0x8046
movsd -0x110(%rbp), %xmm0
movss -0x24(%rbp), %xmm1
movss 0x2305d(%rip), %xmm2    # 0x2b0b8
divss %xmm2, %xmm1
cvtss2sd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x8157
movsd -0x110(%rbp), %xmm1
movq -0x20(%rbp), %rax
movsd 0x10(%rax), %xmm2
movq -0x20(%rbp), %rax
movsd 0x8(%rax), %xmm0
movsd 0x22fd1(%rip), %xmm3    # 0x2b060
mulsd %xmm3, %xmm0
addsd %xmm2, %xmm0
ucomisd %xmm1, %xmm0
jbe 0x8157
movq -0x10(%rbp), %rax
movq %rax, -0x1d8(%rbp)
movq -0x18(%rbp), %rsi
leaq -0x108(%rbp), %rdi
callq 0x8c40
movsd %xmm1, -0x1d0(%rbp)
movsd %xmm0, -0x1c8(%rbp)
jmp 0x80ce
movsd -0x1d0(%rbp), %xmm0
movsd -0x1c8(%rbp), %xmm1
movsd %xmm1, -0x138(%rbp)
movsd %xmm0, -0x130(%rbp)
movsd -0x110(%rbp), %xmm0
movsd %xmm0, -0x1e0(%rbp)
testb $0x1, -0x111(%rbp)
je 0x811a
movq -0x20(%rbp), %rax
movsd 0x30(%rax), %xmm0
movsd %xmm0, -0x1e8(%rbp)
jmp 0x812c
movsd 0x22f0e(%rip), %xmm0    # 0x2b030
movsd %xmm0, -0x1e8(%rbp)
jmp 0x812c
movsd -0x1e0(%rbp), %xmm0
movq -0x1d8(%rbp), %rdi
movsd -0x1e8(%rbp), %xmm1
movq (%rdi), %rax
movq 0x50(%rax), %rax
leaq -0x138(%rbp), %rsi
callq *%rax
jmp 0x8155
jmp 0x81c7
movq -0x10(%rbp), %rax
movq %rax, -0x200(%rbp)
movq -0x18(%rbp), %rsi
leaq -0x108(%rbp), %rdi
callq 0x8c40
movsd %xmm1, -0x1f8(%rbp)
movsd %xmm0, -0x1f0(%rbp)
jmp 0x8184
movq -0x200(%rbp), %rdi
movsd -0x1f8(%rbp), %xmm0
movsd -0x1f0(%rbp), %xmm1
movsd %xmm1, -0x148(%rbp)
movsd %xmm0, -0x140(%rbp)
movsd -0x110(%rbp), %xmm0
movq (%rdi), %rax
movq 0x48(%rax), %rax
leaq -0x148(%rbp), %rsi
callq *%rax
jmp 0x81c5
jmp 0x81c7
jmp 0x81c9
movl -0xe4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xe4(%rbp)
jmp 0x7dac
movsd -0x40(%rbp), %xmm0
movq -0x20(%rbp), %rax
ucomisd 0x28(%rax), %xmm0
jbe 0x820b
testb $0x1, -0x31(%rbp)
jne 0x820b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
movq 0x58(%rax), %rax
movl $0x1, %esi
callq *%rax
jmp 0x8207
movb $0x1, -0x31(%rbp)
jmp 0x820d
movq -0x20(%rbp), %rax
movsd 0x8(%rax), %xmm0
addsd -0x40(%rbp), %xmm0
movsd %xmm0, -0x40(%rbp)
movsd -0x30(%rbp), %xmm0
addsd -0x48(%rbp), %xmm0
movsd %xmm0, -0x48(%rbp)
jmp 0x7ab7
leaq -0x78(%rbp), %rdi
callq 0x84c0
addq $0x200, %rsp            # imm = 0x200
popq %rbp
retq
movq -0x88(%rbp), %rdi
callq 0x3440
nopw %cs:(%rax,%rax)