From 7c24270e6e564757df10f90f8516205acc564b8f Mon Sep 17 00:00:00 2001 From: ParkSuMin Date: Sun, 14 Dec 2025 20:30:08 +0300 Subject: [PATCH 1/3] Horizontal and vertical points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Теперь можно обе точки при ограничении дёргать --- Canvas.cpp | 35 +++++++++++++++++++++++------------ Canvas.h | 3 +++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Canvas.cpp b/Canvas.cpp index b0b61dc..18ec9d8 100644 --- a/Canvas.cpp +++ b/Canvas.cpp @@ -7,7 +7,7 @@ static double dist_P2P(QPointF p1, QPointF p2) { template T makeOrderedPair(A* obj1, B* obj2) { - return (obj1->get_tag() < obj2->get_tag()) ? std::make_pair(obj1, obj2) : std::make_pair(obj2, obj1); + return (obj1 < obj2) ? std::make_pair(obj1, obj2) : std::make_pair(obj2, obj1); } void Canvas::changeMode(Mode _mode) @@ -46,9 +46,18 @@ bool Canvas::areCoincident(Point* p1, Point* p2) return P2Ppairs.count(makeOrderedPair(p1, p2)); } +// False - Horizonta, True - Vertical +bool Canvas::areHorizontalVertical(Point* p1, Point* p2, bool mode) +{ + if (!mode) + return HORIZ_pairs.count(makeOrderedPair(p1, p2)); + else + return VERT_pairs.count(makeOrderedPair(p1, p2)); +} + bool Canvas::areAlreadyParallel(Line* l1, Line* l2) { - return parallelPairs.count(makeOrderedPair(l1, l2)) > 0; + return parallelPairs.count(makeOrderedPair(l1, l2)); } void Canvas::mousePressEvent(QMouseEvent* event) @@ -71,10 +80,14 @@ void Canvas::mousePressEvent(QMouseEvent* event) Line* found = findAt(scene); if (found) { - if (mode == Mode::Horizontal) + if (mode == Mode::Horizontal) { sys.addConstraintHorizontal(*found, constraints_count++); - else + HORIZ_pairs.insert(makeOrderedPair(found->start_ref, found->end_ref)); + } + else { sys.addConstraintVertical(*found, constraints_count++); + VERT_pairs.insert(makeOrderedPair(found->start_ref, found->end_ref)); + } update(); } mode = Mode::None; @@ -244,6 +257,12 @@ void Canvas::mouseMoveEvent(QMouseEvent* event) *pair->x = pos.x(); *pair->y = pos.y(); } + if (areHorizontalVertical(draggedPoint, pair, true)) { + *pair->x = pos.x(); + } + if (areHorizontalVertical(draggedPoint, pair, false)) { + *pair->y = pos.y(); + } } *draggedPoint->x = pos.x(); *draggedPoint->y = pos.y(); @@ -311,18 +330,10 @@ void Canvas::paintEvent(QPaintEvent*) // === Текущая рисуемая линия (DrawingLine) === if (current_line && mode == Mode::DrawingLine) { - QPen pen(Qt::blue, 3, Qt::DashLine); - p.setPen(pen); - p.setBrush(Qt::transparent); - - p.drawLine(QPointF(*current_line->p1.x, *current_line->p1.y), - QPointF(*current_line->p2.x, *current_line->p2.y)); - // Концы текущей линии — синие точки p.setBrush(Qt::blue); p.setPen(Qt::NoPen); p.drawEllipse(QPointF(*current_line->p1.x, *current_line->p1.y), 6, 6); - p.drawEllipse(QPointF(*current_line->p2.x, *current_line->p2.y), 6, 6); } } diff --git a/Canvas.h b/Canvas.h index ca234c9..9c2cf16 100644 --- a/Canvas.h +++ b/Canvas.h @@ -53,6 +53,7 @@ private: Line* findAt(QPointF&); // ищет линию под курсором Point* findPointAt(QPointF, qreal tolerance = 5.0); bool areCoincident(Point*, Point*); + bool areHorizontalVertical(Point*, Point*, bool); // ====================== Параллельность ====================== bool areAlreadyParallel(Line* l1, Line* l2); // проверка на дубликат @@ -68,6 +69,8 @@ private: std::set parallelPairs; // уже запараллеленные пары (защита от дублей) std::set P2Ppairs; + std::set HORIZ_pairs; + std::set VERT_pairs; Line* current_line{ nullptr }; Point* firstPoint{ nullptr }; From d8487951e0b56baefcd511ae302fcb1439bbfb6b Mon Sep 17 00:00:00 2001 From: ParkSuMin Date: Sun, 14 Dec 2025 22:26:50 +0300 Subject: [PATCH 2/3] Moving line in canvas --- Canvas.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ Canvas.h | 1 + 2 files changed, 48 insertions(+) diff --git a/Canvas.cpp b/Canvas.cpp index 18ec9d8..793a1ef 100644 --- a/Canvas.cpp +++ b/Canvas.cpp @@ -73,6 +73,18 @@ void Canvas::mousePressEvent(QMouseEvent* event) if (p) { draggedPoint = p; dragOffset = scene - QPointF(*p->x, *p->y); + return; + } + + Line* found = findAt(scene); + if (found) { + draggedLine = found; + QPointF lineCenter( + (*found->p1.x + *found->p2.x) / 2.0, + (*found->p1.y + *found->p2.y) / 2.0 + ); + dragOffset = scene - lineCenter; + return; } } @@ -268,6 +280,36 @@ void Canvas::mouseMoveEvent(QMouseEvent* event) *draggedPoint->y = pos.y(); update(); } + + else if (draggedLine) { + QPointF newCenter = event->pos() - dragOffset; + QPointF oldCenter( + (*draggedLine->p1.x + *draggedLine->p2.x) / 2.0, + (*draggedLine->p1.y + *draggedLine->p2.y) / 2.0 + ); + + // Смещение для перемещения + double dx = newCenter.x() - oldCenter.x(); + double dy = newCenter.y() - oldCenter.y(); + + Point* linePoints[2] = { draggedLine->start_ref, draggedLine->end_ref }; + + for (int i = 0; i < 2; i++) { + Point* currentPoint = linePoints[i]; + + *currentPoint->x += dx; + *currentPoint->y += dy; + + for (Point* pair : points) { + if (pair != currentPoint && areCoincident(currentPoint, pair)) { + *pair->x = *currentPoint->x; + *pair->y = *currentPoint->y; + } + } + } + + update(); + } } void Canvas::mouseReleaseEvent(QMouseEvent* event) @@ -276,6 +318,11 @@ void Canvas::mouseReleaseEvent(QMouseEvent* event) draggedPoint = nullptr; update(); } + + if (draggedLine) { + draggedLine = nullptr; + update(); + } } void Canvas::paintEvent(QPaintEvent*) diff --git a/Canvas.h b/Canvas.h index 9c2cf16..c129e6a 100644 --- a/Canvas.h +++ b/Canvas.h @@ -59,6 +59,7 @@ private: // ====================== Перемещение ====================== Point* draggedPoint{ nullptr }; + Line* draggedLine{ nullptr }; QPointF dragOffset; // ====================== Данные сцены ====================== From eb946e2e6a25bf35cc46ca1ef4e9c23b3da4fbdd Mon Sep 17 00:00:00 2001 From: ParkSuMin Date: Mon, 15 Dec 2025 11:55:32 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D1=81=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=BE=D0=B3?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B8=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit А ещё сделали так, чтобы линия не могла быть горизонтальной и вертикальной одновременно --- Canvas.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++++------- Canvas.h | 10 +++++ 2 files changed, 114 insertions(+), 14 deletions(-) diff --git a/Canvas.cpp b/Canvas.cpp index 793a1ef..4fe2876 100644 --- a/Canvas.cpp +++ b/Canvas.cpp @@ -53,6 +53,19 @@ bool Canvas::areHorizontalVertical(Point* p1, Point* p2, bool mode) return HORIZ_pairs.count(makeOrderedPair(p1, p2)); else return VERT_pairs.count(makeOrderedPair(p1, p2)); + +} + +bool Canvas::isLineHorizontal(Line* line) +{ + if (!line || !line->start_ref || !line->end_ref) return false; + return HORIZ_pairs.count(makeOrderedPair(line->start_ref, line->end_ref)); +} + +bool Canvas::isLineVertical(Line* line) +{ + if (!line || !line->start_ref || !line->end_ref) return false; + return VERT_pairs.count(makeOrderedPair(line->start_ref, line->end_ref)); } bool Canvas::areAlreadyParallel(Line* l1, Line* l2) @@ -60,6 +73,43 @@ bool Canvas::areAlreadyParallel(Line* l1, Line* l2) return parallelPairs.count(makeOrderedPair(l1, l2)); } +void Canvas::remove_constraints() +{ + sys.clearByTag(constraints_count - 1); + + switch (lastConstraint.mode) { + case Mode::Horizontal: { + if (auto* pair = std::get_if(&lastConstraint.data)) { + HORIZ_pairs.erase(*pair); + } + break; + } + case Mode::Vertical: { + if (auto* pair = std::get_if(&lastConstraint.data)) { + VERT_pairs.erase(*pair); + } + break; + } + case Mode::Parallel: { + if (auto* pair = std::get_if(&lastConstraint.data)) { + parallelPairs.erase(*pair); + } + break; + } + case Mode::Coincedent: { + if (auto* pair = std::get_if(&lastConstraint.data)) { + P2Ppairs.erase(*pair); + } + break; + } + default: + break; + } + + lastConstraint.mode = Mode::None; + constraints_count--; +} + void Canvas::mousePressEvent(QMouseEvent* event) { QPointF scene = event->pos(); @@ -92,18 +142,45 @@ void Canvas::mousePressEvent(QMouseEvent* event) Line* found = findAt(scene); if (found) { + if (mode == Mode::Horizontal && isLineVertical(found)) { + QMessageBox::warning(this, + QString("Невозможно"), + QString("Эта линия уже вертикальна и не может быть горизонтальной!"), + QMessageBox::Ok + ); + mode = Mode::None; + return; + } + + // Проверка: если линия уже горизонтальна, нельзя сделать её вертикальной + if (mode == Mode::Vertical && isLineHorizontal(found)) { + QMessageBox::warning(this, + QString("Невозможно"), + QString("Эта линия уже горизонтальна и не может быть вертикальной!"), + QMessageBox::Ok + ); + mode = Mode::None; + return; + } + if (mode == Mode::Horizontal) { sys.addConstraintHorizontal(*found, constraints_count++); - HORIZ_pairs.insert(makeOrderedPair(found->start_ref, found->end_ref)); + auto pair = makeOrderedPair(found->start_ref, found->end_ref); + HORIZ_pairs.insert(pair); + lastConstraint.mode = Mode::Horizontal; + lastConstraint.data = pair; } else { sys.addConstraintVertical(*found, constraints_count++); - VERT_pairs.insert(makeOrderedPair(found->start_ref, found->end_ref)); + auto pair = makeOrderedPair(found->start_ref, found->end_ref); + VERT_pairs.insert(pair); + lastConstraint.mode = Mode::Vertical; + lastConstraint.data = pair; } update(); + after_constraint = true; } mode = Mode::None; - after_constraint = true; } else if (mode == Mode::DrawingLine) { @@ -189,12 +266,16 @@ void Canvas::mousePressEvent(QMouseEvent* event) } if (!areAlreadyParallel(found, current_line)) { + auto pair = makeOrderedPair(found, current_line); sys.addConstraintParallel(*found, *current_line, constraints_count++); - parallelPairs.insert(makeOrderedPair(found, current_line)); + parallelPairs.insert(pair); + lastConstraint.mode = Mode::Parallel; + lastConstraint.data = pair; + current_line = nullptr; - update(); mode = Mode::None; after_constraint = true; + update(); } else { @@ -251,7 +332,11 @@ void Canvas::mousePressEvent(QMouseEvent* event) } sys.addConstraintP2PCoincident(*clickedPoint, *firstPoint, constraints_count++); - P2Ppairs.insert(makeOrderedPair(clickedPoint, firstPoint)); + auto pair = makeOrderedPair(clickedPoint, firstPoint); + P2Ppairs.insert(pair); + lastConstraint.mode = Mode::Coincedent; + lastConstraint.data = pair; + firstPoint = nullptr; mode = Mode::None; after_constraint = true; @@ -338,8 +423,7 @@ void Canvas::paintEvent(QPaintEvent*) } else if (res == SolveStatus::Failed && after_constraint){ QMessageBox::warning(this, QString("Error!"), QString("Last constraint is unavailable!")); - sys.removeConstraint(sys.get_last_constraint()); - constraints_count--; + remove_constraints(); } after_constraint = false; } @@ -388,7 +472,6 @@ Canvas::Canvas(QWidget *parent) : QWidget(parent) { sys = System(); - current_line = nullptr; setMouseTracking(true); setBackgroundRole(QPalette::Base); setAutoFillBackground(true); @@ -396,19 +479,26 @@ Canvas::Canvas(QWidget *parent) Canvas::~Canvas() { - for (Line* line : lines) { - delete line; - } - for (double* param : params) { delete param; } - lines.clear(); + for (Point* pt : points) { + delete pt; + } + + for (Line* line : lines) { + delete line; + } + params.clear(); points.clear(); + lines.clear(); + parallelPairs.clear(); P2Ppairs.clear(); + VERT_pairs.clear(); + HORIZ_pairs.clear(); if (current_line) delete current_line; diff --git a/Canvas.h b/Canvas.h index c129e6a..ec40cd3 100644 --- a/Canvas.h +++ b/Canvas.h @@ -54,6 +54,8 @@ private: Point* findPointAt(QPointF, qreal tolerance = 5.0); bool areCoincident(Point*, Point*); bool areHorizontalVertical(Point*, Point*, bool); + bool isLineHorizontal(Line* line); // проверяет, горизонтальна ли линия + bool isLineVertical(Line* line); // проверяет, вертикальна ли линия // ====================== Параллельность ====================== bool areAlreadyParallel(Line* l1, Line* l2); // проверка на дубликат @@ -62,6 +64,8 @@ private: Line* draggedLine{ nullptr }; QPointF dragOffset; + // ====================== Работа с парами ограничений ====================== + void remove_constraints(); // ====================== Данные сцены ====================== System sys; // геометрический солвер QVector lines; // завершённые линии @@ -80,4 +84,10 @@ private: int obj_count{ 0 }; // тег для новых объектов int constraints_count{ 0 }; // тег для новых ограничений + + struct LastConstraint { + Mode mode{ Mode::None }; + std::variant data; + }; + LastConstraint lastConstraint; }; \ No newline at end of file