Zobrazování grafů a složitějších věcí na TFT

Dobré dopoledne,

začínám s TFT displeji a rád bych se zeptal zkušenějších, jak na tom vytváříte nějaké grafy, ať už jde o kruhové či sloupcové apod. Dokážu na tom vytvořit obdelník, kruh, elipsy apod., ale u toho kruhového grafu nevim jak na to. Tak jestli používá nějaké už připravené knihovny, či jse si na to přišli sami. :slight_smile: Sloupcový bude vlastně jednoduchý, tam problém nevidim, ale co se týče toho kruhového, tak tam mě toho moc nenapadá, leda tak mít vzít vzorec pro výseč, který bych mi vybarvil určitou část kruhu, ale nevim jestli to je správné řešení a také se bojim, jestli bych to zvládnul.

Snažil jsem se o tom něco najít, ale bohužel marně.

Doufám, že jsem se vyjádřil srozumitelně. :slight_smile:

Děkuji za případné rady

Jestli tam máš vykreslení čáry, tak jen jeď po malých krocích úhlů, sin/cos spočítat koncovou pocizi a vykreslit čáru danou barvou. Sice silně neefektivní metoda, ale při malých nárocích může často stačit.

Další možnost např. - vykreslit čáru pro počáteční a koncový úhel, vykreslit vnější oblouk (např. spojující čáry po malých krocích úhlu), vzít výchozí bod uprostřed výseče a udělat výplň oblasti. Pozadí musí být předmazané spojitou barvou.

Děkuji za odpověď.

Dostal jsem se k tomu až nyní. Ta první varianta bohužel nefunguje, jelikož tam je vždy nějaký prázdný místo, kde se nezaplní všechny pixely.

Druhou variantu asi nevím jak správně naprogramovat.

Další co mě tedy napadlo bylo, že bych si udělal, jak si říkal kružnici + úsečky krajů výseče. Při této práci bych si vytvořil mapu míst, kde jsou dané pixely výseče, takže bych věděl ohraničení a vnitřek bych vyplnil. Zkusim to o víkendu naprogramovat. Bojim se, ale že to nebude zrovna rychlá varianta no.

Co nejmíň operací typu SIN a COS jinak to bude pomalý. Takže ohraničit a pak vertikálně/horizontálně šrafovat. Startovat z druhé ohraňučovací čáry, rozhodnutí zda vertikálně či horizontálně podle kvadrantu a pak jedeš dokud nepotkáš koncovou ohraničující čáru. Bude to trochu pracný pokud bude mít výseč úhel větší než 180°

Šrafování: Kreslit horizontální čáry shora dolů, přitom nejdříve spočítat výchozí a koncový bod X1 a X2 ohraničený kružnicí (jednoduše z pythagorovy věty ze souřadnice Y, tj. je potřeba odmocnina). V horní půlce kruhu: je-li koncová hraniční úsečka < 180°, omezí se jí X1. Je-li počátační hraniční úsečka < 180°, omezí se jí X2. Úsečka se vykreslí když X1<X2. V dolní části kruhu omezí koncová úsečka naopak X2 je-li >180 a počáteční X1.

Tak už se mi to povedlo naprogramovat. Vykreslování podle mě je poměrně rychlé, teda z mého pohledu, zde se můžete podívat:

Využití AD převodníku s potenciometrem.

Překreslování celý výsečí:
youtube.com/watch?v=U9tropnYdn8

Překreslení pouze té části výseče, která se od poslední hodnoty potenciometru změnila.
youtube.com/watch?v=HuWSSc8G3DM

Nakonec sem si to vyřešil po svém. Vykresluji všechny kvadranty najednou, jelikož jsou ty úhly pro každý kvadrant stejné. Kód sem hodim později, jestli se vám bude hodit, i když si myslim, že v mém případě je zbytečně dlouhý, a dal by se nejspíš zkrátit.

Hezký radar :smiley:

Zde přikládám kód:

void drawPie(int x, int y, int r, int startAngle, int endAngle, int color)
{	
	int tempX, tempY, tempX1, tempX2, tempY2;	
	float i=0;	
	bool kvadrant[4];	
	
	if (startAngle < 90 && endAngle > 0)
		kvadrant[3] = TRUE;
	else
		kvadrant[3] = FALSE;
	if (startAngle < 180 && endAngle > 90)
		kvadrant[2] = TRUE;
	else
		kvadrant[2] = FALSE;
	if (startAngle < 270 && endAngle > 180)
		kvadrant[1] = TRUE;
	else
		kvadrant[1] = FALSE;
	if (startAngle < 360 && endAngle > 270)
		kvadrant[0] = TRUE;
	else
		kvadrant[0] = FALSE;

	for (i = 0; i <= 90; i=i+(float)0.5)
	{		
		tempX = (int)(r * returnSinCos("cos", i));
		tempY = (int)(r * returnSinCos("sin", i));
		if (kvadrant[3])
		{
			tempX2 = tempX;
			tempX1 = 0;
			if (startAngle != 0)
				tempX2 = (int)(tempY * TAN(90 - startAngle) * 2]);
			if (endAngle < 90)
				tempX1 = (int)(tempY * TAN(90 - endAngle) * 2]); ;
			if (endAngle >= 90 && startAngle <= 0)
				TFT_DrawLine(x, y + tempY, x + tempX, y + tempY, color);
			else if ((x + tempX2) < (x + tempX))
				TFT_DrawLine(x + tempX1, y + tempY, x + tempX2, y + tempY, color);
			else if ((x + tempX1) < (x + tempX))
				TFT_DrawLine(x + tempX1, y + tempY, x + tempX, y + tempY, color);
		}
		if (kvadrant[2])
		{
			tempX2 = tempX;
			tempX1 = 0;
			if (endAngle < 180)
				tempX2 = (int)(tempY * TAN(endAngle - 90) * 2]);
			if (startAngle > 90)
				tempX1 = (int)(tempY * TAN(startAngle - 90) * 2]);
			if (endAngle >= 180 && startAngle <= 90)
				TFT_DrawLine(x, y + tempY, x - tempX, y + tempY, color);
			else if ((tempX2 + x) < (x + tempX))
				TFT_DrawLine(x - tempX1, y + tempY, x - tempX2, y + tempY, color);
			else if ((tempX1) <= (tempX))
				TFT_DrawLine(x - tempX, y + tempY, x - tempX1, y + tempY, color);

		}
		if (kvadrant[1])
		{
			tempX2 = tempX;
			tempX1 = 0;
			if (startAngle > 180)
				tempX2 = (int)(tempY * TAN(270 - startAngle) * 2]);
			if (endAngle < 270)
				tempX1 = (int)(tempY * TAN(270 - endAngle) * 2]);
			if (startAngle <= 180 && endAngle >= 270)
				TFT_DrawLine(x, y - tempY, x - tempX, y - tempY, color);
			else if (tempX2 < tempX)
				TFT_DrawLine(x - tempX2, y - tempY, x - tempX1, y - tempY, color);
			else if ((tempX1) < (tempX))
				TFT_DrawLine(x - tempX, y - tempY, x - tempX1, y - tempY, color);

		}

		if (kvadrant[0])
		{                    
			tempX1 = 0;
			tempX2 = tempX;
			if (startAngle > 270)
				tempX1 = (int)(tempY * TAN(startAngle - 270) * 2]);
			if (endAngle < 360)
				tempX2 = (int)(tempY * TAN(endAngle - 270) * 2]);
			if (startAngle <= 270 && endAngle >= 360)
				TFT_DrawLine(x, y - tempY, x + tempX, y - tempY, color);
			else if ((x + tempX2) < (x + tempX))
				TFT_DrawLine(x + tempX1, y - tempY, x + tempX2, y - tempY, color);
			else if ((x + tempX1) < (x + tempX))
				TFT_DrawLine(x + tempX, y - tempY, x + tempX1, y - tempY, color);
		}								
	}
}

proměnná TAN jsou hodnoty tangensu od 0 do 90 po 0.5°. Je to možná zbytečné, ale říkal sem si, každá ušetřená milisekunda dobrá. Je to možný nahradit za tan(2M_PIi/360), u SINu a COSinu to samé. funkce returnSinCos():

double returnSinCos(char *function, float angle)
{
	if (angle > 360) angle = angle - 360 * (int)(angle / 360);
	if(function == "sin"){
		float realAngle = angle;
		if (angle <= 90) ;
		else if (angle <= 180) realAngle = 180 - angle;
		else if (angle <= 270) realAngle = angle - 180;
		else if (angle <= 360) realAngle = 360 - angle;                                
		return angle <= 180 ? 1 * SIN(int)(2*realAngle)]: -1 * SIN(int)(2*realAngle)];
	}
	else if (function == "cos")
	{
		float realAngle = angle;
		if (angle <= 90) ;
		else if (angle <= 180) realAngle = 180 - angle;
		else if (angle <= 270) realAngle = angle - 180;
		else if (angle <= 360) realAngle = 360 - angle;                                
		return (angle >=90 && angle<=270) ? -1 * COS(int)(2*realAngle)]: 1 * COS(int)(2*realAngle)];
	}
	return 0;
}

Vím, že by se to dalo ještě zredukovat na podmínku pro vrchní půlkruh a spodní, ale už se mi nad tím nechtělo přemýšlet. Snad se to někomu bude hodit. :slight_smile: