This repository has been archived on 2026-05-28. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
DRAwer_2_0/Canvas.cpp

275 lines
6.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
update();
return;
}
if (!current_line) {
current_line = found;
update();
return;
}
if (found == current_line){
current_line = nullptr;
update();
return;
}
if (!areAlreadyParallel(found, current_line)) {
sys.addConstraintParallel(*found, *current_line, constraints_count++);
parallelPairs.insert(makeOrderedPair(found, current_line));
current_line = nullptr;
update();
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;
update();
return;
}
update();
}
else if (mode == Mode::Coincedent) {
Point* clickedPoint = findPointAt(scene);
if (!clickedPoint) {
firstPoint = nullptr;
update();
return;
}
if (!firstPoint) {
firstPoint = clickedPoint;
update();
return;
}
if (clickedPoint == firstPoint) {
firstPoint = nullptr;
update();
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;
update();
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, true);
// === Решаем систему один раз ===
if (!params.empty()) {
int res = sys.solve(params);
if (res == SolveStatus::Success || res == SolveStatus::Converged) {
sys.applySolution();
}
else {
sys.removeConstraint(sys.get_last_constraint());
constraints_count--;
}
}
for (Line* line : lines) {
bool isSelected = (mode == Mode::Parallel && line == current_line);
QPen linePen = isSelected ? QPen(Qt::red, 4) : QPen(Qt::black, 2);
p.setPen(linePen);
// Рисуем саму линию
p.drawLine(QPointF(*line->p1.x, *line->p1.y),
QPointF(*line->p2.x, *line->p2.y));
// Рисуем концы — с учётом выделения
QBrush pointBrush = isSelected ? QBrush(Qt::red) : QBrush(Qt::darkBlue);
p.setBrush(pointBrush);
p.setPen(Qt::NoPen); // убираем обводку у кружков
p.drawEllipse(QPointF(*line->p1.x, *line->p1.y), 5, 5);
p.drawEllipse(QPointF(*line->p2.x, *line->p2.y), 5, 5);
}
// === Подсветка выбранной точки в режиме Coincident ===
if (mode == Mode::Coincedent && firstPoint) {
QPointF pt(*firstPoint->x, *firstPoint->y);
p.setPen(Qt::NoPen);
p.setBrush(Qt::red);
p.drawEllipse(pt, 12, 12);
p.setBrush(Qt::white);
p.drawEllipse(pt, 8, 8);
p.setBrush(Qt::red);
p.drawEllipse(pt, 4, 4); // маленький центр
}
// === Текущая рисуемая линия (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);
}
}
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;
}