Advertisement
Tvor0zhok

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

Apr 5th, 2022
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.56 KB | None | 0 0
  1. // Matrix.h
  2.  
  3. #pragma once
  4.  
  5. // ВЕКТОРА
  6.  
  7. class vec2
  8. {
  9. public:
  10.  
  11. float x, y;
  12.  
  13. // конструкторы
  14. vec2() {}
  15. vec2(float a, float b) : x(a), y(b) {}
  16.  
  17. // перегурзка операций умножения и адресации по индексу
  18. vec2& operator *= (const vec2& v)
  19. {
  20. x *= v.x;
  21. y *= v.y;
  22.  
  23. return *this;
  24. }
  25.  
  26. const vec2 operator * (const vec2& v)
  27. {
  28. return vec2(*this) *= v;
  29. }
  30.  
  31. float& operator [] (int i)
  32. {
  33. return ((float*)this)[i];
  34. }
  35. };
  36.  
  37. // скалярное умножение
  38. float dot(vec2 v1, vec2 v2)
  39. {
  40. vec2 tmp = v1 * v2; // вычисляем произведения соответствующих координат
  41. return tmp.x + tmp.y; // и возвращаем их сумму
  42. }
  43.  
  44. class vec3
  45. {
  46. public:
  47.  
  48. float x, y, z;
  49.  
  50. // конструкторы
  51. vec3() {}
  52. vec3(float a, float b, float c) : x(a), y(b), z(c) {}
  53. vec3(vec2 v, float z) : vec3(v.x, v.y, z) {}
  54.  
  55. // перегрузка операций *= , * и []
  56.  
  57. vec3& operator *= (const vec3& v)
  58. {
  59. x *= v.x;
  60. y *= v.y;
  61. z *= v.z;
  62.  
  63. return *this;
  64. }
  65.  
  66. const vec3 operator * (const vec3& v)
  67. {
  68. return vec3(*this) *= v; // делаем временную копию текущего объекта, которую
  69. } // домножаем на данный вектор, и возвращаем ее как результат
  70.  
  71. float& operator [] (int i)
  72. {
  73. return ((float*)this)[i]; // ссылку на текующий объект рассматриваем как ссылку на 0-ой элемент
  74. } // массива значений типа float, после чего обращаемся к его i-ому элементу
  75. };
  76.  
  77. // скалярное умножение
  78. float dot(vec3 v1, vec3 v2)
  79. {
  80. vec3 tmp = v1 * v2; // вычисляем произведение соответствующих координат
  81. return tmp.x + tmp.y + tmp.z; // и возвращаем их сумму
  82. }
  83.  
  84. vec2 normalize(vec3 v)
  85. {
  86. return vec2(v.x / v.z, v.y / v.z);
  87. }
  88.  
  89. class vec4
  90. {
  91. public:
  92.  
  93. float x, y, z, a;
  94.  
  95. // конструкторы
  96. vec4() {}
  97. vec4(float a, float b, float c, float d) : x(a), y(b), z(c), a(d) {}
  98. vec4(vec3 v, float c) : vec4(v.x, v.y, v.z, c) {}
  99.  
  100. // перегрузка операции умножения векторов
  101. vec4& operator*=(const vec4& v)
  102. {
  103. x *= v.x;
  104. y *= v.y;
  105. z *= v.z;
  106. a *= v.a;
  107.  
  108. return *this;
  109. }
  110.  
  111. const vec4 operator*(const vec4& v)
  112. {
  113. return vec4(*this) *= v; // делаем временную копию текущего объекта,
  114. // которую домножаем на данный вектор,
  115. // и возвращаем ее как результат
  116. }
  117.  
  118. // перегрузка операции обращения по индексу
  119. float& operator[](int i)
  120. {
  121. return ((float*)this)[i]; // ссылку на текущий объект рассматриваем как ссылку
  122. // на нулевой элемент массива значений типа float,
  123. // после чего, обращаемся к его i-му элемент
  124. }
  125. };
  126.  
  127. // скалярное умножение
  128. float dot(vec4 v1, vec4 v2)
  129. {
  130. vec4 tmp = v1 * v2; // вычисляем произведения соответствующих координат
  131. return tmp.x + tmp.y + tmp.z + tmp.a; // и возвращаем их сумму
  132. }
  133.  
  134. vec3 normalize(vec4 v)
  135. {
  136. // делим первые три координаты на значение четвертой
  137. return vec3(v.x / v.a, v.y / v.a, v.z / v.a);
  138. }
  139.  
  140. // МАТРИЦЫ
  141.  
  142. class mat4
  143. {
  144. public:
  145.  
  146. vec4 row1, row2, row3, row4;
  147.  
  148. // конструкторы
  149. mat4(vec4 r1, vec4 r2, vec4 r3, vec4 r4) : row1(r1), row2(r2), row3(r3), row4(r4) {}
  150. mat4(float a)
  151. {
  152. row1 = vec4(a, 0.f, 0.f, 0.f);
  153. row2 = vec4(0.f, a, 0.f, 0.f);
  154. row3 = vec4(0.f, 0.f, a, 0.f);
  155. row4 = vec4(0.f, 0.f, 0.f, a);
  156. }
  157. mat4() {}
  158.  
  159. // перегрузка операции []
  160. vec4& operator[](int i)
  161. {
  162. return ((vec4*)this)[i]; // массив значений типа vec4
  163. }
  164.  
  165. // транспонирование матрицы
  166. mat4 transpose()
  167. {
  168. mat4 tmp(*this); // делаем временную копию матрицы
  169.  
  170. for (int i = 0; i < 4; i++)
  171. for (int j = 0; j < 4; j++)
  172. (*this)[i][j] = tmp[j][i]; // заменяем элементы текущего объекта
  173. // из временной копии
  174. return *this;
  175. }
  176.  
  177. // перегрузка операций умножения
  178. const vec4 operator* (const vec4& v)
  179. {
  180. vec4* res = new(vec4); // создаем новый вектор (для результата)
  181.  
  182. for (int i = 0; i < 4; i++)
  183. (*res)[i] = dot((*this)[i], v); // i-й элемент вектора - скалярное произведение
  184.  
  185. return *res;
  186. }
  187.  
  188. mat4& operator *= (const mat4& m)
  189. {
  190. mat4 A(*this), B(m); // создаем копии исходных матриц
  191. B.transpose(); // транспонируем вторую матрицу
  192.  
  193. for (int i = 0; i < 4; i++)
  194. (*this)[i] = A * B[i]; // в i-ю строку текущего объекта записываем
  195. // результат перемножения первой матрицы с i-й строкой
  196. // транспонированной матрицы,
  197. return (*this).transpose(); // транспонируем текущий объект, получаем результат
  198. }
  199.  
  200. const mat4 operator* (const mat4& m)
  201. {
  202. return mat4(*this) *= m;
  203. }
  204. };
  205.  
  206. class mat3
  207. {
  208. public:
  209.  
  210. vec3 row1, row2, row3; // строки матрицы
  211.  
  212. // конструкторы
  213. mat3() {}
  214. mat3(vec3 r1, vec3 r2, vec3 r3) : row1(r1), row2(r2), row3(r3) {}
  215.  
  216. mat3(float a) // диагональная матрица
  217. {
  218. row1 = vec3(a, 0.f, 0.f);
  219. row2 = vec3(0.f, a, 0.f);
  220. row3 = vec3(0.f, 0.f, a);
  221. }
  222.  
  223. // перегрузка операции []
  224.  
  225. vec3& operator [] (int i)
  226. {
  227. return ((vec3*)this)[i]; // массив значений типа vec3
  228. }
  229.  
  230. // транспонирование матрицы
  231.  
  232. mat3 transpose()
  233. {
  234. mat3 tmp(*this); // временная копия матрицы
  235.  
  236. for (int i = 0; i < 3; ++i)
  237. for (int j = 0; j < 3; ++j)
  238. (*this)[i][j] = tmp[j][i]; // заменяем элементы текущего объекта
  239. // из временной копии
  240.  
  241. return *this;
  242. }
  243.  
  244. // перегрузка оператора *
  245.  
  246. const vec3 operator * (const vec3& v)
  247. {
  248. vec3* res = new(vec3); // создаем новый вектор-результат
  249.  
  250. for (int i = 0; i < 3; ++i)
  251. (*res)[i] = dot((*this)[i], v); // i-ый элемент веткора - скалярное произведение
  252.  
  253. return *res;
  254. }
  255.  
  256. // перемножение матриц (*= и *)
  257. // 1. B -> B.transpose()
  258. // 2. С = A * B.transpose()
  259. // 3. С -> C.transpose()
  260.  
  261. mat3& operator *= (const mat3& m)
  262. {
  263. mat3 A(*this), B(m); // копии исходных матриц
  264. B.transpose();
  265.  
  266. for (int i = 0; i < 3; ++i)
  267. (*this)[i] = A * B[i]; // в i-ую строку текущего объекта записываем результат перемножения
  268. // 1-ой матрицы с i-ой строкой транспонированной матрицы
  269.  
  270. return (*this).transpose(); // транспонируем и получаем ответ
  271. }
  272.  
  273. const mat3 operator * (const mat3& m)
  274. {
  275. return mat3(*this) *= m;
  276. }
  277.  
  278. // дополнительный конструктор
  279. mat3(mat4 m)
  280. {
  281. row1 = vec3(m.row1.x, m.row1.y, m.row1.z);
  282. row2 = vec3(m.row2.x, m.row2.y, m.row2.z);
  283. row3 = vec3(m.row3.x, m.row3.y, m.row3.z);
  284. }
  285. };
  286.  
  287. class mat2
  288. {
  289. public:
  290.  
  291. vec2 row1, row2;
  292.  
  293. // конструкторы
  294. mat2(vec2 r1, vec2 r2) : row1(r1), row2(r2) {}
  295. mat2(float a)
  296. {
  297. row1 = vec2(a, 0.f);
  298. row2 = vec2(0.f, a);
  299. }
  300. mat2() {}
  301.  
  302. // перегрузка операции []
  303. vec2& operator [] (int i)
  304. {
  305. return ((vec2*)this)[i]; // массив значений типа vec2
  306. }
  307.  
  308. // операции для матриц:
  309.  
  310. // транспонирование
  311. mat2 transpose()
  312. {
  313. mat2 tmp(*this); // делаем временную копию матрицы
  314.  
  315. for (int i = 0; i < 2; ++i)
  316. for (int j = 0; j < 2; ++j)
  317. (*this)[i][j] = tmp[j][i]; // заменяем элементы текущего объекта
  318. // из временной копии
  319.  
  320. return *this;
  321. }
  322.  
  323. // перегрузка операции умножения
  324. const vec2 operator* (const vec2& v)
  325. {
  326. vec2* res = new(vec2); // создаем новый вектор (для результата)
  327.  
  328. for (int i = 0; i < 2; i++)
  329. (*res)[i] = dot((*this)[i], v); // i-й элемент вектора - скалярное произведение
  330.  
  331. return *res;
  332. }
  333.  
  334. mat2& operator *= (const mat2& m)
  335. {
  336. mat2 A(*this), B(m); // создаем копии исходных матриц
  337. B.transpose(); // транспонируем вторую матрицу
  338.  
  339. for (int i = 0; i < 2; i++)
  340. (*this)[i] = A * B[i]; // в i-ю строку текущего объекта записываем
  341. // результат перемножения первой матрицы с i-й строкой
  342. // транспонированной матрицы
  343. return (*this).transpose(); // транспонируем текущий объект, получаем результат
  344. }
  345.  
  346. // допольнительный конструктор
  347. mat2(mat3 m)
  348. {
  349. row1 = vec2(m[0][0], m[0][1]);
  350. row2 = vec2(m[1][0], m[1][1]);
  351. }
  352. };
  353.  
  354. // Transform.h
  355.  
  356. #pragma once
  357. #include "Matrix.h"
  358. #include <math.h>
  359.  
  360. // матрица переноса
  361. mat3 translate(float Tx, float Ty)
  362. {
  363. mat3* res = new mat3(1.f); // матрица-результат
  364.  
  365. (*res)[0][2] = Tx; // поменяли значения
  366. (*res)[1][2] = Ty; // в последнем столбце
  367.  
  368. return *res;
  369. }
  370.  
  371. mat4 translate(float Tx, float Ty, float Tz)
  372. {
  373. mat4* res = new mat4(1.f); // матрица-результат
  374.  
  375. (*res)[0][3] = Tx; // поменяли значения
  376. (*res)[1][3] = Ty; // в последнем столбце
  377. (*res)[2][3] = Tz;
  378.  
  379. return *res;
  380. }
  381.  
  382. // матрица масштабирования
  383. mat3 scale(float Sx, float Sy)
  384. {
  385. mat3* res = new mat3(1.f); // матрица-результат
  386.  
  387. (*res)[0][0] = Sx; // поменяли значения
  388. (*res)[1][1] = Sy; // на главной диагонали
  389.  
  390. return *res;
  391. }
  392.  
  393. // перегрузка: Sx = Sy = S
  394. mat3 scale(float S) { return scale(S, S); }
  395.  
  396. mat4 scale(float Sx, float Sy, float Sz)
  397. {
  398. mat4* res = new mat4(1.f); // матрица-результат
  399.  
  400. (*res)[0][0] = Sx; // поменяли значения
  401. (*res)[1][1] = Sy; // на главной диагонали
  402. (*res)[2][2] = Sz;
  403.  
  404. return *res;
  405. }
  406.  
  407. // матрица поворота (относительно начала координат против часовой стрелки)
  408. mat3 rotate(float theta)
  409. {
  410. mat3* res = new mat3(1.f); // матрица-результат
  411.  
  412. (*res)[0][0] = (*res)[1][1] = (float)cos(theta); // заполнили главную диагональ
  413. (*res)[0][1] = (float)sin(theta); // синус в 1-ой строке (с плюсом)
  414. (*res)[1][0] = -(float)sin(theta); // синус во 2-ой строке (с минусом)
  415.  
  416. return *res;
  417. }
  418.  
  419. // матрица зеркального отображения относительно оси Ox
  420. mat3 mirrorX()
  421. {
  422. mat3* res = new mat3(1.f);
  423. (*res)[1][1] = -1.f;
  424.  
  425. return *res;
  426. }
  427.  
  428. // матрица зеркального отображения относительно оси Oy
  429. mat3 mirrorY()
  430. {
  431. mat3* res = new mat3(1.f);
  432. (*res)[0][0] = -1.f;
  433.  
  434. return *res;
  435. }
  436.  
  437. // Clip.h
  438.  
  439. #pragma once
  440. #include "Matrix.h"
  441. #include <algorithm>
  442. using namespace std;
  443.  
  444. // АЛГОРИТМ КОЭНА-САЗЕРЛЕНДА
  445.  
  446. // Код точки: XXXX (0000 - область видимости)
  447. // 1 - выше; 0 - иначе
  448. // 1 - ниже; 0 - иначе
  449. // 1 - правее; 0 - иначе
  450. // 1 - левее; 0 - иначе
  451.  
  452. // 1001 | 1000 | 1010
  453. // --------------------
  454. // 0001 | 0000 | 0010
  455. // --------------------
  456. // 0101 | 0100 | 0110
  457.  
  458. // Код точки
  459. unsigned int codeKS(vec2 P, float minX, float minY, float maxX, float maxY)
  460. {
  461. unsigned int code = 0; // возращаемый результат
  462.  
  463. if (P.x < minX) // слева
  464. code += 1;
  465. else if (P.x > maxX) // справа
  466. code += 2;
  467.  
  468. if (P.y < minY) // ниже
  469. code += 4;
  470. else if (P.y > maxY) // выше
  471. code += 8;
  472.  
  473. return code;
  474. }
  475.  
  476. // Отсечение отрезка AB областью, заданной параметрами minX, minY, maxX, maxY
  477. // false - отрезок полностью невидим; true - в противном случае
  478.  
  479. bool clip(vec2& A, vec2& B, float minX, float minY, float maxX, float maxY)
  480. {
  481. // находим коды точек A и B
  482. unsigned int codeA = codeKS(A, minX, minY, maxX, maxY);
  483. unsigned int codeB = codeKS(B, minX, minY, maxX, maxY);
  484.  
  485. while (codeA | codeB)
  486. {
  487. // отрезки полностью невидимые
  488. if (codeA & codeB) return false;
  489.  
  490. // чтобы не разбирать много случаев
  491. // для определенности за пределами области
  492. // видимости будем рассматривать только точку A
  493.  
  494. if (codeA == 0)
  495. {
  496. swap(A, B);
  497. swap(codeA, codeB);
  498. }
  499.  
  500. if (codeA & 1) // слева
  501. {
  502. A.y = A.y + (minX - A.x) * (B.y - A.y) / (B.x - A.x);
  503. A.x = minX;
  504. }
  505. else if (codeA & 2) // справа
  506. {
  507. A.y = A.y + (A.x - maxX) * (B.y - A.y) / (A.x - B.x);
  508. A.x = maxX;
  509. }
  510. else if (codeA & 4) // снизу
  511. {
  512. A.x = A.x + (B.x - A.x) * (A.y - minY) / (A.y - B.y);
  513. A.y = minY;
  514. }
  515. else // codeA & 8 == 1, сверху
  516. {
  517. A.x = A.x + (B.x - A.x) * (maxY - A.y) / (B.y - A.y);
  518. A.y = maxY;
  519. }
  520.  
  521. // обновляем код
  522. codeA = codeKS(A, minX, minY, maxX, maxY);
  523. }
  524.  
  525. return true;
  526. }
  527.  
  528. // MyForm.h
  529.  
  530. #pragma once
  531.  
  532. namespace Moskvitin {
  533.  
  534. using namespace System;
  535. using namespace System::ComponentModel;
  536. using namespace System::Collections;
  537. using namespace System::Windows::Forms;
  538. using namespace System::Data;
  539. using namespace System::Drawing;
  540. using namespace std;
  541.  
  542. mat3 T = mat3(1.f); // матрица, в которой накапливаются все преобразования
  543. mat3 initT; // матрица начального преобразования
  544.  
  545. vec2 Vc; // координаты левого нижнего угла
  546. vec2 V; // размеры прямоугольника в пространстве графика
  547. vec2 Vc_work, V_work; // рабочие параметры прямоугольника
  548.  
  549. /// <summary>
  550. /// Сводка для MyForm
  551. /// </summary>
  552. public ref class MyForm : public System::Windows::Forms::Form
  553. {
  554. public:
  555. MyForm(void)
  556. {
  557. InitializeComponent();
  558. //
  559. //TODO: добавьте код конструктора
  560. //
  561. }
  562.  
  563. protected:
  564. /// <summary>
  565. /// Освободить все используемые ресурсы.
  566. /// </summary>
  567. ~MyForm()
  568. {
  569. if (components)
  570. {
  571. delete components;
  572. }
  573. }
  574. private: System::Windows::Forms::OpenFileDialog^ openFileDialog;
  575. protected:
  576.  
  577.  
  578. private:
  579. /// <summary>
  580. /// Обязательная переменная конструктора.
  581. /// </summary>
  582. System::ComponentModel::Container^ components;
  583.  
  584. #pragma region Windows Form Designer generated code
  585. /// <summary>
  586. /// Требуемый метод для поддержки конструктора — не изменяйте
  587. /// содержимое этого метода с помощью редактора кода.
  588. /// </summary>
  589. void InitializeComponent(void)
  590. {
  591. this->openFileDialog = (gcnew System::Windows::Forms::OpenFileDialog());
  592. this->SuspendLayout();
  593. //
  594. // openFileDialog
  595. //
  596. this->openFileDialog->DefaultExt = L"txt";
  597. this->openFileDialog->Filter = L" Текстовые файлы (*.txt)|*.txt|Все файлы (*.*)|*.*";
  598. this->openFileDialog->Title = L"Открыть файл";
  599. //
  600. // MyForm
  601. //
  602. this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
  603. this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
  604. this->ClientSize = System::Drawing::Size(284, 261);
  605. this->DoubleBuffered = true;
  606. this->KeyPreview = true;
  607. this->MinimumSize = System::Drawing::Size(155, 120);
  608. this->Name = L"MyForm";
  609. this->Text = L"MyForm";
  610. this->Load += gcnew System::EventHandler(this, &MyForm::MyForm_Load);
  611. this->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &MyForm::MyForm_Paint);
  612. this->KeyDown += gcnew System::Windows::Forms::KeyEventHandler(this, &MyForm::MyForm_KeyDown);
  613. this->Resize += gcnew System::EventHandler(this, &MyForm::MyForm_Resize);
  614. this->ResumeLayout(false);
  615.  
  616. }
  617. #pragma endregion
  618.  
  619. private: float left = 30, right = 100, top = 20, bottom = 50; // расстояния до границ окна
  620. float minX = left, maxX; // диапазон изменения координат x
  621. float minY = top, maxY; // диапазон изменения координат y
  622. float Wcx = left, Wcy; // координаты левого нижнего угла прямоугольника
  623. float Wx, Wy; // ширина и высота прямоугольника
  624. int numXsect = 5, numYsect = 5; // количество секций координатной сетки по осям
  625.  
  626. // инициализация остальных параметров
  627.  
  628. private: System::Void rectCalc() {
  629. maxX = ClientRectangle.Width - right; // диапазон изменения координат x
  630. maxY = ClientRectangle.Height - bottom; // диапазон изменения координат y
  631. Wcy = maxY; // координаты левого нижнего угла прямоугольника
  632. Wx = maxX - left; // ширина прямоугольника
  633. Wy = maxY - top;
  634. }
  635.  
  636. private: System::Void worldRectCalc() {
  637. Vc_work = normalize(T * vec3(Vc, 1.f));
  638. V_work = mat2(T) * V;
  639. }
  640.  
  641. // сама функция
  642. private: float f(float x) {
  643. return tan(x);
  644. }
  645.  
  646. // проверка, определена ли функция в точке x
  647. private: bool f_exists(float x, float delta) {
  648. return fabs(2.f * acos(cos(x)) - Math::PI) > delta;
  649. }
  650.  
  651. private: System::Void MyForm_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {
  652. // описываем переменную g - область рисования, ссылку на объект типа System::Drawing::Graphics^
  653. Graphics^ g = e->Graphics;
  654.  
  655. Pen^ rectPen = gcnew Pen(Color::Black, 2); // черная ручка
  656. g->DrawRectangle(rectPen, left, top, Wx, Wy); // рисуем область видимости
  657.  
  658. Pen^ pen = gcnew Pen(Color::Blue, 1); // ручка для рисовки графика функции
  659. float deltaX = V_work.x / Wx; // шаг по x в мировых координатах
  660.  
  661. bool hasStart;
  662.  
  663. vec2 start; // точка начала отрезка в координатах экрана
  664. float x, y; // переменные для координат точки в мировой СК
  665. start.x = Wcx; // для начальной точки первого отрезка устанавливаем координату x
  666. x = Vc_work.x; // координата x начальной точки первого отрезка в мировых координатах
  667.  
  668. hasStart = f_exists(x, deltaX);
  669. if (hasStart)
  670. {
  671. y = f(x); // координата y начальной точки в мировых координатах
  672. start.y = Wcy - (y - Vc_work.y) / V_work.y * Wy; // вычисляем соответствующее значение в координатах экрана
  673. }
  674.  
  675. while (start.x < maxX)
  676. {
  677. float deltaY; // высота точки в прямоугольнике (доля общей высоты)
  678. float red, green, blue; // компоненты цвета отрезка
  679.  
  680. vec2 end;// точка конца отрезка в координатах экрана
  681. bool hasEnd;
  682.  
  683. end.x = start.x + 1.f; // координата x отличается на единицу
  684. x += deltaX; // координата x конечной точки отрезка в мировых координатах
  685.  
  686. hasEnd = f_exists(x, deltaX);
  687. if (hasEnd)
  688. {
  689. y = f(x); // координата y начальной точки в мировых координатах
  690.  
  691. // вычисляем соответствующее значение в координатах экрана
  692. deltaY = (y - Vc_work.y) / V_work.y;
  693. end.y = Wcy - deltaY * Wy;
  694. }
  695.  
  696. vec2 tmpEnd = end;
  697. bool visible = hasStart && hasEnd && clip(start, end, minX, minY, maxX, maxY);
  698. if (visible) { // если отрезок видим
  699.  
  700. if (deltaY > 1.f) deltaY = 1.f; // нормализуем значение высоты точки
  701. if (deltaY < 0.f) deltaY = 0.f; // на случай, если отрезок отсекался
  702. green = 510.f * deltaY; // предварительное вычисление произведения
  703. if (deltaY < 0.5) { // если точка ниже середины области видимости
  704. // компонента зеленого уже вычислена
  705. blue = 255.f - green; // синий дополняет зеленый
  706. red = 0.f; // красный равен нулю
  707. }
  708. else { // если точка не ниже середины
  709. blue = 0.f; // синий равен нулю
  710. red = green - 255.f; // вычисляем красный и зеленый
  711. green = 510.f - green; // с использованием вычисленного произведения
  712. }
  713. pen->Color = Color::FromArgb(red, green, blue); // меняем цвет пера
  714.  
  715. // после отсечения, start и end - концы видимой части отрезка
  716. g->DrawLine(pen, start.x, start.y, end.x, end.y); // отрисовка видимых частей
  717. }
  718. // конечная точка неотсеченного отрезка становится начальной точкой следующего
  719. start = tmpEnd;
  720. hasStart = hasEnd;
  721. }
  722.  
  723. Pen^ gridPen = gcnew Pen(Color::Black, 1);
  724. SolidBrush^ drawBrush = gcnew SolidBrush(Color::Black);
  725. System::Drawing::Font^ drawFont = gcnew System::Drawing::Font("Arial", 8);
  726.  
  727. // координатная сетка по X
  728. float gridStep_x = Wx / numXsect; // расстояние между линиями сетки по x
  729. float grid_dX = V_work.x / numXsect; // расстояние между линиями сетки по x в мировых координатах
  730. float tick_x = Vc_work.x; // значение соответствующее первой линии сетки
  731.  
  732. for (int i = 0; i <= numXsect; i++) { // цикл по количеству линий
  733. float tmpXCoord = Wcx + i * gridStep_x;
  734.  
  735. g->DrawLine(gridPen, tmpXCoord, Wcy, tmpXCoord, Wcy - Wy); // i-я вертикальная линия
  736.  
  737. if (i > 0 && i < numXsect) // если линия не крайняя
  738. g->DrawString(tick_x.ToString("F4"), drawFont, drawBrush, tmpXCoord, Wcy);
  739.  
  740. tick_x += grid_dX; // вычисляем значение, соответствующее следующей линии
  741. }
  742.  
  743. // координатная сетка по Y
  744. float gridStep_y = Wy / numYsect; // расстояние между линиями сетки по y
  745. float grid_dY = V_work.y / numYsect; // расстояние между линиями сетки по y в мировых координатах
  746. float tick_y = Vc_work.y; // значение соответствующее первой линии сетки
  747.  
  748. for (int i = 0; i <= numYsect; i++) { // цикл по количеству линий
  749. float tmpYCoord = Wcy - i * gridStep_y;
  750.  
  751. g->DrawLine(gridPen, Wcx, tmpYCoord, Wcx + Wx, tmpYCoord); // i-я горизонтальная линия
  752.  
  753. if (i > 0 && i < numYsect) // если линия не крайняя
  754. g->DrawString(tick_y.ToString("F4"), drawFont, drawBrush, Wcx + Wx, tmpYCoord);
  755.  
  756. tick_y += grid_dY; // вычисляем значение, соответствующее следующей линии
  757. }
  758. }
  759.  
  760. private: System::Void MyForm_Resize(System::Object^ sender, System::EventArgs^ e) {
  761. // Добавляем устойчивость рисунка относительно изменения размера окна
  762. Refresh();
  763. // передподсчет сторон прямоугольника
  764. rectCalc();
  765. }
  766.  
  767. private: System::Void MyForm_Load(System::Object^ sender, System::EventArgs^ e) {
  768. initT = mat3(1.f);
  769. T = initT;
  770.  
  771. // изначально центр прямоугольника находится в начале координат
  772. Vc = vec2(-2.f, -2.f);
  773. V = vec2(4.f, 4.f);
  774.  
  775. rectCalc();
  776. worldRectCalc();
  777. }
  778.  
  779. private: System::Void MyForm_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) {
  780. float centerX = Vc_work.x + V_work.x / 2; // координаты центра прямоугольника
  781. float centerY = Vc_work.y + V_work.y / 2; // в мировой системе координат
  782.  
  783. switch (e->KeyCode)
  784. {
  785. // сброс всех преобразований
  786. case Keys::Escape:
  787. T = initT;
  788. break;
  789. // сдвиг графика ВПРАВО на один пиксел
  790. case Keys::A:
  791. T = translate(-V_work.x / Wx, 0.f) * T;
  792. break;
  793. // сдвиг графика ВЛЕВО на один пиксел
  794. case Keys::D:
  795. T = translate(V_work.x / Wx, 0.f) * T;
  796. break;
  797. // сдвиг графика ВНИЗ на один пиксел
  798. case Keys::W:
  799. T = translate(0.f, V_work.y / Wy) * T;
  800. break;
  801. // сдвиг графика ВВЕРХ на один пиксел
  802. case Keys::S:
  803. T = translate(0.f, -V_work.y / Wy) * T;
  804. break;
  805. // увеличение числа секций координатной сетки по оси Ox
  806. case Keys::D1:
  807. ++numXsect;
  808. break;
  809. // уменьшение числа секций координатной сетки по оси Ox
  810. case Keys::D2:
  811. numXsect = max(numXsect - 1, 2);
  812. break;
  813. // увеличение числа секций координатной сетки по оси Oy
  814. case Keys::D3:
  815. ++numYsect;
  816. break;
  817. // уменьшение числа секций координатной сетки по оси Oy
  818. case Keys::D4:
  819. numYsect = max(numYsect - 1, 2);
  820. break;
  821. // равномерное увеличение прямоугольника в мировой СК относительно центра в 1.1 раз
  822. case Keys::Z:
  823. T = translate(-centerX, -centerY) * T; // перенос начала координат в центр
  824. T = scale(1.1) * T; // масштабирование относительно начала координат
  825. T = translate(centerX, centerY) * T; // возврат позиции начала координат
  826. break;
  827. // равномерное уменьшение прямоугольника в мировой СК относительно центра в 1.1 раз
  828. case Keys::X:
  829. T = translate(-centerX, -centerY) * T; // перенос начала координат в центр
  830. T = scale(10.f / 11.f) * T; // масштабирование относительно начала координат
  831. T = translate(centerX, centerY) * T; // возврат позиции начала координат
  832. break;
  833. // увеличение прямоугольника в мировой СК относительно центра по Ox в 1.1 раз
  834. case Keys::T:
  835. T = translate(-centerX, -centerY) * T; // перенос начала координат в центр
  836. T = scale(1.1, 1) * T; // масштабирование относительно начала координат
  837. T = translate(centerX, centerY) * T; // возврат позиции начала координат
  838. break;
  839. // уменьшение прямоугольника в мировой СК относительно центра по Ox в 1.1 раз
  840. case Keys::G:
  841. T = translate(-centerX, -centerY) * T; // перенос начала координат в центр
  842. T = scale(10.f / 11.f, 1) * T; // масштабирование относительно начала координат
  843. T = translate(centerX, centerY) * T; // возврат позиции начала координат
  844. break;
  845. // увеличение прямоугольника в мировой СК относительно центра по Oy в 1.1 раз
  846. case Keys::Y:
  847. T = translate(-centerX, -centerY) * T; // перенос начала координат в центр
  848. T = scale(1, 1.1) * T; // масштабирование относительно начала координат
  849. T = translate(centerX, centerY) * T; // возврат позиции начала координат
  850. break;
  851. // уменьшение прямоугольника в мировой СК относительно центра по Oy в 1.1 раз
  852. case Keys::H:
  853. T = translate(-centerX, -centerY) * T; // перенос начала координат в центр
  854. T = scale(1, 10.f / 11.f) * T; // масштабирование относительно начала координат
  855. T = translate(centerX, centerY) * T; // возврат позиции начала координат
  856. break;
  857. default:
  858. break;
  859. }
  860.  
  861. worldRectCalc();
  862. Refresh();
  863. }
  864. };
  865. }
  866.  
  867. // MyForm.cpp
  868.  
  869. #include <vector>
  870. #include "Matrix.h"
  871. #include "Transform.h"
  872. #include "Clip.h"
  873. #include "MyForm.h"
  874.  
  875. using namespace System;
  876. using namespace System::Windows::Forms;
  877.  
  878. [STAThreadAttribute]
  879. void Main(cli::array<String^>^ args) {
  880. Application::EnableVisualStyles();
  881. Application::SetCompatibleTextRenderingDefault(false);
  882. Moskvitin::MyForm form;
  883. Application::Run(% form);
  884. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement