#define ZEROS_NUM           2
Complex zeros[ZEROS_NUM] = {{10.0, 0}, {-30, 0}};
#define POLES_NUM           2
Complex poles[POLES_NUM] = {{-20.0, -15.0}, {-20.0, 15.0}};

F64 scale;

Complex *PoleZeroFind(I64 x, I64 y)
{
    I64      i;
    F64      dd, best_dd = F64_MAX;
    Complex *res = NULL;

    for (i = 0; i < POLES_NUM; i++)
    {
        dd = Sqr(poles[i].x - x) + Sqr(poles[i].y - y);
        if (dd < best_dd)
        {
            best_dd = dd;
            res = &poles[i];
        }
    }
    for (i = 0; i < ZEROS_NUM; i++)
    {
        dd = Sqr(zeros[i].x - x) + Sqr(zeros[i].y - y);
        if (dd < best_dd)
        {
            best_dd = dd;
            res = &zeros[i];
        }
    }

    return res;
}

F64 F(Complex *x)
{
    F64     m, a;
    Complex num, denom, n1;

    CPoly(&num,   ZEROS_NUM, zeros, x);
    CPoly(&denom, POLES_NUM, poles, x);
    CDiv(&n1, &num, &denom);

    R2P(&m, &a, n1.x, n1.y);
    if (mouse.rb)
        return pi + a;
    else
        return m;
}

F64 MPDraw(CTask *task)
{
    Complex  xx;
    I64      x, y, w = task->pix_width, h = task->pix_height, cx = w / 2, cy = h / 2, 
             lo = Gs->num * h / mp_count, hi = (Gs->num + 1) * h / mp_count;
    F64      yy, y_total = 0;
    CDC     *dc = DCAlias(, task);

    for (y = lo; y < hi; y++)
    {
        for (x = 0; x < w; x++)
        {
            CEqu(&xx, x - cx, cy - y);
            yy = scale * F(&xx);
            dc->color = Clamp(yy, 0, 14);
            y_total += Clamp(yy, -14, 14);
            GrPlot(dc, x, y);
        }
    }
    DCDel(dc);

    return y_total;
}

U0 Draw()
{
    CJob *tmpm[MP_PROCESSORS_NUM];
    F64   y_total, old_y_total = F64_MAX;
    I64   i, w = Fs->pix_width, h = Fs->pix_height, cx = w / 2, cy = h / 2;
    CDC  *dc = DCAlias;

    while (TRUE)
    {
        for (i = 0; i < mp_count; i++)
            tmpm[i] = JobQueue(&MPDraw, Fs, i, 0);
        y_total = 0;
        for (i = 0; i < mp_count; i++)
            y_total += JobResGet(tmpm[i])(F64);

        if (!y_total)
            break;
        scale *= 7 * GR_WIDTH * GR_HEIGHT / y_total;
        if (Abs(y_total - old_y_total) < 1.0 * GR_WIDTH * GR_HEIGHT)
            break;
        old_y_total = y_total;
    }
    dc->color = 15;
    GrLine(dc, 0, cy, w, cy);
    GrLine(dc, cx, 0, cx, h);
    for (i = 0; i < ZEROS_NUM; i++)
        GrPrint(dc, cx + zeros[i].x - FONT_WIDTH / 2, cy - zeros[i].y - FONT_HEIGHT / 2, "o");
    for (i = 0; i < POLES_NUM; i++)
        GrPrint(dc, cx + poles[i].x - FONT_WIDTH / 2, cy - poles[i].y - FONT_HEIGHT / 2, "x");
    DCDel(dc);
}

U0 PoleZeros()
{
    I64      message_code, arg1, arg2, p11, p22, cx, cy;
    Complex *tmpc = NULL;

    PopUpOk("Drag the poles and zeros with left mouse.\n"
            "Hold right mouse for phase plot.\n");

    SettingsPush; //See SettingsPush
    Fs->win_inhibit = WIG_TASK_DEFAULT - WIF_SELF_FOCUS - WIF_SELF_BORDER;
    GrPaletteSet(gr_palette_gray);
    gr_palette[WHITE] = 0xFF0000; //White is red

    AutoComplete;
    WinBorder;
    WinMax;
    DocClear;
    DCFill;
    scale = 1.0;

    try
    {
        Draw;
        while (TRUE)
        {
            message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN +
                                                    1 << MESSAGE_MS_L_DOWN + 1 << MESSAGE_MS_L_UP +
                                                    1 << MESSAGE_MS_R_DOWN + 1 << MESSAGE_MS_R_UP +
                                                    1 << MESSAGE_MS_MOVE);
pz_message:
            cx = Fs->pix_width  / 2;
            cy = Fs->pix_height / 2;
            switch (message_code)
            {
                case MESSAGE_MS_L_DOWN:
                    tmpc = PoleZeroFind(arg1 - cx, cy - arg2);
                    break;

                case MESSAGE_MS_MOVE:
                    if (tmpc)
                    {
                        p11 = arg1;
                        p22 = arg2;
                        //get to last mouse move
                        while (message_code = MessageScan(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN +
                                                                        1 << MESSAGE_MS_L_DOWN + 1 << MESSAGE_MS_L_UP +
                                                                        1 << MESSAGE_MS_R_DOWN + 1 << MESSAGE_MS_R_UP +
                                                                        1 << MESSAGE_MS_MOVE))
                            if (message_code == MESSAGE_MS_MOVE)
                            {
                                p11 = arg1;
                                p22 = arg2;
                            }
                            else
                                goto pz_message;

                        tmpc->x = p11 - cx;
                        tmpc->y = cy - p22;
                        Draw;
                    }
                    break;

                case MESSAGE_MS_L_UP:
                    if (tmpc)
                    {
                        tmpc->x = arg1 - cx;
                        tmpc->y = cy - arg2;
                        tmpc = NULL;
                        Draw;
                    }
                    break;

                case MESSAGE_MS_R_DOWN:
                case MESSAGE_MS_R_UP:
                    Draw;
                    break;

                case MESSAGE_KEY_DOWN:
                    if (arg1 == CH_SHIFT_ESC || arg1 == CH_ESC)
                        goto pz_done;
            }
            Refresh;
        }
pz_done:
        MessageGet(,, 1 << MESSAGE_KEY_UP);
    }
    catch
        PutExcept;
    SettingsPop;
    DCFill;
}

PoleZeros;