diff --git a/Canvas.cpp b/Canvas.cpp index 6af8eed..e4646a0 100644 --- a/Canvas.cpp +++ b/Canvas.cpp @@ -1,21 +1,43 @@ #include "Canvas.h" + 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; +} + +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(); - changeMode(DrawingLine); -#endif + #ifdef _DEBUG + qDebug() << "Scene point in" << scene.x() << scene.y(); + #endif - if (mode == DrawingLine) { + 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()); @@ -25,6 +47,9 @@ void Canvas::mousePressEvent(QMouseEvent* event) 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; @@ -39,25 +64,83 @@ void Canvas::mousePressEvent(QMouseEvent* event) lines.append(current_line); current_line = nullptr; - } - -//#ifdef _DEBUG -// if (lines.size()) { -// qDebug() << "Line coords" << lines[lines.size() - 1]->p1.get_X() << -// lines[lines.size() - 1]->p1.get_Y() << -// lines[lines.size() - 1]->p2.get_X() << -// lines[lines.size() - 1]->p2.get_Y(); -// changeMode(None); -// } -//#endif - + mode = Mode::None; + obj_count++; + update(); + return; + } } + else if (mode == Mode::Parallel) { + static Line* first = nullptr; + Line* found = findAt(scene); + + if (!found) { + first = nullptr; + return; + } + + if (!first) { + first = found; + return; + } + + if (found == first){ + first = nullptr; + return; + } + + if (!areAlreadyParallel(found, first)) { + sys.addConstraintParallel(*found, *first, constraints_count++); + parallelPairs.insert(makeOrderedPair(found, first)); + first = nullptr; + mode = Mode::None; + } + + else { + + #ifdef _DEBUG + qDebug() << "Line" << first << "and" << found << "are parallel. Abort!"; + #endif + QMessageBox::information(this, + QString("Wrong"), + QString("Parallel lines can not be more parallel!"), + QMessageBox::Ok + ); + first = nullptr; + return; + } + + update(); + } +} + +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); @@ -76,6 +159,7 @@ Canvas::~Canvas() lines.clear(); params.clear(); + points.clear(); if (current_line) delete current_line; diff --git a/Canvas.h b/Canvas.h index 7385c2b..1f0da0f 100644 --- a/Canvas.h +++ b/Canvas.h @@ -2,33 +2,65 @@ #include #include +#include +#include + #ifdef _DEBUG #include #endif +// GCS — геометрический солвер из FreeCAD #include "GCS/Geo.h" +#include "GCS/GCS.h" using namespace GCS; -enum Mode { - None, - DrawingLine +enum class Mode : int +{ + None = 0, + DrawingLine = 1, + Parallel = 2 }; +// Удобный тип для хранения пары параллельных линий (порядок не важен) +using LinePair = std::pair; + +// =================================================================== +// Основной класс холста +// =================================================================== class Canvas : public QWidget { - Q_OBJECT -private: - void changeMode(Mode); - Mode mode = Mode::None; - QVector lines; - QVector points; - QVector params; - Line* current_line; -protected: - void mousePressEvent(QMouseEvent*) override; -public: - Canvas(QWidget *parent); - ~Canvas(); -}; + Q_OBJECT +public: + explicit Canvas(QWidget* parent = nullptr); + ~Canvas() override; + + void changeMode(Mode newMode); + +protected: + void mousePressEvent(QMouseEvent* event) override; + void paintEvent(QPaintEvent* event) override; + +private: + // ====================== Поиск и выбор ====================== + Line* findAt(QPointF&); // ищет линию под курсором + + // ====================== Параллельность ====================== + LinePair makeOrderedPair(Line* l1, Line* l2); + bool areAlreadyParallel(Line* l1, Line* l2); // проверка на дубликат + + // ====================== Данные сцены ====================== + System sys; // геометрический солвер + QVector lines; // завершённые линии + QVector points; // все точки (для удобного доступа) + std::vector params; // все параметры, передаваемые в солвер + + std::set parallelPairs; // уже запараллеленные пары (защита от дублей) + + Line* current_line{ nullptr }; + Mode mode{ Mode::None }; + + int obj_count{ 0 }; // тег для новых объектов + int constraints_count{ 0 }; // тег для новых ограничений +}; \ No newline at end of file diff --git a/DRAWer_2_0.cpp b/DRAWer_2_0.cpp index 8637ffb..9f9ec8c 100644 --- a/DRAWer_2_0.cpp +++ b/DRAWer_2_0.cpp @@ -14,5 +14,18 @@ DRAWer_2_0::~DRAWer_2_0() void DRAWer_2_0::on_pushButton_clicked() { ui.label->setText(QString::number(counter++)); + ui.widget->changeMode(Mode::DrawingLine); +} + + +void DRAWer_2_0::on_pushButton_2_clicked() +{ + ui.widget->changeMode(Mode::Parallel); +} + + +void DRAWer_2_0::on_pushButton_3_clicked() +{ + return; } diff --git a/DRAWer_2_0.h b/DRAWer_2_0.h index 38d52f8..fa5ae79 100644 --- a/DRAWer_2_0.h +++ b/DRAWer_2_0.h @@ -14,6 +14,10 @@ public: private slots: void on_pushButton_clicked(); + void on_pushButton_2_clicked(); + + void on_pushButton_3_clicked(); + private: Ui::DRAWer_2_0Class ui; int counter; diff --git a/GCS/GCS.h b/GCS/GCS.h index 456751e..5bb24ab 100644 --- a/GCS/GCS.h +++ b/GCS/GCS.h @@ -250,6 +250,9 @@ public: void clearByTag(int tagId, bool is_fixed_point = false); int addConstraint(Constraint* constr); void removeConstraint(Constraint* constr); + Constraint* get_last_constraint() { + return clist[clist.size() - 1]; + } // basic constraints int addConstraintFixed(Point& p, int tagId = 0, bool driving = true); diff --git a/GCS/Geo.cpp b/GCS/Geo.cpp index 852191b..ff477ef 100644 --- a/GCS/Geo.cpp +++ b/GCS/Geo.cpp @@ -143,6 +143,33 @@ Line::Line(Point _p1, Point _p2, int _tag) { tag = _tag; } +void Line::set_tag(int _tag) { + tag = _tag; + p1.set_tag(_tag); + p2.set_tag(_tag); +} + +// TODO +bool Line::contains(QPointF pos, qreal tol) const +{ + double x1 = *p1.x, y1 = *p1.y; + double x2 = *p2.x, y2 = *p2.y; + + double A = y1 - y2; + double B = x2 - x1; + double C = x1 * y2 - x2 * y1; + + try { + double distance = abs(A * pos.x() + B * pos.y() + C) / sqrt(A * A + B * B); + return distance < tol; + } + catch (...) { + return false; + } + + +} + DeriVector2 Line::CalculateNormal(const Point& p, const double* derivparam) const { (void)p; diff --git a/GCS/Geo.h b/GCS/Geo.h index ce9ac0f..1a7ec0d 100644 --- a/GCS/Geo.h +++ b/GCS/Geo.h @@ -227,11 +227,8 @@ public: Line* Copy() override; void draw(QPainter& p, bool highlight = false); - void set_tag(int _tag) { - tag = _tag; - p1.set_tag(_tag); - p2.set_tag(_tag); - } + void set_tag(int); + bool contains(QPointF, qreal tol = 10.0) const; }; class Circle: public Curve