[c++] Rysowanie wykresu funkcji - dokladnosc

0

Piszę program rysujący wykres funkcji w zadanym przedziale. Program skaluje wykres tak by wypełnił całe okno. I tu pojawia się problem. Okno ma szerokość ok. 500 pixeli (chyba w pixelach to jest liczone :P ) i przy rysowaniu przedziałów rzędu -10 - 10 zaczynają się problemy z dokładnością. Do tego stopnia że wykres przestaje w ogóle przypominać prawidlowy obraz ;) Domyślam się że rozjeżdża się przy przybliżaniu, jednak nie mam pomysłu jak to poprawić. Jakieś propozycje? Oto mój kod (pod Turbo c++):

float __fastcall TForm1::f(float x)
{
		return x; //Zadana funkcja
}
void __fastcall TForm1::Funkcja(float x1, float x2)
{
	float DlugoscPrzedzialu = abs(x1-x2);
	float kx = ClientWidth / DlugoscPrzedzialu;//skala w osi 0X
	float Maximum = f(x1), Minimum = f(x1);
	for (float i = x1; i <= x2; i+=kx) {//Esktrema funckji w danym przedziale
		if (Maximum < f(i)) Maximum = f(i);
		if (Minimum > f(i)) Minimum = f(i);
	}
	float ky;
	if (Maximum != Minimum) ky = ClientHeight / (Maximum - Minimum);//Skala w osi OY
	else ky = 1;
	//Os OX
	if (Minimum<0) {
		Canvas->MoveTo(0, ClientHeight - (int)(abs(Minimum)*ky + 0.5));
		Canvas->LineTo(ClientWidth, ClientHeight - (int)(abs(Minimum)*ky + 0.5));
	}
	//Os OY
	if (x1<0) {
		Canvas->MoveTo((int)(abs(x1)*kx + 0.5), 0);
		Canvas->LineTo((int)(abs(x1)*kx + 0.5), ClientHeight);
	}
	Canvas->MoveTo(0, ClientHeight-(int)((f(x1)-Minimum)*ky + 0.5));
	for (float i = x1; i <= x2; i+=kx) {//Wlasciwa petla rysujaca wykres funkcji
		Canvas->LineTo((int)((i-x1)*kx + 0.5), ClientHeight-(int)((f(i)-Minimum)*ky + 0.5));
	}
}
0
float __fastcall TForm1::f(float x)
{
	return x*x - 2; //Zadana funkcja
}
void __fastcall TForm1::Funkcja(float x1, float x2)
{
	Canvas->Rectangle(-1, -1, ClientWidth + 1, ClientHeight + 1);
	if(x2 < x1) { float tmp = x1; x1 = x2; x2 = tmp; }
	float DlugoscPrzedzialu = x2 - x1;
	//tu miałeś odwrotność kx ! poza tym malujemy przedziały
	//(w pikselach) 0 - 1, 1 - 2, 2 - 3 ... Width-2 - Width-1
	//więc będzie ich razem (ClientWidth - 1)
	float kx = DlugoscPrzedzialu / (ClientWidth - 1);

	float Maximum = f(x1), Minimum = f(x1);
	//uuu, tutaj zaokrąglenia mogą napieszać, wypada użyć licznka int
	for (int i = 1; i < ClientWidth; i++)
	{
		float y = f(x1 + i * kx); //nie licz 4 razy tego samego
		if (Maximum < y) Maximum = y;
		else //jak maksimum, to nie minimum
		if (Minimum > y) Minimum = y;
	}

	//Jeśli chcesz dodać ostęp od góry i od dołu, to zmień Maximum i Minimum
	//Dodamy 5 pikseli z każdej strony
	static const unsigned margin = 5;
	//tu miałeś odwrtoność ky !!
	float ky = (Maximum - Minimum) / (ClientHeight - 1 - 2 * margin);
	if(ky == 0)
	{
		ky = ((Maximum < 0) ? -1.5 : 1.5 ) * Maximum;
		Maximum += ky;
		Minimum -= ky;
		ky = (Maximum - Minimum) / (ClientHeight - 1);
	}
	else
	{
		Maximum += margin * ky;
		Minimum -= margin * ky;
	}

	Canvas->Pen->Color = clBlack;
	if (Minimum * Maximum < 0) //jeśli końce mają przeciwne znaki
	{
		int osX = -Minimum / ky;
		Canvas->MoveTo(0, ClientHeight - 1 - osX);
		Canvas->LineTo(ClientWidth - 1, ClientHeight - 1 - osX);
	}
	if(x1 * x2 < 0) //jeśli końce mają przeciwne znaki
	{
		int osY = -x1 / kx;
		Canvas->MoveTo(osY, 0);
		Canvas->LineTo(osY, ClientHeight - 1);
	}

	Canvas->Pen->Color = clRed;
	Canvas->MoveTo(0, ClientHeight - 1 - (f(x1) - Minimum) / ky);
	float x, y; //wspolrzedne rzeczywiste
	int ix, iy; //współrzędne na canvasie
	for (int ix = 1; ix < ClientWidth; ix++)
	{
		x = x1 + ix * kx;
		y = f(x);
		iy = (y - Minimum) / ky;
		Canvas->LineTo(ix, ClientHeight - 1 - iy);
	}
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1