Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <windows.h>
- #include <ctime>
- #include <vector>
- #define PROSTOKAT 1
- #define ELIPSA 2
- #define TROJKAT 3
- #define CLR_NUM 16
- #define WSP_X(ID) Figury[i].wsp[ID-1].x
- #define WSP_Y(ID) Figury[i].wsp[ID-1].y
- #define SZEROKOSC_PLOTNA rect.right * 0.75
- #define WYSOKOSC_PALETY rect.bottom * 0.70
- #define BIALY RGB(255, 255, 255)
- #define SZARY RGB(180, 180, 180)
- #define CZARNY RGB(0, 0, 0)
- TCHAR CLNAME[] = TEXT("MojaKlasa");
- TCHAR APPNAME[] = TEXT("Paint - (R - reset)");
- HDC hdc;
- struct figura
- {
- POINT wsp[3];
- COLORREF kolorWnetrza;
- COLORREF kolorRamki;
- int ksztalt;
- };
- COLORREF kolory[CLR_NUM] =
- {
- RGB(0,64,0),RGB(128,0,0),RGB(0,128,0),
- RGB(128,128,64),RGB(0,0,160),RGB(128,0,128),
- RGB(64,128,128),RGB(128,128,128),RGB(192,192,192),
- RGB(255,0,0),RGB(0,255,0),RGB(255,255,0),
- RGB(0,0,255),RGB(255,0,128),RGB(0,255,255), RGB(218,218,218)
- };
- // algorytm z neta http://www.geeksforgeeks.org/check-whether-a-given-point-lies-inside-a-triangle-or-not/ jedyna trudnosc w tym zadaniu imho.
- float area(const int x1, const int y1, const int x2, const int y2, const int x3, const int y3)
- {
- return abs((x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)) / 2.0); // obliczanie pola trójkąta ze wzoru Herona (z samych boków)
- }
- bool isInside(const int x1, const int y1, const int x2, const int y2, const int x3, const int y3, const int x, const int y)
- {
- float A = area(x1, y1, x2, y2, x3, y3);
- float A1 = area(x, y, x2, y2, x3, y3);
- float A2 = area(x1, y1, x, y, x3, y3);
- float A3 = area(x1, y1, x2, y2, x, y);
- return (A == A1 + A2 + A3);
- }
- bool isInElipse(const int x1, const int y1, const int x2, const int y2, const int x, const int y)
- {
- int Ox = (x2 + x1) / 2; // wsp X środka elipsy
- int Oy = (y2 + y1) / 2; // wsp Y środka elipsy
- int r1 = (x2 - x1) / 2; // długość pierwszego promienia elipsy
- int r2 = (y2 - y1) / 2; // długość drugiego promienia elipsy
- if ( ( ( (x - Ox) * (x - Ox) ) / (r1 * r1) ) + ( ( (y - Oy) * (y - Oy) ) / (r2 * r2) ) <= 1 ) // wzór czy punkt należy do elipsy
- return true;
- return false;
- }
- LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
- srand(time(0));
- static RECT rect;
- static std::vector <figura> Figury; // wektor figur
- static unsigned short int iloscFigur = 0; // zmienna przechowująca aktualną ilość figur
- static unsigned short int prostokaty = 0; // zmienna przechowująca aktualną ilość kwadratów
- static unsigned short int elipsy = 0; // zmienna przechowująca aktualną ilość kół
- static unsigned short int trojkaty = 0; // zmienna przechowująca aktualną ilość trójkąty
- static COLORREF aktywnyPedzel = kolory[0]; // zmienna przechowująca aktualny wybrany kolor ramki
- static COLORREF aktywnaRamka = kolory[CLR_NUM-1]; // zmienna przechowująca aktualny wybrany kolor wnętrza
- static HBRUSH brush = (HBRUSH)GetStockObject(DC_BRUSH); // uchwyt do urządzenia pędzla (wypełnianie obszaru jednym kolorem)
- static HPEN pen = (HPEN)GetStockObject(DC_PEN); // uchwyt do długopisu (rysowanie ramki wokół figur)
- switch (msg) {
- case WM_KEYDOWN: {
- switch ((int)wParam)
- {
- case 'r':
- iloscFigur = 0; // zmienna przechowująca aktualną ilość figur
- prostokaty = 0; // zmienna przechowująca aktualną ilość kwadratów
- elipsy = 0; // zmienna przechowująca aktualną ilość kół
- trojkaty = 0; // zmienna przechowująca aktualną ilość trójkąty
- while (!Figury.empty())
- Figury.pop_back();
- default:
- break;
- }
- }
- case WM_CREATE: {
- GetClientRect(hwnd, &rect); //pobieranie obszaru klienckiego (prostokąta)
- iloscFigur = rand() % 10 + 10; //losowanie ilości figur z przedziału 10-19
- int ilosc = iloscFigur; //bufor potrzebny do losowania ilości poszczególnych figur
- prostokaty = rand() % ilosc;
- ilosc -= prostokaty;
- elipsy = rand() % ilosc;
- trojkaty = ilosc - elipsy;
- //losowanie położenia figur na "płótnie" | r.right*0.75 to szerokość płótna dalej jest przybornik, na którym nie chcemy mieć figur rysowanych
- for (unsigned int i = 0; i < iloscFigur; i++)
- {
- Figury.push_back(figura()); // dodajemy nową figurę do wektora
- Figury[i].kolorWnetrza = kolory[rand() % CLR_NUM]; // ustawiamy nowej figurze kolor wnętrza
- Figury[i].kolorRamki = kolory[rand() % CLR_NUM]; // ustawiamy nowej figurze kolor ramki
- WSP_X(1) = rand() % SZEROKOSC_PLOTNA; WSP_Y(1) = rand() % rect.bottom; // losujemy współrzędne figury
- WSP_X(2) = rand() % SZEROKOSC_PLOTNA; WSP_Y(2) = rand() % rect.bottom; // ------------||-------------
- if (WSP_X(1) > WSP_X(2))
- { // sortujemy współrzędne w razie potrzeby, aby otrzymać parami 2 sensowne punkty ( potrzebne do prawidłowego narysowania koła lub kwadratu
- int temp = WSP_X(1);
- WSP_X(1) = WSP_X(2);
- WSP_X(2) = temp;
- }
- if (WSP_Y(1) > WSP_Y(2))
- { // sortujemy współrzędne w razie potrzeby, aby otrzymać parami 2 sensowne punkty ( potrzebne do prawidłowego narysowania koła lub kwadratu
- int temp = WSP_Y(1);
- WSP_Y(1) = WSP_Y(2);
- WSP_Y(2) = temp;
- }
- if (i < prostokaty)
- {
- Figury[i].ksztalt = PROSTOKAT; // przypisujemy po kolei kształty figurom w tablicy (najpierw wszystkie kwadraty, potem kola i trojkaty
- }
- else if (i >= prostokaty && i < prostokaty + elipsy)
- {
- Figury[i].ksztalt = ELIPSA;
- }
- else if (i >= prostokaty + elipsy && i < iloscFigur)
- {
- WSP_Y(2) = WSP_Y(1); // ustawiamy wysokość Y1 i Y2 na taką samą, aby podstawa trójkąta równobocznego byłą równoległa do okna
- WSP_X(3) = (WSP_X(2) + WSP_X(1)) / 2.0; // X3 wyznaczamy jako średnią X1 i X2, gdyż jest to trójkąt równoboczny
- WSP_Y(3) = WSP_Y(1) - ((sqrt(3) / 2.0) * (WSP_X(2) - WSP_X(1))); // wyznaczmy Y3 z wysokości w trójkącie równobocznym
- if (WSP_Y(3) < 0) // jeśli z obliczeń wyszło, że wierzchołek trójkąta jest poza ekranem, to przesuwamy cały trójkąt w dół, aby się zmieścił
- {
- WSP_Y(1) = WSP_Y(2) -= WSP_Y(3);
- WSP_Y(3) = 0;
- }
- Figury[i].ksztalt = TROJKAT;
- }
- }
- InvalidateRect(hwnd, &rect, TRUE); //odświeżanie obszaru klienckiego (płótna)
- }break;
- // obsługa przycisków myszy, obsługujemy wszystkie tak samo, gdyż wszystkie zaczynają się od identycznych intrukcji
- // jedynie w kluczowych momentach w instrukcji switch decydujemy o konkretnych działaniach dla konkretnego przycisku myszy
- case WM_LBUTTONDOWN:
- case WM_RBUTTONDOWN:
- case WM_MBUTTONDOWN:
- {
- int x = LOWORD(lParam); //pobieranie wsp. x klikniętego miejsca z dodatkowego parametru lParam
- int y = HIWORD(lParam); //pobieranie wsp. y klikniętego miejsca z dodatkowego parametru lParam
- if (x < SZEROKOSC_PLOTNA) //sprawdzamy czy wskaźnik znajduje się poza przybornikiem
- {
- if (GetPixel(hdc, x, y) != BIALY)
- { //sprawdzamy za pomocą koloru piksela czy kliknięto na figurę czy na białe tło
- COLORREF temp_kolor = GetPixel(hdc, x, y); //pobieramy kolor pikselu klikniętego
- for (int i = iloscFigur - 1; i >= 0; i--) //pętla poszukiwania figury o pobranym kolorze
- {
- if (temp_kolor == Figury[i].kolorWnetrza) // po kolorze sprawdzamy czy kliknięto w figurę
- { // jednak może być więcej figur o takim kolorze, więc dokładnie sprawdzamy po współrzędnych co kliknięto
- if (Figury[i].ksztalt == PROSTOKAT && x >= WSP_X(1) && x <= WSP_X(2) && y >= WSP_Y(1) && y <= WSP_Y(2))
- {
- switch (msg)
- {
- case WM_LBUTTONDOWN: // dla lewego przycisku myszy po kliknięciu na prostokąt/elipsę zmieniamy jej kolor wnętrza i ramki
- {
- Figury[i].kolorWnetrza = aktywnyPedzel;
- Figury[i].kolorRamki = aktywnaRamka;
- break;
- }
- case WM_RBUTTONDOWN: // dla prawego przycisku myszy po kliknięciu w prostokąt/elipsę obracamy ją o 90 stopni
- {
- // obracanie koła lub kwadratu, algorytm jednakowy i prosty
- x = (WSP_X(2) - WSP_X(1)) / 2.0; y = (WSP_Y(2) - WSP_Y(1)) / 2.0;
- WSP_X(1) += x - y; WSP_Y(1) += y - x;
- WSP_X(2) += -x + y; WSP_Y(2) += -y + x;
- break;
- }
- case WM_MBUTTONDOWN: // dla środkowego przycisku myszy po kliknięciu w prostokąt/elipsę usuwamy ją
- {
- iloscFigur--;
- prostokaty--;
- Figury.erase(Figury.begin() + i);
- break;
- }
- }
- break;
- }
- else if (Figury[i].ksztalt == ELIPSA && isInElipse(WSP_X(1), WSP_Y(1), WSP_X(2), WSP_Y(2), x, y))
- {
- switch (msg)
- {
- case WM_LBUTTONDOWN: // dla lewego przycisku myszy po kliknięciu na prostokąt/elipsę zmieniamy jej kolor wnętrza i ramki
- {
- Figury[i].kolorWnetrza = aktywnyPedzel;
- Figury[i].kolorRamki = aktywnaRamka;
- break;
- }
- case WM_RBUTTONDOWN: // dla prawego przycisku myszy po kliknięciu w prostokąt/elipsę obracamy ją o 90 stopni
- {
- // obracanie koła lub kwadratu, algorytm jednakowy i prosty
- x = (WSP_X(2) - WSP_X(1)) / 2.0; y = (WSP_Y(2) - WSP_Y(1)) / 2.0;
- WSP_X(1) += x - y; WSP_Y(1) += y - x;
- WSP_X(2) += -x + y; WSP_Y(2) += -y + x;
- break;
- }
- case WM_MBUTTONDOWN: // dla środkowego przycisku myszy po kliknięciu w prostokąt/elipsę usuwamy ją
- {
- iloscFigur--;
- elipsy--;
- Figury.erase(Figury.begin() + i);
- break;
- }
- }
- break;
- }
- else if (Figury[i].ksztalt == TROJKAT) //dla trojkąta potrzebne jest specjalne sprawdzanie czy kliknięto w jego obszar
- {
- if (isInside(WSP_X(1), WSP_Y(1), WSP_X(2), WSP_Y(2), WSP_X(3), WSP_Y(3), x, y))
- {
- switch (msg)
- {
- case WM_LBUTTONDOWN: // dla lewego przycisku myszy po kliknięciu na trójkąt zmieniamy jego kolor wnętrza i ramki
- {
- Figury[i].kolorWnetrza = aktywnyPedzel;
- Figury[i].kolorRamki = aktywnaRamka;
- }break;
- case WM_RBUTTONDOWN: // dla prawego przycisku myszy po kliknięciu w trójkąt obracamy go o 90 stopni
- {
- x = (WSP_X(1) + WSP_X(2) + WSP_X(3)) / 3.0; y = (WSP_Y(1) + WSP_Y(2) + WSP_Y(3)) / 3.0;
- int temp = WSP_X(1);
- WSP_X(1) = x - (WSP_Y(1) - y); WSP_Y(1) = y + temp - x;
- temp = WSP_X(2);
- WSP_X(2) = x - (WSP_Y(2) - y); WSP_Y(2) = y + temp - x;
- temp = WSP_X(3);
- WSP_X(3) = x - (WSP_Y(3) - y); WSP_Y(3) = y + temp - x;
- }break;
- case WM_MBUTTONDOWN: // dla środkowego przycisku myszy po kliknięciu w trójkąt usuwamy go
- {
- trojkaty--;
- iloscFigur--;
- Figury.erase(Figury.begin() + i);
- }break;
- }
- break;
- }
- }
- }
- }
- }
- }
- else if (x > SZEROKOSC_PLOTNA && y < WYSOKOSC_PALETY) //jeśli kliknięto w obszar przybornika to sprawdzamy czy kliknięto w kolor
- {
- if (GetPixel(hdc, x, y) != SZARY) // sprawdzamy czy kliknięto w jakiś kolor a nie w szare tło
- {
- switch (msg)
- {
- case WM_LBUTTONDOWN:
- {
- aktywnyPedzel = GetPixel(hdc, x, y); // pobieramy nowy kolor dla wnętrza figury
- break;
- }
- case WM_RBUTTONDOWN:
- {
- aktywnaRamka = GetPixel(hdc, x, y); // pobieramy nowy kolor dla ramki figury
- break;
- }
- }
- }
- }
- InvalidateRect(hwnd, &rect, TRUE); //odświeżanie obszaru klienckiego (płótna)
- }break;
- case WM_PAINT: {
- PAINTSTRUCT ps;
- GetClientRect(hwnd, &rect);
- HDC hdc = BeginPaint(hwnd, &ps); // rozpoczynamy rysowanie
- SetDCBrushColor(hdc, BIALY); // ustawiamy kolor tła całego okna na biały
- FillRect(hdc, &rect, brush);
- for (short int i = 0; i < iloscFigur; i++)
- {
- SetDCBrushColor(hdc, Figury[i].kolorWnetrza); // ustawiamy kolor pędzla na kolor wnętrza figury
- SelectObject(hdc, brush); // aktualizujemy kolor pędzla przypisanego do naszego okna
- SetDCPenColor(hdc, Figury[i].kolorRamki); // ustawiamy kolor ramki na kolor ramki figury
- SelectObject(hdc, pen); // aktualizujemy kolor ramki przypisanego do naszego okna
- // poniżej sprawdzamy jaką figurę należy narysować i używamy odpowiedniej funkcji
- if (Figury[i].ksztalt == PROSTOKAT)
- Rectangle(hdc, WSP_X(1), WSP_Y(1), WSP_X(2), WSP_Y(2));
- else if (Figury[i].ksztalt == ELIPSA)
- Ellipse(hdc, WSP_X(1), WSP_Y(1), WSP_X(2), WSP_Y(2));
- else if (Figury[i].ksztalt == TROJKAT)
- Polygon(hdc, Figury[i].wsp, 3);
- }
- // przywracamy kolor pędzla na szary (tło przybornika)
- SetDCBrushColor(hdc, SZARY);
- SelectObject(hdc, brush);
- // przywracamy kolor pędzla na czarny (ramka kolorów w przyborniku)
- SetDCPenColor(hdc, CZARNY);
- SelectObject(hdc, pen);
- Rectangle(hdc, SZEROKOSC_PLOTNA, rect.top, rect.right, rect.bottom); // rysujemy szary prostokąt (tło przybornika)
- for (int i = 0, przerwa = 0; i < CLR_NUM / 2; i++, przerwa += rect.bottom * 0.08)
- { // pętla rysująca naszą paletę kolorów, rysujemy w jednej iteracji po dwa kolory w rzędzie
- SetDCBrushColor(hdc, kolory[i]); // ustawiamy pędzel na dany kolor palety
- SelectObject(hdc, brush); // aktualizujemy pędzel naszego okna
- Rectangle(hdc, rect.right * 0.8, (rect.bottom * 0.001) + (rect.bottom * 0.05) + przerwa, rect.right - (0.15 * rect.right), (rect.bottom * 0.12) + przerwa);
- SetDCBrushColor(hdc, kolory[i + 8]); // ustawiamy pędzel na dany kolor palety
- SelectObject(hdc, brush); // aktualizujemy pędzel naszego okna
- Rectangle(hdc, rect.right * 0.9, (rect.bottom * 0.001) + (rect.bottom * 0.05) + przerwa, rect.right - (0.05 * rect.right), (rect.bottom * 0.12) + przerwa);
- }
- wchar_t text1[32];
- SetBkColor(hdc, SZARY); // ustawiamy kolor tła tekstu
- SetTextColor(hdc, CZARNY); // ustawiamy kolor tekstu
- // poniżej formatujemy napisy szczegółowego stanu figur i je wyświetlamy
- wsprintfW(text1, L"Ilość figur : %d", iloscFigur);
- TextOutW(hdc, rect.right * 0.80, rect.bottom * 0.68, text1, wcslen(text1));
- wsprintfW(text1, L"Kwadraty : %d", prostokaty);
- TextOutW(hdc, rect.right*0.80, rect.bottom * 0.71, text1, wcslen(text1));
- wsprintfW(text1, L"Elipsy : %d", elipsy);
- TextOutW(hdc, rect.right * 0.80, rect.bottom * 0.74, text1, wcslen(text1));
- wsprintfW(text1, L"Trójkąty : %d", trojkaty);
- TextOutW(hdc, rect.right * 0.80, rect.bottom * 0.77, text1, wcslen(text1));
- // wyświetlamy graficznie kolor wybranego aktualnie pędzla
- TextOutW(hdc, rect.right * 0.80, rect.bottom * 0.82, L"Aktualny pędzel", 16);
- SetDCBrushColor(hdc, aktywnyPedzel);
- Rectangle(hdc, rect.right * 0.80, rect.bottom * 0.86, rect.right * 0.95, rect.bottom * 0.90);
- // wyświetlamy graficznie kolor wybranej aktualnie ramki
- TextOutW(hdc, rect.right * 0.80, rect.bottom * 0.91, L"Aktualny długopis", 17);
- SetDCBrushColor(hdc, aktywnaRamka);
- Rectangle(hdc, rect.right * 0.80, rect.bottom * 0.95, rect.right * 0.95, rect.bottom * 0.99);
- EndPaint(hwnd, &ps);
- }break;
- case WM_CLOSE: {
- if (MessageBox(hwnd, TEXT("Czy chcesz zamknąć program?"), TEXT("Ostrzeżenie"), MB_ICONINFORMATION | MB_YESNO) == IDNO)
- break;
- // zwalniamy zasoby, czyli kontekst urządzenia, pędzel, pióro, figury
- ReleaseDC(hwnd, hdc);
- DeleteObject(brush);
- DeleteObject(pen);
- Figury.clear();
- DestroyWindow(hwnd);
- }break;
- case WM_DESTROY: {
- PostQuitMessage(0);
- }break;
- default: return DefWindowProc(hwnd, msg, wParam, lParam);
- }
- return 0;
- }
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
- WNDCLASSEX wc;
- wc.cbClsExtra = 0;
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.cbWndExtra = 0;
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- wc.hCursor = LoadCursor(0, IDC_ARROW);
- wc.hIcon = LoadIcon(0, IDI_APPLICATION);
- wc.hIconSm = LoadIcon(0, IDI_APPLICATION);
- wc.hInstance = hInstance;
- wc.lpfnWndProc = WndProc;
- wc.lpszClassName = CLNAME;
- wc.lpszMenuName = 0;
- wc.style = CS_VREDRAW | CS_HREDRAW;
- if (!RegisterClassEx(&wc)) {
- MessageBox(0, TEXT("Nie mogę rejestrować klasy!"), TEXT("ERROR"), MB_OK | MB_ICONERROR);
- return 1;
- }
- HWND hwnd = CreateWindowEx(0, CLNAME, APPNAME, WS_OVERLAPPEDWINDOW, 0, 0, 800, 600, 0, 0, hInstance, 0);
- if (hwnd == NULL) {
- MessageBox(0, TEXT("Nie mogę utworzyć okna!"), TEXT("ERROR"), MB_OK | MB_ICONERROR);
- UnregisterClass(CLNAME, hInstance);
- return 1;
- }
- ShowWindow(hwnd, nCmdShow);
- MSG msg;
- hdc = GetDC(hwnd); // pobieramy kontekst urządzenia
- while (GetMessage(&msg, 0, 0, 0) > 0) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- UnregisterClass(CLNAME, hInstance);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement