src/tools/drawtool.cpp

changeset 191
d355d4c52d51
parent 190
3dbdc243f053
child 192
e6faeffed1d1
equal deleted inserted replaced
190:3dbdc243f053 191:d355d4c52d51
1 #include <QMessageBox>
2 #include <document.h>
3 #include "linetypes/edge.h"
4 #include "linetypes/triangle.h"
5 #include "linetypes/quadrilateral.h"
6 #include "drawtool.h"
7 #include "modeleditor.h"
8
9 static const QBrush pointBrush = {Qt::white};
10 static const QPen polygonPen = {QBrush{Qt::black}, 2.0, Qt::DashLine};
11 static const QPen badPolygonPen = {QBrush{Qt::red}, 2.0, Qt::DashLine};
12 static const QPen pointPen = {QBrush{Qt::black}, 2.0};
13 static const QBrush greenPolygonBrush = {QColor{64, 255, 128, 192}};
14 static const QBrush redPolygonBrush = {QColor{255, 96, 96, 192}};
15
16 AbstractDrawTool::AbstractDrawTool(Document *document) :
17 BaseTool{document}
18 {
19 }
20
21 DrawTool::DrawTool(Document* document) :
22 AbstractDrawTool{document}
23 {
24 }
25
26 QString DrawTool::name() const
27 {
28 static const QString result = tr("Draw");
29 return result;
30 }
31
32 QString DrawTool::toolTip() const
33 {
34 static const QString result = tr("Draw new elements into the model.");
35 return result;
36 }
37
38 bool AbstractDrawTool::mouseClick(Canvas* canvas, QMouseEvent* event)
39 {
40 if (event->button() == Qt::LeftButton)
41 {
42 this->addCurrentPoint(canvas);
43 return true;
44 }
45 else if (event->button() == Qt::RightButton)
46 {
47 this->removeLastPoint();
48 return true;
49 }
50 else
51 {
52 return false;
53 }
54 }
55
56 bool AbstractDrawTool::mouseMove(Document* document, Canvas* canvas, QMouseEvent *event)
57 {
58 static_cast<void>(document);
59 static_cast<void>(event);
60 const auto& worldPosition = canvas->getWorldPosition();
61 if (worldPosition.has_value())
62 {
63 this->previewPoint = worldPosition.value();
64 this->updatePreviewPolygon();
65 }
66 return false;
67 }
68
69 bool AbstractDrawTool::keyReleased(Document*, Canvas* canvas, QKeyEvent* event)
70 {
71 if (event->key() == Qt::Key_Escape)
72 {
73 this->polygon.clear();
74 this->updatePreviewPolygon();
75 canvas->update();
76 return true;
77 }
78 else
79 {
80 return false;
81 }
82 }
83
84 void AbstractDrawTool::addCurrentPoint(Canvas* canvas)
85 {
86 const auto& worldPosition = canvas->getWorldPosition();
87 if (worldPosition.has_value())
88 {
89 const glm::vec3& pos = worldPosition.value();
90 if (this->isCloseToExistingPoints(pos))
91 {
92 this->closeShape();
93 }
94 else
95 {
96 this->addPoint(pos);
97 }
98 }
99 }
100
101 void AbstractDrawTool::updatePreviewPolygon()
102 {
103 this->previewPolygon = this->polygon;
104 this->previewPolygon.resize(this->polygon.size() + 1);
105 this->previewPolygon.back() = this->previewPoint;
106 if (this->previewPolygon.size() > 2)
107 {
108 this->isconcave = not geom::isConvex(this->previewPolygon);
109 }
110 }
111
112 void AbstractDrawTool::reset()
113 {
114 this->polygon.clear();
115 }
116
117 void AbstractDrawTool::overpaint(Canvas* canvas, QPainter* painter) const
118 {
119 painter->setPen(this->isconcave ? ::badPolygonPen : ::polygonPen);
120 if (this->previewPolygon.size() > 2 and not this->isconcave)
121 {
122 if (canvas->worldPolygonWinding(this->previewPolygon) == Winding::Clockwise)
123 {
124 painter->setBrush(::greenPolygonBrush);
125 }
126 else
127 {
128 painter->setBrush(::redPolygonBrush);
129 }
130 canvas->drawWorldPolygon(painter, this->previewPolygon);
131 }
132 else
133 {
134 canvas->drawWorldPolyline(painter, this->previewPolygon);
135 }
136 painter->setBrush(::pointBrush);
137 painter->setPen(::pointPen);
138 for (const glm::vec3& point : this->polygon)
139 {
140 canvas->drawWorldPoint(painter, point);
141 }
142 canvas->drawWorldPoint(painter, this->previewPoint);
143 }
144
145 void AbstractDrawTool::addPoint(const glm::vec3 &pos)
146 {
147 this->polygon.push_back(pos);
148 this->updatePreviewPolygon();
149 }
150
151 void AbstractDrawTool::removeLastPoint()
152 {
153 if (this->polygon.size() > 0)
154 {
155 this->polygon.erase(this->polygon.end() - 1);
156 this->updatePreviewPolygon();
157 }
158 }
159
160 void AbstractDrawTool::clearPoints()
161 {
162 this->polygon.clear();
163 this->updatePreviewPolygon();
164 }
165
166 bool AbstractDrawTool::isCloseToExistingPoints(const glm::vec3 &pos) const
167 {
168 const auto isCloseToPos = [&](const glm::vec3& x)
169 {
170 return geom::isclose(x, pos);
171 };
172 return any(this->polygon, isCloseToPos);
173 }
174
175 QString DrawTool::iconName() const
176 {
177 return ":/icons/pencil-outline.png";
178 }
179
180 void DrawTool::addPoint(const glm::vec3 &pos)
181 {
182 AbstractDrawTool::addPoint(pos);
183 if (this->polygon.size() == 4)
184 {
185 this->closeShape();
186 }
187 }
188
189 template<std::size_t N, typename T>
190 std::array<T, N> vectorToArray(const std::vector<T>& x)
191 {
192 std::array<T, N> result;
193 for (std::size_t i = 0; i < x.size() and i < N; i += 1)
194 {
195 result[i] = x[i];
196 }
197 return result;
198 }
199
200 void DrawTool::closeShape()
201 {
202 if (this->polygon.size() >= 2 and this->polygon.size() <= 4)
203 {
204 std::unique_ptr<ModelEditor> modelEditor = this->document->editModel();
205 switch (this->polygon.size())
206 {
207 case 2:
208 modelEditor->append<ldraw::Edge>(vectorToArray<2>(this->polygon), ldraw::EDGE_COLOR);
209 break;
210 case 3:
211 modelEditor->append<ldraw::Triangle>(vectorToArray<3>(this->polygon), ldraw::MAIN_COLOR);
212 break;
213 case 4:
214 modelEditor->append<ldraw::Quadrilateral>(vectorToArray<4>(this->polygon), ldraw::MAIN_COLOR);
215 break;
216 }
217 }
218 this->clearPoints();
219 }

mercurial