#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 ã + 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 $LK,"SettingsPush",A="MN: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;
