// File: /workspace/github_cpp_makefile_star2_O2/misohena[P]drawstars/drawstars.cpp
// Function: void fillCircleOnEquirectangular<PixelPlotter>(Image<ColorRGB<double>>&, float, float, float, PixelPlotter)
void fillCircleOnEquirectangular(
    ImageType &canvas,
    float ra, float dec, float radius,
    F funcPlot)
{
    const int canvasW = canvas.width();
    const int canvasH = canvas.height();
    const float canvasW_2 = 0.5f * canvas.width(); //=canvasH?

    const float px2rad = float(PI / canvasH);
    const float x2rad = float(PI / canvasW_2);
    const float y2rad = float(PI / canvasH);
    const float rad2px = float(canvasH / PI);
    const float rad2x = float(canvasW_2 / PI);
    const float rad2y = float(canvasH / PI);

    const float centerX = canvasW * (360 - ra) / 360;
    const float centerY = canvasH * (90 - dec) / 180;

    const float centerXRad = centerX * x2rad;
    const float centerYRad = centerY * y2rad - (float(PI/2));
    const float sinCenterYRad = std::sin(centerYRad);
    const float cosCenterYRad = std::cos(centerYRad);

    const float radiusRad = radius * px2rad;
    const float cosRadiusRad = std::cos(radiusRad);

    // y方向の描画範囲は、中心から上下にradiusの範囲内
    // (正距円筒図法では経線上のピクセル数と度数の比率は常に一定なので)
    // x方向についてはy(dec:赤偉)ごとに計算する。
    const float ymin = std::max(std::floor(centerY - radius), 0.0f);
    const float ymax = std::min(std::ceil(centerY + radius), float(canvasH));
    for(float y = ymin; y < ymax; ++y){
        // [y, y+1)のラインを描画する。

        // y+0.5のライン上(緯線上)でのxの範囲を求める。
        //
        // - 円の中心の方角 : 赤経cx, 赤偉cy [rad]
        // - 描画する点の方角 : 赤経px, 赤偉py [rad]
        // - 円の中心の方角と描画する点の方角とのなす角 : r [rad]
        // とすると次の関係が成り立つ。
        // r=acos(sin(cy)*sin(py) + cos(cy)*cos(py)*cos(cx - px))
        //
        // これをpxについて解くと次のようになる。
        // px = -2*PI*n - acos(-sec(cy)*sec(py)*(sin(cy)*sin(py) - cos(r))) + cx
        // (nは任意の整数、secは1/cos)
        const float plotYRad = (y + 0.5f) * y2rad - float(PI/2);
        const float sinPlotYRad = sin(plotYRad);
        const float cosPlotYRad = cos(plotYRad);
        const float MIN_COS = 1e-6f;
        const float cosRX =
            (std::abs(cosCenterYRad) < MIN_COS || std::abs(cosPlotYRad) < MIN_COS) ? -2 :
            -(1/cosCenterYRad)*(1/cosPlotYRad) * (sinCenterYRad*sinPlotYRad - cosRadiusRad);
        const float rx =
            cosRX > 1 ? 0 : //緯線上は全て円の外
            cosRX < -1 ? canvasW_2 : // 緯線上は全て円の中
            std::acos(cosRX) * rad2px;
        //printf("rx=%f cosRX=%f \n", rx, cosRX);

        const float xmin = std::floor(centerX - rx);
        const float xmax = std::ceil(centerX + rx);
        for(float x = xmin; x < xmax; ++x){
            // [ (x, y) - (x+1, y+1) )の点を描画する(代表点は(x+0.5, y+0.5))。
            const float plotXRad = (x + 0.5f) * x2rad;
            // 中心(centerX, centerY)と(x+0.5, y+0.5)との距離を求める。
            const float dist = std::acos(sinCenterYRad*sinPlotYRad + cosCenterYRad*cosPlotYRad*std::cos(centerXRad - plotXRad)) * rad2px;
            const int ix = static_cast<int>(x + canvasW) % canvasW;// xは左右端で繰り返し処理。
            const int iy = static_cast<int>(y);
            if(canvas.includes(ix, iy)){ //念のため
                funcPlot(canvas.at(ix, iy), plotXRad, plotYRad, centerXRad, centerYRad, dist);
            }
        }
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0x98, %rsp
movq %rdi, %rbx
movl (%rdi), %r15d
cvtsi2ss %r15, %xmm5
movss %xmm2, (%rsp)
mulss 0x10eb(%rip), %xmm5     # 0xc01c
movl 0x4(%rdi), %eax
cvtsi2sd %eax, %xmm2
movsd 0x1220(%rip), %xmm3     # 0xc160
movapd %xmm3, %xmm4
divsd %xmm2, %xmm4
cvtsd2ss %xmm4, %xmm6
movss %xmm6, 0x20(%rsp)
movss %xmm5, 0x1c(%rsp)
cvtss2sd %xmm5, %xmm4
divsd %xmm3, %xmm2
divsd %xmm4, %xmm3
cvtsd2ss %xmm3, %xmm3
cvtsd2ss %xmm2, %xmm2
movss %xmm2, 0x2c(%rsp)
cvtsi2ss %r15d, %xmm4
leaq 0xc0(%rsp), %r14
movss 0x1099(%rip), %xmm2     # 0xc020
movaps %xmm2, %xmm5
subss %xmm0, %xmm5
movss %xmm4, 0x44(%rsp)
mulss %xmm4, %xmm5
cvtsi2ss %eax, %xmm0
movss %xmm0, 0x18(%rsp)
divss %xmm2, %xmm5
movss 0x1076(%rip), %xmm2     # 0xc024
subss %xmm1, %xmm2
mulss %xmm0, %xmm2
divss 0x106a(%rip), %xmm2     # 0xc028
movss %xmm2, 0x10(%rsp)
movss %xmm5, 0x24(%rsp)
movss %xmm3, 0x48(%rsp)
mulss %xmm3, %xmm5
movss %xmm5, 0x38(%rsp)
movaps %xmm2, %xmm0
mulss %xmm6, %xmm0
addss 0x1043(%rip), %xmm0     # 0xc02c
movss %xmm0, 0x28(%rsp)
callq 0x4290
movss %xmm0, 0x30(%rsp)
movss 0x28(%rsp), %xmm0
callq 0x4230
movaps %xmm0, 0x70(%rsp)
movss 0x20(%rsp), %xmm0
mulss (%rsp), %xmm0
callq 0x4230
movaps %xmm0, 0x50(%rsp)
movss 0x10(%rsp), %xmm0
subss (%rsp), %xmm0
callq 0x4110
xorps %xmm1, %xmm1
maxss %xmm0, %xmm1
movss %xmm1, 0xc(%rsp)
movss 0x10(%rsp), %xmm0
addss (%rsp), %xmm0
callq 0x41b0
movss 0xc(%rsp), %xmm1
movss 0x18(%rsp), %xmm2
minss %xmm0, %xmm2
movss %xmm2, 0x18(%rsp)
movaps 0x1187(%rip), %xmm0     # 0xc1f0
movaps 0x70(%rsp), %xmm2
andps %xmm2, %xmm0
movaps %xmm0, 0x80(%rsp)
movss 0xf97(%rip), %xmm0      # 0xc018
divss %xmm2, %xmm0
movss %xmm0, 0x3c(%rsp)
movaps 0x50(%rsp), %xmm0
xorps 0x1119(%rip), %xmm0     # 0xc1b0
movaps %xmm0, 0x50(%rsp)
movss 0x18(%rsp), %xmm0
ucomiss %xmm1, %xmm0
jbe 0xb2b0
movss %xmm1, 0xc(%rsp)
addss 0xf63(%rip), %xmm1      # 0xc01c
mulss 0x20(%rsp), %xmm1
addss 0xf65(%rip), %xmm1      # 0xc02c
movss %xmm1, 0x40(%rsp)
cvtss2sd %xmm1, %xmm0
movsd %xmm0, 0x10(%rsp)
callq 0x4080
movsd %xmm0, (%rsp)
movsd 0x10(%rsp), %xmm0
callq 0x4550
movss 0xf3c(%rip), %xmm1      # 0xc030
ucomiss 0x80(%rsp), %xmm1
cvtsd2ss (%rsp), %xmm1
movss %xmm1, 0x34(%rsp)
cvtsd2ss %xmm0, %xmm3
movss 0x1c(%rsp), %xmm1
movaps %xmm3, 0x60(%rsp)
ja 0xb189
movaps %xmm3, %xmm0
andps 0x10ce(%rip), %xmm0     # 0xc1f0
movss 0xf06(%rip), %xmm1      # 0xc030
ucomiss %xmm0, %xmm1
movss 0x1c(%rsp), %xmm1
ja 0xb189
movss 0xed7(%rip), %xmm2      # 0xc014
movaps %xmm2, %xmm1
divss %xmm3, %xmm1
mulss 0x3c(%rsp), %xmm1
movss 0x30(%rsp), %xmm0
mulss 0x34(%rsp), %xmm0
addss 0x50(%rsp), %xmm0
mulss %xmm1, %xmm0
xorps %xmm1, %xmm1
ucomiss %xmm2, %xmm0
ja 0xb189
movss 0xea8(%rip), %xmm1      # 0xc018
ucomiss %xmm0, %xmm1
movss 0x1c(%rsp), %xmm1
ja 0xb189
callq 0x4320
movaps %xmm0, %xmm1
mulss 0x2c(%rsp), %xmm1
movss %xmm1, 0x10(%rsp)
movss 0x24(%rsp), %xmm0
subss %xmm1, %xmm0
callq 0x4110
movss %xmm0, (%rsp)
movss 0x10(%rsp), %xmm0
addss 0x24(%rsp), %xmm0
callq 0x41b0
movss (%rsp), %xmm3
movaps 0x60(%rsp), %xmm2
movss %xmm0, 0x4c(%rsp)
mulss 0x70(%rsp), %xmm2
movss 0xc(%rsp), %xmm1
cvttss2si %xmm1, %ebp
movaps %xmm2, 0x60(%rsp)
movss 0x4c(%rsp), %xmm0
ucomiss %xmm3, %xmm0
jbe 0xb2a3
movaps %xmm3, %xmm1
addss 0xe29(%rip), %xmm1      # 0xc01c
mulss 0x48(%rsp), %xmm1
movss 0x38(%rsp), %xmm0
movss %xmm1, 0x10(%rsp)
subss %xmm1, %xmm0
movss %xmm3, (%rsp)
callq 0x4230
mulss 0x60(%rsp), %xmm0
movss 0x30(%rsp), %xmm1
mulss 0x34(%rsp), %xmm1
addss %xmm1, %xmm0
callq 0x4320
movss (%rsp), %xmm3
movaps %xmm0, %xmm4
movaps %xmm3, %xmm0
addss 0x44(%rsp), %xmm0
cvttss2si %xmm0, %eax
cltd
idivl %r15d
movl %edx, %eax
orl %ebp, %eax
js 0xb290
movl (%rbx), %eax
cmpl %edx, %eax
jbe 0xb290
cmpl %ebp, 0x4(%rbx)
jbe 0xb290
mulss 0x2c(%rsp), %xmm4
imull %ebp, %eax
addl %edx, %eax
imulq $0x18, %rax, %rsi
addq 0x8(%rbx), %rsi
movq %r14, %rdi
movss 0x10(%rsp), %xmm0
movss 0x40(%rsp), %xmm1
movss 0x38(%rsp), %xmm2
movss 0x28(%rsp), %xmm3
callq 0xb376
movss (%rsp), %xmm3
addss 0xd7c(%rip), %xmm3      # 0xc014
movss 0xc(%rsp), %xmm1
jmp 0xb1d9
addss 0xd69(%rip), %xmm1      # 0xc014
jmp 0xb09c
addq $0x98, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq