src/editmodes/circleMode.cpp

changeset 1217
314e12e23c3a
parent 1213
f2827b16f941
child 1218
e0b59d183f96
equal deleted inserted replaced
1216:12f9ea615cbc 1217:314e12e23c3a
25 #include "../primitives.h" 25 #include "../primitives.h"
26 #include "../glRenderer.h" 26 #include "../glRenderer.h"
27 #include "../mainwindow.h" 27 #include "../mainwindow.h"
28 #include "../ldObjectMath.h" 28 #include "../ldObjectMath.h"
29 29
30 CircleMode::CircleMode (GLRenderer* renderer) : 30 CircleMode::CircleMode(GLRenderer* renderer) :
31 Super (renderer) {} 31 Super(renderer) {}
32 32
33 EditModeType CircleMode::type() const 33 EditModeType CircleMode::type() const
34 { 34 {
35 return EditModeType::Circle; 35 return EditModeType::Circle;
36 } 36 }
37 37
38 double CircleMode::getCircleDrawDist (int pos) const 38 double CircleMode::getCircleDrawDist(int pos) const
39 { 39 {
40 if (m_drawedVerts.size() >= pos + 1) 40 if (m_drawedVerts.size() >= pos + 1)
41 { 41 {
42 Vertex v1 = (m_drawedVerts.size() >= pos + 2) ? m_drawedVerts[pos + 1] : 42 Vertex v1 = (m_drawedVerts.size() >= pos + 2) ? m_drawedVerts[pos + 1] :
43 renderer()->convert2dTo3d (renderer()->mousePosition(), false); 43 renderer()->convert2dTo3d(renderer()->mousePosition(), false);
44 Axis localx, localy; 44 Axis localx, localy;
45 renderer()->getRelativeAxes (localx, localy); 45 renderer()->getRelativeAxes(localx, localy);
46 double dx = m_drawedVerts[0][localx] - v1[localx]; 46 double dx = m_drawedVerts[0][localx] - v1[localx];
47 double dy = m_drawedVerts[0][localy] - v1[localy]; 47 double dy = m_drawedVerts[0][localy] - v1[localy];
48 return Grid::Snap (sqrt ((dx * dx) + (dy * dy)), Grid::Coordinate); 48 return Grid::Snap(sqrt((dx * dx) +(dy * dy)), Grid::Coordinate);
49 } 49 }
50 50
51 return 0.0; 51 return 0.0;
52 } 52 }
53 53
54 Matrix CircleMode::getCircleDrawMatrix (double scale) 54 Matrix CircleMode::getCircleDrawMatrix(double scale)
55 { 55 {
56 // Matrix templates. 2 is substituted with the scale value, 1 is inverted to -1 if needed. 56 // Matrix templates. 2 is substituted with the scale value, 1 is inverted to -1 if needed.
57 static const Matrix templates[3] = 57 static const Matrix templates[3] =
58 { 58 {
59 { 2, 0, 0, 0, 1, 0, 0, 0, 2 }, 59 { 2, 0, 0, 0, 1, 0, 0, 0, 2 },
75 } 75 }
76 76
77 void CircleMode::buildCircle() 77 void CircleMode::buildCircle()
78 { 78 {
79 LDObjectList objs; 79 LDObjectList objs;
80 const int segments (m_window->ringToolSegments()); 80 const int segments(m_window->ringToolSegments());
81 const int divisions (m_window->ringToolHiRes() ? HighResolution : LowResolution); 81 const int divisions(m_window->ringToolHiRes() ? HighResolution : LowResolution);
82 double dist0 (getCircleDrawDist (0)); 82 double dist0(getCircleDrawDist(0));
83 double dist1 (getCircleDrawDist (1)); 83 double dist1(getCircleDrawDist(1));
84 LDDocument* refFile; 84 LDDocument* refFile;
85 Matrix transform; 85 Matrix transform;
86 bool circleOrDisc = false; 86 bool circleOrDisc = false;
87 87
88 if (dist1 < dist0) 88 if (dist1 < dist0)
89 qSwap (dist0, dist1); 89 qSwap(dist0, dist1);
90 90
91 if (dist0 == dist1) 91 if (dist0 == dist1)
92 { 92 {
93 // If the radii are the same, there's no ring space to fill. Use a circle. 93 // If the radii are the same, there's no ring space to fill. Use a circle.
94 refFile = GetPrimitive (::Circle, segments, divisions, 0); 94 refFile = GetPrimitive(::Circle, segments, divisions, 0);
95 transform = getCircleDrawMatrix (dist0); 95 transform = getCircleDrawMatrix(dist0);
96 circleOrDisc = true; 96 circleOrDisc = true;
97 } 97 }
98 else if (dist0 == 0 or dist1 == 0) 98 else if (dist0 == 0 or dist1 == 0)
99 { 99 {
100 // If either radii is 0, use a disc. 100 // If either radii is 0, use a disc.
101 refFile = GetPrimitive (::Disc, segments, divisions, 0); 101 refFile = GetPrimitive(::Disc, segments, divisions, 0);
102 transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1); 102 transform = getCircleDrawMatrix((dist0 != 0) ? dist0 : dist1);
103 circleOrDisc = true; 103 circleOrDisc = true;
104 } 104 }
105 else if (g_RingFinder.findRings (dist0, dist1)) 105 else if (g_RingFinder.findRings(dist0, dist1))
106 { 106 {
107 // The ring finder found a solution, use that. Add the component rings to the file. 107 // The ring finder found a solution, use that. Add the component rings to the file.
108 for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->getComponents()) 108 for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->getComponents())
109 { 109 {
110 refFile = GetPrimitive (::Ring, segments, divisions, cmp.num); 110 refFile = GetPrimitive(::Ring, segments, divisions, cmp.num);
111 LDSubfileReference* ref = LDSpawn<LDSubfileReference>(); 111 LDSubfileReference* ref = LDSpawn<LDSubfileReference>();
112 ref->setFileInfo (refFile); 112 ref->setFileInfo(refFile);
113 ref->setTransform (getCircleDrawMatrix (cmp.scale)); 113 ref->setTransform(getCircleDrawMatrix(cmp.scale));
114 ref->setPosition (m_drawedVerts[0]); 114 ref->setPosition(m_drawedVerts[0]);
115 ref->setColor (MainColor); 115 ref->setColor(MainColor);
116 objs << ref; 116 objs << ref;
117 } 117 }
118 } 118 }
119 else 119 else
120 { 120 {
121 // Ring finder failed, last resort: draw the ring with quads 121 // Ring finder failed, last resort: draw the ring with quads
122 QList<QLineF> c0, c1; 122 QList<QLineF> c0, c1;
123 Axis localx, localy, localz; 123 Axis localx, localy, localz;
124 renderer()->getRelativeAxes (localx, localy); 124 renderer()->getRelativeAxes(localx, localy);
125 localz = (Axis) (3 - localx - localy); 125 localz = (Axis)(3 - localx - localy);
126 double x0 (m_drawedVerts[0][localx]); 126 double x0(m_drawedVerts[0][localx]);
127 double y0 (m_drawedVerts[0][localy]); 127 double y0(m_drawedVerts[0][localy]);
128 128
129 Vertex templ; 129 Vertex templ;
130 templ.setCoordinate (localx, x0); 130 templ.setCoordinate(localx, x0);
131 templ.setCoordinate (localy, y0); 131 templ.setCoordinate(localy, y0);
132 templ.setCoordinate (localz, renderer()->getDepthValue()); 132 templ.setCoordinate(localz, renderer()->getDepthValue());
133 133
134 // Calculate circle coords 134 // Calculate circle coords
135 MakeCircle (segments, divisions, dist0, c0); 135 MakeCircle(segments, divisions, dist0, c0);
136 MakeCircle (segments, divisions, dist1, c1); 136 MakeCircle(segments, divisions, dist1, c1);
137 137
138 for (int i = 0; i < segments; ++i) 138 for (int i = 0; i < segments; ++i)
139 { 139 {
140 Vertex v0, v1, v2, v3; 140 Vertex v0, v1, v2, v3;
141 v0 = v1 = v2 = v3 = templ; 141 v0 = v1 = v2 = v3 = templ;
142 v0.setCoordinate (localx, v0[localx] + c0[i].x1()); 142 v0.setCoordinate(localx, v0[localx] + c0[i].x1());
143 v0.setCoordinate (localy, v0[localy] + c0[i].y1()); 143 v0.setCoordinate(localy, v0[localy] + c0[i].y1());
144 v1.setCoordinate (localx, v1[localx] + c0[i].x2()); 144 v1.setCoordinate(localx, v1[localx] + c0[i].x2());
145 v1.setCoordinate (localy, v1[localy] + c0[i].y2()); 145 v1.setCoordinate(localy, v1[localy] + c0[i].y2());
146 v2.setCoordinate (localx, v2[localx] + c1[i].x2()); 146 v2.setCoordinate(localx, v2[localx] + c1[i].x2());
147 v2.setCoordinate (localy, v2[localy] + c1[i].y2()); 147 v2.setCoordinate(localy, v2[localy] + c1[i].y2());
148 v3.setCoordinate (localx, v3[localx] + c1[i].x1()); 148 v3.setCoordinate(localx, v3[localx] + c1[i].x1());
149 v3.setCoordinate (localy, v3[localy] + c1[i].y1()); 149 v3.setCoordinate(localy, v3[localy] + c1[i].y1());
150 150
151 LDQuad* quad (LDSpawn<LDQuad> (v0, v1, v2, v3)); 151 LDQuad* quad(LDSpawn<LDQuad>(v0, v1, v2, v3));
152 quad->setColor (MainColor); 152 quad->setColor(MainColor);
153 153
154 // Ensure the quads always are BFC-front towards the camera 154 // Ensure the quads always are BFC-front towards the camera
155 if (renderer()->camera() % 3 <= 0) 155 if (renderer()->camera() % 3 <= 0)
156 quad->invert(); 156 quad->invert();
157 157
160 } 160 }
161 161
162 if (circleOrDisc and refFile) 162 if (circleOrDisc and refFile)
163 { 163 {
164 LDSubfileReference* ref = LDSpawn<LDSubfileReference>(); 164 LDSubfileReference* ref = LDSpawn<LDSubfileReference>();
165 ref->setFileInfo (refFile); 165 ref->setFileInfo(refFile);
166 ref->setTransform (transform); 166 ref->setTransform(transform);
167 ref->setPosition (m_drawedVerts[0]); 167 ref->setPosition(m_drawedVerts[0]);
168 ref->setColor (MainColor); 168 ref->setColor(MainColor);
169 objs << ref; 169 objs << ref;
170 } 170 }
171 171
172 if (not objs.isEmpty()) 172 if (not objs.isEmpty())
173 { 173 {
174 Axis relZ = renderer()->getRelativeZ();; 174 Axis relZ = renderer()->getRelativeZ();;
175 const int l (relZ == X ? 1 : 0); 175 const int l(relZ == X ? 1 : 0);
176 const int m (relZ == Y ? 1 : 0); 176 const int m(relZ == Y ? 1 : 0);
177 const int n (relZ == Z ? 1 : 0); 177 const int n(relZ == Z ? 1 : 0);
178 RotateObjects (l, m, n, -m_angleOffset, objs); 178 RotateObjects(l, m, n, -m_angleOffset, objs);
179 } 179 }
180 180
181 finishDraw (objs); 181 finishDraw(objs);
182 } 182 }
183 183
184 double CircleMode::getAngleOffset() const 184 double CircleMode::getAngleOffset() const
185 { 185 {
186 if (m_drawedVerts.isEmpty()) 186 if (m_drawedVerts.isEmpty())
187 return 0.0; 187 return 0.0;
188 188
189 const int divisions (m_window->ringToolHiRes() ? HighResolution : LowResolution); 189 const int divisions(m_window->ringToolHiRes() ? HighResolution : LowResolution);
190 QPointF originspot (renderer()->convert3dTo2d (m_drawedVerts.first())); 190 QPointF originspot(renderer()->convert3dTo2d(m_drawedVerts.first()));
191 QLineF bearing (originspot, renderer()->mousePositionF()); 191 QLineF bearing(originspot, renderer()->mousePositionF());
192 QLineF bearing2 (originspot, QPointF (originspot.x(), 0.0)); 192 QLineF bearing2(originspot, QPointF(originspot.x(), 0.0));
193 double angleoffset (-bearing.angleTo (bearing2) + 90); 193 double angleoffset(-bearing.angleTo(bearing2) + 90);
194 angleoffset /= (360.0 / divisions); // convert angle to 0-16 scale 194 angleoffset /= (360.0 / divisions); // convert angle to 0-16 scale
195 angleoffset = round (angleoffset); // round to nearest 16th 195 angleoffset = round(angleoffset); // round to nearest 16th
196 angleoffset *= ((2 * Pi) / divisions); // convert to radians 196 angleoffset *= ((2 * Pi) / divisions); // convert to radians
197 angleoffset *= renderer()->depthNegateFactor(); // negate based on camera 197 angleoffset *= renderer()->depthNegateFactor(); // negate based on camera
198 return angleoffset; 198 return angleoffset;
199 } 199 }
200 200
201 void CircleMode::render (QPainter& painter) const 201 void CircleMode::render(QPainter& painter) const
202 { 202 {
203 QFontMetrics metrics = QFontMetrics (QFont()); 203 QFontMetrics metrics = QFontMetrics(QFont());
204 204
205 // If we have not specified the center point of the circle yet, preview it on the screen. 205 // If we have not specified the center point of the circle yet, preview it on the screen.
206 if (m_drawedVerts.isEmpty()) 206 if (m_drawedVerts.isEmpty())
207 { 207 {
208 QPoint pos2d = renderer()->convert3dTo2d (renderer()->position3D()); 208 QPoint pos2d = renderer()->convert3dTo2d(renderer()->position3D());
209 renderer()->drawBlip (painter, pos2d); 209 renderer()->drawBlip(painter, pos2d);
210 renderer()->drawBlipCoordinates (painter, renderer()->position3D(), pos2d); 210 renderer()->drawBlipCoordinates(painter, renderer()->position3D(), pos2d);
211 return; 211 return;
212 } 212 }
213 213
214 QVector<Vertex> innerverts, outerverts; 214 QVector<Vertex> innerverts, outerverts;
215 QVector<QPointF> innerverts2d, outerverts2d; 215 QVector<QPointF> innerverts2d, outerverts2d;
216 const double innerdistance (getCircleDrawDist (0)); 216 const double innerdistance(getCircleDrawDist(0));
217 const double outerdistance (m_drawedVerts.size() >= 2 ? getCircleDrawDist (1) : -1); 217 const double outerdistance(m_drawedVerts.size() >= 2 ? getCircleDrawDist(1) : -1);
218 const int divisions (m_window->ringToolHiRes() ? HighResolution : LowResolution); 218 const int divisions(m_window->ringToolHiRes() ? HighResolution : LowResolution);
219 const int segments (m_window->ringToolSegments()); 219 const int segments(m_window->ringToolSegments());
220 const double angleUnit (2 * Pi / divisions); 220 const double angleUnit(2 * Pi / divisions);
221 Axis relX, relY; 221 Axis relX, relY;
222 renderer()->getRelativeAxes (relX, relY); 222 renderer()->getRelativeAxes(relX, relY);
223 const double angleoffset (m_drawedVerts.size() < 3 ? getAngleOffset() : m_angleOffset); 223 const double angleoffset(m_drawedVerts.size() < 3 ? getAngleOffset() : m_angleOffset);
224 224
225 // Calculate the preview positions of vertices 225 // Calculate the preview positions of vertices
226 for (int i = 0; i < segments + 1; ++i) 226 for (int i = 0; i < segments + 1; ++i)
227 { 227 {
228 const double sinangle (sin (angleoffset + i * angleUnit)); 228 const double sinangle(sin(angleoffset + i * angleUnit));
229 const double cosangle (cos (angleoffset + i * angleUnit)); 229 const double cosangle(cos(angleoffset + i * angleUnit));
230 Vertex v (Origin); 230 Vertex v(Origin);
231 v.setCoordinate (relX, m_drawedVerts[0][relX] + (cosangle * innerdistance)); 231 v.setCoordinate(relX, m_drawedVerts[0][relX] +(cosangle * innerdistance));
232 v.setCoordinate (relY, m_drawedVerts[0][relY] + (sinangle * innerdistance)); 232 v.setCoordinate(relY, m_drawedVerts[0][relY] +(sinangle * innerdistance));
233 innerverts << v; 233 innerverts << v;
234 innerverts2d << renderer()->convert3dTo2d (v); 234 innerverts2d << renderer()->convert3dTo2d(v);
235 235
236 if (outerdistance != -1) 236 if (outerdistance != -1)
237 { 237 {
238 v.setCoordinate (relX, m_drawedVerts[0][relX] + (cosangle * outerdistance)); 238 v.setCoordinate(relX, m_drawedVerts[0][relX] +(cosangle * outerdistance));
239 v.setCoordinate (relY, m_drawedVerts[0][relY] + (sinangle * outerdistance)); 239 v.setCoordinate(relY, m_drawedVerts[0][relY] +(sinangle * outerdistance));
240 outerverts << v; 240 outerverts << v;
241 outerverts2d << renderer()->convert3dTo2d (v); 241 outerverts2d << renderer()->convert3dTo2d(v);
242 } 242 }
243 } 243 }
244 244
245 QVector<QLineF> lines (segments); 245 QVector<QLineF> lines(segments);
246 246
247 if (outerdistance != -1 and outerdistance != innerdistance) 247 if (outerdistance != -1 and outerdistance != innerdistance)
248 { 248 {
249 painter.setBrush (m_polybrush); 249 painter.setBrush(m_polybrush);
250 painter.setPen (Qt::NoPen); 250 painter.setPen(Qt::NoPen);
251 251
252 // Compile polygons 252 // Compile polygons
253 for (int i = 0; i < segments; ++i) 253 for (int i = 0; i < segments; ++i)
254 { 254 {
255 QVector<QPointF> points; 255 QVector<QPointF> points;
256 points << innerverts2d[i] 256 points << innerverts2d[i]
257 << innerverts2d[i + 1] 257 << innerverts2d[i + 1]
258 << outerverts2d[i + 1] 258 << outerverts2d[i + 1]
259 << outerverts2d[i]; 259 << outerverts2d[i];
260 painter.drawPolygon (QPolygonF (points)); 260 painter.drawPolygon(QPolygonF(points));
261 lines << QLineF (innerverts2d[i], innerverts2d[i + 1]); 261 lines << QLineF(innerverts2d[i], innerverts2d[i + 1]);
262 lines << QLineF (outerverts2d[i], outerverts2d[i + 1]); 262 lines << QLineF(outerverts2d[i], outerverts2d[i + 1]);
263 } 263 }
264 264
265 // Add bordering edges for unclosed rings/discs 265 // Add bordering edges for unclosed rings/discs
266 if (segments != divisions) 266 if (segments != divisions)
267 { 267 {
268 lines << QLineF (innerverts2d.first(), outerverts2d.first()); 268 lines << QLineF(innerverts2d.first(), outerverts2d.first());
269 lines << QLineF (innerverts2d.last(), outerverts2d.last()); 269 lines << QLineF(innerverts2d.last(), outerverts2d.last());
270 } 270 }
271 } 271 }
272 else 272 else
273 { 273 {
274 for (int i = 0; i < segments; ++i) 274 for (int i = 0; i < segments; ++i)
275 lines << QLineF (innerverts2d[i], innerverts2d[i + 1]); 275 lines << QLineF(innerverts2d[i], innerverts2d[i + 1]);
276 } 276 }
277 277
278 // Draw green blips at where the points are 278 // Draw green blips at where the points are
279 for (QPointF const& point : innerverts2d + outerverts2d) 279 for (QPointF const& point : innerverts2d + outerverts2d)
280 renderer()->drawBlip (painter, point); 280 renderer()->drawBlip(painter, point);
281 281
282 // Draw edge lines 282 // Draw edge lines
283 painter.setPen (renderer()->linePen()); 283 painter.setPen(renderer()->linePen());
284 painter.drawLines (lines); 284 painter.drawLines(lines);
285 285
286 // Draw the current radius in the middle of the circle. 286 // Draw the current radius in the middle of the circle.
287 QPoint origin = renderer()->convert3dTo2d (m_drawedVerts[0]); 287 QPoint origin = renderer()->convert3dTo2d(m_drawedVerts[0]);
288 QString label = QString::number (innerdistance); 288 QString label = QString::number(innerdistance);
289 painter.setPen (renderer()->textPen()); 289 painter.setPen(renderer()->textPen());
290 painter.drawText (origin.x() - (metrics.width (label) / 2), origin.y(), label); 290 painter.drawText(origin.x() -(metrics.width(label) / 2), origin.y(), label);
291 291
292 if (m_drawedVerts.size() >= 2) 292 if (m_drawedVerts.size() >= 2)
293 { 293 {
294 painter.drawText (origin.x() - (metrics.width (label) / 2), 294 painter.drawText(origin.x() -(metrics.width(label) / 2),
295 origin.y() + metrics.height(), QString::number (outerdistance)); 295 origin.y() + metrics.height(), QString::number(outerdistance));
296 } 296 }
297 } 297 }
298 298
299 bool CircleMode::mouseReleased (MouseEventData const& data) 299 bool CircleMode::mouseReleased(MouseEventData const& data)
300 { 300 {
301 if (data.releasedButtons & Qt::LeftButton) 301 if (data.releasedButtons & Qt::LeftButton)
302 { 302 {
303 if (m_drawedVerts.size() < 2) 303 if (m_drawedVerts.size() < 2)
304 addDrawnVertex (renderer()->position3D()); 304 addDrawnVertex(renderer()->position3D());
305 else 305 else
306 buildCircle(); 306 buildCircle();
307 return true; 307 return true;
308 } 308 }
309 else 309 else
310 { 310 {
311 return Super::mouseReleased(data); 311 return Super::mouseReleased(data);
312 } 312 }
313 } 313 }
314 314
315 bool CircleMode::preAddVertex (const Vertex&) 315 bool CircleMode::preAddVertex(const Vertex&)
316 { 316 {
317 m_angleOffset = getAngleOffset(); 317 m_angleOffset = getAngleOffset();
318 return false; 318 return false;
319 } 319 }

mercurial