// File: /workspace/github_c_makefile_star2_O2/zpole[P]IICV/vl/imopv.c
// Function: vl_image_distance_transform_f
VL_EXPORT void
VL_XCAT(vl_image_distance_transform_,SFX)
(T const * image,
 vl_size numColumns,
 vl_size numRows,
 vl_size columnStride,
 vl_size rowStride,
 T * distanceTransform,
 vl_uindex * indexes,
 T coeff,
 T offset)
{
  /* Each image pixel corresponds to a parabola. The algorithm scans
   such parabolas from left to right, keeping track of which
   parabolas belong to the lower envelope and in which interval. There are
   NUM active parabolas, FROM stores the beginning of the interval
   for which a certain parabola is part of the envoelope, and WHICH store
   the index of the parabola (that is, the pixel x from which the parabola
   originated).
   */
  vl_uindex x, y ;
  T * from = vl_malloc (sizeof(T) * (numColumns + 1)) ;
  T * base = vl_malloc (sizeof(T) * numColumns) ;
  vl_uindex * baseIndexes = vl_malloc (sizeof(vl_uindex) * numColumns) ;
  vl_uindex * which = vl_malloc (sizeof(vl_uindex) * numColumns) ;
  vl_uindex num = 0 ;

  for (y = 0 ; y < numRows ; ++y) {
    num = 0 ;
    for (x = 0 ; x < numColumns ; ++x) {
      T r = image[x  * columnStride + y * rowStride] ;
      T x2 = x * x ;
#if (FLT == VL_TYPE_FLOAT)
      T from_ = - VL_INFINITY_F ;
#else
      T from_ = - VL_INFINITY_D ;
#endif

      /*
       Add next parabola (there are NUM so far). The algorithm finds
       intersection INTERS with the previously added parabola. If
       the intersection is on the right of the "starting point" of
       this parabola, then the previous parabola is kept, and the
       new one is added to its right. Otherwise the new parabola
       "eats" the old one, which gets deleted and the check is
       repeated with the parabola added before the deleted one.
       */

      while (num >= 1) {
        vl_uindex x_ = which[num - 1] ;
        T x2_ = x_ * x_ ;
        T r_ = image[x_ * columnStride + y * rowStride] ;
        T inters ;
        if (r == r_) {
          /* handles the case r = r_ = \pm inf */
          inters = (x + x_) / 2.0 + offset ;
        }
#if (FLT == VL_TYPE_FLOAT)
        else if (coeff > VL_EPSILON_F)
#else
        else if (coeff > VL_EPSILON_D)
#endif
        {
          inters = ((r - r_) + coeff * (x2 - x2_)) / (x - x_) / (2*coeff) + offset ;
        } else {
          /* If coeff is very small, the parabolas are flat (= lines).
           In this case the previous parabola should be deleted if the current
           pixel has lower score */
#if (FLT == VL_TYPE_FLOAT)
          inters = (r < r_) ? - VL_INFINITY_F : VL_INFINITY_F ;
#else
          inters = (r < r_) ? - VL_INFINITY_D : VL_INFINITY_D ;
#endif
        }
        if (inters <= from [num - 1]) {
          /* delete a previous parabola */
          -- num ;
        } else {
          /* accept intersection */
          from_ = inters ;
          break ;
        }
      }

      /* add a new parabola */
      which[num] = x ;
      from[num] = from_ ;
      base[num] = r ;
      if (indexes) baseIndexes[num] = indexes[x  * columnStride + y * rowStride] ;
      num ++ ;
    } /* next column */

#if (FLT == VL_TYPE_FLOAT)
    from[num] = VL_INFINITY_F ;
#else
    from[num] = VL_INFINITY_D ;
#endif

    /* fill in */
    num = 0 ;
    for (x = 0 ; x < numColumns ; ++x) {
      double delta ;
      while (x >= from[num + 1]) ++ num ;
      delta = (double) x - (double) which[num] - offset ;
      distanceTransform[x  * columnStride + y * rowStride]
      = base[num] + coeff * delta * delta ;
      if (indexes) {
        indexes[x  * columnStride + y * rowStride]
        = baseIndexes[num] ;
      }
    }
  } /* next row */

  vl_free (from) ;
  vl_free (which) ;
  vl_free (base) ;
  vl_free (baseIndexes) ;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movss %xmm1, 0x8(%rsp)
movss %xmm0, 0xc(%rsp)
movq %r9, 0x30(%rsp)
movq %r8, 0x18(%rsp)
movq %rcx, %r15
movq %rdx, 0x20(%rsp)
movq %rsi, %r13
movq %rdi, 0x10(%rsp)
movq 0x70(%rsp), %rbx
leaq (,%rsi,4), %r14
leaq 0x4(,%rsi,4), %rdi
callq 0x95e0
movq %rax, %r12
movq %r14, %rdi
callq 0x95e0
movq %rax, %r14
leaq (,%r13,8), %rbp
movq %rbp, %rdi
callq 0x95e0
movq %rax, (%rsp)
movq %rbp, %rdi
callq 0x95e0
movss 0x8(%rsp), %xmm15
movq %rax, %rbp
movss 0xc(%rsp), %xmm2
movaps %xmm2, %xmm0
addss %xmm2, %xmm0
cvtss2sd %xmm15, %xmm1
movaps %xmm2, %xmm5
cvtss2sd %xmm2, %xmm2
xorl %edx, %edx
movq 0x161e7(%rip), %xmm3    # 0x2d160
movapd 0x161ef(%rip), %xmm4    # 0x2d170
movapd 0x161e7(%rip), %xmm6    # 0x2d170
movsd 0x1622f(%rip), %xmm7    # 0x2d1c0
movss 0x16392(%rip), %xmm8    # 0x2d32c
leaq 0x16bef(%rip), %rcx     # 0x2db90
cmpq 0x20(%rsp), %rdx
je 0x17237
movq %rdx, 0x28(%rsp)
imulq 0x18(%rsp), %rdx
movq 0x10(%rsp), %rax
leaq (%rax,%rdx,4), %rsi
xorl %edi, %edi
xorl %r8d, %r8d
cmpq %r13, %r8
je 0x1714b
movq %r8, %r9
imulq %r8, %r9
testq %r9, %r9
js 0x16fe1
cvtsi2ss %r9, %xmm9
jmp 0x16ff8
movq %r9, %r10
shrq %r10
andl $0x1, %r9d
orq %r10, %r9
cvtsi2ss %r9, %xmm9
addss %xmm9, %xmm9
movq %r8, %r9
imulq %r15, %r9
addq %rdx, %r9
movq 0x10(%rsp), %rax
movss (%rax,%r9,4), %xmm10
incq %rdi
movq %rdi, %r10
movq %r10, %rdi
cmpq $0x1, %r10
je 0x17115
movq -0x10(%rbp,%rdi,8), %r10
movq %r10, %r11
imulq %r10, %r11
testq %r11, %r11
js 0x17038
cvtsi2ss %r11, %xmm11
jmp 0x1704f
movq %r11, %rax
shrq %rax
andl $0x1, %r11d
orq %rax, %r11
cvtsi2ss %r11, %xmm11
addss %xmm11, %xmm11
movq %r10, %rax
imulq %r15, %rax
movss (%rsi,%rax,4), %xmm12
ucomiss %xmm12, %xmm10
jne 0x17096
jp 0x17096
addq %r8, %r10
movq %r10, %xmm11
punpckldq %xmm3, %xmm11   # xmm11 = xmm11[0],xmm3[0],xmm11[1],xmm3[1]
subpd %xmm6, %xmm11
movapd %xmm11, %xmm12
unpckhpd %xmm11, %xmm12          # xmm12 = xmm12[1],xmm11[1]
addsd %xmm11, %xmm12
mulsd %xmm7, %xmm12
addsd %xmm1, %xmm12
cvtsd2ss %xmm12, %xmm12
jmp 0x170fe
ucomiss %xmm8, %xmm5
jbe 0x170ab
movq %r8, %r11
subq %r10, %r11
js 0x170bc
cvtsi2ss %r11, %xmm13
jmp 0x170d3
xorl %eax, %eax
ucomiss %xmm10, %xmm12
seta %al
movss (%rcx,%rax,4), %xmm12
jmp 0x170fe
movq %r11, %rax
shrq %rax
andl $0x1, %r11d
orq %rax, %r11
cvtsi2ss %r11, %xmm13
addss %xmm13, %xmm13
movaps %xmm10, %xmm14
subss %xmm12, %xmm14
movaps %xmm9, %xmm12
subss %xmm11, %xmm12
mulss %xmm5, %xmm12
addss %xmm14, %xmm12
divss %xmm13, %xmm12
divss %xmm0, %xmm12
addss %xmm15, %xmm12
movss -0x8(%r12,%rdi,4), %xmm11
leaq -0x1(%rdi), %r10
ucomiss %xmm12, %xmm11
jae 0x17013
jmp 0x1711e
movss 0x163b2(%rip), %xmm12   # 0x2d4d0
movq %r8, -0x8(%rbp,%rdi,8)
movss %xmm12, -0x4(%r12,%rdi,4)
movss %xmm10, -0x4(%r14,%rdi,4)
testq %rbx, %rbx
je 0x17143
movq (%rbx,%r9,8), %rax
movq (%rsp), %r9
movq %rax, -0x8(%r9,%rdi,8)
incq %r8
jmp 0x16fc5
movl $0x7f800000, (%r12,%rdi,4) # imm = 0x7F800000
xorl %edi, %edi
xorl %esi, %esi
cmpq %r13, %rsi
je 0x1722a
testq %rsi, %rsi
js 0x1716c
cvtsi2ss %rsi, %xmm9
jmp 0x17186
movq %rsi, %rax
shrq %rax
movl %esi, %r8d
andl $0x1, %r8d
orq %rax, %r8
cvtsi2ss %r8, %xmm9
addss %xmm9, %xmm9
decq %rdi
ucomiss 0x8(%r12,%rdi,4), %xmm9
leaq 0x1(%rdi), %rdi
jae 0x17189
movq %rsi, %r8
imulq %r15, %r8
addq %rdx, %r8
movq %rsi, %xmm9
punpckldq %xmm3, %xmm9    # xmm9 = xmm9[0],xmm3[0],xmm9[1],xmm3[1]
subpd %xmm4, %xmm9
movapd %xmm9, %xmm10
unpckhpd %xmm9, %xmm10           # xmm10 = xmm10[1],xmm9[1]
addsd %xmm9, %xmm10
movq (%rbp,%rdi,8), %xmm9
punpckldq %xmm3, %xmm9    # xmm9 = xmm9[0],xmm3[0],xmm9[1],xmm3[1]
subpd %xmm4, %xmm9
movapd %xmm9, %xmm11
unpckhpd %xmm9, %xmm11           # xmm11 = xmm11[1],xmm9[1]
addsd %xmm9, %xmm11
subsd %xmm11, %xmm10
subsd %xmm1, %xmm10
cvtss2sd (%r14,%rdi,4), %xmm9
movapd %xmm10, %xmm11
mulsd %xmm2, %xmm11
mulsd %xmm10, %xmm11
addsd %xmm9, %xmm11
cvtsd2ss %xmm11, %xmm9
movq 0x30(%rsp), %rax
movss %xmm9, (%rax,%r8,4)
testq %rbx, %rbx
je 0x17222
movq (%rsp), %rax
movq (%rax,%rdi,8), %rax
movq %rax, (%rbx,%r8,8)
incq %rsi
jmp 0x17157
movq 0x28(%rsp), %rdx
incq %rdx
jmp 0x16fa1
movq %r12, %rdi
callq 0x95b0
movq %rbp, %rdi
callq 0x95b0
movq %r14, %rdi
callq 0x95b0
movq (%rsp), %rdi
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x95b0