Определить базовый класс «множество точек», породить от него класс «многоугольник», а от класса «многоугольник» породить класс «выпуклый многоугольник», конструктор которого строит выпуклую оболочку методом заворачивания подарка.
Написать программу, которая позволяет вводить множество точек, по которым строится выпуклый многоугольник, и определять принадлежность выбранной точки построенному многоугольнику.
Текст программы
Код на C++ //Модуль «stdafx.h»: #pragma once #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdlib.h> #include <malloc.h> #include <memory.h> #include <tchar.h> #include <math.h> Модуль «CPoint.h»: #ifndef CPOINT_H #define CPOINT_H #include "stdafx.h" class CPoint { private: float x, y; public: CPoint(); CPoint(float _x, float _y); float operator[](int n); CPoint operator-(CPoint& p); float operator*(CPoint& p); void SetX(float _x); void SetY(float _y); void SetXY(float _x, float _y); float GetX(); float GetY(); }; #endif //Модуль «CPoint.cpp»: #include "CPoint.h" CPoint::CPoint() : x(0), y(0) {}; CPoint::CPoint(float _x, float _y) : x(_x), y(_y) {}; float CPoint::operator [](int n) { switch (n) { case 0: return x; case 1: return y; default: return 0; } } CPoint CPoint::operator-(CPoint& p) { CPoint np; np.SetXY(x - p.GetX(), y - p.GetY()); return np; } float CPoint::operator*(CPoint& p) { return x * p.GetX() + y * p.GetY(); } float CPoint::GetX() { return x; } float CPoint::GetY() { return y; } void CPoint::SetX(float _x) { x = _x; } void CPoint::SetY(float _y) { y = _y; } void CPoint::SetXY(float _x, float _y) { x = _x; y = _y; } //Модуль «CPoints.h»: #ifndef CPOINTS_H #define CPOINTS_H #include "CPoint.h" class CPoints { protected: CPoint *points; int n; public: CPoints(); CPoints(int _n); CPoints(CPoint **p, int _n); virtual ~CPoints(); CPoint* operator[](int ind); int Count(); }; #endif //Модуль «CPoints.cpp»: #include "CPoints.h" CPoints::CPoints() : n(0) {}; CPoints::CPoints(int _n) : n(_n) { points = new CPoint[n]; } CPoints::CPoints(CPoint **p, int _n) : n(_n) { points = new CPoint[n]; for (int i = 0; i < n; i++) points[i].SetXY(p[i]->GetX(), p[i]->GetY()); } CPoints::~CPoints() { delete[] points; } CPoint* CPoints::operator [](int ind) { return &points[ind]; } int CPoints::Count() { return n; } //Модуль «CPolygon.h»: #ifndef CPOLYGON_H #define CPOLYGON_H #include "CPoints.h" class CPolygon : public CPoints { private: void Line(HDC hDC, int x0, int y0, int x1, int y1); public: CPolygon(); CPolygon(CPoints &p); void Show(HDC hDC); }; #endif //Модуль «CPolygon.cpp»: #include "CPolygon.h" CPolygon::CPolygon() { n = 0; } CPolygon::CPolygon(CPoints &p) { n = p.Count(); points = new CPoint[n]; for (int i = 0; i < n; i++) points[i].SetXY(p[i]->GetX(), p[i]->GetY()); } void CPolygon::Line(HDC hDC, int x0, int y0, int x1, int y1) { MoveToEx(hDC, x0, y0, NULL); LineTo(hDC, x1, y1); } void CPolygon::Show(HDC hDC) { for (int i = 1; i < n; i++) Line( hDC, points[i - 1].GetX(), points[i - 1].GetY(), points[i].GetX(), points[i].GetY() ); Line( hDC, points[0].GetX(), points[0].GetY(), points[n - 1].GetX(), points[n - 1].GetY() ); } //Модуль «CPPolygon.h»: #include "CPolygon.h" class CPPolygon : public CPolygon { public: CPPolygon(); CPPolygon(CPolygon &p); }; //Модуль «CPPolygon.cpp»: #include "CPPolygon.h" #include <math.h> CPPolygon::CPPolygon() { n = 0; } CPPolygon::CPPolygon(CPolygon &p) { if ( p.Count() <= 0 ) return; // Поиск первой точки ( минимум по Y ) int k = 0; for ( int i = p.Count(); --i > 0; ) { if ( p[k]->GetY() > p[i]->GetY() ) k = i; else if ( p[k]->GetY() == p[i]->GetY() && p[k]->GetX() < p[i]->GetX() ) k = i; } // Если она не первая в массиве, то сделаем обмен if ( k ) { CPoint v = *p[k]; *p[k] = *p[0]; *p[0] = v; } // Поиск остальных точек (обход против часовой стрелки) CPoint w(1, 0); int l = 0; double c = -2., q = 0.; for(;;) { int k = 0; if ( l > 0 ) { CPoint v = *p[0] - *p[l]; q = v.GetX() * v.GetX() + v.GetY() * v.GetY(); c = w * v; c *= fabs(c) / q; } for ( i = l+1; i < p.Count(); ++i ) { CPoint v = *p[i] - *p[l]; double tq = v.GetX() * v.GetX() + v.GetY() * v.GetY(); if ( tq > 0 ) { double tc = w * v; tc *= fabs(tc) / tq; if ( c < tc ) c = tc, q = tq, k = i; else if ( c == tc && q < tq ) q = tq, k = i; } } if ( k == 0 ) break; ++l; if ( k != l ) { CPoint v = *p[k]; *p[k] = *p[l]; *p[l] = v; } w = *p[l] - *p[l-1]; } n = l + 1; points = new CPoint[n]; for (int i = 0; i < n; i++) (points[i]).SetXY(p[i]->GetX(), p[i]->GetY()); } //Модуль «OOP5.cpp»: #include "stdafx.h" #include "resource.h" #include "globals.h" #define MAX_LOADSTRING 100 CPoint *Points[MAXPOINTS]; int PointsCount = 0; bool IsInput = true; bool IsSelPoint = false; CPPolygon *poly; HDC hdcComp; HBITMAP hBitmap; // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); void FreeMem() { for (int i = 0; i < PointsCount; i++) delete Points[i]; } int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { MSG msg; HACCEL hAccelTable; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_OOP5, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) return FALSE; hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_OOP5); HDC hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL); hdcComp = CreateCompatibleDC(hdcScreen); hBitmap = CreateCompatibleBitmap(hdcScreen, GetDeviceCaps(hdcScreen, HORZRES) * 2, GetDeviceCaps(hdcScreen, VERTRES) * 2); SelectObject(hdcComp, hBitmap); HPEN hOldPen, hPen = CreatePen(PS_SOLID, 3, 0); hOldPen = (HPEN)SelectObject(hdcComp, hPen); while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } FreeMem(); SelectObject(hdcComp, hOldPen); DeleteObject(hPen); delete poly; return (int) msg.wParam; } ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_OOP5); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = (LPCTSTR)IDC_OOP5; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx(&wcex); } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent, x, y; PAINTSTRUCT ps; HDC hdc; RECT r; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case ID_POLYGON_ENDPOLY: IsInput = false; break; case ID_POLYGON_RESET: FreeMem(); PointsCount = 0; IsSelPoint = false; IsInput = true; break; case ID_TEST_SELECTPOINT: IsSelPoint = true; return 0; case IDM_EXIT: PostQuitMessage(0); return 0; default: return DefWindowProc(hWnd, message, wParam, lParam); } UpdateScreen(hWnd, hdcComp); InvalidateRect(hWnd, NULL, NULL); return 0; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); GetWindowRect(hWnd, &r); BitBlt(hdc, 0, 0, r.right - r.left, r.bottom - r.top, hdcComp, 0, 0, SRCCOPY); EndPaint(hWnd, &ps); return 0; case WM_SIZE: break; case WM_LBUTTONDOWN: x = LOWORD(lParam); y = HIWORD(lParam); if (IsSelPoint) if (IsIn(x, y)) MessageBox(NULL, "Точка находится внутри многоугольника!", "Info", MB_OK | MB_ICONINFORMATION); else MessageBox(NULL, "Точка находится вне многоугольника!", "Info", MB_OK | MB_ICONINFORMATION); else if (IsInput && PointsCount < MAXPOINTS) Points[PointsCount++] = new CPoint(x, y); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } UpdateScreen(hWnd, hdcComp); InvalidateRect(hWnd, NULL, NULL); return 0; } //Модуль «globals.h»: #include "CPPolygon.h" #define MAXPOINTS 20 extern CPoint *Points[MAXPOINTS]; extern int PointsCount; extern bool IsInput; extern CPPolygon *poly; extern void UpdateScreen(HWND hWnd, HDC hDC); extern bool IsIn(int x, int y); //Модуль «globals.cpp»: #include "stdafx.h" #include "globals.h" #include "CPolygon.h" void DrawPolygon(HWND hWnd, HDC hdcComp) { CPoints pts(&Points[0], PointsCount); CPolygon p(pts); delete poly; poly = new CPPolygon(p); poly->Show(hdcComp); } void UpdateScreen(HWND hWnd, HDC hDC) { int x, y; RECT r; GetWindowRect(hWnd, &r); PatBlt(hDC, 0, 0, r.right - r.left, r.bottom - r.top, PATCOPY); for (int i = 0; i < PointsCount; i++) { x = Points[i]->GetX(); y = Points[i]->GetY(); MoveToEx(hDC, x, y, 0); LineTo(hDC, x + 1, y); } if (!IsInput && PointsCount) DrawPolygon(hWnd, hDC); } int sign(int n) { if (n > 0) return 1; else if (n < 0) return -1; else return 0; } float Dis(int x0, int y0, int x1, int y1) { return sqrtf((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); } float Geron(int x0, int y0, int x1, int y1, int x2, int y2) { float da, db, dc, p; da = Dis(x1, y1, x2, y2); db = Dis(x0, y0, x2, y2); dc = Dis(x0, y0, x1, y1); p = (da + db + dc) / 2; return sqrtf(fabs(p * (p - da) * (p - db) * (p - dc))); } bool IsInTriangle(int x0, int y0, int x1, int y1, int x2, int y2, int x, int y) { return !(Geron(x0, y0, x1, y1, x2, y2) * 1.0001 < Geron(x, y, x0, y0, x1, y1) + Geron(x, y, x0, y0, x2, y2) + Geron(x, y, x1, y1, x2, y2)); } bool IsIn(int x, int y) { if (IsInput) return false; for (int i = 1; i < poly->Count() - 1; i++) if (IsInTriangle( (*poly)[0]->GetX(), (*poly)[0]->GetY(), (*poly)[i]->GetX(), (*poly)[i]->GetY(), (*poly)[i + 1]->GetX(), (*poly)[i + 1]->GetY(), x, y )) return true; return false; }
|