// File: 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:
subq $0xc8, %rsp
leaq 0xd0(%rsp), %rax
movq %rax, 0x18(%rsp)
movq %rdi, 0xc0(%rsp)
movss %xmm0, 0xbc(%rsp)
movss %xmm1, 0xb8(%rsp)
movss %xmm2, 0xb4(%rsp)
movq 0xc0(%rsp), %rdi
callq 0x11c00
movl %eax, 0xb0(%rsp)
movq 0xc0(%rsp), %rdi
callq 0x11c10
movl %eax, 0xac(%rsp)
movq 0xc0(%rsp), %rdi
callq 0x11c00
movl %eax, %eax
cvtsi2ss %rax, %xmm1
movss 0x2755(%rip), %xmm0     # 0x1e030
mulss %xmm1, %xmm0
movss %xmm0, 0xa8(%rsp)
cvtsi2sdl 0xac(%rsp), %xmm1
movsd 0x2857(%rip), %xmm0     # 0x1e150
divsd %xmm1, %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0xa4(%rsp)
movss 0xa8(%rsp), %xmm0
cvtss2sd %xmm0, %xmm1
movsd 0x2831(%rip), %xmm0     # 0x1e150
divsd %xmm1, %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0xa0(%rsp)
cvtsi2sdl 0xac(%rsp), %xmm1
movsd 0x280f(%rip), %xmm0     # 0x1e150
divsd %xmm1, %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x9c(%rsp)
cvtsi2sdl 0xac(%rsp), %xmm0
movsd 0x27ed(%rip), %xmm1     # 0x1e150
divsd %xmm1, %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x98(%rsp)
movss 0xa8(%rsp), %xmm0
cvtss2sd %xmm0, %xmm0
movsd 0x27c7(%rip), %xmm1     # 0x1e150
divsd %xmm1, %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x94(%rsp)
cvtsi2sdl 0xac(%rsp), %xmm0
movsd 0x27a5(%rip), %xmm1     # 0x1e150
divsd %xmm1, %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x90(%rsp)
cvtsi2ssl 0xb0(%rsp), %xmm0
movss 0x265f(%rip), %xmm1     # 0x1e02c
subss 0xbc(%rsp), %xmm1
mulss %xmm1, %xmm0
movss 0x264a(%rip), %xmm1     # 0x1e02c
divss %xmm1, %xmm0
movss %xmm0, 0x8c(%rsp)
cvtsi2ssl 0xac(%rsp), %xmm0
movss 0x2628(%rip), %xmm1     # 0x1e028
subss 0xb8(%rsp), %xmm1
mulss %xmm1, %xmm0
movss 0x260f(%rip), %xmm1     # 0x1e024
divss %xmm1, %xmm0
movss %xmm0, 0x88(%rsp)
movss 0x8c(%rsp), %xmm0
mulss 0xa0(%rsp), %xmm0
movss %xmm0, 0x84(%rsp)
movss 0x88(%rsp), %xmm0
movss 0x9c(%rsp), %xmm1
mulss %xmm1, %xmm0
movss 0x25c5(%rip), %xmm1     # 0x1e020
addss %xmm1, %xmm0
movss %xmm0, 0x80(%rsp)
movss 0x80(%rsp), %xmm0
callq 0xea30
movss %xmm0, 0x7c(%rsp)
movss 0x80(%rsp), %xmm0
callq 0xea10
movss %xmm0, 0x78(%rsp)
movss 0xb4(%rsp), %xmm0
mulss 0xa4(%rsp), %xmm0
movss %xmm0, 0x74(%rsp)
movss 0x74(%rsp), %xmm0
callq 0xea10
movss %xmm0, 0x70(%rsp)
movss 0x88(%rsp), %xmm0
subss 0xb4(%rsp), %xmm0
callq 0x1c2a0
movss %xmm0, 0x68(%rsp)
xorps %xmm0, %xmm0
movss %xmm0, 0x64(%rsp)
leaq 0x68(%rsp), %rdi
leaq 0x64(%rsp), %rsi
callq 0x1b580
movss (%rax), %xmm0
movss %xmm0, 0x6c(%rsp)
movss 0x88(%rsp), %xmm0
addss 0xb4(%rsp), %xmm0
callq 0x1c2c0
movss %xmm0, 0x5c(%rsp)
cvtsi2ssl 0xac(%rsp), %xmm0
movss %xmm0, 0x58(%rsp)
leaq 0x5c(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0x1bf90
movss (%rax), %xmm0
movss %xmm0, 0x60(%rsp)
movss 0x6c(%rsp), %xmm0
movss %xmm0, 0x54(%rsp)
movss 0x54(%rsp), %xmm1
movss 0x60(%rsp), %xmm0
ucomiss %xmm1, %xmm0
jbe 0x1be92
movss 0x24ca(%rip), %xmm0     # 0x1e030
addss 0x54(%rsp), %xmm0
movss 0x9c(%rsp), %xmm1
mulss %xmm1, %xmm0
movss 0x249f(%rip), %xmm1     # 0x1e020
addss %xmm1, %xmm0
movss %xmm0, 0x50(%rsp)
movss 0x50(%rsp), %xmm0
cvtss2sd %xmm0, %xmm0
callq 0x4090
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x4c(%rsp)
movss 0x50(%rsp), %xmm0
cvtss2sd %xmm0, %xmm0
callq 0x4630
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x48(%rsp)
movss 0x246f(%rip), %xmm0     # 0x1e034
movss %xmm0, 0x44(%rsp)
movss 0x78(%rsp), %xmm0
callq 0x1c2e0
movaps %xmm0, %xmm1
movss 0x2453(%rip), %xmm0     # 0x1e034
ucomiss %xmm1, %xmm0
ja 0x1bc01
movss 0x48(%rsp), %xmm0
callq 0x1c2e0
movaps %xmm0, %xmm1
movss 0x2438(%rip), %xmm0     # 0x1e034
ucomiss %xmm1, %xmm0
jbe 0x1bc11
movss 0x242f(%rip), %xmm0     # 0x1e038
movss %xmm0, 0x14(%rsp)
jmp 0x1bc6f
movss 0x23f3(%rip), %xmm0     # 0x1e00c
divss 0x78(%rsp), %xmm0
movd %xmm0, %eax
xorl $0x80000000, %eax       # imm = 0x80000000
movd %eax, %xmm0
movss 0x23d8(%rip), %xmm1     # 0x1e00c
divss 0x48(%rsp), %xmm1
mulss %xmm1, %xmm0
movss 0x7c(%rsp), %xmm1
movss 0x4c(%rsp), %xmm3
movss 0x70(%rsp), %xmm2
movd %xmm2, %eax
xorl $0x80000000, %eax       # imm = 0x80000000
movd %eax, %xmm2
mulss %xmm3, %xmm1
addss %xmm2, %xmm1
mulss %xmm1, %xmm0
movss %xmm0, 0x14(%rsp)
movss 0x14(%rsp), %xmm0
movss %xmm0, 0x40(%rsp)
movss 0x40(%rsp), %xmm0
movss 0x2383(%rip), %xmm1     # 0x1e00c
ucomiss %xmm1, %xmm0
jbe 0x1bc99
xorps %xmm0, %xmm0
movss %xmm0, 0x10(%rsp)
jmp 0x1bcdf
movss 0x2377(%rip), %xmm0     # 0x1e018
ucomiss 0x40(%rsp), %xmm0
jbe 0x1bcb9
movss 0xa8(%rsp), %xmm0
movss %xmm0, 0xc(%rsp)
jmp 0x1bcd3
movss 0x40(%rsp), %xmm0
callq 0x1c300
mulss 0x98(%rsp), %xmm0
movss %xmm0, 0xc(%rsp)
movss 0xc(%rsp), %xmm0
movss %xmm0, 0x10(%rsp)
movss 0x10(%rsp), %xmm0
movss %xmm0, 0x3c(%rsp)
movss 0x8c(%rsp), %xmm0
subss 0x3c(%rsp), %xmm0
callq 0x1c2a0
movss %xmm0, 0x38(%rsp)
movss 0x8c(%rsp), %xmm0
addss 0x3c(%rsp), %xmm0
callq 0x1c2c0
movss %xmm0, 0x34(%rsp)
movss 0x38(%rsp), %xmm0
movss %xmm0, 0x30(%rsp)
movss 0x30(%rsp), %xmm1
movss 0x34(%rsp), %xmm0
ucomiss %xmm1, %xmm0
jbe 0x1be77
movss 0x22e8(%rip), %xmm0     # 0x1e030
addss 0x30(%rsp), %xmm0
mulss 0xa0(%rsp), %xmm0
movss %xmm0, 0x2c(%rsp)
movss 0x7c(%rsp), %xmm0
movss %xmm0, 0x8(%rsp)
movss 0x4c(%rsp), %xmm0
movss %xmm0, 0x4(%rsp)
movss 0x78(%rsp), %xmm0
mulss 0x48(%rsp), %xmm0
movss %xmm0, (%rsp)
movss 0x84(%rsp), %xmm0
subss 0x2c(%rsp), %xmm0
callq 0xea10
movss (%rsp), %xmm1
movss 0x4(%rsp), %xmm2
movaps %xmm0, %xmm3
movss 0x8(%rsp), %xmm0
mulss %xmm3, %xmm1
mulss %xmm2, %xmm0
addss %xmm1, %xmm0
callq 0x1c300
mulss 0x98(%rsp), %xmm0
movss %xmm0, 0x28(%rsp)
movss 0x30(%rsp), %xmm0
cvtsi2ssl 0xb0(%rsp), %xmm1
addss %xmm1, %xmm0
cvttss2si %xmm0, %eax
cltd
idivl 0xb0(%rsp)
movl %edx, 0x24(%rsp)
cvttss2si 0x54(%rsp), %eax
movl %eax, 0x20(%rsp)
movq 0xc0(%rsp), %rdi
movl 0x24(%rsp), %esi
movl 0x20(%rsp), %edx
callq 0x1c320
testb $0x1, %al
jne 0x1be16
jmp 0x1be5c
movq 0xc0(%rsp), %rdi
movl 0x24(%rsp), %esi
movl 0x20(%rsp), %edx
callq 0x1c470
movq 0x18(%rsp), %rdi
movq %rax, %rsi
movss 0x2c(%rsp), %xmm0
movss 0x50(%rsp), %xmm1
movss 0x84(%rsp), %xmm2
movss 0x80(%rsp), %xmm3
movss 0x28(%rsp), %xmm4
callq 0x1c380
jmp 0x1be5e
movss 0x21a6(%rip), %xmm0     # 0x1e00c
addss 0x30(%rsp), %xmm0
movss %xmm0, 0x30(%rsp)
jmp 0x1bd2b
jmp 0x1be79
movss 0x218b(%rip), %xmm0     # 0x1e00c
addss 0x54(%rsp), %xmm0
movss %xmm0, 0x54(%rsp)
jmp 0x1bb49
addq $0xc8, %rsp
retq
nopw (%rax,%rax)