Merge Move_line info master
This commit is contained in:
198
Canvas.cpp
198
Canvas.cpp
@@ -7,7 +7,7 @@ static double dist_P2P(QPointF p1, QPointF p2) {
|
||||
template <typename T, typename A, typename B>
|
||||
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,68 @@ bool Canvas::areCoincident(Point* p1, Point* p2)
|
||||
return P2Ppairs.count(makeOrderedPair<PointPair>(p1, p2));
|
||||
}
|
||||
|
||||
// False - Horizonta, True - Vertical
|
||||
bool Canvas::areHorizontalVertical(Point* p1, Point* p2, bool mode)
|
||||
{
|
||||
if (!mode)
|
||||
return HORIZ_pairs.count(makeOrderedPair<PointPair>(p1, p2));
|
||||
else
|
||||
return VERT_pairs.count(makeOrderedPair<PointPair>(p1, p2));
|
||||
|
||||
}
|
||||
|
||||
bool Canvas::isLineHorizontal(Line* line)
|
||||
{
|
||||
if (!line || !line->start_ref || !line->end_ref) return false;
|
||||
return HORIZ_pairs.count(makeOrderedPair<PointPair>(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<PointPair>(line->start_ref, line->end_ref));
|
||||
}
|
||||
|
||||
bool Canvas::areAlreadyParallel(Line* l1, Line* l2)
|
||||
{
|
||||
return parallelPairs.count(makeOrderedPair<LinePair>(l1, l2)) > 0;
|
||||
return parallelPairs.count(makeOrderedPair<LinePair>(l1, l2));
|
||||
}
|
||||
|
||||
void Canvas::remove_constraints()
|
||||
{
|
||||
sys.clearByTag(constraints_count - 1);
|
||||
|
||||
switch (lastConstraint.mode) {
|
||||
case Mode::Horizontal: {
|
||||
if (auto* pair = std::get_if<PointPair>(&lastConstraint.data)) {
|
||||
HORIZ_pairs.erase(*pair);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::Vertical: {
|
||||
if (auto* pair = std::get_if<PointPair>(&lastConstraint.data)) {
|
||||
VERT_pairs.erase(*pair);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::Parallel: {
|
||||
if (auto* pair = std::get_if<LinePair>(&lastConstraint.data)) {
|
||||
parallelPairs.erase(*pair);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::Coincedent: {
|
||||
if (auto* pair = std::get_if<PointPair>(&lastConstraint.data)) {
|
||||
P2Ppairs.erase(*pair);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
lastConstraint.mode = Mode::None;
|
||||
constraints_count--;
|
||||
}
|
||||
|
||||
void Canvas::mousePressEvent(QMouseEvent* event)
|
||||
@@ -64,6 +123,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,14 +142,45 @@ void Canvas::mousePressEvent(QMouseEvent* event)
|
||||
Line* found = findAt(scene);
|
||||
|
||||
if (found) {
|
||||
if (mode == Mode::Horizontal)
|
||||
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++);
|
||||
else
|
||||
auto pair = makeOrderedPair<PointPair>(found->start_ref, found->end_ref);
|
||||
HORIZ_pairs.insert(pair);
|
||||
lastConstraint.mode = Mode::Horizontal;
|
||||
lastConstraint.data = pair;
|
||||
}
|
||||
else {
|
||||
sys.addConstraintVertical(*found, constraints_count++);
|
||||
auto pair = makeOrderedPair<PointPair>(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) {
|
||||
@@ -164,12 +266,16 @@ void Canvas::mousePressEvent(QMouseEvent* event)
|
||||
}
|
||||
|
||||
if (!areAlreadyParallel(found, current_line)) {
|
||||
auto pair = makeOrderedPair<LinePair>(found, current_line);
|
||||
sys.addConstraintParallel(*found, *current_line, constraints_count++);
|
||||
parallelPairs.insert(makeOrderedPair<LinePair>(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 {
|
||||
|
||||
@@ -226,7 +332,11 @@ void Canvas::mousePressEvent(QMouseEvent* event)
|
||||
}
|
||||
|
||||
sys.addConstraintP2PCoincident(*clickedPoint, *firstPoint, constraints_count++);
|
||||
P2Ppairs.insert(makeOrderedPair<PointPair>(clickedPoint, firstPoint));
|
||||
auto pair = makeOrderedPair<PointPair>(clickedPoint, firstPoint);
|
||||
P2Ppairs.insert(pair);
|
||||
lastConstraint.mode = Mode::Coincedent;
|
||||
lastConstraint.data = pair;
|
||||
|
||||
firstPoint = nullptr;
|
||||
mode = Mode::None;
|
||||
after_constraint = true;
|
||||
@@ -244,11 +354,47 @@ 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();
|
||||
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)
|
||||
@@ -257,6 +403,11 @@ void Canvas::mouseReleaseEvent(QMouseEvent* event)
|
||||
draggedPoint = nullptr;
|
||||
update();
|
||||
}
|
||||
|
||||
if (draggedLine) {
|
||||
draggedLine = nullptr;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::paintEvent(QPaintEvent*)
|
||||
@@ -271,9 +422,8 @@ void Canvas::paintEvent(QPaintEvent*)
|
||||
sys.applySolution();
|
||||
}
|
||||
else if (res == SolveStatus::Failed && after_constraint){
|
||||
QMessageBox::critical(this, QString("Error!"), QString("Last constraint is unavailable!"));
|
||||
sys.removeConstraint(sys.get_last_constraint());
|
||||
constraints_count--;
|
||||
QMessageBox::warning(this, QString("Error!"), QString("Last constraint is unavailable!"));
|
||||
remove_constraints();
|
||||
}
|
||||
after_constraint = false;
|
||||
}
|
||||
@@ -311,18 +461,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,7 +472,6 @@ Canvas::Canvas(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
sys = System();
|
||||
current_line = nullptr;
|
||||
setMouseTracking(true);
|
||||
setBackgroundRole(QPalette::Base);
|
||||
setAutoFillBackground(true);
|
||||
@@ -338,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;
|
||||
|
||||
14
Canvas.h
14
Canvas.h
@@ -53,13 +53,19 @@ private:
|
||||
Line* findAt(QPointF&); // ищет линию под курсором
|
||||
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); // проверка на дубликат
|
||||
|
||||
// ====================== Перемещение ======================
|
||||
Point* draggedPoint{ nullptr };
|
||||
Line* draggedLine{ nullptr };
|
||||
QPointF dragOffset;
|
||||
|
||||
// ====================== Работа с парами ограничений ======================
|
||||
void remove_constraints();
|
||||
// ====================== Данные сцены ======================
|
||||
System sys; // геометрический солвер
|
||||
QVector<Line*> lines; // завершённые линии
|
||||
@@ -68,6 +74,8 @@ private:
|
||||
|
||||
std::set<LinePair> parallelPairs; // уже запараллеленные пары (защита от дублей)
|
||||
std::set<PointPair> P2Ppairs;
|
||||
std::set<PointPair> HORIZ_pairs;
|
||||
std::set<PointPair> VERT_pairs;
|
||||
|
||||
Line* current_line{ nullptr };
|
||||
Point* firstPoint{ nullptr };
|
||||
@@ -76,4 +84,10 @@ private:
|
||||
|
||||
int obj_count{ 0 }; // тег для новых объектов
|
||||
int constraints_count{ 0 }; // тег для новых ограничений
|
||||
|
||||
struct LastConstraint {
|
||||
Mode mode{ Mode::None };
|
||||
std::variant<LinePair, PointPair> data;
|
||||
};
|
||||
LastConstraint lastConstraint;
|
||||
};
|
||||
Reference in New Issue
Block a user