Добавил:
надеюсь это добро кому-то поможет Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
практика лето 25 Программирование графического интерфейса и основы визуализации структур данных.docx
Скачиваний:
0
Добавлен:
09.07.2025
Размер:
4.9 Mб
Скачать
  1. Ввод координат

textBoxCenterX -ввод координаты Х

textBoxCenterY - ввод координаты Y

Свойство

Значение

Значение

Text

400

300

Size

60 x 26

60 x 26

Location

X = 1117, Y = 126

X = 1117, Y = 164

  1. Выпадающие списки

comboBoxLineWidth - Выбор толщины линии

comboBoxLineStyle - Выбор стиля траектории

ComboBoxWidth - выбор ширины траектории

Свойство

Значение

Значение

Значение

Items

1, 2, 3, 4, 5

Непрерывная, Пунктирная, Точка-Тире

1, 2, 3, 4, 5, 6, 8, 10

Location

X = 1015, Y = 329

X = 1197, Y = 329

X = 1353, Y = 329

DropDownStyle

DropDownList

DropDownList

DropDownList

  1. Меню выбора цветов MenuStrip

Свойство

Значение

Name

menuStrip1

Size

Width: 1012, Height: 33

Items

"Цвета" — содержит три подпункта:

FillColorToolStripMenuItem — Цвет заливки - Выбор цвета заливки шестиугольника borderColorToolStripMenuItem — Цвет контура - Выбор цвета границы шестиугольника

trajectoryColorToolStripMenuItem - Цвет траектории - Выбор цвета траектории

  1. Системные компоненты

Thread — отдельный поток animationThread для анимации

List<PointF> — коллекции для хранения координат (eggPoints) и длины (cumulativeDistances)

Описание используемых графических примитивов:

  1. Кривая траектории яйца Хюгельшеффера

Примитив: Graphics::DrawClosedCurve(Pen^, array<PointF>^) - для отрисовки кривой по списку точек.

Точки генерируются с шагом 0.01 вдоль оси Х и преобразуются в координаты, которые образуют кривую, автоматически сглаженную с помощью DrawClosedCurve.

  1. Движущийся объект - шестиугольник

Примитивы:

Graphics::FillPolygon(Brush^, array<PointF>^) — заливка

Graphics::DrawPolygon(Pen^, array<PointF>^) — контур

Рисует правильный шестиугольник с центром с текущей позиции на траектории. Цвет заливки: пользовательский (hexagonFillColor)

Цвет контура: пользовательский (hexagonBorderColor)

  1. Фон

Примитив: Graphics::Clear(Color::White)

Для того чтобы избежать наложения старых изображений при новой отрисовке, фон очищается.

Текст программы:

MyForm.h

#pragma once

#include <cmath>

namespace IDZ1 {

using namespace System;

using namespace System::ComponentModel;

using namespace System::Collections;

using namespace System::Windows::Forms; //визуалка

using namespace System::Drawing; //отрисовка

using namespace System::Threading; //потоки анимация

public ref class MyForm : public System::Windows::Forms::Form

{ public:

MyForm(void)

{ InitializeComponent(); textBoxCenterX->Text = (pictureBox1->Width / 2).ToString();

textBoxCenterY->Text = (pictureBox1->Height / 2).ToString(); InitializeApp(); }

protected:

~MyForm()

{ if (components)delete components; StopAnimation();}

private:

System::Windows::Forms::PictureBox^ pictureBox1; //перем интерфейса

System::Windows::Forms::Button^ buttonStart;

System::Windows::Forms::Button^ buttonStop;

System::Windows::Forms::Label^ labelTitle;

System::Windows::Forms::Label^ labelSpeed;

System::Windows::Forms::TrackBar^ trackBarSpeed;

System::Windows::Forms::Button^ buttonDirection;

System::Windows::Forms::MenuStrip^ menuStrip1;

System::Windows::Forms::ToolStripMenuItem^ colorsToolStripMenuItem; //подменюшки к заданию вар 4

System::Windows::Forms::ToolStripMenuItem^ fillColorToolStripMenuItem;

System::Windows::Forms::ToolStripMenuItem^ borderColorToolStripMenuItem;

System::ComponentModel::Container^ components;

//ввод центра

System::Windows::Forms::TextBox^ textBoxCenterX;

System::Windows::Forms::TextBox^ textBoxCenterY;

System::Windows::Forms::Label^ labelCenterX;

System::Windows::Forms::Label^ labelCenterY;

System::Windows::Forms::Button^ buttonUpdateCenter;

System::Collections::Generic::List<PointF>^ eggPoints;

System::Collections::Generic::List<float>^ cumulativeDistances;

Thread^ animationThread;

bool isMoving; float currentDistance; float speed; float totalLength; bool clockwise;

Color hexagonFillColor;Color hexagonBorderColor;

System::Windows::Forms::Label^ labelSize;

System::Windows::Forms::TrackBar^ trackBarSize; float hexagonSize;

System::Windows::Forms::ComboBox^ comboBoxLineWidth;

System::Windows::Forms::Label^ labelLineWidth; float borderWidth;

System::Windows::Forms::ComboBox^ comboBoxLineStyle;

System::Windows::Forms::Label^ label1;

System::Drawing::Drawing2D::DashStyle currentLineStyle;

System::Windows::Forms::Button^ buttonRotate;

float hexagonRotationAngle; // угол в градусах bool isRotating;

System::Windows::Forms::Label^ labelRotationSpeed;

System::Windows::Forms::TrackBar^ trackBarRotationSpeed;

bool isPulsating = false; bool pulsateIncreasing = true; float minSize = 10.0f; float maxSize = 50.0f;

float pulsateStep = 0.5f;

System::Windows::Forms::Button^ buttonPulse;

System::Windows::Forms::Label^ labelPulsateSpeed;

System::Windows::Forms::TrackBar^ trackBarPulsateSpeed;float pulsateStep2 = 0.5f; int rotationSpeed;

void InitializeApp()

{eggPoints = gcnew System::Collections::Generic::List<PointF>();

cumulativeDistances = gcnew System::Collections::Generic::List<float>();

isMoving = false; currentDistance = 0.0f;speed = 2.0f; clockwise = true;

hexagonFillColor = Color::Blue; hexagonBorderColor = Color::DarkBlue;

trackBarSpeed->Minimum = 1; trackBarSpeed->Maximum = 10; trackBarSpeed->Value = (int)speed;

trackBarSpeed->TickFrequency = 1; labelSpeed->Text = String::Format("Скорость: {0}", speed);

buttonDirection->Text = L"Против часовой";

hexagonSize = 20.0f; trackBarSize->Minimum = 10; trackBarSize->Maximum = 50;

trackBarSize->Value = (int)hexagonSize;trackBarSize->TickFrequency = 5;

labelSize->Text = String::Format("Размер: {0}", hexagonSize);borderWidth = 2.0f;

currentLineStyle = System::Drawing::Drawing2D::DashStyle::Solid;

//кручение

hexagonRotationAngle = 0.0f; isRotating = false; rotationSpeed = 5;DrawHugelschafferEgg(); }

void DrawHugelschafferEgg()

{if (pictureBox1->Width == 0 || pictureBox1->Height == 0) return;

int centerX, centerY;

if (!Int32::TryParse(textBoxCenterX->Text, centerX)) centerX = pictureBox1->Width / 2;

if (!Int32::TryParse(textBoxCenterY->Text, centerY)) centerY = pictureBox1->Height / 2;

Bitmap^ bmp = gcnew Bitmap(pictureBox1->Width, pictureBox1->Height);

Graphics^ g = Graphics::FromImage(bmp);

g->Clear(Color::White);

g->SmoothingMode = System::Drawing::Drawing2D::SmoothingMode::AntiAlias;

const float scale = 30.0f;const float step = 0.01f;

eggPoints->Clear();cumulativeDistances->Clear();

GenerateEggPoints(scale, step, centerX, centerY);

if (eggPoints->Count > 0) eggPoints->Add(eggPoints[0]); CalculateCumulativeDistances();DrawCurrentPosition();}

void GenerateEggPoints(float scale, float step, int centerX, int centerY)

{ for (float x = -10.0f; x <= 12.0f; x += step) // увеличенный диапазон AddEggPoint(x, scale, centerX, centerY, -1.0f);

for (float x = 12.0f; x >= -10.0f; x -= step) AddEggPoint(x, scale, centerX, centerY, 1.0f);}

void AddEggPoint(float x, float scale, int centerX, int centerY, float yMultiplier)

{float denominator = 25.0f + 2.0f * x; if (denominator <= 0.0f) return;float numerator = 36.0f - (x - 1.0f) * (x - 1.0f);

if (numerator < 0.0f) return; float y = 4.0f * Math::Sqrt(numerator / denominator) * yMultiplier;

float plotX = centerX + x * scale; float plotY = centerY + y * scale; eggPoints->Add(PointF(plotX, plotY));}

void CalculateCumulativeDistances()

{ cumulativeDistances->Clear(); if (eggPoints->Count == 0) return; cumulativeDistances->Add(0.0f); totalLength = 0.0f;

for (int i = 1; i < eggPoints->Count; i++)

{float dx = eggPoints[i].X - eggPoints[i - 1].X; //ро между точками

float dy = eggPoints[i].Y - eggPoints[i - 1].Y;float distance = (float)Math::Sqrt(dx * dx + dy * dy);

totalLength += distance; cumulativeDistances->Add(totalLength);//в список ее}}

void DrawHexagon(Graphics^ g, PointF center)

{ g->TranslateTransform(center.X, center.Y); g->RotateTransform(hexagonRotationAngle);

g->TranslateTransform(-center.X, -center.Y);

array<PointF>^ points = gcnew array<PointF>(6); //массив 6 точек

for (int i = 0; i < 6; i++){float angle = (float)(Math::PI / 3 * i); points[i] = PointF(

center.X + hexagonSize * (float)Math::Cos(angle), center.Y + hexagonSize * (float)Math::Sin(angle) );}

g->FillPolygon(gcnew SolidBrush(hexagonFillColor), points);

g->DrawPolygon(gcnew Pen(hexagonBorderColor, borderWidth), points);}

void DrawEggWithHexagon(Graphics^ g, PointF hexagonPosition)

{g->Clear(Color::White);

if (eggPoints->Count > 1) { Pen^ eggPen = gcnew Pen(Color::Black, 2); eggPen->DashStyle = currentLineStyle;

g->DrawClosedCurve(eggPen, eggPoints->ToArray()); }

//шестиугольник даже если он за границами DrawHexagon(g, hexagonPosition);}

void DrawCurrentPosition()

{ if (eggPoints->Count == 0 || cumulativeDistances->Count == 0) return;

int segment = FindCurrentSegment(currentDistance);

PointF position = CalculateHexagonPosition(segment, currentDistance);

Bitmap^ bmp = gcnew Bitmap(pictureBox1->Width, pictureBox1->Height);

Graphics^ g = Graphics::FromImage(bmp);DrawEggWithHexagon(g, position);pictureBox1->Image = bmp;}

void AnimateHexagon()

{while (isMoving)

{ this->Invoke(gcnew Action(this, &MyForm::UpdateHexagonPosition)); //обновление позиции на потоке

Thread::Sleep(30); //чтобы плавненько}}

void UpdateHexagonPosition()

{if (eggPoints->Count == 0 || cumulativeDistances->Count == 0) return; currentDistance += clockwise ? speed : -speed;

if (currentDistance > totalLength) currentDistance -= totalLength;

else if (currentDistance < 0) currentDistance += totalLength;

if (isRotating)

{ hexagonRotationAngle += rotationSpeed;if (hexagonRotationAngle >= 360.0f) hexagonRotationAngle -= 360.0f;}

if (isPulsating)

{if (pulsateIncreasing)

{ hexagonSize += pulsateStep2; if (hexagonSize >= maxSize){hexagonSize = maxSize;pulsateIncreasing = false;}}

else

{hexagonSize -= pulsateStep2;if (hexagonSize <= minSize) {hexagonSize = minSize;pulsateIncreasing = true;}}

labelSize->Text = String::Format("Размер: {0}", hexagonSize);}DrawCurrentPosition(); }

int FindCurrentSegment(float distance) //интервал на котором будем строить

{int segment = 0;while (segment < cumulativeDistances->Count - 1 &&

cumulativeDistances[segment + 1] < distance){ segment++;}return segment;}

PointF CalculateHexagonPosition(int segment, float distance) //текущая координата для объ

{float segStart = cumulativeDistances[segment]; float segEnd = (segment < cumulativeDistances->Count - 1) ?

cumulativeDistances[segment + 1] : totalLength;float t = (distance - segStart) / (segEnd - segStart);

if (segment < eggPoints->Count - 1) //линейная интерполяция

{ return PointF(eggPoints[segment].X + t * (eggPoints[segment + 1].X - eggPoints[segment].X),

eggPoints[segment].Y + t * (eggPoints[segment + 1].Y - eggPoints[segment].Y)); }return eggPoints[0];}

void StartAnimation()

{if (!isMoving && eggPoints->Count > 0)

{isMoving = true;

animationThread = gcnew Thread(gcnew ThreadStart(this, &MyForm::AnimateHexagon)); //поток

animationThread->Start();} }

void StopAnimation()

{isMoving = false;

if (animationThread != nullptr){animationThread->Join(); //завершение и сбросanimationThread = nullptr;}}

void UpdateHexagonColors()

{ if (!isMoving && eggPoints->Count > 0){DrawCurrentPosition();}}

void SetFillColor(Color color)

{hexagonFillColor = color;UpdateHexagonColors(); }

void SetBorderColor(Color color)

{ hexagonBorderColor = color;UpdateHexagonColors();}

Void comboBoxLineStyle_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e) {

switch (comboBoxLineStyle->SelectedIndex) {

case 0: // Непрерывная currentLineStyle = System::Drawing::Drawing2D::DashStyle::Solid;break;

case 1: // Пунктирная currentLineStyle = System::Drawing::Drawing2D::DashStyle::Dash; break;

case 2: // Точка-Тире currentLineStyle = System::Drawing::Drawing2D::DashStyle::DashDotDot;break;

default: currentLineStyle = System::Drawing::Drawing2D::DashStyle::Solid;break;} DrawCurrentPosition(); }

pragma endregion обработчки событий

private:

System::Void buttonStart_Click(System::Object^ sender, System::EventArgs^ e) {

StartAnimation();}

System::Void buttonStop_Click(System::Object^ sender, System::EventArgs^ e) {

StopAnimation(); }

System::Void trackBarSpeed_ValueChanged(System::Object^ sender, System::EventArgs^ e) {

speed = trackBarSpeed->Value;

labelSpeed->Text = String::Format("Скорость: {0}", speed); }

System::Void buttonDirection_Click(System::Object^ sender, System::EventArgs^ e) {

clockwise = !clockwise;

buttonDirection->Text = clockwise ? L"Против часовой" : L"По часовой";

DrawCurrentPosition(); }

System::Void fillColorToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) {

ColorDialog^ colorDialog = gcnew ColorDialog();

colorDialog->Color = hexagonFillColor;

if (colorDialog->ShowDialog() == System::Windows::Forms::DialogResult::OK)

SetFillColor(colorDialog->Color);}

System::Void borderColorToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) {

ColorDialog^ colorDialog = gcnew ColorDialog();

colorDialog->Color = hexagonBorderColor;

if (colorDialog->ShowDialog() == System::Windows::Forms::DialogResult::OK)

SetBorderColor(colorDialog->Color); }

System::Void trackBarSize_ValueChanged(System::Object^ sender, System::EventArgs^ e) {

hexagonSize = trackBarSize->Value;

labelSize->Text = String::Format("Размер: {0}", hexagonSize);

DrawCurrentPosition(); }

System::Void buttonUpdateCenter_Click(System::Object^ sender, System::EventArgs^ e) {

StopAnimation();

currentDistance = 0.0f;

DrawHugelschafferEgg();}

System::Void comboBoxLineWidth_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e) {

int selected = comboBoxLineWidth->SelectedIndex + 1;

borderWidth = (float)selected;

DrawCurrentPosition(); }

System::Void buttonRotate_Click(System::Object^ sender, System::EventArgs^ e) {

isRotating = !isRotating;

buttonRotate->Text = isRotating ? L"Стоп вращение" : L"Вращать"; }

System::Void trackBarRotationSpeed_ValueChanged(System::Object^ sender, System::EventArgs^ e) {

rotationSpeed = trackBarRotationSpeed->Value;

labelRotationSpeed->Text = String::Format("Скорость вращения: {0}", rotationSpeed); }

System::Void buttonPulse_Click(System::Object^ sender, System::EventArgs^ e) {

isPulsating = !isPulsating;

buttonPulse->Text = isPulsating ? L"Без пульсации" : L"Пульсация"; }

System::Void trackBarPulsateSpeed_ValueChanged(System::Object^ sender, System::EventArgs^ e)

{ pulsateStep2 = trackBarPulsateSpeed->Value * 0.1f;

labelPulsateSpeed->Text = String::Format("Скорость пульсации: {0:F1}", pulsateStep2);}};}

Main.cpp

#include "MyForm.h"

using namespace System;

using namespace System::Windows::Forms;

[STAThread]

int main(array<String^>^ args)

{

Application::EnableVisualStyles();

Application::SetCompatibleTextRenderingDefault(false);

IDZ1::MyForm form;

Application::Run(% form);

return 0;

}