#include "Canvas.h" static double dist_P2P(QPointF p1, QPointF p2) { return sqrt(pow(p2.x() - p1.x(), 2) + pow(p2.y() - p1.y(), 2)); } void Canvas::changeMode(Mode _mode) { mode = _mode; } // TODO Line* Canvas::findAt(QPointF& pos) { for (Line* line : lines) { if (line->contains(pos)) { return line; } } return nullptr; } Point* Canvas::findPointAt(QPointF pos, qreal tolerance) { for (Line* line : lines) { QPointF p1(*line->p1.x, *line->p1.y); QPointF p2(*line->p2.x, *line->p2.y); if (dist_P2P(p1, pos) <= tolerance) return &line->p1; else if (dist_P2P(p2, pos) <= tolerance) return &line->p2; } return nullptr; } LinePair Canvas::makeOrderedPair(Line* l1, Line* l2) { return (l1 < l2) ? std::make_pair(l1, l2) : std::make_pair(l2, l1); } bool Canvas::areAlreadyParallel(Line* l1, Line* l2) { return parallelPairs.count(makeOrderedPair(l1, l2)) > 0; } void Canvas::mousePressEvent(QMouseEvent* event) { QPointF scene = event->pos(); #ifdef _DEBUG qDebug() << "Scene point in" << scene.x() << scene.y(); #endif if (mode == Mode::DrawingLine) { if (!current_line) { current_line = new Line(); current_line->set_tag(obj_count); double* x1 = new double(scene.x()); double* y1 = new double(scene.y()); double* x2 = new double(scene.x()); double* y2 = new double(scene.y()); params.push_back(x1); params.push_back(y1); points.push_back(Point(x1, y1, obj_count)); points.push_back(Point(x2, y2, obj_count)); current_line->p1.x = x1; current_line->p1.y = y1; current_line->p2.x = x2; current_line->p2.y = y2; } else { *current_line->p2.x = scene.x(); *current_line->p2.y = scene.y(); params.push_back(current_line->p2.x); params.push_back(current_line->p2.y); lines.append(current_line); current_line = nullptr; mode = Mode::None; obj_count++; update(); return; } } else if (mode == Mode::Parallel) { Line* found = findAt(scene); if (!found) { current_line = nullptr; return; } if (!current_line) { current_line = found; return; } if (found == current_line){ current_line = nullptr; return; } if (!areAlreadyParallel(found, current_line)) { sys.addConstraintParallel(*found, *current_line, constraints_count++); parallelPairs.insert(makeOrderedPair(found, current_line)); current_line = nullptr; mode = Mode::None; } else { #ifdef _DEBUG qDebug() << "Line" << current_line << "and" << found << "are parallel. Abort!"; #endif QMessageBox::warning(this, QString("Wrong"), QString("Parallel lines can not be more parallel!"), QMessageBox::Ok ); current_line = nullptr; return; } update(); } else if (mode == Mode::Coincedent) { Point* clickedPoint = findPointAt(scene); if (!clickedPoint) { firstPoint = nullptr; return; } if (!firstPoint) { firstPoint = clickedPoint; return; } if (clickedPoint == firstPoint) { firstPoint = nullptr; return; } Line *l1 = nullptr, *l2 = nullptr; for (Line* l : lines) { if (&l->p1 == firstPoint || &l->p2 == firstPoint) l1 = l; if (&l->p1 == clickedPoint || &l->p2 == clickedPoint) l2 = l; } if (l1 == l2) { QMessageBox::warning(this, QString("NO!"), QString("P2P failed")); firstPoint = nullptr; return; } sys.addConstraintP2PCoincident(*firstPoint, *clickedPoint, constraints_count++); firstPoint = nullptr; mode = Mode::None; update(); return; } } void Canvas::paintEvent(QPaintEvent*) { QPainter p(this); p.setRenderHint(QPainter::Antialiasing); if (!params.empty()) { int res = sys.solve(params); if (res == SolveStatus::Success) { sys.applySolution(); } else { #ifdef _DEBUG qDebug() << "INVAILD LAST CONSTRAINT. REMOVE HIM"; #endif sys.removeConstraint(sys.get_last_constraint()); } } for (Line* line : lines) { line->draw(p); } return; } Canvas::Canvas(QWidget *parent) : QWidget(parent) { sys = System(); current_line = nullptr; setMouseTracking(true); setBackgroundRole(QPalette::Base); setAutoFillBackground(true); } Canvas::~Canvas() { for (Line* line : lines) { delete line; } for (double* param : params) { delete param; } lines.clear(); params.clear(); points.clear(); if (current_line) delete current_line; if (firstPoint) delete firstPoint; }