166 lines
7.0 KiB
C++
166 lines
7.0 KiB
C++
#pragma once
|
||
constexpr auto EPS = 1e-9;
|
||
constexpr auto ZOOM_STEP = 0.05;
|
||
|
||
#include <QWidget>
|
||
#include <QMouseEvent>
|
||
#include <QPointF>
|
||
#include <QMessageBox>
|
||
#include <QToolTip>
|
||
#include <QKeyEvent>
|
||
|
||
#ifdef _DEBUG
|
||
#include <QDebug>
|
||
#endif
|
||
|
||
// GCS — геометрический солвер из FreeCAD
|
||
#include "GCS/Geo.h"
|
||
#include "GCS/GCS.h"
|
||
using namespace GCS;
|
||
|
||
// ===================================================================
|
||
// Типы и перечисления
|
||
// ===================================================================
|
||
|
||
/// Режимы работы с холстом
|
||
enum class Mode : int
|
||
{
|
||
None = 0, ///< Режим отсутствия действия
|
||
DrawingLine = 1, ///< Режим рисования линии
|
||
Parallel = 2, ///< Режим задания параллельности
|
||
Coincedent = 3, ///< Режим задания совпадения точек
|
||
Horizontal = 4, ///< Режим задания горизонтальности
|
||
Vertical = 5, ///< Режим задания вертикальности
|
||
Perpendicular = 6
|
||
};
|
||
|
||
/// Удобный тип для хранения пары параллельных линий (порядок не важен)
|
||
using LinePair = std::pair<Line*, Line*>;
|
||
|
||
/// Удобный тип для хранения пары точек (порядок не важен)
|
||
using PointPair = std::pair<Point*, Point*>;
|
||
|
||
// ===================================================================
|
||
// Основной класс холста
|
||
// ===================================================================
|
||
|
||
class Canvas : public QWidget
|
||
{
|
||
Q_OBJECT
|
||
|
||
public:
|
||
explicit Canvas(QWidget* parent = nullptr);
|
||
~Canvas() override;
|
||
|
||
/// Изменить текущий режим работы
|
||
void changeMode(Mode newMode);
|
||
|
||
/// Увеличить масштаб
|
||
void zoomIn();
|
||
|
||
/// Уменьшить масштаб
|
||
void zoomOut();
|
||
|
||
/// Сбросить масштаб к 100%
|
||
void zoomReset();
|
||
|
||
protected:
|
||
// Обработчики событий Qt
|
||
void mousePressEvent(QMouseEvent* event) override;
|
||
void mouseMoveEvent(QMouseEvent* event) override;
|
||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||
void wheelEvent(QWheelEvent* event) override;
|
||
void paintEvent(QPaintEvent* event) override;
|
||
void keyPressEvent(QKeyEvent* event);
|
||
void leaveEvent(QEvent* event) override;
|
||
|
||
private:
|
||
|
||
#ifdef _DEBUG
|
||
void showObjectTag(QPointF pos);
|
||
#endif
|
||
|
||
QPointF screenToLogical(const QPointF& screenPos) const;
|
||
void getCoincidentGroup(Point* p);
|
||
// ====================== Методы поиска и выбора ======================
|
||
|
||
/// Найти линию под указанной позицией
|
||
Line* findAt(QPointF& pos, qreal tolerance = 5.0);
|
||
|
||
/// Найти точку в указанной позиции с заданной точностью
|
||
Point* findPointAt(QPointF position, qreal tolerance = 5.0);
|
||
|
||
/// Проверить, совпадают ли две точки (ограничение P2P)
|
||
bool areCoincident(Point* point1, Point* point2);
|
||
|
||
/// Проверить горизонтальность или вертикальность между двумя точками
|
||
/// @param mode: false - горизонтальность, true - вертикальность
|
||
bool areHorizontalVertical(Point* point1, Point* point2, bool mode);
|
||
|
||
/// Проверить, является ли линия горизонтальной
|
||
bool isLineHorizontal(Line* line);
|
||
|
||
/// Проверить, является ли линия вертикальной
|
||
bool isLineVertical(Line* line);
|
||
|
||
/// Проверить, являются ли две линии уже параллельными (дубликат ограничения)
|
||
bool areAlreadyParallel(Line* line1, Line* line2);
|
||
|
||
bool areAlreadyPerpendicular(Line* line1, Line* line2);
|
||
|
||
// ====================== Методы работы с ограничениями ======================
|
||
|
||
/// Удалить последние добавленные ограничения при ошибке солвера
|
||
void remove_constraint(int);
|
||
|
||
// ====================== Данные для перемещения объектов ======================
|
||
|
||
Point* draggedPoint{ nullptr }; ///< Точка, которую перемещают
|
||
Line* draggedLine{ nullptr }; ///< Линия, которую перемещают
|
||
QPointF dragOffset; ///< Смещение при начале перемещения
|
||
|
||
// ====================== Данные геометрической системы ======================
|
||
|
||
System sys; ///< Геометрический солвер
|
||
QVector<Line*> lines; ///< Завершённые линии
|
||
QVector<Point*> points; ///< Все точки сцены
|
||
std::vector<double*> params; ///< Все параметры, передаваемые в солвер
|
||
|
||
// ====================== Коллекции ограничений ======================
|
||
|
||
std::set<LinePair> parallelPairs; ///< Пары параллельных линий
|
||
std::set<LinePair> perpendicularPairs;
|
||
std::set<PointPair> P2Ppairs; ///< Пары совпадающих точек
|
||
std::set<PointPair> HORIZ_pairs; ///< Пары точек горизонтальных линий
|
||
std::set<PointPair> VERT_pairs; ///< Пары точек вертикальных линий
|
||
|
||
// ====================== Временные данные для режимов ======================
|
||
|
||
Line* current_line{ nullptr }; ///< Текущая линия в режимах рисования/параллельности
|
||
Point* firstPoint{ nullptr }; ///< Первая точка в режиме совпадения
|
||
Mode mode{ Mode::None }; ///< Текущий режим работы
|
||
|
||
// ====================== Флаги состояния ======================
|
||
|
||
bool after_constraint{ false }; ///< Флаг, что только что добавлено ограничение
|
||
double scaleFactor { 1.0 };
|
||
|
||
// ====================== Счётчики ======================
|
||
|
||
int obj_count{ 0 }; ///< Счётчик объектов (для тегов)
|
||
int constraints_count{ 0 }; ///< Счётчик ограничений (для тегов)
|
||
|
||
// ====================== Информация о последнем ограничении ======================
|
||
|
||
/// Структура для хранения информации о последнем добавленном ограничении
|
||
/// (используется для отката при ошибке солвера)
|
||
|
||
struct ConstraintInfo {
|
||
Mode mode;
|
||
std::variant<LinePair, PointPair> data;
|
||
};
|
||
std::map<int, ConstraintInfo> C_Info;
|
||
|
||
void solve_for_canvas();
|
||
void clearCanvas();
|
||
}; |