algorytm rysowania trójkąta ?

algorytm rysowania trójkąta ?
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

zna ktoś algorytm rysowania trójkąta 2D w całości rysowany jednym kolorem w c++ ? , mam dostępne punkty i odcinki do rysowania , na google są ale z reguły wzrory a to mi nic nie daje , nie jestem matematykiem aby takie wzory rozpisać sobie na kod

edytowany 3x, ostatnio: wilkwielki
AN
  • Rejestracja:około 19 lat
  • Ostatnio:około 10 godzin
0

Chodzi o narysowanie pełnego trójkąta piksel po pikselu na ekranie lub bitmapie?

Jakiś czas temu zastosowałem taki algorytm, bo sam potrzebowałem:
https://github.com/andrzejlisek/ScriptSDCCWeb/blob/main/ProjWeb/prog/guigraphinstance_draw.cpp - funkcja IOGraphWin::DrawTriangle (jeden kolor) i IOGraphWin::DrawTriangle0 (gradient na podstawie kolorów w wierzchołkach)

W mojej funkcji argumenty mają następujące znaczenie:
X1, Y1, X2, Y2, X3, Y3 - współrzędne wierzchołków na ekranie - potrzebne do faktycznego narysowania
Z1, Z2, Z3 - punkt głębi, które służą do obliczania wierzchołków w buforze głębi - to można pominąć w przypadku rysowania 2D
R0, G0, B0 - kolor trójkąta w przypadku trójkąta jednokolorowego
R1, G1, B1, R2, G2, B2, R3, G3, B3 - kolory wierzchołków w RGB do narysowania gradientu
LightAngle - Kąt światła potrzebny do obliczania wynikowego koloru rysowania w 3D - niepotrzebne przy rysowaniu w 2D, mój program ma prostą symulację 3D

Zasadnicza funkcja, która jest wywoływana i odpowiada za faktyczne rysowanie trójkąta to tak naprawdę DrawHalfTriangle i DrawHalfTriangle0, te dwie funkcje tan naprawdę malują połowę trójkąta, czyli tak naprawdę cały trójkąt, w którym jeden bok jest linią poziomą.

Pozostanie usunąć argumenty Z1, Z2, Z3, LightAngle i usunąć obliczenia z ich udziałem, potem przerobić samo malowanie, bo ten program rysuje do bufora będącego tablicą bajtową.

edytowany 1x, ostatnio: andrzejlisek
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

przepraszam ale za duzo tego nie moge sie połąpać jesli chodzi o twój projekt z kodem.... mozesz napiać samą wersje rysowania na jednym kolorze bez światła bez gradientu i bez bufforawania głębi , prosił bym , po kazdym oblicznie u mnie jest putpixel(X,Y) i tyle starczy dla tego trójkąta co napisałeś bez warotści osi Z tzn głębi

edytowany 3x, ostatnio: wilkwielki
AN
  • Rejestracja:około 19 lat
  • Ostatnio:około 10 godzin
0

Usunąłem wszystko, co niepotrzebne i teraz można łatwo testować. Ustawianie ImgRaw możesz zmienić na to swoje putpixel bez problemu, teraz kod można bez trudu testować:

W pliku *.h powinny być takie zmienne:

Kopiuj
typedef unsigned char uchar;

    std::vector<uchar> ImgRaw;
    int ImgW = 640;
    int ImgH = 480;

W pliku *.cpp powinny być takie funkcje:

Kopiuj

// Rysowanie połowy trójkąta
void MainWindow::DrawHalfTriangle(int X0, int Y0, int X1, int X2, int Y_, uchar R0, uchar G0, uchar B0)
{
    int DrawX0 = X0;
    int DrawY0 = Y0;
    int DrawX1 = X1;
    int DrawX2 = X2;
    int DrawY_ = Y_;

    int X, Y, YI1, YI2, XI1, XI2;
    double DX1, DX2, DZ1, DZ2, DY, DYX, A1, A2, A1Z, A2Z;

    if (DrawX1 > DrawX2)
    {
        X = DrawX1;
        DrawX1 = DrawX2;
        DrawX2 = X;
    }

    DX1 = DrawX1 - DrawX0;
    DX2 = DrawX2 - DrawX0;
    DY = DrawY0 - DrawY_;
    A1 = DX1 / DY;
    A2 = DX2 / DY;
    A1Z = DZ1 / DY;
    A2Z = DZ2 / DY;

    if (DrawY_ < DrawY0)
    {
        YI1 = DrawY_;
        YI2 = DrawY0;
    }
    else
    {
        YI1 = DrawY0;
        YI2 = DrawY_;
    }

    for (Y = YI1; Y <= YI2; Y++)
    {
        DYX = (DrawY_ - Y);
        XI1 = round(DYX * A1) + DrawX1;
        XI2 = round(DYX * A2) + DrawX2;
        for (X = XI1; X <= XI2; X++)
        {
            int Pos = (Y * ImgW) + X;
            int Pos4X = Pos << 2;
            ImgRaw[Pos4X + 0] = R0;
            ImgRaw[Pos4X + 1] = G0;
            ImgRaw[Pos4X + 2] = B0;
        }
    }
}

// Rysowanie trójkąta z wykorzystaniem funkcji rysujących połowę
void MainWindow::DrawTriangle(int X1, int Y1, int X2, int Y2, int X3, int Y3, uchar R0, uchar G0, uchar B0)
{
    int XMin;
    int XMax;
    int YMin;
    int YMax;

    double F1, F2, F3, F4;

    int P0X_;
    int P0X__;
    int P0Y_;
    int P1X_;
    int P1Y_;
    int P2X_;
    int P2Y_;

    XMin = X1;
    XMax = X1;
    if (XMin > X2) { XMin = X2; }
    if (XMax < X2) { XMax = X2; }
    if (XMin > X3) { XMin = X3; }
    if (XMax < X3) { XMax = X3; }

    YMin = Y1;
    YMax = Y1;
    if (YMin > Y2) { YMin = Y2; }
    if (YMax < Y2) { YMax = Y2; }
    if (YMin > Y3) { YMin = Y3; }
    if (YMax < Y3) { YMax = Y3; }

    P0Y_ = YMin;

    if ((Y1 > YMin) && (Y1 < YMax))
    {
        P0X_ = X1; P0Y_ = Y1;
        if (Y2 == YMin)
        {
            P1X_ = X2; P1Y_ = Y2;
            P2X_ = X3; P2Y_ = Y3;
        }
        else
        {
            P1X_ = X3; P1Y_ = Y3;
            P2X_ = X2; P2Y_ = Y2;
        }
    }
    else
    {
        if ((Y2 > YMin) && (Y2 < YMax))
        {
            P0X_ = X2; P0Y_ = Y2;
            if (Y3 == YMin)
            {
                P1X_ = X3; P1Y_ = Y3;
                P2X_ = X1; P2Y_ = Y1;
            }
            else
            {
                P1X_ = X1; P1Y_ = Y1;
                P2X_ = X3; P2Y_ = Y3;
            }
        }
        else
        {
            if ((Y3 > YMin) && (Y3 < YMax))
            {
                P0X_ = X3; P0Y_ = Y3;
                if (Y1 == YMin)
                {
                    P1X_ = X1; P1Y_ = Y1;
                    P2X_ = X2; P2Y_ = Y2;
                }
                else
                {
                    P1X_ = X2; P1Y_ = Y2;
                    P2X_ = X1; P2Y_ = Y1;
                }
            }
        }
    }



    if ((P0Y_ > YMin) && (P0Y_ < YMax))
    {
        F1 = P0Y_ - P1Y_;
        F2 = P2Y_ - P1Y_;

        F3 = P2X_ - P1X_;
        F4 = F3 * (F1 / F2);

        P0X__ = P1X_ + F4;

        DrawHalfTriangle(P1X_, P1Y_, P0X_, P0X__, P0Y_, R0, G0, B0);
        DrawHalfTriangle(P2X_, P2Y_, P0X_, P0X__, P0Y_, R0, G0, B0);
    }
    else
    {
        if (Y1 == Y2)
        {
            DrawHalfTriangle(X3, Y3, X1, X2, Y1, R0, G0, B0);
        }
        if (Y2 == Y3)
        {
            DrawHalfTriangle(X1, Y1, X2, X3, Y2, R0, G0, B0);
        }
        if (Y3 == Y1)
        {
            DrawHalfTriangle(X2, Y2, X3, X1, Y3, R0, G0, B0);
        }
    }
}


// Przykładowa funkcja w programie
void MainWindow::on_pushButton_clicked()
{

    // Przygotowanie tablicy "unsigned char" symulującej bitmapę
    ImgW = 40;
    ImgH = 40;
    ImgRaw.clear();
    for (int i = 0; i < (ImgW * ImgH * 4); i++)
    {
        ImgRaw.push_back(0);
    }


    // Rysowanie przykładowych trójkątow
    DrawTriangle(5, 5, 18, 7, 10, 30, 1, 1, 1);
    DrawTriangle(20, 37, 17, 28, 38, 26, 2, 2, 2);


    // Wypisanie tablicy symulującej bitmapę
    int ptr = 0;
    for (int y = 0; y < ImgH; y++)
    {
        for (int x = 0; x < ImgW; x++)
        {
            switch (ImgRaw[ptr])
            {
                case 0: std::cout << "."; break;
                case 1: std::cout << "#"; break;
                case 2: std::cout << "@"; break;
            }
            ptr += 4;
        }
        std::cout << std::endl;
    }
}

W powyższym kodzie kolory są symulowane znakami i wypisywany jest co czwarty bajt. Zakładam, że przekształcenie tego na rysowanie na bitmapie za pomocą putpixel nie będzie żadnym wyzwaniem. Zmieni się tylko techniczny sposób malowania, same obliczenia pozostaną te same.

Samo stawianie piksela to jest poniższy kod, użyty w DrawHalfTriangle, gdzie X i Y to współrzędne piksela, a R0, G0, B0 to składowe koloru:

Kopiuj
            int Pos = (Y * ImgW) + X;
            int Pos4X = Pos << 2;
            ImgRaw[Pos4X + 0] = R0;
            ImgRaw[Pos4X + 1] = G0;
            ImgRaw[Pos4X + 2] = B0;
edytowany 6x, ostatnio: andrzejlisek
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

dobra dzięki teraz lepiej powinniem sobie poradzić

wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

czy to jest C++ 17

Kopiuj
void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
    // Find the bounding box of the triangle
    int minY = min({y1, y2, y3});
    int maxY = max({y1, y2, y3});

    // Loop through each scanline from minY to maxY
    for (int y = minY; y <= maxY; ++y) {
        // Find the intersections of the scanline with the triangle edges
        int x_intersection1 = -1, x_intersection2 = -1;

        // Check if the scanline intersects with the edge (x1, y1) to (x2, y2)
        if ((y1 <= y && y2 > y) || (y2 <= y && y1 > y)) {
            x_intersection1 = x1 + (y - y1) * (x2 - x1) / (y2 - y1);
        }

        // Check if the scanline intersects with the edge (x2, y2) to (x3, y3)
        if ((y2 <= y && y3 > y) || (y3 <= y && y2 > y)) {
            x_intersection2 = x2 + (y - y2) * (x3 - x2) / (y3 - y2);
        }

        // Check if the scanline intersects with the edge (x3, y3) to (x1, y1)
        if ((y3 <= y && y1 > y) || (y1 <= y && y3 > y)) {
            x_intersection1 = x3 + (y - y3) * (x1 - x3) / (y1 - y3);
        }

        // Ensure the intersection points are ordered from left to right
        if (x_intersection1 > x_intersection2)
            swap(x_intersection1, x_intersection2);

        // Fill the pixels between the two intersections
        for (int x = x_intersection1; x <= x_intersection2; ++x) {
            putPixel(x, y);
        }
    }
}

jesli tak to potrafi ktos kto ma wiedze przerobic na C++ 98 , chociaż na C++20 gdzie nie potrzeba #include <algorithm> tylko czysta matma , bo u mnie na VC++6.0 tego nie ma tzn min , max ,swap

edytowany 2x, ostatnio: MarekR22
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

swap zaimienia warotsciami min pobiera najmniejszą a max największą ale jeszcze jedno chodzi o to:
int x_intersection1 = -1, x_intersection2 = -1;
tutaj jest przecinek czy to wymagane bo powinnien byc srednik
tuaj jest potrójna wartosc i mi nie działa min({y1, y2, y3});

edytowany 1x, ostatnio: wilkwielki
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

zrobiłem sam swap, działa

Kopiuj
void swap(int &a, int &b)
{
	int c=a;
	a=b;
	b=c;
}

takie pytanie jak są trzy wartosci to dalej jak normalnie najwiekszą z max gdzy było by tylko dwie wartości i z min tak samo ?
mam tak niby działa sam napisałem

Kopiuj
int Min(int a,int b,int c)
{
	if(a<b && a<c)
		return a;
	if(b<a && b<c)
		return b;
	if(c<a && c<b)
		return c;
}

int Max(int a,int b,int c)
{
	if(a>b && a>c)
		return a;
	if(b>a && b>c)
		return b;
	if(c>a && c>b)
		return c;
}

proszę o komentarz czy na pewno właściwie napisalem jak powinno działać , wg testów które robiłem działa dobrze

edytowany 7x, ostatnio: MarekR22
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

zapodałem swojego Min , Max i swap i działa mi funkcja fillTriangle
to wszystko ... temat do zamknięcia 😀

edytowany 1x, ostatnio: wilkwielki
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:4 minuty
2
wilkwielki napisał(a):

czy to jest C++ 17

  1. Ile mam razy prosić, byś zaczął używać kolorowania składni dla kodu? tak trudno dopisać: ```cpp przed kodem i ``` po kodzie?
  2. To przeładowanie std::max (3) (4) jest z C++11, inne przeładowania są starsze od C++98 (1) (2), od wersji C++14 zmieniły się na wersję constexpr:

std::max - cppreference.com

template< class T >
const T& max( const T& a, const T& b );
(1) (constexpr since C++14)
template< class T, class Compare >
const T& max( const T& a, const T& b, Compare comp );
(2) (constexpr since C++14)
template< class T >
T max( std::initializer_list<T> ilist );
(3) (since C++11)
(constexpr since C++14)
template< class T, class Compare >
T max( std::initializer_list<T> ilist, Compare comp );
(4) (since C++11)
(constexpr since C++14)
  1. Jak masz tylko C++98 nie prościej było zrobić kaskadę std::max ?
Kopiuj
std::max(std::max(a, b), c);

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
1
Kopiuj
int a;

przepraszam juz sie nauczyłem trzeba klawiszem tyldy ja tego nie wiedziałem . przepraszam

edytowany 1x, ostatnio: wilkwielki
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0
Kopiuj
int minY = Min(y1, Min(y2, y3));
int maxY = Max(y1, Max(y2, y3));

ta funkcja fillTriangle z tym algorytmem jest skopana, błędna , raz działa a raz pokazuje śmieci

edytowany 1x, ostatnio: wilkwielki
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

spoko na OpenGl to ja sie znam tylko pisze i juz koncze silniczek od rysowania grafiki w konsoli odwolywane przez funkcje SetPixel(mydc, x, y, COLOR); grzeibie na google i są urywki kodów ale ciężko znaeść coś działającego albo same wzory matematyczne , ze tez kurcze szkoda ze prawie nigdzie nie ma kodu działajacej funkcji od rysowanie trójkąta wypełnionego

edytowany 2x, ostatnio: wilkwielki
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

no tak funkcja SetPixel nie jest z opengl wiem o tym , są algorytmy rysujące trójkąty wypełnione ale trudno dostępne

wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

to prawda liczone przez CPU ja to wpisuje putpixel do tablicy a na koncu rendreruje tablice po pwszystkim

loza_prowizoryczna
loza_prowizoryczna
  • Rejestracja:ponad 2 lata
  • Ostatnio:15 dni
  • Postów:1629
0
wilkwielki napisał(a):

zna ktoś algorytm rysowania trójkąta 2D w całości rysowany jednym kolorem w c++ ? , mam dostępne punkty i odcinki do rysowania , na google są ale z reguły wzrory a to mi nic nie daje , nie jestem matematykiem aby takie wzory rozpisać sobie na kod

Ja ci dam prosty algorytm ale bez koloru;

  1. Wybierasz sobie punkt
  2. Przez punkt przeprowadzasz prostą
  3. Następnie wybierasz sobie losowo inny punkt
  4. Przez punkt z 1. i 3. przeprowadzasz kolejną prostą
  5. W pewnej odległości od punktu 1. rysujesz kolejną prostą
  6. Wychodząc z punktu podążasz zgodnie z kierunkiem ruchu wskazówek zegara aż powrócisz do punktu wyjścia

Właśnie otrzymałeś trójkąt!


Przetrzyma wszystko
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

ja nie jestem inźynierem po studiach nie potrafie odczytać tego projektu ktory zapodałeś , za mało informacji przepraszam

loza_prowizoryczna
loza_prowizoryczna
Tego się nie czyta tylko stosuje!
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

no tak stosuje tylko jak ja mam ten projekt przedłożyć na kod ? za mało informacji ...

BR
  • Rejestracja:11 miesięcy
  • Ostatnio:około 14 godzin
  • Postów:25
0

Trudno oczekiwać że znajdziesz dokładnie to czego potrzebujesz. Jak zapytasz LLM to może... Nic dziwnego że są wzory matematyczne. Jak inaczej chcesz opisać trójkąt w układzie współrzędnych? Już pomijam ograniczenia które sam na siebie nakładasz (C++98, VC++6 i tym podobne). Ten OpenGL (> 2.0) o którym wspominasz także. Jakbyśmy nie wyszli poza 2002.

Ja właśnie zapytałem. Sprawdziłem na starym komputerze i rysuje. Poprosiłem też o wyjaśnienie. Może to coś pomoże.

Kod który otrzymałem:

Kopiuj
#include <windows.h>

struct Point {
    int x, y;
};

// Swap two points
void Swap(Point& a, Point& b) {
    Point temp = a;
    a = b;
    b = temp;
}

// Sort vertices by y-coordinate
void SortVertices(Point& p1, Point& p2, Point& p3) {
    if (p1.y > p2.y) Swap(p1, p2);
    if (p1.y > p3.y) Swap(p1, p3);
    if (p2.y > p3.y) Swap(p2, p3);
}

// Draw horizontal line
void DrawSpan(HDC hdc, int x1, int x2, int y, COLORREF color) {
    if (x1 > x2) Swap(*(Point*)&x1, *(Point*)&x2);
    for (int x = x1; x <= x2; ++x) {
        SetPixel(hdc, x, y, color);
    }
}

// Scanline fill algorithm
void FillTriangle(HDC hdc, Point p1, Point p2, Point p3, COLORREF color) {
    SortVertices(p1, p2, p3);

    int totalHeight = p3.y - p1.y;
    if (totalHeight == 0) return; // Avoid division by zero

    // Compute slopes
    for (int i = 0; i < totalHeight; i++) {
        bool secondHalf = (i > (p2.y - p1.y)) || (p1.y == p2.y);
        int segmentHeight = secondHalf ? (p3.y - p2.y) : (p2.y - p1.y);
        float alpha = (float)i / totalHeight;
        float beta = (float)(i - (secondHalf ? (p2.y - p1.y) : 0)) / segmentHeight;

        Point A = { p1.x + (int)((p3.x - p1.x) * alpha), p1.y + i };
        Point B = secondHalf
            ? Point{ p2.x + (int)((p3.x - p2.x) * beta), p2.y + (i - (p2.y - p1.y)) }
            : Point{ p1.x + (int)((p2.x - p1.x) * beta), p1.y + i };

        DrawSpan(hdc, A.x, B.x, p1.y + i, color);
    }
}

// Example usage in a WinAPI window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    switch (msg) {
        case WM_PAINT: {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);

            Point p1 = {50, 250}, p2 = {350, 250}, p3 = {200, 50};
            FillTriangle(hdc, p1, p2, p3, RGB(255, 0, 0));

            EndPaint(hwnd, &ps);
            break;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wp, lp);
    }
    return 0;
}

// WinAPI boilerplate
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nCmdShow) {
    WNDCLASS wc = { CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInst, NULL, LoadCursor(NULL, IDC_ARROW),
                    (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("TriangleWin") };
    RegisterClass(&wc);
    HWND hwnd = CreateWindow(TEXT("TriangleWin"), TEXT("WinAPI Triangle"), WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, NULL, NULL, hInst, NULL);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}


Wyjaśnienie:

Rysowanie wypełnionego trójkąta za pomocą SetPixel w WinAPI (kompatybilne z VC++6)

Opis algorytmu

Ponieważ SetPixel działa tylko na pojedynczych pikselach, rysowanie trójkąta wymaga metody skanowania wierszy (ang. scanline fill). Oto jak działa nasz algorytm:

  1. Sortowanie wierzchołków

    • Trójkąt ma trzy punkty: p1, p2 i p3.
    • Sortujemy je według współrzędnej y, aby mieć p1 u góry, p3 na dole, a p2 w środku.
    • Dzięki temu możemy łatwo podzielić trójkąt na dwie części: dolną i górną.

  2. Podział na dwa trójkąty

    • Górna część jest trójkątem płaskim od góry.
    • Dolna część jest trójkątem płaskim od dołu.
    • Oba fragmenty można wypełnić iterując wiersz po wierszu (po współrzędnej y).

  3. Wypełnianie trójkąta metodą skanowania wierszy

    • Dla każdego wiersza y obliczamy dwa krańcowe punkty A i B.
    • Punkty te są uzyskiwane przez interpolację liniową między wierzchołkami trójkąta.
    • Następnie rysujemy poziomą linię między A a B za pomocą SetPixel.
Omówienie funkcji w kodzie
Struktura Point
Kopiuj
struct Point {
    int x, y;
};
  • Definiuje prostą strukturę dla współrzędnych punktu (x, y).
Funkcja Swap – zamiana wartości dwóch punktów
Kopiuj
void Swap(Point& a, Point& b) {
    Point temp = a;
    a = b;
    b = temp;
}
  • Używana do sortowania wierzchołków trójkąta.
Sortowanie wierzchołków według współrzędnej y
Kopiuj
void SortVertices(Point& p1, Point& p2, Point& p3) {
    if (p1.y > p2.y) Swap(p1, p2);
    if (p1.y > p3.y) Swap(p1, p3);
    if (p2.y > p3.y) Swap(p2, p3);
}
  • Zapewnia, że p1 ma najmniejsze y, a p3 największe.
Rysowanie poziomej linii między dwoma punktami w jednym wierszu
Kopiuj
void DrawSpan(HDC hdc, int x1, int x2, int y, COLORREF color) {
    if (x1 > x2) Swap(*(Point*)&x1, *(Point*)&x2);
    for (int x = x1; x <= x2; ++x) {
        SetPixel(hdc, x, y, color);
    }
}
  • Upewnia się, że x1 ≤ x2, a następnie rysuje poziomą linię.
Wypełnianie trójkąta metodą skanowania wierszy
Kopiuj
void FillTriangle(HDC hdc, Point p1, Point p2, Point p3, COLORREF color) {
    SortVertices(p1, p2, p3);

    int totalHeight = p3.y - p1.y;
    if (totalHeight == 0) return;

    for (int i = 0; i < totalHeight; i++) {
        bool secondHalf = (i > (p2.y - p1.y)) || (p1.y == p2.y);
        int segmentHeight = secondHalf ? (p3.y - p2.y) : (p2.y - p1.y);
        float alpha = (float)i / totalHeight;
        float beta = (float)(i - (secondHalf ? (p2.y - p1.y) : 0)) / segmentHeight;

        Point A = { p1.x + (int)((p3.x - p1.x) * alpha), p1.y + i };
        Point B = secondHalf
            ? Point{ p2.x + (int)((p3.x - p2.x) * beta), p2.y + (i - (p2.y - p1.y)) }
            : Point{ p1.x + (int)((p2.x - p1.x) * beta), p1.y + i };

        DrawSpan(hdc, A.x, B.x, p1.y + i, color);
    }
}
  • Oblicza interpolację liniową dla każdego wiersza y, aby znaleźć skrajne punkty.
  • Sprawdza, czy jesteśmy w górnej czy dolnej części trójkąta.
  • Rysuje poziome odcinki między punktami.
Implementacja w procedurze okna
Kopiuj
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    switch (msg) {
        case WM_PAINT: {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);

            Point p1 = {100, 50}, p2 = {50, 150}, p3 = {150, 150};
            FillTriangle(hdc, p1, p2, p3, RGB(255, 0, 0));

            EndPaint(hwnd, &ps);
            break;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wp, lp);
    }
    return 0;
}
  • WM_PAINT wywołuje FillTriangle, aby narysować trójkąt podczas odświeżania okna.
  • WM_DESTROY kończy program po zamknięciu okna.
Funkcja WinMain – uruchamianie aplikacji
Kopiuj
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nCmdShow) {
    WNDCLASS wc = { CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInst, NULL, LoadCursor(NULL, IDC_ARROW),
                    (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("TriangleWin") };
    RegisterClass(&wc);
    HWND hwnd = CreateWindow(TEXT("TriangleWin"), TEXT("WinAPI Triangle"), WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, NULL, NULL, hInst, NULL);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
  • Rejestruje i tworzy okno WinAPI.
  • Obsługuje główną pętlę komunikatów systemowych.
Podsumowanie
  • Algorytm oparty jest na interpolacji liniowej i wypełnianiu wierszy.
  • SetPixel jest stosowany do rysowania pojedynczych pikseli, co działa nawet na bardzo starych systemach.
  • Kod jest w pełni kompatybilny z VC++6 i Windows API z 2001 roku.

Jeśli niepotrzebnie się powtarzam - przepraszam. Jeśli się mylę proszę mnie poprawić.
edytowany 4x, ostatnio: brokenelevator
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

dużo tego , dziękuje , połapałem sie tym kodem dam sobie rade tak mysle ..

edytowany 1x, ostatnio: wilkwielki
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

mam problem pokazuje błedy z tym

Kopiuj
 Point B = secondHalf
            ? Point{ p2.x + (int)((p3.x - p2.x) * beta), p2.y + (i - (p2.y - p1.y)) }
            : Point{ p1.x + (int)((p2.x - p1.x) * beta), p1.y + i };

opis

Kopiuj
error C2143: syntax error : missing ',' before '{'
C:\projekty\konsola\konsola.cpp(660) : error C2143: syntax error : missing ';' before '{'
C:\projekty\konsola\konsola.cpp(660) : error C2143: syntax error : missing ';' before '}'
C:\projekty\konsola\konsola.cpp(661) : error C2143: syntax error : missing ';' before ':'
C:\projekty\konsola\konsola.cpp(661) : error C2143: syntax error : missing ';' before '{'
C:\projekty\konsola\konsola.cpp(661) : error C2143: syntax error : missing ';' before '}'
edytowany 1x, ostatnio: Riddle
BR
  • Rejestracja:11 miesięcy
  • Ostatnio:około 14 godzin
  • Postów:25
0

myślę że problem tkwi w tym - list initialization. To jest C++11. I wierz tu człowieku LLM'om 🤣


Jeśli niepotrzebnie się powtarzam - przepraszam. Jeśli się mylę proszę mnie poprawić.
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

czyli nic u mnie , ja jade na c++98

BR
  • Rejestracja:11 miesięcy
  • Ostatnio:około 14 godzin
  • Postów:25
0

bez przesady. to latwo poprawic (w sensie uniknac list initialization).


Jeśli niepotrzebnie się powtarzam - przepraszam. Jeśli się mylę proszę mnie poprawić.
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

jak ten PointB rozpisać jesli ktos wie?

BR
  • Rejestracja:11 miesięcy
  • Ostatnio:około 14 godzin
  • Postów:25
0

Ręce mi opadają ale może ja mam za wysokie oczekiwania.

Wersja A - pierwotny kod:

Kopiuj
Point B = secondHalf
            ? Point{ p2.x + (int)((p3.x - p2.x) * beta), p2.y + (i - (p2.y - p1.y)) }
            : Point{ p1.x + (int)((p2.x - p1.x) * beta), p1.y + i };

Wersja B (bez ternary i list initialization) - nie testowałem:

Kopiuj
Point B;
if (secondHalf) {
  B.x = p2.x + (int)((p3.x - p2.x) * beta);
  B.y = p2.y + (i - (p2.y - p1.y));
} else {
  B.x = p1.x + (int)((p2.x - p1.x) * beta);
  B.y = p1.y + i;
}

Jeśli niepotrzebnie się powtarzam - przepraszam. Jeśli się mylę proszę mnie poprawić.
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:427
0

teraz to działa rysuje trójkąt , dzieki za treściwy przekaz wiedzy ... 😀

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.