Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <windows.h>
- #include <time.h>
- #include <math.h>
- using namespace std;
- #pragma comment(lib,"msimg32.lib")
- /**************************************************************************************************************/
- HWND hwnd = GetConsoleWindow();
- HDC hdc = GetDC(hwnd);
- HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
- COORD c;
- POINT p; //***** для функции MoveToEx
- const float OneDegree = 3.14 / 180; //***** коэффициент перевода градусов в радианы и обратно
- const int GROUND = 200; //***** высота линии, вдоль которой покатится фигура
- //***** градусы = радианы / OneDegree ( для переменных и массивов этой программы, хранящих углы )
- //***** радианы = градусы * OneDegree ( для математических функций sinf, cosf, atanf... )
- /**************************************************************************************************************/
- /*********************************************** К Л А С С ****************************************************/
- class POLYGON
- {
- //***** поля класса:
- int maxTopNumber; //***** наибольший порядковый номер вершины (т.е. кол-во вершин)
- int leftGroundTop, rightGroundTop; //***** порядковые номера ОПОРНЫХ вершин многоугольника
- int gorizontalOffset; //***** стартовый горизонтальный сдвиг фигуры
- int *PolarRadius; float *PolarAngle; //***** массивы ПОЛЯРНЫХ координат вершин относительно центральной точки
- int *X, *Y; //***** массивы ДЕКАРТОВЫХ координат вершин многоугольника
- int *LeftNumber, *RightNumber; //***** массивы "соседей" каждой вершины
- bool *Convexity; //***** массив выпуклостей вершин
- HBRUSH *Brush; //***** массив заливок
- //***** методы класса:
- void FillConvexity();
- void FindBeginRotationAngle();
- void PolarToDecart(float);
- void FineRotateAndShow(int, int);
- void Show(bool);
- public:
- POLYGON();
- ~POLYGON();
- void Move();
- };
- /**************************************************************************************************************/
- /************************************************ конструктор *************************************************/
- POLYGON::POLYGON()
- {
- maxTopNumber = rand() % 8 + 4;
- leftGroundTop = rightGroundTop = 1;
- gorizontalOffset = 200;
- //***** выделение динамической памяти под массивы атрибутов вершин многоугольника
- PolarRadius = new int[maxTopNumber + 1]; PolarAngle = new float[maxTopNumber + 1];
- X = new int[maxTopNumber + 1]; Y = new int[maxTopNumber + 1];
- LeftNumber = new int[maxTopNumber + 1]; RightNumber = new int[maxTopNumber + 1];
- Brush = new HBRUSH[maxTopNumber + 1]; Convexity = new bool[maxTopNumber + 1];
- //***** инициализация массивов атрибутов
- PolarRadius[0] = PolarAngle[0] = X[0] = Y[0] = 0; //***** в 0-ых ячейках находятся координаты "центральной" точки многоугольника
- Brush[0] = CreateSolidBrush(RGB(0, 0, 0));
- for (int topNumber = 1; topNumber <= maxTopNumber; topNumber++)
- {
- //***** инициализация вершин в полярных координатах:
- PolarRadius[topNumber] = rand() % 100 + 30;
- PolarAngle[topNumber] = rand() % (360 / maxTopNumber) + (topNumber - 1) * (360 / maxTopNumber);
- //***** конверсия полярных координат в декартовы:
- X[topNumber] = PolarRadius[topNumber] * cosf(PolarAngle[topNumber] * OneDegree);
- Y[topNumber] = PolarRadius[topNumber] * sinf(PolarAngle[topNumber] * OneDegree);
- //***** заполнение массива заливок секторов:
- Brush[topNumber] = CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256));
- //***** заполнение массивов соседей каждой точки:
- LeftNumber[topNumber] = topNumber + 1;
- RightNumber[topNumber] = topNumber - 1;
- if (topNumber == 1) RightNumber[topNumber] = maxTopNumber;
- else if (topNumber == maxTopNumber) LeftNumber[topNumber] = 1;
- }
- //***** проведение горизонтальной линии, по которой покатится многоугольник:
- HPEN bluePen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
- MoveToEx(hdc, 0, (GROUND + 1), &p); SelectObject(hdc, bluePen); LineTo(hdc, 600, GROUND + 1);
- MoveToEx(hdc, 200, 0, &p); SelectObject(hdc, bluePen); LineTo(hdc, 200, 300);
- FillConvexity();
- }
- /*******************************************************************************************************************/
- /************************************* заполнение массивов выпуклостей вершин ***************************************/
- void POLYGON::FillConvexity()
- {
- int prevTop, nextTop, prevAng, nextAng;
- float k1 = 1, k2 = 1, b1 = 1;
- float pX, pY, dist;
- for (int topNumber = 1; topNumber <= maxTopNumber; topNumber++) //***** topNumber - номер текущей вершины
- {
- prevTop = topNumber - 1; prevAng = PolarAngle[prevTop]; //***** угловая точка, предыдущая относительно текущей точки
- nextTop = topNumber + 1; nextAng = PolarAngle[nextTop]; //***** угловая точка, следующая за текущей точкой (по часовой стрелке)
- if (topNumber == 1) {
- prevTop = maxTopNumber; prevAng = 360 - PolarAngle[prevTop];
- }
- else if (topNumber == maxTopNumber) {
- nextTop = 1; nextAng = 360 + PolarAngle[nextTop];
- }
- //***** выпуклости (добавить условие X[ nextTop ] != X[ prevTop ]
- if (nextAng - prevAng < 180)
- {
- k1 = ((float)Y[nextTop] - Y[prevTop]) / (X[nextTop] - X[prevTop]);
- b1 = Y[nextTop] - k1 * X[nextTop];
- k2 = (float)Y[topNumber] / X[topNumber];
- //***** координаты точки пересечения 2-х отрезков:
- //***** первый отрезок соединяет следующую и предыдущую (относительно текущей точки) угловые точки
- //***** второй соединяет центральную точку и текущую точку
- pX = b1 / (k2 - k1);
- pY = k2 * pX;
- dist = sqrtf(pX*pX + pY*pY); //***** расстояние от точки (pX, pY) до начала координат
- if (dist > PolarRadius[topNumber]) Convexity[topNumber] = false;
- else Convexity[topNumber] = true;
- }
- else Convexity[topNumber] = true;
- }
- FindBeginRotationAngle();
- }
- /************************************************************************************************************************/
- /****************************** нахождение угла поворота для установки в исходную позицию *******************************/
- void POLYGON::FindBeginRotationAngle()
- {
- float rotationAngle;
- //***** ищем выпуклую вершину, начиная с первой, которая послужит правой опорной точкой:
- for (rightGroundTop = 1; Convexity[rightGroundTop] == false; rightGroundTop++);
- //***** ищем выпуклую вершину, начиная со следующей за правой опорной точкой, которая послужит левой опорной точкой:
- for (leftGroundTop = rightGroundTop + 1; Convexity[leftGroundTop] == false; leftGroundTop++);
- //***** "грубый" расчет угла поворота фигуры
- if (X[rightGroundTop] != X[leftGroundTop])
- rotationAngle = atanf((float)(Y[leftGroundTop] - Y[rightGroundTop]) /
- (X[rightGroundTop] - X[leftGroundTop])) / OneDegree;
- else
- rotationAngle = 90;
- PolarToDecart(rotationAngle);
- FineRotateAndShow(leftGroundTop, rightGroundTop);
- //***** временная задержка отображения фигуры в стартовом положении:
- Sleep(100);
- }
- /**********************************************************************************************************************/
- /**************** подгонка угла поворота фигуры, чтобы обе опорные вершины оказались на уровне линии ******************/
- void POLYGON::FineRotateAndShow(int leftTop, int rightTop)
- {
- int direction; float fineTuneAngle = 0.1;
- //***** требуется ли подгонка фигуры с большей точностью?
- if (Y[leftTop] > Y[rightTop])
- direction = 1;
- else if (Y[leftTop] < Y[rightTop])
- direction = -1;
- else
- return;
- Show(false);
- for (int i = 0; Y[leftTop] != Y[rightTop] && i < 10; i++)
- PolarToDecart(fineTuneAngle * direction);
- Show(true);
- }
- /**********************************************************************************************************************/
- /********** пересчет декартовых координат точек для поворота фигуры вокруг ЦЕНТРАЛЬНОЙ точки на заданный угол *************/
- void POLYGON::PolarToDecart(float ang)
- {
- for (int topNumber = 1; topNumber <= maxTopNumber; topNumber++)
- {
- PolarAngle[topNumber] += ang;
- X[topNumber] = PolarRadius[topNumber] * cosf(PolarAngle[topNumber] * OneDegree); //***** конверсия полярных координат в декартовы
- Y[topNumber] = PolarRadius[topNumber] * sinf(PolarAngle[topNumber] * OneDegree);
- }
- }
- /********************************************************************************************************************/
- /************************ управление выводом фигуры, которая катится вдоль горизонтальной прямой ********************/
- void POLYGON::Move()
- {
- int prevRightGroundTop, nextRightGroundTop;
- while (gorizontalOffset < 800)
- {
- //***** ищем следующую правую опорную точку
- for (nextRightGroundTop = RightNumber[rightGroundTop]; Convexity[nextRightGroundTop] == false;
- nextRightGroundTop = RightNumber[nextRightGroundTop]);
- Show(true);
- //***** вращаем фигуру вокруг неподвижной текущей правой опорной точки до тех пор,
- //***** пока следуюшая правая опорная точка не коснется линии
- while (Y[nextRightGroundTop] < Y[rightGroundTop])
- {
- //***** выдерживаем время и стираем фигуру в старом положении:
- Sleep(10);
- Show(false);
- //***** фактически вращение фигуры происходит вокруг ЦЕНТРАЛЬНОЙ точки, имеющей декартовы координаты (0,0) - так проще
- PolarToDecart(1);
- //***** однако при выводе смещение подбирается каждый раз таким образом,
- //***** чтобы правая опорная вершина оказывалась в одном и том же месте экрана
- Show(true);
- }
- //***** осуществляем подгонку фигуры:
- FineRotateAndShow(rightGroundTop, nextRightGroundTop);
- gorizontalOffset += X[nextRightGroundTop] - X[rightGroundTop];
- //***** делаем следущую правую опорную точку текущей:
- rightGroundTop = nextRightGroundTop;
- }
- }
- /********************************************************************************************************************/
- /********************************* отображение фигуры в ее текущем положении на консоли ****************************/
- void POLYGON::Show(bool v)
- {
- HPEN pen = CreatePen(PS_SOLID, 1, RGB(255 * v, 255 * v, 255 * v));
- int midX, midY;
- int offsetX = gorizontalOffset - X[rightGroundTop];
- int offsetY = GROUND - Y[rightGroundTop];
- MoveToEx(hdc, offsetX, offsetY, &p); //***** установка кисти в центральную точку
- for (int topNumber = 1; topNumber <= maxTopNumber; topNumber++) //***** соединение точек линиями
- {
- SelectObject(hdc, pen);
- LineTo(hdc, (X[topNumber] + offsetX), (Y[topNumber] + offsetY)); //***** от центральной к текущей угловой точке
- LineTo(hdc, (X[LeftNumber[topNumber]] + offsetX), (Y[LeftNumber[topNumber]] + offsetY));
- LineTo(hdc, offsetX, offsetY); //***** к центральной точке
- //***** вычисление внутренней точки сектора, образованного текущей точкой, следующей и центральной точками:
- midX = (X[LeftNumber[topNumber]] + X[topNumber]) / 4;
- midY = (Y[LeftNumber[topNumber]] + Y[topNumber]) / 4;
- SelectObject(hdc, Brush[topNumber * v]);
- FloodFill(hdc, (midX + offsetX), (midY + offsetY), RGB(255 * v, 255 * v, 255 * v));
- //Sleep (100);
- }
- }
- /***************************************************************************************************************/
- /*************************************************** M A I N ***************************************************/
- void main()
- {
- system("title Rolling Polygones");
- srand(time(0));
- system("mode con cols=120 lines=20");
- while (true)
- {
- POLYGON figure;
- figure.Move();
- }
- }
- /**************************************************************************************************************/
- /************************************************ деструктор *************************************************/
- POLYGON :: ~POLYGON()
- {
- delete[]PolarRadius;
- delete[]PolarAngle;
- delete[]X;
- delete[]Y;
- delete[]LeftNumber;
- delete[]RightNumber;
- delete[]Convexity;
- delete[]Brush;
- }
Add Comment
Please, Sign In to add comment