Niedziela 19 Maj 2024r. Godz 00:00:00      
Postów: 251      

Rysowanie lini VGA

Nad wymyśleniem tej funkcji pracowałem jakieś 2 miesiące. Jakoś nie mogłem wpaść jak to zrobić. Ale do rzeczy.Jest to troszkę zagmatwane ale działa.

 

  • Sprawdzamy czy odcinek nie jest pionowy.
      Tak:
    • Wiemy że tangens jest równy nieskończoność.
    • Sprwdzamy czy przypadkiem nie jest poziomy.
        Tak:
      • Jeżeli są spełnione oba warunki to punkt końca i początka odcinka się pokrywa. Czyli rysujemy punkt.
        Nie:
      • Jeżeli warunek poziomu nie jest spełniony to rysujemy pionową linię. Uzywamy funkcji lini używającej cotangensa.
      Nie:
    • Wiemy że tangens istnieje, czyli możemy go obliczyć. Napewno nie będziemy mieli błędu dzielenia przez zero.
    • Obliczamy tangens
    • Jeżeli tangens kąta jest większy od 1 i mniejszy od -1 to do rysowania odcinka dokładniejsza będzie funkcja używająca cotangensa.
    • W przeciwnym wypadku używamy funkcji z tangensem.

 

A tak wygląda szkielet funkcji.


void inline linia(float x1, float y1, float x2, float y2,char kolor=0x0F)
{
        float tga;
        if((x2-x1)==0)
        {
                if((y2-y1)==0)
                {
                        punkt(x1, x2, kolor);
                        return;
                }
                else
                {
                        ctg(x1, y1, x2, y2, kolor);
                        return;
                }
        }
        tga=(float)(y2-y1)/(x2-x1);
        if(tga>=1||tga<=-1)
        {
                ctg(x1, y1, x2, y2, kolor);
                return;
        }
        else
        {
                tg(x1, y1, x2, y2, kolor);
                return;
        }
}

Dlaczego jest podział na funkcje używające tangensa i cotangensa. Zakładam że wiesz jak wyglądają te funkcje. Do 45 stopni czyli gdy tangens ma wartość 1 dokładniejszy w obliczeniach jest tangens jeżeli byśmy zastosowali przy moim algorytmie funkcię z tangensem powyżej 45 stopni to w odcinku były by dziury. czym większy kont tym większe dziury. A pionowego odcinka byśmy nie narysowali wogóle bo tg 90 = nieskończoność

A proste rysujemy następująco:

 

  • Obliczamy sobie tangens z tych dwóch punktów.
  • Sprawdzamy który punkt jest wyżej i od niego kolejno piksel po pikselu wyznaczamy współżędną poziomą, kożystając z wcześniej obliczonego tangensa.


Podobnie robi się dla cotangensa z tym że idzie się w poziomie obliczając współżędną pionową.

 

Istnieje jeszcze jeden problem do rozwiązania. Komputerm przy przekształceniach liczb dziesiętnych na całkowite obcina końcówkę a nie przybliża. No i przez tę niedogodność wychodzą odcinki troszkę przesunięte po osi x albo y. Ale oczywiście jest to do rozwiązania. Zrobimy sobie funkcję do zaokrąglania. Wykożystamy w tym celu właściwość która była nam niewygodą. przypisujemy do zmiennej całkowitej a liczbę z ułamkiem x. I w zależności czy jest to liczba ujemna czy dodatnia odpowiednio dodajemy lub odejmujemy do naszego ułamka tak że pozostaje nam liczba mniejsza od 1 i większa od -1 i teraz nic prostszego sprawdzić czy jest mniejsza czy większa od 0.5 i odpowiednio zaokrąglić.


int inline zaok(float x)
{
        int a=x;
        if(x>0)
        {
                x-=a;
                if(x<0.5)
                        return a;
                else
                {
                        a+=1;
                        return a;
                }
        }
        else
        {
                x+=a;
                if(x> -0.5)
                        return a;
                else
                {
                        a-=1;
                        return a;
                }
        }
}

void tg(float x1, float y1, float x2, float y2, char kolor)
{
        int register i;
        float tga=(y2-y1)/(x2-x1);
        if(x1<=x2)
		for(i=x1; i<=x2; i++)
			punkt(i, zaok(tga*(i-x1)+y1), kolor);
	else
		for(i=x2; i<=x1; i++)
			punkt(i, zaok(tga*(i-x1)+y1), kolor);
}

void ctg(float x1, float y1, float x2, float y2, char kolor)
{
	int register i;
	float ctga=(x2-x1)/(y2-y1);
	if(y1<=y2)
		for(i=y1; i<=y2; i++)
			punkt(zaok(ctga*(i-y1)+x1), i, kolor);
	else
		for(i=y2; i<=y1; i++)
			punkt(zaok(ctga*(i-y1)+x1), i, kolor);

}

Oczywiście definicjia funkcji linia(...) powinna być za tymi trzema funkcjami. W przeciwnym wypadku się to nie skompiluje.
No to przebrneliśmy przez linie, no to możemy iść dalej.