Tvor0zhok

КГ лабораторная №5_3D

Apr 5th, 2022 (edited)
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 22.81 KB | None | 0 0
  1. #pragma once
  2.  
  3. namespace Moskvitin {
  4.  
  5.     using namespace System;
  6.     using namespace System::ComponentModel;
  7.     using namespace System::Collections;
  8.     using namespace System::Windows::Forms;
  9.     using namespace System::Data;
  10.     using namespace System::Drawing;
  11.     using namespace std;
  12.  
  13.     mat4 T; // матрица, в которой накапливаются все преобразования
  14.     mat4 initT; // матрица начального преобразования
  15.  
  16.     vec3 Vc; // координаты дальнего левого нижнего угла
  17.     vec3 V; // размеры параллелепипеда в пространстве графика
  18.     vec3 Vc_work, V_work; // рабочие параметры параллелепипеда
  19.  
  20.     /// <summary>
  21.     /// Сводка для MyForm
  22.     /// </summary>
  23.     public ref class MyForm : public System::Windows::Forms::Form
  24.     {
  25.     public:
  26.         MyForm(void)
  27.         {
  28.             InitializeComponent();
  29.             //
  30.             //TODO: добавьте код конструктора
  31.             //
  32.         }
  33.  
  34.     protected:
  35.         /// <summary>
  36.         /// Освободить все используемые ресурсы.
  37.         /// </summary>
  38.         ~MyForm()
  39.         {
  40.             if (components)
  41.             {
  42.                 delete components;
  43.             }
  44.         }
  45.     private: System::Windows::Forms::OpenFileDialog^ openFileDialog;
  46.     protected:
  47.  
  48.  
  49.     private:
  50.         /// <summary>
  51.         /// Обязательная переменная конструктора.
  52.         /// </summary>
  53.         System::ComponentModel::Container^ components;
  54.  
  55. #pragma region Windows Form Designer generated code
  56.         /// <summary>
  57.         /// Требуемый метод для поддержки конструктора — не изменяйте
  58.         /// содержимое этого метода с помощью редактора кода.
  59.         /// </summary>
  60.         void InitializeComponent(void)
  61.         {
  62.             this->openFileDialog = (gcnew System::Windows::Forms::OpenFileDialog());
  63.             this->SuspendLayout();
  64.             //
  65.             // openFileDialog
  66.             //
  67.             this->openFileDialog->DefaultExt = L"txt";
  68.             this->openFileDialog->Filter = L"Текстовые файлы (*.txt)|*.txt|Все файлы (*.*)|*.*";
  69.             this->openFileDialog->Title = L"Открыть файл";
  70.             //
  71.             // MyForm
  72.             //
  73.             this->AutoScaleDimensions = System::Drawing::SizeF(9, 20);
  74.             this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
  75.             this->ClientSize = System::Drawing::Size(578, 744);
  76.             this->DoubleBuffered = true;
  77.             this->KeyPreview = true;
  78.             this->MinimumSize = System::Drawing::Size(230, 170);
  79.             this->Name = L"MyForm";
  80.             this->Text = L"MyForm";
  81.             this->Load += gcnew System::EventHandler(this, &MyForm::MyForm_Load);
  82.             this->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &MyForm::MyForm_Paint);
  83.             this->KeyDown += gcnew System::Windows::Forms::KeyEventHandler(this, &MyForm::MyForm_KeyDown);
  84.             this->Resize += gcnew System::EventHandler(this, &MyForm::MyForm_Resize);
  85.             this->ResumeLayout(false);
  86.  
  87.         }
  88. #pragma endregion
  89.  
  90.     private: float left = 30, right = 100, top = 20, bottom = 50; // расстояния до границ окна
  91.            float minX = left, maxX; // диапазон изменения координат x
  92.            float minY = top, maxY; // диапазон изменения координат y
  93.            float Wcx = left, Wcy; // координаты левого нижнего угла прямоугольника
  94.            float Wx, Wy; // ширина и высота прямоугольника
  95.            float Wx_work, Wy_work; // ширина и высота области вывода одной линии графика
  96.            float Wx_part = 0.6, Wy_part = 0.6; // доля Wx_work, Wy_work от Wx, Wy соответственно
  97.            float Wcx_work, Wcy_work; // координаты левого нижнего угла самого дальнего прямоугольника
  98.            float Wz_work; // количество рабочих прямоугольников
  99.            int numXsect = 5, numYsect = 5, numZsect = 5; // количество секций координатной сетки по осям
  100.  
  101.   // инициализация остальных параметров
  102.  
  103.     private: System::Void rectCalc() {
  104.         maxX = ClientRectangle.Width - right; // диапазон изменения координат x
  105.         maxY = ClientRectangle.Height - bottom; // диапазон изменения координат y
  106.         Wcy = maxY; // координаты левого нижнего угла прямоугольника
  107.         Wx = maxX - left; // ширина прямоугольника
  108.         Wy = maxY - top;
  109.  
  110.         Wx_work = Wx_part * Wx; // вычисление ширины и высоты
  111.         Wy_work = Wy_part * Wy; // рабочего прямоугольника
  112.         Wcx_work = maxX - Wx_work; // вычисление координат нижнего левого
  113.         Wcy_work = minY + Wy_work; // угла самого дальнего рабочего прямоугольника
  114.         Wz_work = Wcy - Wcy_work; // количество рабочих прямоугольников
  115.     }
  116.  
  117.     private: System::Void worldRectCalc() {
  118.         Vc_work = normalize(T * vec4(Vc, 1.f));
  119.         V_work = mat3(T) * V;
  120.     }
  121.  
  122.            // сама функция
  123.     private: float f(float x, float z) {
  124.         return x * sin(sqrtf(x * x + z * z));
  125.     }
  126.  
  127.            // проверка, определена ли функция в точке x
  128.     private: bool f_exists(float x, float z, float delta) {
  129.         return true;
  130.     }
  131.  
  132.     private: System::Void MyForm_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {
  133.         // описываем переменную g - область рисования, ссылку на объект типа System::Drawing::Graphics^
  134.         Graphics^ g = e->Graphics;
  135.  
  136.         Pen^ rectPen = gcnew Pen(Color::Black, 2); // черная ручка
  137.         g->DrawRectangle(rectPen, left, top, Wx, Wy); // рисуем область видимости
  138.  
  139.         Pen^ pen = gcnew Pen(Color::Blue, 1); // ручка для рисовки графика функции
  140.         float deltaX = V_work.x / Wx_work; // шаг по x в мировых координатах
  141.         float deltaZ = V_work.z / Wz_work; // шаг по z в мировых координатах
  142.         float deltaWcx = (Wcx_work - Wcx) / Wz_work; // шаг прямоугольников по x в координатах экрана
  143.  
  144.         bool hasStart;
  145.  
  146.         float z = Vc_work.z; // координата z соответствующая дальнему прямоугольнику
  147.         float Wcx_w = Wcx_work, Wcy_w = Wcy_work; // координаты левого нижнего угла рабочего прямоугольника (инициализация)
  148.  
  149.         while (Wcy_w <= Wcy) { // пока не перебрали все прямоугольники
  150.             vec2 start, end; // концы отрезка в координатах экрана
  151.             float x, y; // переменные для координат точки в мировой СК
  152.             start.x = Wcx_w; // для начальной точки первого отрезка устанавливаем координату x
  153.             x = Vc_work.x; // координата x начальной точки первого отрезка в мировых координатах
  154.  
  155.             hasStart = f_exists(x, z, deltaX);
  156.  
  157.             if (hasStart)
  158.             {
  159.                 y = f(x, z); // координата y начальной точки в мировых координатах
  160.                 start.y = Wcy_w - (y - Vc_work.y) / V_work.y * Wy_work; // вычисляем соответствующее значение в координатах экрана
  161.             }
  162.  
  163.             float maxX = Wcx_w + Wx_work; // максимальное значение x в рабочем прямоугольнике
  164.  
  165.             while (start.x < maxX)
  166.             {
  167.                 float deltaY; // высота точки в прямоугольнике (доля общей высоты)
  168.                 float red, green, blue; // компоненты цвета отрезка
  169.  
  170.                 vec2 end;// точка конца отрезка в координатах экрана
  171.                 bool hasEnd;
  172.  
  173.                 end.x = start.x + 1.f; // координата x отличается на единицу
  174.                 x += deltaX; // координата x конечной точки отрезка в мировых координатах
  175.  
  176.                 hasEnd = f_exists(x, z, deltaX);
  177.                 if (hasEnd)
  178.                 {
  179.                     y = f(x, z); // координата y начальной точки в мировых координатах
  180.  
  181.                     // вычисляем соответствующее значение в координатах экрана
  182.                     deltaY = (y - Vc_work.y) / V_work.y;
  183.                     end.y = Wcy_w - deltaY * Wy_work;
  184.                 }
  185.  
  186.                 vec2 tmpEnd = end;
  187.                 //bool visible = hasStart && hasEnd && clip(start, end, minX, minY, maxX, maxY);
  188.                 bool visible = hasStart && hasEnd && clip(start, end, Wcx_w, Wcy_w - Wy_work, Wcx_w + Wcx_w + Wx_work, Wcy_w);
  189.                 if (visible) { // если отрезок видим
  190.  
  191.                     if (deltaY > 1.f) deltaY = 1.f; // нормализуем значение высоты точки
  192.                     if (deltaY < 0.f) deltaY = 0.f; // на случай, если отрезок отсекался
  193.                     green = 510.f * deltaY; // предварительное вычисление произведения
  194.                     if (deltaY < 0.5) { // если точка ниже середины области видимости
  195.                     // компонента зеленого уже вычислена
  196.                         blue = 255.f - green; // синий дополняет зеленый
  197.                         red = 0.f; // красный равен нулю
  198.                     }
  199.                     else { // если точка не ниже середины
  200.                         blue = 0.f; // синий равен нулю
  201.                         red = green - 255.f; // вычисляем красный и зеленый
  202.                         green = 510.f - green; // с использованием вычисленного произведения
  203.                     }
  204.                     pen->Color = Color::FromArgb(red, green, blue); // меняем цвет пера
  205.  
  206.                     // после отсечения, start и end - концы видимой части отрезка
  207.                     g->DrawLine(pen, start.x, start.y, end.x, end.y); // отрисовка видимых частей
  208.                 }
  209.                 // конечная точка неотсеченного отрезка становится начальной точкой следующего
  210.                 start = tmpEnd;
  211.                 hasStart = hasEnd;
  212.             }
  213.  
  214.             Wcy_w += 1.f; // переходим к следующему прямоугольнику, он будет ниже на один пиксел
  215.             Wcx_w -= deltaWcx; // и левее на некоторое значение
  216.             z += deltaZ; // вычисляем соответствующее значение z для очередного прямоугольника
  217.         }
  218.  
  219.         Pen^ gridPen = gcnew Pen(Color::Black, 1);
  220.         SolidBrush^ drawBrush = gcnew SolidBrush(Color::Black);
  221.         System::Drawing::Font^ drawFont = gcnew System::Drawing::Font("Arial", 8);
  222.  
  223.         // координатная сетка по X
  224.         float gridStep_x = Wx_work / numXsect; // расстояние между линиями сетки по x
  225.         float grid_dX = V_work.x / numXsect; // расстояние между линиями сетки по x в мировых координатах
  226.         float tick_x = Vc_work.x; // значение соответствующее первой линии сетки
  227.  
  228.         for (int i = 0; i <= numXsect; i++) { // цикл по количеству линий
  229.             float tmpXCoord_d = Wcx + i * gridStep_x; // нижняя координата x i-й диагональной линии
  230.             float tmpXCoord_v = Wcx_work + i * gridStep_x; // координата x i-й вертикальной линии
  231.  
  232.             g->DrawLine(gridPen, tmpXCoord_d, Wcy, tmpXCoord_v, Wcy_work); // i-я диагональная линия
  233.             g->DrawLine(gridPen, tmpXCoord_v, Wcy_work, tmpXCoord_v, minY); // i-я вертикальная линия
  234.  
  235.             if (i > 0 && i < numXsect) // если линия не крайняя
  236.                 g->DrawString(tick_x.ToString("F4"), drawFont, drawBrush, tmpXCoord_d, Wcy); // выводим текст в нижней точке диагональной линии
  237.  
  238.             tick_x += grid_dX; // вычисляем значение, соответствующее следующей линии
  239.         }
  240.  
  241.         // координатная сетка по Z
  242.         gridStep_x = (Wx - Wx_work) / numZsect; // расстояние между вертикальными линиями сетки по горизонтали
  243.         float gridStep_y = Wz_work / numZsect; // расстояние между горизонтальными линиями сетки по вертикали
  244.  
  245.         float grid_dZ = V_work.z / numZsect; // расстояние между линиями сетки по $z$ в мировых координатах
  246.         float tick_z = Vc_work.z; // значение, соответствующее первой линии сетки
  247.  
  248.         for (int i = 0; i <= numZsect; i++) { // цикл по количеству линий
  249.             float tmpXCoord_v = Wcx_work - i * gridStep_x; // координата x вертикальных линий
  250.             float tmpYCoord_g = Wcy_work + i * gridStep_y; // координата y горизонтальных линий
  251.             float tmpXCoord_g = tmpXCoord_v + Wx_work; // вторая координата x горизонтальных линий
  252.  
  253.             g->DrawLine(gridPen, tmpXCoord_v, tmpYCoord_g, tmpXCoord_v, tmpYCoord_g - Wy_work); // i-я вертикальная линия
  254.             g->DrawLine(gridPen, tmpXCoord_v, tmpYCoord_g, tmpXCoord_g, tmpYCoord_g); // i-я горизонтальная линия
  255.  
  256.             if (i > 0 && i < numZsect) // если линия не крайняя
  257.                 g->DrawString(tick_z.ToString("F4"), drawFont, drawBrush, tmpXCoord_g, tmpYCoord_g); // выводим текст в правой точке горизонтальной линии
  258.  
  259.             tick_z += grid_dZ; // вычисляем значение, соответствующее следующей линии
  260.         }
  261.  
  262.         // координатная сетка по Y
  263.         gridStep_x = (Wx - Wx_work) / numYsect;
  264.         gridStep_y = Wy_work / numYsect;
  265.  
  266.         float grid_dY = V_work.y / numYsect; // расстояние между линиями сетки по $y$ в мировых координатах
  267.         float tick_y = Vc_work.y; // значение, соответствующее первой линии сетки
  268.  
  269.         for (int i = 0; i <= numYsect; i++) { // цикл по количеству линий
  270.             float tmpYCoord_d = Wcy - i * gridStep_y;
  271.             float tmpYCoord_v = Wcy_work - i * gridStep_y; // координата y вертикальной лини
  272.  
  273.             g->DrawLine(gridPen, Wcx, tmpYCoord_d, Wcx_work, tmpYCoord_v); // i-я вертикальная линия
  274.             g->DrawLine(gridPen, Wcx_work, tmpYCoord_v, Wcx_work + Wx_work, tmpYCoord_v); // i-я горизонтальная линия
  275.  
  276.             if (i > 0 && i < numYsect) // если линия не крайняя
  277.                 g->DrawString(tick_y.ToString("F4"), drawFont, drawBrush, Wcx_work + Wx_work, tmpYCoord_v); // выводим текст в правой точке горизонтальной линии
  278.  
  279.             tick_y += grid_dY; // вычисляем значение, соответствующее следующей линии
  280.         }
  281.     }
  282.  
  283.     private: System::Void MyForm_Resize(System::Object^ sender, System::EventArgs^ e) {
  284.         // Добавляем устойчивость рисунка относительно изменения размера окна
  285.         Refresh();
  286.         // передподсчет сторон прямоугольника
  287.         rectCalc();
  288.     }
  289.  
  290.     private: System::Void MyForm_Load(System::Object^ sender, System::EventArgs^ e) {
  291.         initT = mat4(1.f);
  292.         T = initT;
  293.  
  294.         Vc = vec3(-2.f, -2.f, -2.f);
  295.         V = vec3(4.f, 4.f, 4.f);
  296.  
  297.         rectCalc();
  298.         worldRectCalc();
  299.     }
  300.  
  301.     private: System::Void MyForm_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) {
  302.         float centerX = Vc_work.x + V_work.x / 2; // координаты центра параллелепипеда
  303.         float centerY = Vc_work.y + V_work.y / 2; // в мировой системе координат
  304.         float centerZ = Vc_work.z + V_work.z / 2;
  305.  
  306.         switch (e->KeyCode)
  307.         {
  308.             // сброс всех преобразований
  309.         case Keys::Escape:
  310.             numXsect = 5; numYsect = 5; numZsect = 5;
  311.             Wx_part = 0.6; Wy_part = 0.6;
  312.             T = initT;
  313.             break;
  314.             // сдвиг графика вправо на один пиксель
  315.         case Keys::A:
  316.             T = translate(-V_work.x / Wx, 0.f, 0.f) * T;
  317.             break;
  318.             // равномерное увеличение прямоугольника в 1.1 раз относительно центра
  319.         case Keys::Z:
  320.             T = translate(-centerX, -centerY, -centerZ) * T; // перенос начала координат в центр
  321.             T = scale(1.1, 1.1, 1.1) * T; // масштабирование относительно начала координат
  322.             T = translate(centerX, centerY, centerZ) * T; // возврат позиции начала координат
  323.             break;
  324.             // сдвиг графика влево на один пиксель
  325.         case Keys::D:
  326.             T = translate(V_work.x / Wx, 0.f, 0.f) * T;
  327.             break;
  328.             // сдвиг графика вниз на один пиксель
  329.         case Keys::R:
  330.             T = translate(0.f, V_work.y / Wy, 0.f) * T;
  331.             break;
  332.             // сдвиг графика вверх на один пиксел
  333.         case Keys::F:
  334.             T = translate(0.f, -V_work.y / Wy, 0.f) * T;
  335.             break;
  336.             // уменьшение в 1.1 раз параллелепипеда видимости
  337.         case Keys::X:
  338.             T = translate(-centerX, -centerY, -centerZ) * T; // перенос начала координат в центр
  339.             T = scale(10.f / 11.f, 10.f / 11.f, 10.f / 11.f) * T; // масштабирование относительно начала координат
  340.             T = translate(centerX, centerY, centerZ) * T; // возврат позиции начала координат
  341.             break;
  342.             // увеличение в 1.1 раз параллелепипеда видимости относительно центра по Ox
  343.         case Keys::T:
  344.             T = translate(-centerX, -centerY, -centerZ) * T; // перенос начала координат в центр
  345.             T = scale(1.1, 1.f, 1.f) * T; // масштабирование относительно начала координат
  346.             T = translate(centerX, centerY, centerZ) * T; // возврат позиции начала координат
  347.             break;
  348.             // уменьшение в 1.1 раз параллелепипеда видимости относительно центра по Ox
  349.         case Keys::G:
  350.             T = translate(-centerX, -centerY, -centerZ) * T; // перенос начала координат в центр
  351.             T = scale(10.f / 11.f, 1.f, 1.f) * T; // масштабирование относительно начала координат
  352.             T = translate(centerX, centerY, centerZ) * T; // возврат позиции начала координат
  353.             break;
  354.             // увеличение в 1.1 раз параллелепипеда видимости относительно центра по Oy
  355.         case Keys::Y:
  356.             T = translate(-centerX, -centerY, -centerZ) * T; // перенос начала координат в центр
  357.             T = scale(1.f, 1.1, 1.f) * T; // масштабирование относительно начала координат
  358.             T = translate(centerX, centerY, centerZ) * T; // возврат позиции начала координат
  359.             break;
  360.             // уменьшение в 1.1 раз параллелепипеда видимости относительно центра по Oy
  361.         case Keys::H:
  362.             T = translate(-centerX, -centerY, -centerZ) * T; // перенос начала координат в центр
  363.             T = scale(1.f, 10.f / 11.f, 1.f) * T; // масштабирование относительно начала координат
  364.             T = translate(centerX, centerY, centerZ) * T; // возврат позиции начала координат
  365.             break;
  366.             // увеличение в 1.1 раз параллелепипеда видимости относительно центра по Oz
  367.         case Keys::U:
  368.             T = translate(-centerX, -centerY, -centerZ) * T; // перенос начала координат в центр
  369.             T = scale(1.f, 1.f, 1.1) * T; // масштабирование относительно начала координат
  370.             T = translate(centerX, centerY, centerZ) * T; // возврат позиции начала координат
  371.             break;
  372.             // уменьшение в 1.1 раз параллелепипеда видимости относительно центра по Oz
  373.         case Keys::J:
  374.             T = translate(-centerX, -centerY, -centerZ) * T; // перенос начала координат в центр
  375.             T = scale(1.f, 1.f, 10.f / 11.f) * T; // масштабирование относительно начала координат
  376.             T = translate(centerX, centerY, centerZ) * T; // возврат позиции начала координат
  377.             break;
  378.         // добавление секции в коорд. сетке по Ox
  379.         case Keys::D1:
  380.             ++numXsect;
  381.             break;
  382.             // изъятие секции из коорд. сетки по Ox
  383.         case Keys::D2:
  384.             numXsect = max(numXsect - 1, 2);
  385.             break;
  386.             // добавление секции в коорд. сетке по Oy
  387.         case Keys::D3:
  388.             ++numYsect;
  389.             break;
  390.             // изъятие секции из коорд. сетки по Oy
  391.         case Keys::D4:
  392.             numYsect = max(numYsect - 1, 2);
  393.             break;
  394.             // добавление секции в коорд. сетке по Oz
  395.         case Keys::D5:
  396.             ++numZsect;
  397.             break;
  398.             // изъятие секции из коорд. сетки по Oz
  399.         case Keys::D6:
  400.             numZsect = max(numZsect - 1, 2);
  401.             break;
  402.             // увеличение размера рабочего прямоугольника по оси Ox в 1.1 раза
  403.         case Keys::Q:
  404.             Wx_part = min(Wx_part * 1.1, 0.9);
  405.             break;
  406.             // уменьшение размера рабочего прямоугольника по оси Ox в 1.1 раза
  407.         case Keys::E:
  408.             Wx_part = max(Wx_part * 10.0 / 11.0, 0.2);
  409.             break;
  410.             // увеличение размера рабочего прямоугольника по оси Oy в 1.1 раза
  411.         case Keys::C:
  412.             Wy_part = min(Wy_part * 1.1, 0.9);
  413.             break;
  414.             // уменьшение размера рабочего прямоугольника по оси Oy в 1.1 раза
  415.         case Keys::V:
  416.             Wy_part = max(Wy_part * 10.0 / 11.0, 0.2);
  417.             break;
  418.             // сдвиг графика на наблюдателя на один пиксел
  419.         case Keys::W:
  420.             T = translate(0.f, 0.f, V_work.z / Wz_work) * T;
  421.             break;
  422.             // сдвиг графика от наблюдателя на один пиксел
  423.         case Keys::S:
  424.             T = translate(0.f, 0.f, -V_work.z / Wz_work) * T;
  425.             break;
  426.         default:
  427.             break;
  428.         }
  429.  
  430.         worldRectCalc();
  431.         rectCalc();
  432.         Refresh();
  433.     }
  434.     };
  435. }
Add Comment
Please, Sign In to add comment