src/editmodes/abstractEditMode.cpp

changeset 1042
b54b78ac41a5
parent 1041
9fc08b73b8c4
child 1056
27b7991b3bea
equal deleted inserted replaced
1041:9fc08b73b8c4 1042:b54b78ac41a5
32 #include "../grid.h" 32 #include "../grid.h"
33 33
34 ConfigOption (bool DrawLineLengths = true) 34 ConfigOption (bool DrawLineLengths = true)
35 ConfigOption (bool DrawAngles = false) 35 ConfigOption (bool DrawAngles = false)
36 36
37 AbstractEditMode::AbstractEditMode (GLRenderer* renderer) : 37 AbstractEditMode::AbstractEditMode(GLRenderer* renderer) :
38 QObject (renderer), 38 QObject(renderer),
39 HierarchyElement (renderer), 39 HierarchyElement(renderer),
40 m_renderer (renderer) {} 40 m_renderer(renderer) {}
41 41
42 AbstractEditMode::~AbstractEditMode() {} 42 AbstractEditMode::~AbstractEditMode() {}
43 43
44 AbstractEditMode* AbstractEditMode::createByType (GLRenderer* renderer, EditModeType type) 44 AbstractEditMode* AbstractEditMode::createByType(GLRenderer* renderer, EditModeType type)
45 { 45 {
46 switch (type) 46 switch (type)
47 { 47 {
48 case EditModeType::Select: return new SelectMode (renderer); 48 case EditModeType::Select: return new SelectMode (renderer);
49 case EditModeType::Draw: return new DrawMode (renderer); 49 case EditModeType::Draw: return new DrawMode (renderer);
52 case EditModeType::MagicWand: return new MagicWandMode (renderer); 52 case EditModeType::MagicWand: return new MagicWandMode (renderer);
53 case EditModeType::LinePath: return new LinePathMode (renderer); 53 case EditModeType::LinePath: return new LinePathMode (renderer);
54 case EditModeType::Curve: return new CurveMode (renderer); 54 case EditModeType::Curve: return new CurveMode (renderer);
55 } 55 }
56 56
57 throw std::logic_error ("bad type given to AbstractEditMode::createByType"); 57 throw std::logic_error("bad type given to AbstractEditMode::createByType");
58 } 58 }
59 59
60 GLRenderer* AbstractEditMode::renderer() const 60 GLRenderer* AbstractEditMode::renderer() const
61 { 61 {
62 return m_renderer; 62 return m_renderer;
63 } 63 }
64 64
65 AbstractDrawMode::AbstractDrawMode (GLRenderer* renderer) : 65 AbstractDrawMode::AbstractDrawMode(GLRenderer* renderer) :
66 AbstractEditMode (renderer), 66 AbstractEditMode(renderer),
67 m_polybrush (QBrush (QColor (64, 192, 0, 128))) 67 m_polybrush{QBrush{QColor{64, 192, 0, 128}}}
68 { 68 {
69 renderer->setContextMenuPolicy (Qt::NoContextMenu); // We need the right mouse button for removing vertices 69 renderer->setContextMenuPolicy (Qt::NoContextMenu); // We need the right mouse button for removing vertices
70 renderer->setCursor (Qt::CrossCursor); 70 renderer->setCursor (Qt::CrossCursor);
71 m_window->currentDocument()->clearSelection(); 71 m_window->currentDocument()->clearSelection();
72 m_window->updateSelection(); 72 m_window->updateSelection();
80 renderer->setContextMenuPolicy (Qt::DefaultContextMenu); 80 renderer->setContextMenuPolicy (Qt::DefaultContextMenu);
81 } 81 }
82 82
83 // ============================================================================= 83 // =============================================================================
84 // 84 //
85 void AbstractDrawMode::addDrawnVertex (Vertex const& pos) 85 void AbstractDrawMode::addDrawnVertex(const Vertex& position)
86 { 86 {
87 if (preAddVertex (pos)) 87 if (preAddVertex(position))
88 return; 88 return;
89 89
90 m_drawedVerts << pos; 90 m_drawedVerts << position;
91 } 91 }
92 92
93 bool AbstractDrawMode::mouseReleased (MouseEventData const& data) 93 bool AbstractDrawMode::mouseReleased(MouseEventData const& data)
94 { 94 {
95 if (Super::mouseReleased (data)) 95 if (Super::mouseReleased(data))
96 return true; 96 return true;
97 97
98 if ((data.releasedButtons & Qt::MidButton) and (m_drawedVerts.size() < 4) and (not data.mouseMoved)) 98 if ((data.releasedButtons & Qt::MidButton) and (m_drawedVerts.size() < 4) and (not data.mouseMoved))
99 { 99 {
100 // Find the closest vertex to our cursor 100 // Find the closest vertex to our cursor
101 double minimumDistance = 1024.0; 101 double minimumDistance = 1024.0;
102 const Vertex* closest = nullptr; 102 const Vertex* closest = nullptr;
103 Vertex cursorPosition = renderer()->convert2dTo3d (data.ev->pos(), false); 103 Vertex cursorPosition = renderer()->convert2dTo3d (data.ev->pos(), false);
104 QPoint cursorPosition2D (data.ev->pos()); 104 QPoint cursorPosition2D (data.ev->pos());
105 const Axis relZ = renderer()->getRelativeZ(); 105 const Axis depthAxis = renderer()->getRelativeZ();
106 QList<Vertex> vertices = renderer()->document()->inlineVertices().toList(); 106 QList<Vertex> vertices = renderer()->document()->inlineVertices().toList();
107 107
108 // Sort the vertices in order of distance to camera 108 // Sort the vertices in order of distance to camera
109 std::sort (vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool 109 std::sort (vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool
110 { 110 {
111 if (renderer()->cameraInfo (renderer()->camera()).negatedDepth) 111 if (renderer()->cameraInfo (renderer()->camera()).negatedDepth)
112 return a[relZ] > b[relZ]; 112 return a[depthAxis] > b[depthAxis];
113 113 else
114 return a[relZ] < b[relZ]; 114 return a[depthAxis] < b[depthAxis];
115 }); 115 });
116 116
117 for (const Vertex& vrt : vertices) 117 for (const Vertex& vrt : vertices)
118 { 118 {
119 // If the vertex in 2d space is very close to the cursor then we use it regardless of depth. 119 // If the vertex in 2d space is very close to the cursor then we use it regardless of depth.
144 addDrawnVertex (*closest); 144 addDrawnVertex (*closest);
145 145
146 return true; 146 return true;
147 } 147 }
148 148
149 if ((data.releasedButtons & Qt::RightButton) and (not m_drawedVerts.isEmpty())) 149 if ((data.releasedButtons & Qt::RightButton) and not m_drawedVerts.isEmpty())
150 { 150 {
151 // Remove the last vertex 151 // Remove the last vertex
152 m_drawedVerts.removeLast(); 152 m_drawedVerts.removeLast();
153 return true; 153 return true;
154 } 154 }
155 155
156 if (data.releasedButtons & Qt::LeftButton) 156 if (data.releasedButtons & Qt::LeftButton)
157 { 157 {
158 if (maxVertices() and m_drawedVerts.size() >= maxVertices()) 158 if (maxVertices() and m_drawedVerts.size() >= maxVertices())
159 {
160 endDraw(); 159 endDraw();
161 return true; 160 else
162 } 161 addDrawnVertex (getCursorVertex());
163
164 addDrawnVertex (getCursorVertex());
165 return true; 162 return true;
166 } 163 }
167 164
168 return false; 165 return false;
169 } 166 }
170 167
171 void AbstractDrawMode::finishDraw (LDObjectList const& objs) 168 void AbstractDrawMode::finishDraw(LDObjectList const& objs)
172 { 169 {
173 int pos = m_window->suggestInsertPoint(); 170 int pos = m_window->suggestInsertPoint();
174 171
175 if (objs.size() > 0) 172 if (objs.size() > 0)
176 { 173 {
185 } 182 }
186 183
187 m_drawedVerts.clear(); 184 m_drawedVerts.clear();
188 } 185 }
189 186
190 void AbstractDrawMode::drawLength (QPainter &painter, const Vertex &v0, const Vertex &v1, 187 void AbstractDrawMode::drawLineLength(QPainter &painter, const Vertex &v0, const Vertex &v1,
191 const QPointF& v0p, const QPointF& v1p) const 188 const QPointF& v0p, const QPointF& v1p) const
192 { 189 {
193 if (not m_config->drawLineLengths()) 190 if (not m_config->drawLineLengths())
194 return; 191 return;
195 192
196 const QString label = QString::number ((v1 - v0).length(), 'f', 2); 193 const QString label = QString::number ((v1 - v0).length(), 'f', 2);
197 QPoint origin = QLineF (v0p, v1p).pointAt (0.5).toPoint(); 194 QPoint origin = QLineF (v0p, v1p).pointAt (0.5).toPoint();
198 painter.drawText (origin, label); 195 painter.drawText (origin, label);
199 } 196 }
200 197
201 void AbstractDrawMode::renderPolygon (QPainter& painter, const QVector<Vertex>& poly3d, 198 void AbstractDrawMode::renderPolygon(QPainter& painter, const QVector<Vertex>& polygon3d,
202 bool withlengths, bool withangles) const 199 bool drawLineLengths, bool drawAngles ) const
203 { 200 {
204 QVector<QPoint> poly (poly3d.size()); 201 QVector<QPoint> polygon2d (polygon3d.size());
205 QFontMetrics metrics = QFontMetrics (QFont()); 202 QFontMetrics metrics = QFontMetrics(QFont());
206 203
207 // Convert to 2D 204 // Convert to 2D
208 for (int i = 0; i < poly3d.size(); ++i) 205 for (int i = 0; i < polygon3d.size(); ++i)
209 poly[i] = renderer()->convert3dTo2d (poly3d[i]); 206 polygon2d[i] = renderer()->convert3dTo2d(polygon3d[i]);
210 207
211 // Draw the polygon-to-be 208 // Draw the polygon-to-be
212 painter.setBrush (m_polybrush); 209 painter.setBrush(m_polybrush);
213 painter.drawPolygon (QPolygonF (poly)); 210 painter.drawPolygon(QPolygonF{polygon2d});
214 211
215 // Draw vertex blips 212 // Draw vertex blips
216 for (int i = 0; i < poly3d.size(); ++i) 213 for (int i = 0; i < polygon3d.size(); ++i)
217 { 214 {
218 renderer()->drawBlip (painter, poly[i]); 215 renderer()->drawBlip(painter, polygon2d[i]);
219 renderer()->drawBlipCoordinates (painter, poly3d[i], poly[i]); 216 renderer()->drawBlipCoordinates(painter, polygon3d[i], polygon2d[i]);
220 } 217 }
221 218
222 // Draw line lenghts and angle info if appropriate 219 // Draw line lenghts and angle info if appropriate
223 if (poly3d.size() >= 2 and (withlengths or withangles)) 220 if (polygon3d.size() >= 2 and (drawLineLengths or drawAngles))
224 { 221 {
225 painter.setPen (renderer()->textPen()); 222 painter.setPen (renderer()->textPen());
226 223
227 for (int i = 0; i < poly3d.size(); ++i) 224 for (int i = 0; i < polygon3d.size(); ++i)
228 { 225 {
229 const int j = (i + 1) % poly3d.size(); 226 int j = (i + 1) % polygon3d.size();
230 const int h = (i - 1 >= 0) ? (i - 1) : (poly3d.size() - 1); 227 int prior = (i - 1 >= 0) ? (i - 1) : (polygon3d.size() - 1);
231 228
232 if (withlengths) 229 if (drawLineLengths)
233 drawLength (painter, poly3d[i], poly3d[j], poly[i], poly[j]); 230 drawLineLength(painter, polygon3d[i], polygon3d[j], polygon2d[i], polygon2d[j]);
234 231
235 if (withangles and m_config->drawAngles()) 232 if (drawAngles and m_config->drawAngles())
236 { 233 {
237 QLineF l0 (poly[h], poly[i]), 234 QLineF line0 = {polygon2d[prior], polygon2d[i]};
238 l1 (poly[i], poly[j]); 235 QLineF line1 = {polygon2d[i], polygon2d[j]};
239 236 double angle = 180 - line0.angleTo(line1);
240 double angle = 180 - l0.angleTo (l1);
241 237
242 if (angle < 0) 238 if (angle < 0)
243 angle = 180 - l1.angleTo (l0); 239 angle = 180 - line1.angleTo(line0);
244 240
245 QString label = QString::number (angle) + QString::fromUtf8 (QByteArray ("\302\260")); 241 QString label = QString::number(angle) + "°";
246 QPoint pos = poly[i]; 242 QPoint textPosition = polygon2d[i];
247 pos.setY (pos.y() + metrics.height()); 243 textPosition.setY(textPosition.y() + metrics.height());
248 244 painter.drawText(textPosition, label);
249 painter.drawText (pos, label);
250 } 245 }
251 } 246 }
252 } 247 }
253 } 248 }
254 249
264 } 259 }
265 260
266 return false; 261 return false;
267 } 262 }
268 263
264 //
265 // roundToInterval
266 //
267 // Rounds 'a' to the nearest multiple of 'interval'.
268 //
269 template<typename T> 269 template<typename T>
270 T intervalClamp (T a, T interval) 270 T roundToInterval (T a, T interval)
271 { 271 {
272 T remainder = a % interval; 272 T remainder = a % interval;
273 273
274 if (remainder >= float (interval / 2)) 274 if (remainder >= interval / 2.0)
275 a += interval; 275 a += interval;
276 276
277 a -= remainder; 277 a -= remainder;
278 return a; 278 return a;
279 } 279 }
280 280
281 Vertex AbstractDrawMode::getCursorVertex() const 281 Vertex AbstractDrawMode::getCursorVertex() const
282 { 282 {
283 Vertex result = renderer()->position3D(); 283 Vertex result = renderer()->position3D();
284 284
285 if (renderer()->keyboardModifiers() & Qt::ControlModifier 285 if ((renderer()->keyboardModifiers() & Qt::ControlModifier) and not m_drawedVerts.isEmpty())
286 and not m_drawedVerts.isEmpty()) 286 {
287 { 287 Vertex const& vertex0 = m_drawedVerts.last();
288 Vertex const& v0 = m_drawedVerts.last(); 288 Vertex const& vertex1 = result;
289 Vertex const& v1 = result; 289 Axis relativeX, relativeY;
290 Axis relX, relY; 290
291 291 renderer()->getRelativeAxes (relativeX, relativeY);
292 renderer()->getRelativeAxes (relX, relY); 292 QLineF line = {vertex0[relativeX], vertex0[relativeY], vertex1[relativeX], vertex1[relativeY]};
293 QLineF ln (v0[relX], v0[relY], v1[relX], v1[relY]); 293 line.setAngle(roundToInterval<int>(line.angle(), 45));
294 ln.setAngle (intervalClamp<int> (ln.angle(), 45)); 294 result.setCoordinate(relativeX, grid()->snap(line.x2(), Grid::Coordinate));
295 result.setCoordinate (relX, grid()->snap(ln.x2(), Grid::Coordinate)); 295 result.setCoordinate(relativeY, grid()->snap(line.y2(), Grid::Coordinate));
296 result.setCoordinate (relY, grid()->snap(ln.y2(), Grid::Coordinate));
297 } 296 }
298 297
299 return result; 298 return result;
300 } 299 }

mercurial