algorytm rysowania trójkąta ?

algorytm rysowania trójkąta ?
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:376
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:prawie 19 lat
  • Ostatnio:około 2 godziny
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:376
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:prawie 19 lat
  • Ostatnio:około 2 godziny
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:376
0

dobra dzięki teraz lepiej powinniem sobie poradzić

wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:376
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:376
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:376
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:376
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:około 17 lat
  • Ostatnio:3 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:376
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:376
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:376
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:376
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:376
wilkwielki
  • Rejestracja:ponad rok
  • Ostatnio:około 18 godzin
  • Postów:376
0

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

loza_prowizoryczna
  • Rejestracja:ponad 2 lata
  • Ostatnio:około 5 godzin
  • Postów:1595
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:376
0

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

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

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

BR
  • Rejestracja:9 miesięcy
  • Ostatnio:minuta
  • 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:376
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:376
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:9 miesięcy
  • Ostatnio:minuta
  • 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:376
0

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

BR
  • Rejestracja:9 miesięcy
  • Ostatnio:minuta
  • 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:376
0

jak ten PointB rozpisać jesli ktos wie?

BR
  • Rejestracja:9 miesięcy
  • Ostatnio:minuta
  • 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:376
0

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

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)