#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;