Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Matrix.h
- #pragma once
- class vec2
- {
- public:
- float x, y;
- // конструкторы
- vec2() {}
- vec2(float a, float b) : x(a), y(b) {}
- };
- class vec3
- {
- public:
- float x, y, z;
- // конструкторы
- vec3() {}
- vec3(float a, float b, float c) : x(a), y(b), z(c) {}
- vec3(vec2 v, float z) : vec3(v.x, v.y, z) {}
- // перегрузка операций *= , * и []
- vec3& operator *= (const vec3& v)
- {
- x *= v.x;
- y *= v.y;
- z *= v.z;
- return *this;
- }
- const vec3 operator * (const vec3& v)
- {
- return vec3(*this) *= v; // делаем временную копию текущего объекта, которую
- } // домножаем на данный вектор, и возвращаем ее как результат
- float& operator [] (int i)
- {
- return ((float*)this)[i]; // ссылку на текующий объект рассматриваем как ссылку на 0-ой элемент
- } // массива значений типа float, после чего обращаемся к его i-ому элементу
- };
- // скалярное умножение
- float dot(vec3 v1, vec3 v2)
- {
- vec3 tmp = v1 * v2; // вычисляем произведение соответствующих координат
- return tmp.x + tmp.y + tmp.z; // и возвращаем их сумму
- }
- class mat3
- {
- public:
- vec3 row1, row2, row3; // строки матрицы
- // конструкторы
- mat3() {}
- mat3(vec3 r1, vec3 r2, vec3 r3) : row1(r1), row2(r2), row3(r3) {}
- mat3(float a) // диагональная матрица
- {
- row1 = vec3(a, 0.f, 0.f);
- row2 = vec3(0.f, a, 0.f);
- row3 = vec3(0.f, 0.f, a);
- }
- // перегрузка операции []
- vec3& operator [] (int i)
- {
- return ((vec3*)this)[i]; // массив значений типа vec3
- }
- // транспонирование матрицы
- mat3 transpose()
- {
- mat3 tmp(*this); // временная копия матрицы
- for (int i = 0; i < 3; ++i)
- for (int j = 0; j < 3; ++j)
- (*this)[i][j] = tmp[j][i]; // заменяем элементы текущего объекта
- // из временной копии
- return *this;
- }
- // перегрузка оператора *
- const vec3 operator * (const vec3& v)
- {
- vec3* res = new(vec3); // создаем новый вектор-результат
- for (int i = 0; i < 3; ++i)
- (*res)[i] = dot((*this)[i], v); // i-ый элемент веткора - скалярное произведение
- return *res;
- }
- // перемножение матриц (*= и *)
- // 1. B -> B.transpose()
- // 2. С = A * B.transpose()
- // 3. С -> C.transpose()
- mat3& operator *= (const mat3& m)
- {
- mat3 A(*this), B(m); // копии исходных матриц
- B.transpose();
- for (int i = 0; i < 3; ++i)
- (*this)[i] = A * B[i]; // в i-ую строку текущего объекта записываем результат перемножения
- // 1-ой матрицы с i-ой строкой транспонированной матрицы
- return (*this).transpose(); // транспонируем и получаем ответ
- }
- const mat3 operator * (const mat3& m)
- {
- return mat3(*this) *= m;
- }
- };
- vec2 normalize(vec3 v)
- {
- return vec2(v.x / v.z, v.y / v.z);
- }
- // Transform.h
- #pragma once
- #include "Matrix.h"
- #include <math.h>
- // матрица переноса
- mat3 translate(float Tx, float Ty)
- {
- mat3* res = new mat3(1.f); // матрица-результат
- (*res)[0][2] = Tx; // поменяли значения
- (*res)[1][2] = Ty; // в последнем столбце
- return *res;
- }
- // матрица масштабирования
- mat3 scale(float Sx, float Sy)
- {
- mat3* res = new mat3(1.f); // матрица-результат
- (*res)[0][0] = Sx; // поменяли значения
- (*res)[1][1] = Sy; // на главной диагонали
- return *res;
- }
- // перегрузка: Sx = Sy = S
- mat3 scale(float S) { return scale(S, S); }
- // матрица поворота (относительно начала координат против часовой стрелки)
- mat3 rotate(float theta)
- {
- mat3* res = new mat3(1.f); // матрица-результат
- (*res)[0][0] = (*res)[1][1] = (float)cos(theta); // заполнили главную диагональ
- (*res)[0][1] = (float)sin(theta); // синус в 1-ой строке (с плюсом)
- (*res)[1][0] = -(float)sin(theta); // синус во 2-ой строке (с минусом)
- return *res;
- }
- // матрица зеркального отображения относительно оси Ox
- mat3 mirrorX()
- {
- mat3* res = new mat3(1.f);
- (*res)[1][1] = -1.f;
- return *res;
- }
- // матрица зеркального отображения относительно оси Oy
- mat3 mirrorY()
- {
- mat3* res = new mat3(1.f);
- (*res)[0][0] = -1.f;
- return *res;
- }
- // Figure.h
- #pragma once
- #include "Matrix.h"
- #include <vector>
- class path
- {
- public:
- std::vector <vec2> vertices; // последовательность точек
- vec3 color; // цвет, разбитый на составляющие RGB
- float thickness; // толщина линии
- path(std::vector <vec2> verts, vec3 col, float thickn)
- {
- vertices = verts;
- color = col;
- thickness = thickn;
- }
- };
- // MyForm.h
- #pragma once
- namespace Moskvitin {
- using namespace System;
- using namespace System::ComponentModel;
- using namespace System::Collections;
- using namespace System::Windows::Forms;
- using namespace System::Data;
- using namespace System::Drawing;
- using namespace std;
- mat3 T = mat3(1.f); // матрица, в которой накапливаются все преобразования
- mat3 initT; // матрица начального преобразования
- vector <path> figure;
- float Vx, Vy; // размеры рисунка по горизонтали и вертикали
- float aspectFig; // соотношение сторон рисунка
- /// <summary>
- /// Сводка для MyForm
- /// </summary>
- public ref class MyForm : public System::Windows::Forms::Form
- {
- public:
- MyForm(void)
- {
- InitializeComponent();
- //
- //TODO: добавьте код конструктора
- //
- }
- protected:
- /// <summary>
- /// Освободить все используемые ресурсы.
- /// </summary>
- ~MyForm()
- {
- if (components)
- {
- delete components;
- }
- }
- private: System::Windows::Forms::OpenFileDialog^ openFileDialog;
- protected:
- private: System::Windows::Forms::Button^ btnOpen;
- private:
- /// <summary>
- /// Обязательная переменная конструктора.
- /// </summary>
- System::ComponentModel::Container ^components;
- #pragma region Windows Form Designer generated code
- /// <summary>
- /// Требуемый метод для поддержки конструктора — не изменяйте
- /// содержимое этого метода с помощью редактора кода.
- /// </summary>
- void InitializeComponent(void)
- {
- this->openFileDialog = (gcnew System::Windows::Forms::OpenFileDialog());
- this->btnOpen = (gcnew System::Windows::Forms::Button());
- this->SuspendLayout();
- //
- // openFileDialog
- //
- this->openFileDialog->DefaultExt = L"txt";
- this->openFileDialog->Filter = L"Текстовые файлы (*.txt)|*.txt|Все файлы (*.*)|*.*";
- this->openFileDialog->Title = L"Открыть файл";
- //
- // btnOpen
- //
- this->btnOpen->Location = System::Drawing::Point(178, 12);
- this->btnOpen->Name = L"btnOpen";
- this->btnOpen->Size = System::Drawing::Size(88, 31);
- this->btnOpen->TabIndex = 0;
- this->btnOpen->Text = L"Открыть";
- this->btnOpen->UseVisualStyleBackColor = true;
- this->btnOpen->Click += gcnew System::EventHandler(this, &MyForm::btnOpen_Click);
- //
- // MyForm
- //
- this->AutoScaleDimensions = System::Drawing::SizeF(9, 20);
- this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
- this->ClientSize = System::Drawing::Size(278, 244);
- this->Controls->Add(this->btnOpen);
- this->KeyPreview = true;
- this->Name = L"MyForm";
- this->Text = L"MyForm";
- this->Load += gcnew System::EventHandler(this, &MyForm::MyForm_Load);
- this->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &MyForm::MyForm_Paint);
- this->KeyDown += gcnew System::Windows::Forms::KeyEventHandler(this, &MyForm::MyForm_KeyDown);
- this->Resize += gcnew System::EventHandler(this, &MyForm::MyForm_Resize);
- this->ResumeLayout(false);
- }
- #pragma endregion
- private: System::Void MyForm_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {
- // описываем переменную g - область рисования, ссылку на объект типа System::Drawing::Graphics^
- Graphics^ g = e->Graphics;
- g->Clear(Color::White);
- for (int i = 0; i < figure.size(); ++i)
- {
- path lines = figure[i]; // очередная ломаная линия
- Pen^ pen = gcnew Pen(Color::FromArgb(lines.color.x, lines.color.y, lines.color.z));
- pen->Width = lines.thickness;
- vec2 start = normalize(T * vec3(lines.vertices[0], 1.0)); // 1-ая начальная точка
- for (int j = 1; j < lines.vertices.size(); ++j)
- {
- vec2 end = normalize(T * vec3(lines.vertices[j], 1.0)); // конечная точка
- g->DrawLine(pen, start.x, start.y, end.x, end.y);
- start = end; // конечная точка текущего отрезка становится начальной точкой следующего
- }
- }
- }
- private: System::Void MyForm_Resize(System::Object^ sender, System::EventArgs^ e) {
- // Добавляем устойчивость рисунка относительно изменения размера окна
- Refresh();
- }
- private: System::Void MyForm_Load(System::Object^ sender, System::EventArgs^ e) {
- }
- private: System::Void MyForm_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) {
- // координаты центров
- float Wcx = ClientRectangle.Width / 2.f; // по ширине
- float Wcy = ClientRectangle.Height / 2.f; // по высоте
- switch (e->KeyCode)
- {
- // поворот на 0.01 радиан против часовой стрелки
- case Keys::Q:
- T = translate(-Wcx, -Wcy) * T; // перенос начала координат в (Wcx, Wcy)
- T = rotate(0.01f) * T; // поворот
- T = translate(Wcx, Wcy) * T; // перенос начала координат обратно
- break;
- // сдвиг изображения вверх на 1 пиксель
- case Keys::W:
- T = translate(0.f, -1.f) * T;
- break;
- // сброс всех преобразований
- case Keys::Escape:
- T = initT;
- break;
- // поворот на 0.01 радиан по часовой стрелке
- case Keys::E:
- T = translate(-Wcx, -Wcy) * T; // перенос начала координат в (Wcx, Wcy)
- T = rotate(-0.01f) * T; // поворот
- T = translate(Wcx, Wcy) * T; // перенос начала координат обратно
- break;
- // сдвиг изображения вниз на 1 пиксель
- case Keys::S:
- T = translate(0.f, 1.f) * T;
- break;
- // сдвиг изображения влево на 1 пиксель
- case Keys::A:
- T = translate(-1.f, 0.f) * T;
- break;
- // сдвиг изображения вправо на 1 пиксель
- case Keys::D:
- T = translate(1.f, 0.f) * T;
- break;
- // поворот на 0.05 радиан по часовой стрелке
- case Keys::R:
- T = translate(-Wcx, -Wcy) * T;
- T = rotate(-0.05f) * T;
- T = translate(Wcx, Wcy) * T;
- break;
- // поворот на 0.05 радиан против часовой стрелки
- case Keys::Y:
- T = translate(-Wcx, -Wcy) * T;
- T = rotate(0.05f) * T;
- T = translate(Wcx, Wcy) * T;
- break;
- // сдвиг изображения вверх на 10 пикселей
- case Keys::T:
- T = translate(0.f, -10.f) * T;
- break;
- // сдвиг изображения вниз на 10 пикселей
- case Keys::G:
- T = translate(0.f, 10.f) * T;
- break;
- // сдвиг изображения влево на 10 пикселей
- case Keys::F:
- T = translate(-10.f, 0.f) * T;
- break;
- // сдвиг изображения вправо на 10 пикселей
- case Keys::H:
- T = translate(10.f, 0.f) * T;
- break;
- // увеличение изображения в 1.1 раз
- case Keys::Z:
- T = translate(-Wcx, -Wcy) * T;
- T = scale(1.1f) * T;
- T = translate(Wcx, Wcy) * T;
- break;
- // уменьшение изображения в 1.1 раз
- case Keys::X:
- T = translate(-Wcx, -Wcy) * T;
- T = scale(10.f / 11.f) * T;
- T = translate(Wcx, Wcy) * T;
- break;
- // зеркальное отражения относительно горизонтальной оси, проходящей через центр окна
- case Keys::U:
- T = translate(-Wcx, -Wcy) * T;
- T = mirrorX() * T;
- T = translate(Wcx, Wcy) * T;
- break;
- // зеркальное отражение относительно вертикальной оси, проходящей через центр окна
- case Keys::J:
- T = translate(-Wcx, -Wcy) * T;
- T = mirrorY() * T;
- T = translate(Wcx, Wcy) * T;
- break;
- // растяжение изображения по горизонтали в 1.1 раз
- case Keys::I:
- T = translate(-Wcx, -Wcy) * T;
- T = scale(1.1f, 1.f) * T;
- T = translate(Wcx, Wcy) * T;
- break;
- // сжатие изображения по горизонтали в 1.1 раз
- case Keys::K:
- T = translate(-Wcx, -Wcy) * T;
- T = scale(10.f / 11.f, 1.f) * T;
- T = translate(Wcx, Wcy) * T;
- break;
- // растяжение изображения по вертикали в 1.1 раз
- case Keys::O:
- T = translate(-Wcx, -Wcy) * T;
- T = scale(1.f, 1.1f) * T;
- T = translate(Wcx, Wcy) * T;
- break;
- // сжатие изображения по вертикали в 1.1 раз
- case Keys::L:
- T = translate(-Wcx, -Wcy) * T;
- T = scale(1.f, 10.f / 11.f) * T;
- T = translate(Wcx, Wcy) * T;
- break;
- default:break;
- }
- Refresh();
- }
- private: System::Void btnOpen_Click(System::Object^ sender, System::EventArgs^ e) {
- if (openFileDialog->ShowDialog() == System::Windows::Forms::DialogResult::OK)
- {
- // в файловом диалоге нажата кнопка OK
- // перезапись имени файла из openFileDialog->FileName в fileName
- wchar_t fileName[1024]; // переменная, в которой посимвольно сохраним имя файла
- for (int i = 0; i < openFileDialog->FileName->Length; i++)
- fileName[i] = openFileDialog->FileName[i];
- fileName[openFileDialog->FileName->Length] = '\0';
- // объявление и открытие файла
- ifstream in;
- in.open(fileName);
- if (in.is_open())
- {
- // файл успешно открыт
- figure.clear(); // очищаем имеющийся список ломаных
- // временные переменные для чтения из файла
- float thickness = 2; // толщина со значением по умолчанию 2
- float r, g, b; // составляющие цвета
- r = g = b = 0; // значение составляющих цвета по умолчанию (черный)
- // непосредственно работа с файлом
- string str; // строка, в которую считываем строки файла
- getline(in, str); // считываем из входного файла первую строку
- while (in) // если очередная строка считана успешно
- {
- // обрабатываем строку
- if ((str.find_first_not_of(" \t\r\n") != string::npos) && (str[0] != '#'))
- {
- // прочитанная строка не пуста и не комментарий
- stringstream s(str); // строковый поток из строки str
- string cmd; // переменная для имени команды
- s >> cmd; // считываем имя команды
- if (cmd == "frame") { // размеры изображения
- s >> Vx >> Vy; // считываем глобальные значение Vx и Vy
- aspectFig = Vx / Vy; // обновление соотношения сторон
- // размеры окна
- float Wx = ClientRectangle.Width; // ширина окна
- float Wy = ClientRectangle.Height; // высота окна
- // соотношение сторон окна рисования
- float aspectForm = Wx / Wy;
- // коэффициент увеличения при сохранении исходного соотношения сторон
- float S = aspectFig < aspectForm ? Wy / Vy : Wx / Vx;
- float Ty = S * Vy; // смещение в положительную сторону по оси Oy после смены знака
- initT = translate(0.f, Ty) * scale(S, -S); // масштабирование и перенос
- T = initT;
- }
- else if (cmd == "color") { // цвет линии
- s >> r >> g >> b; // считываем три составляющие цвета
- }
- else if (cmd == "thickness") { // толщина линии
- s >> thickness; // считываем значение толщины
- }
- else if (cmd == "path") { // набор точек
- vector<vec2> vertices; // список точек ломаной
- int N; // количество точек
- s >> N;
- string str1; // дополнительная строка для чтения из файла
- while (N > 0) { // пока не все точки считали
- getline(in, str1); // считываем в str1 из входного файла очередную строку
- // так как файл корректный, то на конец файла проверять не нужно
- if ((str1.find_first_not_of(" \t\r\n") != string::npos) && (str1[0] != '#')) {
- // прочитанная строка не пуста и не комментарий
- // значит в ней пара координат
- float x, y; // переменные для считывания
- stringstream s1(str1); // еще один строковый поток из строки str1
- s1 >> x >> y;
- vertices.push_back(vec2(x, y)); // добавляем точку в список
- N--; // уменьшаем счетчик после успешного считывания точки
- }
- }
- // все точки считаны, генерируем ломаную (path) и кладем ее в список figure
- figure.push_back(path(vertices, vec3(r, g, b), thickness));
- }
- }
- // считываем очередную строку
- getline(in, str);
- }
- Refresh();
- }
- }
- }
- };
- }
- // MyForm.cpp
- #include <fstream>
- #include <sstream>
- #include <vector>
- #include "Matrix.h"
- #include "Transform.h"
- #include "Figure.h"
- #include "Clip.h"
- #include "MyForm.h"
- using namespace System;
- using namespace System::Windows::Forms;
- [STAThreadAttribute]
- void Main(cli::array<String^>^ args) {
- Application::EnableVisualStyles();
- Application::SetCompatibleTextRenderingDefault(false);
- Moskvitin::MyForm form;
- Application::Run(% form);
- }
Add Comment
Please, Sign In to add comment