"#pragma once #define WIN32_LEAN_AND_MEAN #include...
作成日: 2025年11月25日
使用モデル GPT-5.1 Thinking by Chat01
作成日: 2025年11月25日
使用モデル GPT-5.1 Thinking by Chat01
"#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;
using namespace System::Drawing::Drawing2D;
using namespace System::Diagnostics;
using namespace System::Globalization;
typedef void(__cdecl* P_MANIP)(int, bool, float, float, float, int, int, float, bool, float, unsigned int, float**, size_t*, float*, float*, float*, size_t*, float*);
typedef void(__cdecl* P_FREE)(float*);
typedef void(__cdecl* P_START)(int, bool, float, float, float, int, int, float, bool, float, unsigned int);
namespace TESTAGP {
textpublic enum class OptimizerBackend { AgpCpp = 0, Optuna = 1, IOpt = 2 }; public ref class MyForm : public Form { public: MyForm(HMODULE hLib) : hLib(hLib) { this->SetStyle(ControlStyles::AllPaintingInWmPaint | ControlStyles::UserPaint | ControlStyles::OptimizedDoubleBuffer, true); this->Text = L"AGP Manipulator 2D"; this->ClientSize = System::Drawing::Size(1200, 800); this->Resize += gcnew EventHandler(this, &MyForm::OnResize); fManip = reinterpret_cast<P_MANIP>(GetProcAddress(hLib, "AGP_Manip2D")); pFree = reinterpret_cast<P_FREE>(GetProcAddress(hLib, "AGP_Free")); pStart = reinterpret_cast<P_START>(GetProcAddress(hLib, "AgpStartManipND")); angles = gcnew List<float>(0); lengths = gcnew List<float>(0); backend = OptimizerBackend::AgpCpp; InitUI(); ResetRandomConfig(); } private: initonly HMODULE hLib; initonly P_MANIP fManip; initonly P_FREE pFree; initonly P_START pStart; OptimizerBackend backend; ComboBox^ cbBackend; int nSegments; bool variableLengths; List<float>^ angles; List<float>^ lengths; CheckBox^ cbVarLen; NumericUpDown^ nudMinTheta; NumericUpDown^ nudBaseLength; NumericUpDown^ nudStretchFactor; NumericUpDown^ nudTargetX; NumericUpDown^ nudTargetY; NumericUpDown^ nudLevels; NumericUpDown^ nudMaxIter; CheckBox^ cbAdaptive; NumericUpDown^ nudR; NumericUpDown^ nudEps; Button^ btnAdd; Button^ btnRem; Button^ btnOptimize; Label^ lblInfo; System::UInt32 rngState = 0xA5C39E0Du; void InitUI() { cbBackend = gcnew ComboBox(); cbBackend->Location = Point(920, 52); cbBackend->Width = 260; // Увеличил ширину для лучшего отображения cbBackend->Height = 28; // Добавил высоту для согласованности cbBackend->DropDownStyle = ComboBoxStyle::DropDownList; cbBackend->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); // Размер 11 как у других элементов // Установим тот же цвет фона, что у других элементов cbBackend->BackColor = System::Drawing::SystemColors::Info; // Сделаем границу более заметной для согласованности cbBackend->FlatStyle = FlatStyle::Flat; cbBackend->Items->Add(L"AGP"); cbBackend->Items->Add(L"Optuna"); cbBackend->Items->Add(L"iOpt"); cbBackend->SelectedIndex = 0; cbBackend->SelectedIndexChanged += gcnew EventHandler(this, &MyForm::OnBackendChanged); this->Controls->Add(cbBackend); Label^ L; L = gcnew Label(); L->Text = L"Мин. угол (рад)"; L->Location = Point(20, 20); L->Width = 200; L->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); this->Controls->Add(L); nudMinTheta = gcnew NumericUpDown(); nudMinTheta->Location = Point(20, 52); nudMinTheta->Width = 200; nudMinTheta->DecimalPlaces = 3; nudMinTheta->Minimum = Decimal(1) / Decimal(100); nudMinTheta->Maximum = Decimal(314159) / Decimal(100000); nudMinTheta->Value = Decimal(150) / Decimal(100); nudMinTheta->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); nudMinTheta->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudMinTheta); L = gcnew Label(); L->Text = L"Базовая длина"; L->Location = Point(245, 20); L->Width = 200; L->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); this->Controls->Add(L); nudBaseLength = gcnew NumericUpDown(); nudBaseLength->Location = Point(245, 52); nudBaseLength->Width = 200; nudBaseLength->DecimalPlaces = 2; nudBaseLength->Minimum = Decimal(1) / Decimal(2); nudBaseLength->Maximum = Decimal(200) / Decimal(100); nudBaseLength->Value = Decimal(100) / Decimal(100); nudBaseLength->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); nudBaseLength->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudBaseLength); L = gcnew Label(); L->Text = L"Коэф. растяжения"; L->Location = Point(470, 20); L->Width = 200; L->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); this->Controls->Add(L); nudStretchFactor = gcnew NumericUpDown(); nudStretchFactor->Location = Point(470, 52); nudStretchFactor->Width = 200; nudStretchFactor->DecimalPlaces = 2; nudStretchFactor->Minimum = Decimal(100) / Decimal(100); nudStretchFactor->Maximum = Decimal(150) / Decimal(100); nudStretchFactor->Increment = Decimal(1) / Decimal(100); nudStretchFactor->Value = Decimal(150) / Decimal(100); nudStretchFactor->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); nudStretchFactor->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudStretchFactor); cbVarLen = gcnew CheckBox(); cbVarLen->Text = L"Переменные длины"; cbVarLen->Location = Point(695, 52); cbVarLen->Width = 200; cbVarLen->Checked = false; cbVarLen->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); cbVarLen->CheckedChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(cbVarLen); L = gcnew Label(); L->Text = L"Цель X"; L->Location = Point(20, 107); L->Width = 200; L->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); this->Controls->Add(L); nudTargetX = gcnew NumericUpDown(); nudTargetX->Location = Point(20, 139); nudTargetX->Width = 200; nudTargetX->DecimalPlaces = 2; nudTargetX->Minimum = Decimal(-100) / Decimal(10); nudTargetX->Maximum = Decimal(100) / Decimal(10); nudTargetX->Value = Decimal(25) / Decimal(10); nudTargetX->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); nudTargetX->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudTargetX); L = gcnew Label(); L->Text = L"Цель Y"; L->Location = Point(245, 107); L->Width = 200; L->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); this->Controls->Add(L); nudTargetY = gcnew NumericUpDown(); nudTargetY->Location = Point(245, 139); nudTargetY->Width = 200; nudTargetY->DecimalPlaces = 2; nudTargetY->Minimum = Decimal(-100) / Decimal(10); nudTargetY->Maximum = Decimal(100) / Decimal(10); nudTargetY->Value = Decimal(-10) / Decimal(10); nudTargetY->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); nudTargetY->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudTargetY); L = gcnew Label(); L->Text = L"Глубина развёрток"; L->Location = Point(470, 107); L->Width = 200; L->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); this->Controls->Add(L); nudLevels = gcnew NumericUpDown(); nudLevels->Location = Point(470, 139); nudLevels->Width = 200; nudLevels->Minimum = 7; nudLevels->Maximum = 20; nudLevels->Value = 12; nudLevels->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); nudLevels->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudLevels); L = gcnew Label(); L->Text = L"Надежность (r)"; L->Location = Point(695, 107); L->Width = 200; L->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); this->Controls->Add(L); nudR = gcnew NumericUpDown(); nudR->Location = Point(695, 139); nudR->Width = 200; nudR->DecimalPlaces = 2; nudR->Minimum = Decimal(100) / Decimal(100); nudR->Maximum = Decimal(2000) / Decimal(100); nudR->Value = Decimal(250) / Decimal(100); nudR->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); nudR->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudR); cbAdaptive = gcnew CheckBox(); cbAdaptive->Text = L"Адаптивная схема"; cbAdaptive->Location = Point(920, 139); cbAdaptive->Width = 200; cbAdaptive->Checked = true; cbAdaptive->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); cbAdaptive->CheckedChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(cbAdaptive); L = gcnew Label(); L->Text = L"Точность"; L->Location = Point(20, 194); L->Width = 200; L->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); this->Controls->Add(L); nudEps = gcnew NumericUpDown(); nudEps->Location = Point(20, 226); nudEps->Width = 200; nudEps->DecimalPlaces = 9; nudEps->Minimum = Decimal(1) / Decimal(1000000000); nudEps->Maximum = Decimal(1) / Decimal(10); nudEps->Value = Decimal(1) / Decimal(100000); nudEps->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); nudEps->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudEps); L = gcnew Label(); L->Text = L"Макс. итераций"; L->Location = Point(245, 194); L->Width = 200; L->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); this->Controls->Add(L); nudMaxIter = gcnew NumericUpDown(); nudMaxIter->Location = Point(245, 226); nudMaxIter->Width = 200; nudMaxIter->Minimum = 10; nudMaxIter->Maximum = 500000; nudMaxIter->Value = 1000; nudMaxIter->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); nudMaxIter->Increment = 100; nudMaxIter->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudMaxIter); btnAdd = gcnew Button(); btnAdd->Text = L"+ Звено"; btnAdd->Location = Point(465, 226); btnAdd->Width = 90; btnAdd->Height = 35; btnAdd->BackColor = System::Drawing::SystemColors::Info; btnAdd->Cursor = Cursors::Hand; btnAdd->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnAdd->FlatAppearance->BorderSize = 3; btnAdd->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnAdd->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnAdd->FlatStyle = FlatStyle::Flat; btnAdd->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); btnAdd->ForeColor = System::Drawing::SystemColors::ControlDarkDark; btnAdd->Click += gcnew EventHandler(this, &MyForm::OnAddClick); this->Controls->Add(btnAdd); btnRem = gcnew Button(); btnRem->Text = L"- Звено"; btnRem->Location = Point(560, 226); btnRem->Width = 90; btnRem->Height = 35; btnRem->BackColor = System::Drawing::SystemColors::Info; btnRem->Cursor = Cursors::Hand; btnRem->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnRem->FlatAppearance->BorderSize = 3; btnRem->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnRem->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnRem->FlatStyle = FlatStyle::Flat; btnRem->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); btnRem->ForeColor = System::Drawing::SystemColors::ControlDarkDark; btnRem->Click += gcnew EventHandler(this, &MyForm::OnRemClick); this->Controls->Add(btnRem); btnOptimize = gcnew Button(); btnOptimize->Text = L"Оптимизировать"; btnOptimize->Location = Point(680, 226); btnOptimize->Width = 150; btnOptimize->Height = 35; btnOptimize->BackColor = System::Drawing::SystemColors::Info; btnOptimize->Cursor = Cursors::Hand; btnOptimize->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnOptimize->FlatAppearance->BorderSize = 3; btnOptimize->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnOptimize->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnOptimize->FlatStyle = FlatStyle::Flat; btnOptimize->Font = gcnew System::Drawing::Font("Yu Gothic UI", 11, FontStyle::Bold); btnOptimize->ForeColor = System::Drawing::SystemColors::ControlDarkDark; btnOptimize->Click += gcnew EventHandler(this, &MyForm::OnOptimizeClick); this->Controls->Add(btnOptimize); lblInfo = gcnew Label(); lblInfo->Location = Point(835, 194); lblInfo->Size = System::Drawing::Size(335, 140); lblInfo->BorderStyle = BorderStyle::FixedSingle; lblInfo->Text = L"Готов"; lblInfo->Font = gcnew System::Drawing::Font("Yu Gothic UI", 10, FontStyle::Bold); this->Controls->Add(lblInfo); } void ResetRandomConfig() { nSegments = 1; angles->Clear(); lengths->Clear(); angles->Add(1.57079637f); lengths->Add(static_cast<float>(nudBaseLength->Value)); variableLengths = false; this->Invalidate(); } float Rand01() { rngState ^= rngState << 13; rngState ^= rngState >> 17; rngState ^= rngState << 5; return static_cast<float>(static_cast<double>(static_cast<unsigned int>(rngState)) / 4294967296.0); } float RandAngle() { return (Rand01() * 6.28318548f) - 3.14159274f; } void RunAgpCpp() { variableLengths = cbVarLen->Checked; float minTheta = static_cast<float>(nudMinTheta->Value); float tx = static_cast<float>(nudTargetX->Value); float ty = static_cast<float>(nudTargetY->Value); int levels = static_cast<int>(nudLevels->Value); int maxIter = static_cast<int>(nudMaxIter->Value); bool adaptive = cbAdaptive->Checked; float r_param = static_cast<float>(nudR->Value); float eps = static_cast<float>(nudEps->Value); unsigned int seed = static_cast<unsigned int>(GetTickCount()); pStart(nSegments, variableLengths, minTheta, tx, ty, levels, maxIter, r_param, adaptive, eps, seed); LARGE_INTEGER t0, t1, fq; QueryPerformanceCounter(&t0); float* bestQ = nullptr; size_t bestQLen = 0; float bestX = 0.0f; float bestY = 0.0f; float bestF = 0.0f; size_t actualIterations = 0u; float achievedEps = 0.0f; fManip(nSegments, variableLengths, minTheta, tx, ty, levels, maxIter, r_param, adaptive, eps, seed, &bestQ, &bestQLen, &bestX, &bestY, &bestF, &actualIterations, &achievedEps); QueryPerformanceCounter(&t1); QueryPerformanceFrequency(&fq); double micros = 1e6 * static_cast<double>(t1.QuadPart - t0.QuadPart) / static_cast<double>(fq.QuadPart); angles->Clear(); for (int i = 0; i < nSegments; ++i) { angles->Add(bestQ[i]); } if (variableLengths) { lengths->Clear(); for (int i = 0; i < nSegments; ++i) { lengths->Add(bestQ[nSegments + i]); } } else { lengths->Clear(); for (int i = 0; i < nSegments; ++i) { lengths->Add(static_cast<float>(nudBaseLength->Value)); } } pFree(bestQ); float dx = bestX - tx; float dy = bestY - ty; lblInfo->Text = String::Format( L"Результат:\n" L"Близость захвата: {0:F5}\n" L"Функционал: {1:F5}\n" L"Точка: ({2:F3}, {3:F3})\n" L"Время: {4:F0} мкс\n" L"Число шагов: {5}\n" L"Достигнутая точность: {6:E3}", System::Math::Sqrt(dx * dx + dy * dy), bestF, bestX, bestY, micros, actualIterations, achievedEps); this->Invalidate(); } bool ParseFloat(String^ s, float% out) { return Single::TryParse( s, NumberStyles::Float, CultureInfo::InvariantCulture, out); } void RunPythonBackend(String^ which) { int nSeg = nSegments; bool varLen = cbVarLen->Checked; float minTheta = static_cast<float>(nudMinTheta->Value); float tx = static_cast<float>(nudTargetX->Value); float ty = static_cast<float>(nudTargetY->Value); int levels = static_cast<int>(nudLevels->Value); int maxIter = static_cast<int>(nudMaxIter->Value); float r_param = static_cast<float>(nudR->Value); float eps = static_cast<float>(nudEps->Value); bool adaptive = cbAdaptive->Checked; // Добавляем состояние чекбокса String^ pythonExe = System::IO::Path::Combine( Application::StartupPath, "env", "Scripts", "python.exe"); String^ scriptPath = System::IO::Path::Combine( Application::StartupPath, "optimizer_bridge.py"); ProcessStartInfo^ psi = gcnew ProcessStartInfo(); psi->FileName = pythonExe; // Добавляем adaptive как 11-й параметр psi->Arguments = String::Format( CultureInfo::InvariantCulture, "\"{0}\" {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11}", scriptPath, which, nSeg, varLen ? 1 : 0, minTheta, tx, ty, levels, maxIter, r_param, eps, adaptive ? 1 : 0 // Передаем 1 или 0 ); // Остальной код без изменений... psi->UseShellExecute = false; psi->CreateNoWindow = true; psi->RedirectStandardOutput = true; psi->RedirectStandardError = false; psi->WorkingDirectory = Application::StartupPath; Process^ proc = Process::Start(psi); String^ stdoutAll = proc->StandardOutput->ReadToEnd(); proc->WaitForExit(); float bestF = 0.0f; float bestX = 0.0f; float bestY = 0.0f; float achievedEps = 0.0f; int iterations = 0; float micros = 0.0f; array<float>^ tempAngles = gcnew array<float>(nSeg); array<float>^ tempLengths = gcnew array<float>(nSeg); for (int i = 0; i < nSeg; ++i) { tempAngles[i] = 0.0f; tempLengths[i] = static_cast<float>(nudBaseLength->Value); } array<String^>^ lines = stdoutAll->Split( gcnew array<wchar_t>{ '\r', '\n' }, StringSplitOptions::RemoveEmptyEntries); int qIndex = 0; for each (String ^ line in lines) { array<String^>^ parts = line->Split( gcnew array<wchar_t>{ ' ', '\t' }, StringSplitOptions::RemoveEmptyEntries); String^ key = parts[0]; if (key == "Q") { for (int i = 1; i < parts->Length && qIndex < (varLen ? 2 * nSeg : nSeg); ++i) { float qVal; if (ParseFloat(parts[i], qVal)) { if (qIndex < nSeg) { tempAngles[qIndex] = qVal; } else if (varLen && qIndex < 2 * nSeg) { tempLengths[qIndex - nSeg] = qVal; } ++qIndex; } } } else { String^ value = parts[1]; if (key == "BEST_F") { ParseFloat(value, bestF); } else if (key == "BEST_X") { ParseFloat(value, bestX); } else if (key == "BEST_Y") { ParseFloat(value, bestY); } else if (key == "ITERATIONS") { Int32::TryParse(value, iterations); } else if (key == "EPS") { ParseFloat(value, achievedEps); } else if (key == "TIME") { ParseFloat(value, micros); } } } angles->Clear(); lengths->Clear(); for (int i = 0; i < nSeg; ++i) { angles->Add(tempAngles[i]); lengths->Add(tempLengths[i]); } String^ anglesStr = ""; for each (float angle in angles) { anglesStr += angle.ToString("F3") + ", "; } anglesStr = anglesStr->TrimEnd(',', ' '); String^ lengthsStr = ""; for each (float length in lengths) { lengthsStr += length.ToString("F3") + ", "; } lengthsStr = lengthsStr->TrimEnd(',', ' '); float dx = bestX - tx; float dy = bestY - ty; double distance = Math::Sqrt(dx * dx + dy * dy); String^ resultText = String::Format( L"Результат:\n" L"Близость захвата: {0:F5}\n" L"Функционал: {1:F5}\n" L"Точка: ({2:F3}, {3:F3})\n" L"Время: {4:F0} мкс\n" L"Число шагов: {5}\n" L"Достигнутая точность: {6:E3}", distance, bestF, bestX, bestY, micros, iterations, achievedEps); lblInfo->Text = resultText; this->Invalidate(); this->Refresh(); } System::Void OnBackendChanged(System::Object^ sender, System::EventArgs^ e) { switch (cbBackend->SelectedIndex) { case 0: backend = OptimizerBackend::AgpCpp; cbAdaptive->Enabled = true; break; case 1: backend = OptimizerBackend::Optuna; cbAdaptive->Enabled = false; break; case 2: backend = OptimizerBackend::IOpt; cbAdaptive->Enabled = true; break; default: backend = OptimizerBackend::AgpCpp; cbAdaptive->Enabled = true; break; } } System::Void OnResize(System::Object^ sender, System::EventArgs^ e) { this->Invalidate(); } System::Void OnAnyChanged(System::Object^ sender, System::EventArgs^ e) { this->Invalidate(); } System::Void OnAddClick(System::Object^ sender, System::EventArgs^ e) { ++nSegments; angles->Add(RandAngle()); lengths->Add(static_cast<float>(nudBaseLength->Value)); this->Invalidate(); } System::Void OnRemClick(System::Object^ sender, System::EventArgs^ e) { if (nSegments > 1) { --nSegments; angles->RemoveAt(angles->Count - 1); lengths->RemoveAt(lengths->Count - 1); this->Invalidate(); } } System::Void OnOptimizeClick(System::Object^ sender, System::EventArgs^ e) { switch (backend) { case OptimizerBackend::AgpCpp: RunAgpCpp(); break; case OptimizerBackend::Optuna: RunPythonBackend(L"optuna"); break; case OptimizerBackend::IOpt: RunPythonBackend(L"iopt"); break; } } protected: virtual void OnPaint(PaintEventArgs^ e) override { Form::OnPaint(e); Graphics^ g = e->Graphics; g->SmoothingMode = System::Drawing::Drawing2D::SmoothingMode::HighQuality; g->Clear(this->BackColor); System::Drawing::Rectangle drawArea = System::Drawing::Rectangle(0, 180, this->ClientSize.Width, 620); g->FillRectangle(Brushes::White, drawArea); int leftWallX = drawArea.Left + this->ClientSize.Width * 25 / 100; Pen^ wallPen = gcnew Pen(Color::Black, 2); g->DrawLine(wallPen, leftWallX, drawArea.Top, leftWallX, drawArea.Bottom); HatchBrush^ hatchBrush = gcnew HatchBrush(HatchStyle::BackwardDiagonal, Color::LightGray, Color::White); g->FillRectangle(hatchBrush, leftWallX - 100, drawArea.Top, 100, drawArea.Height); float targetX = static_cast<float>(nudTargetX->Value); float targetY = static_cast<float>(nudTargetY->Value); int baseX = leftWallX; int baseY = drawArea.Top + 310; float pixelTargetX = static_cast<float>(baseX) + targetX * 160.0f; float pixelTargetY = static_cast<float>(baseY) - targetY * 160.0f; int rightWallX = static_cast<int>(pixelTargetX + 8.0f); rightWallX = Math::Min(rightWallX, drawArea.Right - 10); Pen^ dashedPen = gcnew Pen(Color::Black, 2); dashedPen->DashStyle = DashStyle::Dash; g->DrawLine(dashedPen, rightWallX, drawArea.Top, rightWallX, drawArea.Bottom); g->FillRectangle(hatchBrush, rightWallX, drawArea.Top, 100, drawArea.Height); Pen^ targetPen = gcnew Pen(Color::Green, 3.0f); targetPen->DashStyle = DashStyle::Dot; g->DrawEllipse(targetPen, pixelTargetX - 8.0f, pixelTargetY - 8.0f, 16.0f, 16.0f); cli::array<PointF>^ pts = gcnew cli::array<PointF>(nSegments + 1); pts[0] = PointF(static_cast<float>(baseX), static_cast<float>(baseY)); float x = 0.0f; float y = 0.0f; float phi = 0.0f; array<float>^ anglesArray = angles->ToArray(); array<float>^ lengthsArray = lengths->ToArray(); for (int i = 0; i < nSegments; ++i) { float theta = anglesArray[i]; float L = lengthsArray[i]; phi += theta; x += L * static_cast<float>(Math::Cos(static_cast<double>(phi))); y += L * static_cast<float>(Math::Sin(static_cast<double>(phi))); pts[i + 1] = PointF(static_cast<float>(baseX) + x * 160.0f, static_cast<float>(baseY) - y * 160.0f); } Pen^ penRod = gcnew Pen(Color::Red, 6.0f); for (int i = 0; i < nSegments; ++i) { g->DrawLine(penRod, pts[i], pts[i + 1]); } SolidBrush^ brJoint = gcnew SolidBrush(Color::Blue); for (int i = 0; i <= nSegments; ++i) { g->FillEllipse(brJoint, pts[i].X - 8.0f, pts[i].Y - 8.0f, 16.0f, 16.0f); } delete wallPen; delete dashedPen; delete targetPen; delete penRod; delete brJoint; delete hatchBrush; } };
}" - код интерфейса c++/clr приложения, всё написано корректно и работает как надо, проведи рефакторинг, удали неиспользуемые блоки кода или диррективы или включения, немного безопасной оптимизации для скорости работы интерфейса, старайся не вносить радикальных изменений - главное сохранить функционал, но если видишь лазейки для безопасной оптимизации по скорости - применяй агрессивные низкоуровневые трюки и другие методы для оптимизации кода по скорости, можно улучшить локальность данных - размещая однотипные данные рядом, можно помечать методы специальными диррективами для агрессивной оптимизации компилятором, можно помечать переменные и методы как константные, применять ключевые слова как final для классов и структур, инлайнинг и т д, от бессмысленных проверок которые скорее всего выполняются так как код работает можно отказаться так как это уже релиз версия и сейчас важна скорость - а лишние проверки которые скорее выполнены могут замедлять, мне приведи полный оптимизированный отрефакторенный код без пропусков, отредактированный в стенфордском стиле без комментариев, думай дольше для ответа удовлетворяющего всем моим требованиям
Вот полностью отрефакторенный и слегка агрессивно оптимизированный вариант, в одном куске, без комментариев и с сохранением функционала:
cpp#pragma once #define WIN32_LEAN_AND_MEAN #include <Windows.h> using namespace System; using namespace System::Drawing; using namespace System::Windows::Forms; using namespace System::Collections::Generic; using namespace System::Drawing::Drawing2D; using namespace System::Diagnostics; using namespace System::Globalization; using namespace System::Runtime::CompilerServices; typedef void(__cdecl* P_MANIP)(int, bool, float, float, float, int, int, float, bool, float, unsigned int, float**, size_t*, float*, float*, float*, size_t*, float*); typedef void(__cdecl* P_FREE)(float*); typedef void(__cdecl* P_START)(int, bool, float, float, float, int, int, float, bool, float, unsigned int); namespace TESTAGP { public enum class OptimizerBackend { AgpCpp = 0, Optuna = 1, IOpt = 2 }; public ref class MyForm sealed : public Form { public: MyForm(HMODULE hLib) : hLib(hLib) { this->SetStyle(ControlStyles::AllPaintingInWmPaint | ControlStyles::UserPaint | ControlStyles::OptimizedDoubleBuffer, true); this->Text = L"AGP Manipulator 2D"; this->ClientSize = System::Drawing::Size(1200, 800); this->Resize += gcnew EventHandler(this, &MyForm::OnResize); fManip = reinterpret_cast<P_MANIP>(GetProcAddress(hLib, "AGP_Manip2D")); pFree = reinterpret_cast<P_FREE>(GetProcAddress(hLib, "AGP_Free")); pStart = reinterpret_cast<P_START>(GetProcAddress(hLib, "AgpStartManipND")); angles = gcnew List<float>(8); lengths = gcnew List<float>(8); backend = OptimizerBackend::AgpCpp; InitGraphicsResources(); InitUI(); ResetRandomConfig(); } private: initonly HMODULE hLib; initonly P_MANIP fManip; initonly P_FREE pFree; initonly P_START pStart; OptimizerBackend backend; ComboBox^ cbBackend; int nSegments; bool variableLengths; List<float>^ angles; List<float>^ lengths; CheckBox^ cbVarLen; NumericUpDown^ nudMinTheta; NumericUpDown^ nudBaseLength; NumericUpDown^ nudStretchFactor; NumericUpDown^ nudTargetX; NumericUpDown^ nudTargetY; NumericUpDown^ nudLevels; NumericUpDown^ nudMaxIter; CheckBox^ cbAdaptive; NumericUpDown^ nudR; NumericUpDown^ nudEps; Button^ btnAdd; Button^ btnRem; Button^ btnOptimize; Label^ lblInfo; UInt32 rngState = 0xA5C39E0Du; Font^ uiFontBold11; Font^ uiFontBold10; Pen^ wallPen; Pen^ dashedPen; Pen^ targetPen; Pen^ penRod; SolidBrush^ jointBrush; HatchBrush^ wallHatchBrush; void InitGraphicsResources() { uiFontBold11 = gcnew Font("Yu Gothic UI", 11, FontStyle::Bold); uiFontBold10 = gcnew Font("Yu Gothic UI", 10, FontStyle::Bold); wallPen = gcnew Pen(Color::Black, 2.0f); dashedPen = gcnew Pen(Color::Black, 2.0f); dashedPen->DashStyle = DashStyle::Dash; targetPen = gcnew Pen(Color::Green, 3.0f); targetPen->DashStyle = DashStyle::Dot; penRod = gcnew Pen(Color::Red, 6.0f); jointBrush = gcnew SolidBrush(Color::Blue); wallHatchBrush = gcnew HatchBrush(HatchStyle::BackwardDiagonal, Color::LightGray, Color::White); } void InitUI() { cbBackend = gcnew ComboBox(); cbBackend->Location = Point(920, 52); cbBackend->Width = 260; cbBackend->Height = 28; cbBackend->DropDownStyle = ComboBoxStyle::DropDownList; cbBackend->Font = uiFontBold11; cbBackend->BackColor = SystemColors::Info; cbBackend->FlatStyle = FlatStyle::Flat; cbBackend->Items->Add(L"AGP"); cbBackend->Items->Add(L"Optuna"); cbBackend->Items->Add(L"iOpt"); cbBackend->SelectedIndex = 0; cbBackend->SelectedIndexChanged += gcnew EventHandler(this, &MyForm::OnBackendChanged); this->Controls->Add(cbBackend); Label^ L; L = gcnew Label(); L->Text = L"Мин. угол (рад)"; L->Location = Point(20, 20); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudMinTheta = gcnew NumericUpDown(); nudMinTheta->Location = Point(20, 52); nudMinTheta->Width = 200; nudMinTheta->DecimalPlaces = 3; nudMinTheta->Minimum = Decimal(1) / Decimal(100); nudMinTheta->Maximum = Decimal(314159) / Decimal(100000); nudMinTheta->Value = Decimal(150) / Decimal(100); nudMinTheta->Font = uiFontBold10; nudMinTheta->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudMinTheta); L = gcnew Label(); L->Text = L"Базовая длина"; L->Location = Point(245, 20); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudBaseLength = gcnew NumericUpDown(); nudBaseLength->Location = Point(245, 52); nudBaseLength->Width = 200; nudBaseLength->DecimalPlaces = 2; nudBaseLength->Minimum = Decimal(1) / Decimal(2); nudBaseLength->Maximum = Decimal(200) / Decimal(100); nudBaseLength->Value = Decimal(100) / Decimal(100); nudBaseLength->Font = uiFontBold10; nudBaseLength->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudBaseLength); L = gcnew Label(); L->Text = L"Коэф. растяжения"; L->Location = Point(470, 20); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudStretchFactor = gcnew NumericUpDown(); nudStretchFactor->Location = Point(470, 52); nudStretchFactor->Width = 200; nudStretchFactor->DecimalPlaces = 2; nudStretchFactor->Minimum = Decimal(100) / Decimal(100); nudStretchFactor->Maximum = Decimal(150) / Decimal(100); nudStretchFactor->Increment = Decimal(1) / Decimal(100); nudStretchFactor->Value = Decimal(150) / Decimal(100); nudStretchFactor->Font = uiFontBold10; nudStretchFactor->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudStretchFactor); cbVarLen = gcnew CheckBox(); cbVarLen->Text = L"Переменные длины"; cbVarLen->Location = Point(695, 52); cbVarLen->Width = 200; cbVarLen->Checked = false; cbVarLen->Font = uiFontBold11; cbVarLen->CheckedChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(cbVarLen); L = gcnew Label(); L->Text = L"Цель X"; L->Location = Point(20, 107); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudTargetX = gcnew NumericUpDown(); nudTargetX->Location = Point(20, 139); nudTargetX->Width = 200; nudTargetX->DecimalPlaces = 2; nudTargetX->Minimum = Decimal(-100) / Decimal(10); nudTargetX->Maximum = Decimal(100) / Decimal(10); nudTargetX->Value = Decimal(25) / Decimal(10); nudTargetX->Font = uiFontBold10; nudTargetX->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudTargetX); L = gcnew Label(); L->Text = L"Цель Y"; L->Location = Point(245, 107); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudTargetY = gcnew NumericUpDown(); nudTargetY->Location = Point(245, 139); nudTargetY->Width = 200; nudTargetY->DecimalPlaces = 2; nudTargetY->Minimum = Decimal(-100) / Decimal(10); nudTargetY->Maximum = Decimal(100) / Decimal(10); nudTargetY->Value = Decimal(-10) / Decimal(10); nudTargetY->Font = uiFontBold10; nudTargetY->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudTargetY); L = gcnew Label(); L->Text = L"Глубина развёрток"; L->Location = Point(470, 107); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudLevels = gcnew NumericUpDown(); nudLevels->Location = Point(470, 139); nudLevels->Width = 200; nudLevels->Minimum = 7; nudLevels->Maximum = 20; nudLevels->Value = 12; nudLevels->Font = uiFontBold10; nudLevels->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudLevels); L = gcnew Label(); L->Text = L"Надежность (r)"; L->Location = Point(695, 107); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudR = gcnew NumericUpDown(); nudR->Location = Point(695, 139); nudR->Width = 200; nudR->DecimalPlaces = 2; nudR->Minimum = Decimal(100) / Decimal(100); nudR->Maximum = Decimal(2000) / Decimal(100); nudR->Value = Decimal(250) / Decimal(100); nudR->Font = uiFontBold10; nudR->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudR); cbAdaptive = gcnew CheckBox(); cbAdaptive->Text = L"Адаптивная схема"; cbAdaptive->Location = Point(920, 139); cbAdaptive->Width = 200; cbAdaptive->Checked = true; cbAdaptive->Font = uiFontBold11; cbAdaptive->CheckedChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(cbAdaptive); L = gcnew Label(); L->Text = L"Точность"; L->Location = Point(20, 194); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudEps = gcnew NumericUpDown(); nudEps->Location = Point(20, 226); nudEps->Width = 200; nudEps->DecimalPlaces = 9; nudEps->Minimum = Decimal(1) / Decimal(1000000000); nudEps->Maximum = Decimal(1) / Decimal(10); nudEps->Value = Decimal(1) / Decimal(100000); nudEps->Font = uiFontBold10; nudEps->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudEps); L = gcnew Label(); L->Text = L"Макс. итераций"; L->Location = Point(245, 194); L->Width = 200; L->Font = uiFontBold11; this->Controls->Add(L); nudMaxIter = gcnew NumericUpDown(); nudMaxIter->Location = Point(245, 226); nudMaxIter->Width = 200; nudMaxIter->Minimum = 10; nudMaxIter->Maximum = 500000; nudMaxIter->Value = 1000; nudMaxIter->Font = uiFontBold10; nudMaxIter->Increment = 100; nudMaxIter->ValueChanged += gcnew EventHandler(this, &MyForm::OnAnyChanged); this->Controls->Add(nudMaxIter); btnAdd = gcnew Button(); btnAdd->Text = L"+ Звено"; btnAdd->Location = Point(465, 226); btnAdd->Width = 90; btnAdd->Height = 35; btnAdd->BackColor = SystemColors::Info; btnAdd->Cursor = Cursors::Hand; btnAdd->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnAdd->FlatAppearance->BorderSize = 3; btnAdd->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnAdd->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnAdd->FlatStyle = FlatStyle::Flat; btnAdd->Font = uiFontBold11; btnAdd->ForeColor = SystemColors::ControlDarkDark; btnAdd->Click += gcnew EventHandler(this, &MyForm::OnAddClick); this->Controls->Add(btnAdd); btnRem = gcnew Button(); btnRem->Text = L"- Звено"; btnRem->Location = Point(560, 226); btnRem->Width = 90; btnRem->Height = 35; btnRem->BackColor = SystemColors::Info; btnRem->Cursor = Cursors::Hand; btnRem->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnRem->FlatAppearance->BorderSize = 3; btnRem->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnRem->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnRem->FlatStyle = FlatStyle::Flat; btnRem->Font = uiFontBold11; btnRem->ForeColor = SystemColors::ControlDarkDark; btnRem->Click += gcnew EventHandler(this, &MyForm::OnRemClick); this->Controls->Add(btnRem); btnOptimize = gcnew Button(); btnOptimize->Text = L"Оптимизировать"; btnOptimize->Location = Point(680, 226); btnOptimize->Width = 150; btnOptimize->Height = 35; btnOptimize->BackColor = SystemColors::Info; btnOptimize->Cursor = Cursors::Hand; btnOptimize->FlatAppearance->BorderColor = Color::FromArgb(64, 64, 64); btnOptimize->FlatAppearance->BorderSize = 3; btnOptimize->FlatAppearance->MouseDownBackColor = Color::FromArgb(128, 128, 255); btnOptimize->FlatAppearance->MouseOverBackColor = Color::FromArgb(192, 192, 255); btnOptimize->FlatStyle = FlatStyle::Flat; btnOptimize->Font = uiFontBold11; btnOptimize->ForeColor = SystemColors::ControlDarkDark; btnOptimize->Click += gcnew EventHandler(this, &MyForm::OnOptimizeClick); this->Controls->Add(btnOptimize); lblInfo = gcnew Label(); lblInfo->Location = Point(835, 194); lblInfo->Size = System::Drawing::Size(335, 140); lblInfo->BorderStyle = BorderStyle::FixedSingle; lblInfo->Text = L"Готов"; lblInfo->Font = uiFontBold10; this->Controls->Add(lblInfo); } void ResetRandomConfig() { nSegments = 1; angles->Clear(); lengths->Clear(); angles->Add(1.57079637f); lengths->Add(static_cast<float>(nudBaseLength->Value)); variableLengths = false; this->Invalidate(); } [MethodImpl(MethodImplOptions::AggressiveInlining)] float Rand01() { rngState ^= rngState << 13; rngState ^= rngState >> 17; rngState ^= rngState << 5; const float inv = 1.0f / 4294967296.0f; return static_cast<float>(static_cast<unsigned int>(rngState)) * inv; } [MethodImpl(MethodImplOptions::AggressiveInlining)] float RandAngle() { return Rand01() * 6.28318548f - 3.14159274f; } [MethodImpl(MethodImplOptions::AggressiveOptimization)] void RunAgpCpp() { variableLengths = cbVarLen->Checked; const float minTheta = static_cast<float>(nudMinTheta->Value); const float tx = static_cast<float>(nudTargetX->Value); const float ty = static_cast<float>(nudTargetY->Value); const int levels = static_cast<int>(nudLevels->Value); const int maxIter = static_cast<int>(nudMaxIter->Value); const bool adaptive = cbAdaptive->Checked; const float r_param = static_cast<float>(nudR->Value); const float eps = static_cast<float>(nudEps->Value); const unsigned int seed = static_cast<unsigned int>(GetTickCount()); pStart(nSegments, variableLengths, minTheta, tx, ty, levels, maxIter, r_param, adaptive, eps, seed); LARGE_INTEGER t0; LARGE_INTEGER t1; LARGE_INTEGER fq; QueryPerformanceCounter(&t0); float* bestQ = nullptr; size_t bestQLen = 0; float bestX = 0.0f; float bestY = 0.0f; float bestF = 0.0f; size_t actualIterations = 0u; float achievedEps = 0.0f; fManip(nSegments, variableLengths, minTheta, tx, ty, levels, maxIter, r_param, adaptive, eps, seed, &bestQ, &bestQLen, &bestX, &bestY, &bestF, &actualIterations, &achievedEps); QueryPerformanceCounter(&t1); QueryPerformanceFrequency(&fq); const double micros = 1e6 * static_cast<double>(t1.QuadPart - t0.QuadPart) / static_cast<double>(fq.QuadPart); angles->Clear(); for (int i = 0; i < nSegments; ++i) { angles->Add(bestQ[i]); } lengths->Clear(); if (variableLengths) { for (int i = 0; i < nSegments; ++i) { lengths->Add(bestQ[nSegments + i]); } } else { const float baseLen = static_cast<float>(nudBaseLength->Value); for (int i = 0; i < nSegments; ++i) { lengths->Add(baseLen); } } pFree(bestQ); const float dx = bestX - tx; const float dy = bestY - ty; lblInfo->Text = String::Format( L"Результат:\n" L"Близость захвата: {0:F5}\n" L"Функционал: {1:F5}\n" L"Точка: ({2:F3}, {3:F3})\n" L"Время: {4:F0} мкс\n" L"Число шагов: {5}\n" L"Достигнутая точность: {6:E3}", Math::Sqrt(dx * dx + dy * dy), bestF, bestX, bestY, micros, actualIterations, achievedEps); this->Invalidate(); } [MethodImpl(MethodImplOptions::AggressiveInlining)] bool ParseFloat(String^ s, float% out) { return Single::TryParse( s, NumberStyles::Float, CultureInfo::InvariantCulture, out); } [MethodImpl(MethodImplOptions::AggressiveOptimization)] void RunPythonBackend(String^ which) { const int nSeg = nSegments; const bool varLen = cbVarLen->Checked; const float minTheta = static_cast<float>(nudMinTheta->Value); const float tx = static_cast<float>(nudTargetX->Value); const float ty = static_cast<float>(nudTargetY->Value); const int levels = static_cast<int>(nudLevels->Value); const int maxIter = static_cast<int>(nudMaxIter->Value); const float r_param = static_cast<float>(nudR->Value); const float eps = static_cast<float>(nudEps->Value); const bool adaptive = cbAdaptive->Checked; String^ pythonExe = System::IO::Path::Combine( Application::StartupPath, "env", "Scripts", "python.exe"); String^ scriptPath = System::IO::Path::Combine( Application::StartupPath, "optimizer_bridge.py"); ProcessStartInfo^ psi = gcnew ProcessStartInfo(); psi->FileName = pythonExe; psi->Arguments = String::Format( CultureInfo::InvariantCulture, "\"{0}\" {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11}", scriptPath, which, nSeg, varLen ? 1 : 0, minTheta, tx, ty, levels, maxIter, r_param, eps, adaptive ? 1 : 0); psi->UseShellExecute = false; psi->CreateNoWindow = true; psi->RedirectStandardOutput = true; psi->RedirectStandardError = false; psi->WorkingDirectory = Application::StartupPath; Process^ proc = Process::Start(psi); String^ stdoutAll = proc->StandardOutput->ReadToEnd(); proc->WaitForExit(); float bestF = 0.0f; float bestX = 0.0f; float bestY = 0.0f; float achievedEps = 0.0f; int iterations = 0; float micros = 0.0f; array<float>^ tempAngles = gcnew array<float>(nSeg); array<float>^ tempLengths = gcnew array<float>(nSeg); const float baseLen = static_cast<float>(nudBaseLength->Value); for (int i = 0; i < nSeg; ++i) { tempAngles[i] = 0.0f; tempLengths[i] = baseLen; } array<wchar_t>^ separators = gcnew array<wchar_t>{ '\r', '\n' }; array<String^>^ lines = stdoutAll->Split( separators, StringSplitOptions::RemoveEmptyEntries); int qIndex = 0; for each (String ^ line in lines) { array<wchar_t>^ partSeparators = gcnew array<wchar_t>{ ' ', '\t' }; array<String^>^ parts = line->Split( partSeparators, StringSplitOptions::RemoveEmptyEntries); if (parts->Length == 0) { continue; } String^ key = parts[0]; if (key == "Q") { for (int i = 1; i < parts->Length && qIndex < (varLen ? 2 * nSeg : nSeg); ++i) { float qVal; if (ParseFloat(parts[i], qVal)) { if (qIndex < nSeg) { tempAngles[qIndex] = qVal; } else if (varLen && qIndex < 2 * nSeg) { tempLengths[qIndex - nSeg] = qVal; } ++qIndex; } } } else if (parts->Length > 1) { String^ value = parts[1]; if (key == "BEST_F") { ParseFloat(value, bestF); } else if (key == "BEST_X") { ParseFloat(value, bestX); } else if (key == "BEST_Y") { ParseFloat(value, bestY); } else if (key == "ITERATIONS") { Int32::TryParse(value, iterations); } else if (key == "EPS") { ParseFloat(value, achievedEps); } else if (key == "TIME") { ParseFloat(value, micros); } } } angles->Clear(); lengths->Clear(); for (int i = 0; i < nSeg; ++i) { angles->Add(tempAngles[i]); lengths->Add(tempLengths[i]); } const float dx = bestX - tx; const float dy = bestY - ty; const double distance = Math::Sqrt(dx * dx + dy * dy); lblInfo->Text = String::Format( L"Результат:\n" L"Близость захвата: {0:F5}\n" L"Функционал: {1:F5}\n" L"Точка: ({2:F3}, {3:F3})\n" L"Время: {4:F0} мкс\n" L"Число шагов: {5}\n" L"Достигнутая точность: {6:E3}", distance, bestF, bestX, bestY, micros, iterations, achievedEps); this->Invalidate(); this->Refresh(); } System::Void OnBackendChanged(System::Object^ sender, System::EventArgs^ e) { switch (cbBackend->SelectedIndex) { case 0: backend = OptimizerBackend::AgpCpp; cbAdaptive->Enabled = true; break; case 1: backend = OptimizerBackend::Optuna; cbAdaptive->Enabled = false; break; case 2: backend = OptimizerBackend::IOpt; cbAdaptive->Enabled = true; break; default: backend = OptimizerBackend::AgpCpp; cbAdaptive->Enabled = true; break; } } System::Void OnResize(System::Object^ sender, System::EventArgs^ e) { this->Invalidate(); } System::Void OnAnyChanged(System::Object^ sender, System::EventArgs^ e) { this->Invalidate(); } System::Void OnAddClick(System::Object^ sender, System::EventArgs^ e) { ++nSegments; angles->Add(RandAngle()); lengths->Add(static_cast<float>(nudBaseLength->Value)); this->Invalidate(); } System::Void OnRemClick(System::Object^ sender, System::EventArgs^ e) { if (nSegments > 1) { --nSegments; angles->RemoveAt(angles->Count - 1); lengths->RemoveAt(lengths->Count - 1); this->Invalidate(); } } System::Void OnOptimizeClick(System::Object^ sender, System::EventArgs^ e) { switch (backend) { case OptimizerBackend::AgpCpp: RunAgpCpp(); break; case OptimizerBackend::Optuna: RunPythonBackend(L"optuna"); break; case OptimizerBackend::IOpt: RunPythonBackend(L"iopt"); break; } } protected: [MethodImpl(MethodImplOptions::AggressiveOptimization)] virtual void OnPaint(PaintEventArgs^ e) override { Form::OnPaint(e); Graphics^ g = e->Graphics; g->SmoothingMode = SmoothingMode::HighQuality; g->Clear(this->BackColor); System::Drawing::Rectangle drawArea(0, 180, this->ClientSize.Width, 620); g->FillRectangle(Brushes::White, drawArea); const int leftWallX = drawArea.Left + this->ClientSize.Width * 25 / 100; g->DrawLine(wallPen, leftWallX, drawArea.Top, leftWallX, drawArea.Bottom); g->FillRectangle(wallHatchBrush, leftWallX - 100, drawArea.Top, 100, drawArea.Height); const float targetX = static_cast<float>(nudTargetX->Value); const float targetY = static_cast<float>(nudTargetY->Value); const int baseX = leftWallX; const int baseY = drawArea.Top + 310; const float pixelTargetX = static_cast<float>(baseX) + targetX * 160.0f; const float pixelTargetY = static_cast<float>(baseY) - targetY * 160.0f; int rightWallX = static_cast<int>(pixelTargetX + 8.0f); if (rightWallX > drawArea.Right - 10) { rightWallX = drawArea.Right - 10; } g->DrawLine(dashedPen, rightWallX, drawArea.Top, rightWallX, drawArea.Bottom); g->FillRectangle(wallHatchBrush, rightWallX, drawArea.Top, 100, drawArea.Height); g->DrawEllipse(targetPen, pixelTargetX - 8.0f, pixelTargetY - 8.0f, 16.0f, 16.0f); cli::array<PointF>^ pts = gcnew cli::array<PointF>(nSegments + 1); pts[0] = PointF(static_cast<float>(baseX), static_cast<float>(baseY)); float x = 0.0f; float y = 0.0f; float phi = 0.0f; List<float>^ localAngles = angles; List<float>^ localLengths = lengths; for (int i = 0; i < nSegments; ++i) { const float theta = localAngles[i]; const float L = localLengths[i]; phi += theta; x += L * static_cast<float>(Math::Cos(static_cast<double>(phi))); y += L * static_cast<float>(Math::Sin(static_cast<double>(phi))); pts[i + 1] = PointF(static_cast<float>(baseX) + x * 160.0f, static_cast<float>(baseY) - y * 160.0f); } for (int i = 0; i < nSegments; ++i) { g->DrawLine(penRod, pts[i], pts[i + 1]); } for (int i = 0; i <= nSegments; ++i) { g->FillEllipse(jointBrush, pts[i].X - 8.0f, pts[i].Y - 8.0f, 16.0f, 16.0f); } } }; }