diff --git a/Canvas.cpp b/Canvas.cpp index d268241..c613cbb 100644 --- a/Canvas.cpp +++ b/Canvas.cpp @@ -1,4 +1,6 @@ #include "Canvas.h" +#define WIDGET_POSITION event->pos() +#define UCS_POSITION screenToLogical(WIDGET_POSITION) // =================================================================== // Вспомогательные функции @@ -181,6 +183,12 @@ void Canvas::remove_constraint(int tag) } break; } + case Mode::Perpendicular: { + if (auto* pair = std::get_if(&info.data)) { + perpendicularPairs.erase(*pair); + } + break; + } default: break; } @@ -259,7 +267,7 @@ void Canvas::mousePressEvent(QMouseEvent* event) VERT_pairs.insert(pair); C_Info[constraints_count - 1] = { Mode::Vertical, pair }; } - update(); + solve_for_canvas(); after_constraint = true; } mode = Mode::None; @@ -320,7 +328,7 @@ void Canvas::mousePressEvent(QMouseEvent* event) mode = Mode::None; QMessageBox::critical(this, "WHOOPS", "Sorry, your line is very short", QMessageBox::Ok); - update(); + solve_for_canvas(); return; } @@ -335,7 +343,7 @@ void Canvas::mousePressEvent(QMouseEvent* event) obj_count++; after_constraint = true; } - update(); + solve_for_canvas(); return; } @@ -345,21 +353,21 @@ void Canvas::mousePressEvent(QMouseEvent* event) if (!found) { current_line = nullptr; - update(); + solve_for_canvas(); return; } // Первый клик: выбираем первую линию if (!current_line) { current_line = found; - update(); + solve_for_canvas(); return; } // Повторный клик на ту же линию: сброс выбора if (found == current_line) { current_line = nullptr; - update(); + solve_for_canvas(); return; } @@ -373,7 +381,7 @@ void Canvas::mousePressEvent(QMouseEvent* event) current_line = nullptr; mode = Mode::None; after_constraint = true; - update(); + solve_for_canvas(); } else { // Линии уже параллельны - сообщаем об ошибке @@ -387,7 +395,7 @@ void Canvas::mousePressEvent(QMouseEvent* event) QMessageBox::Ok ); current_line = nullptr; - update(); + solve_for_canvas(); return; } } @@ -397,21 +405,21 @@ void Canvas::mousePressEvent(QMouseEvent* event) Point* clickedPoint = findPointAt(scene); if (!clickedPoint) { firstPoint = nullptr; - update(); + solve_for_canvas(); return; } // Первый клик: выбираем первую точку if (!firstPoint) { firstPoint = clickedPoint; - update(); + solve_for_canvas(); return; } // Повторный клик на ту же точку: сброс выбора if (clickedPoint == firstPoint) { firstPoint = nullptr; - update(); + solve_for_canvas(); return; } @@ -430,7 +438,7 @@ void Canvas::mousePressEvent(QMouseEvent* event) QMessageBox::critical(this, QString("NO!"), QString("P2P failed")); firstPoint = nullptr; mode = Mode::None; - update(); + solve_for_canvas(); return; } @@ -443,7 +451,7 @@ void Canvas::mousePressEvent(QMouseEvent* event) firstPoint = nullptr; mode = Mode::None; after_constraint = true; - update(); + solve_for_canvas(); return; } @@ -452,21 +460,21 @@ void Canvas::mousePressEvent(QMouseEvent* event) if (!found) { current_line = nullptr; - update(); + solve_for_canvas(); return; } // Первый клик: выбираем первую линию if (!current_line) { current_line = found; - update(); + solve_for_canvas(); return; } // Повторный клик на ту же линию: сброс выбора if (found == current_line) { current_line = nullptr; - update(); + solve_for_canvas(); return; } @@ -474,11 +482,12 @@ void Canvas::mousePressEvent(QMouseEvent* event) auto pair = makeOrderedPair(found, current_line); sys.addConstraintPerpendicular(*found, *current_line, constraints_count++); perpendicularPairs.insert(pair); + C_Info[constraints_count - 1] = { Mode::Perpendicular, pair }; current_line = nullptr; mode = Mode::None; after_constraint = true; - update(); + solve_for_canvas(); } else { @@ -488,7 +497,7 @@ void Canvas::mousePressEvent(QMouseEvent* event) QMessageBox::Ok ); current_line = nullptr; - update(); + solve_for_canvas(); return; } } @@ -500,6 +509,9 @@ void Canvas::mouseMoveEvent(QMouseEvent* event) if (draggedPoint) { QPointF pos = UCS_POSITION - dragOffset; + *draggedPoint->x = pos.x(); + *draggedPoint->y = pos.y(); + // TODO for (Point* pair : points) { if (areCoincident(draggedPoint, pair)) { @@ -525,9 +537,16 @@ void Canvas::mouseMoveEvent(QMouseEvent* event) } } - *draggedPoint->x = pos.x(); - *draggedPoint->y = pos.y(); - update(); + for (Point* other : points) { + if (areHorizontalVertical(draggedPoint, other, true)) { + *other->x = pos.x(); + } + if (areHorizontalVertical(draggedPoint, other, false)) { + *other->y = pos.y(); + } + } + + solve_for_canvas(); } // ====================== Перемещение линии ====================== @@ -559,7 +578,7 @@ void Canvas::mouseMoveEvent(QMouseEvent* event) } } } - update(); + solve_for_canvas(); } #ifdef _DEBUG else @@ -573,12 +592,12 @@ void Canvas::mouseReleaseEvent(QMouseEvent* event) if (draggedPoint) { draggedPoint = nullptr; - update(); + solve_for_canvas(); } if (draggedLine) { draggedLine = nullptr; - update(); + solve_for_canvas(); } } @@ -599,23 +618,6 @@ void Canvas::paintEvent(QPaintEvent* event) p.drawLine(-5, 0, 5, 0); p.drawLine(0, -5, 0, 5); - - // ====================== Решение системы уравнений ====================== - if (!params.empty()) { - int res = sys.solve(params); - if (res == SolveStatus::Success || res == SolveStatus::Converged) { - sys.applySolution(); - } - else if (res == SolveStatus::Failed && after_constraint) { - // Ошибка решения: удаляем последнее добавленное ограничение - QMessageBox::warning(this, QString("Error!"), - QString("Last constraint is unavailable!")); - remove_constraint(constraints_count - 1); - constraints_count--; - } - after_constraint = false; - } - // ====================== Отрисовка линий ====================== for (Line* line : lines) { bool isSelected = (mode == Mode::Parallel && line == current_line); @@ -708,3 +710,30 @@ std::vector Canvas::getCoincidentGroup(Point* p) } return group; } + +void Canvas::solve_for_canvas() +{ + bool flag = false; + int res = sys.solve(params); + if (res != SolveStatus::Success && res != SolveStatus::Converged) { + flag = true; + } + else { + sys.applySolution(); + for (Line* line : lines) { + if (abs(*line->p1.x - *line->p2.x) < EPS && abs(*line->p1.y - *line->p2.y) < EPS && after_constraint) { + sys.undoSolution(); + flag = true; + break; + } + } + } + + if (flag) { + QMessageBox::warning(this, QString("Error!"), QString("Last constraint is unavailable!")); + remove_constraint(constraints_count - 1); + constraints_count--; + } + after_constraint = false; + update(); +} \ No newline at end of file diff --git a/Canvas.h b/Canvas.h index 4f6f31a..fc2bfb2 100644 --- a/Canvas.h +++ b/Canvas.h @@ -1,7 +1,5 @@ #pragma once - -#define WIDGET_POSITION event->pos() -#define UCS_POSITION screenToLogical(WIDGET_POSITION) +constexpr auto EPS = 1e-9; #include #include @@ -148,4 +146,6 @@ private: std::variant data; }; std::map C_Info; + + void solve_for_canvas(); }; \ No newline at end of file diff --git a/DRAWer_2_0.cpp b/DRAWer_2_0.cpp index 4458cb3..1575b58 100644 --- a/DRAWer_2_0.cpp +++ b/DRAWer_2_0.cpp @@ -40,3 +40,9 @@ void DRAWer_2_0::on_Vertical_Button_clicked() ui.widget->changeMode(Mode::Vertical); } + +void DRAWer_2_0::on_Perpendicular_Button_clicked() +{ + ui.widget->changeMode(Mode::Perpendicular); +} + diff --git a/DRAWer_2_0.h b/DRAWer_2_0.h index 9d40eca..218e250 100644 --- a/DRAWer_2_0.h +++ b/DRAWer_2_0.h @@ -22,6 +22,8 @@ private slots: void on_Vertical_Button_clicked(); + void on_Perpendicular_Button_clicked(); + private: Ui::DRAWer_2_0Class ui; int counter; diff --git a/DRAWer_2_0.ui b/DRAWer_2_0.ui index fe011c0..a906a54 100644 --- a/DRAWer_2_0.ui +++ b/DRAWer_2_0.ui @@ -52,6 +52,13 @@ + + + + Perpendicular + + +