--- a/src/editmodes/circlemode.cc Fri Jul 04 22:40:35 2014 +0300 +++ b/src/editmodes/circlemode.cc Fri Jul 04 23:43:39 2014 +0300 @@ -2,19 +2,22 @@ #include "circlemode.h" #include "../miscallenous.h" #include "../ldObject.h" +#include "../ldDocument.h" +#include "../misc/ringFinder.h" +#include "../primitives.h" CircleMode::CircleMode (GLRenderer* renderer) : Super (renderer) {} double CircleMode::getCircleDrawDist (int pos) const { - assert (m_drawedVerts.size() >= pos + 1); - Vertex v1 = (m_drawedVerts.size() >= pos + 2) ? m_drawedVerts[pos + 1] : + assert (_drawedVerts.size() >= pos + 1); + Vertex v1 = (_drawedVerts.size() >= pos + 2) ? _drawedVerts[pos + 1] : renderer()->coordconv2_3 (renderer()->mousePosition(), false); Axis localx, localy; renderer()->getRelativeAxes (localx, localy); - double dx = m_drawedVerts[0][localx] - v1[localx]; - double dy = m_drawedVerts[0][localy] - v1[localy]; + double dx = _drawedVerts[0][localx] - v1[localx]; + double dy = _drawedVerts[0][localy] - v1[localy]; return Grid::snap (sqrt ((dx * dx) + (dy * dy)), Grid::Coordinate); } @@ -41,12 +44,116 @@ return transform; } +void CircleMode::buildCircle() +{ + LDObjectList objs; + const int segs = g_lores, divs = g_lores; // TODO: make customizable + double dist0 = getCircleDrawDist (0), + dist1 = getCircleDrawDist (1); + LDDocumentPtr refFile; + Matrix transform; + bool circleOrDisc = false; + + if (dist1 < dist0) + std::swap<double> (dist0, dist1); + + if (dist0 == dist1) + { + // If the radii are the same, there's no ring space to fill. Use a circle. + refFile = getDocument ("4-4edge.dat"); + transform = getCircleDrawMatrix (dist0); + circleOrDisc = true; + } + elif (dist0 == 0 || dist1 == 0) + { + // If either radii is 0, use a disc. + refFile = getDocument ("4-4disc.dat"); + transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1); + circleOrDisc = true; + } + elif (g_RingFinder.findRings (dist0, dist1)) + { + // The ring finder found a solution, use that. Add the component rings to the file. + for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->getComponents()) + { + // Get a ref file for this primitive. If we cannot find it in the + // LDraw library, generate it. + if ((refFile = ::getDocument (radialFileName (::Ring, g_lores, g_lores, cmp.num))) == null) + { + refFile = generatePrimitive (::Ring, g_lores, g_lores, cmp.num); + refFile->setImplicit (false); + } + + LDSubfilePtr ref = spawn<LDSubfile>(); + ref->setFileInfo (refFile); + ref->setTransform (getCircleDrawMatrix (cmp.scale)); + ref->setPosition (_drawedVerts[0]); + ref->setColor (maincolor()); + objs << ref; + } + } + else + { + // Ring finder failed, last resort: draw the ring with quads + QList<QLineF> c0, c1; + Axis localx, localy, localz; + renderer()->getRelativeAxes (localx, localy); + localz = (Axis) (3 - localx - localy); + double x0 = _drawedVerts[0][localx], + y0 = _drawedVerts[0][localy]; + + Vertex templ; + templ.setCoordinate (localx, x0); + templ.setCoordinate (localy, y0); + templ.setCoordinate (localz, renderer()->getDepthValue()); + + // Calculate circle coords + makeCircle (segs, divs, dist0, c0); + makeCircle (segs, divs, dist1, c1); + + for (int i = 0; i < segs; ++i) + { + Vertex v0, v1, v2, v3; + v0 = v1 = v2 = v3 = templ; + v0.setCoordinate (localx, v0[localx] + c0[i].x1()); + v0.setCoordinate (localy, v0[localy] + c0[i].y1()); + v1.setCoordinate (localx, v1[localx] + c0[i].x2()); + v1.setCoordinate (localy, v1[localy] + c0[i].y2()); + v2.setCoordinate (localx, v2[localx] + c1[i].x2()); + v2.setCoordinate (localy, v2[localy] + c1[i].y2()); + v3.setCoordinate (localx, v3[localx] + c1[i].x1()); + v3.setCoordinate (localy, v3[localy] + c1[i].y1()); + + LDQuadPtr quad (spawn<LDQuad> (v0, v1, v2, v3)); + quad->setColor (maincolor()); + + // Ensure the quads always are BFC-front towards the camera + if (renderer()->camera() % 3 <= 0) + quad->invert(); + + objs << quad; + } + } + + if (circleOrDisc && refFile != null) + { + LDSubfilePtr ref = spawn<LDSubfile>(); + ref->setFileInfo (refFile); + ref->setTransform (transform); + ref->setPosition (_drawedVerts[0]); + ref->setColor (maincolor()); + objs << ref; + } + + finishDraw (objs); +} + void CircleMode::render (QPainter& painter) const { QFontMetrics const metrics (QFont()); // If we have not specified the center point of the circle yet, preview it on the screen. - if (m_drawedVerts.isEmpty()) + if (_drawedVerts.isEmpty()) { renderer()->drawBlip (painter, renderer()->coordconv3_2 (renderer()->position3D())); } @@ -54,7 +161,7 @@ { QVector<Vertex> verts, verts2; const double dist0 = getCircleDrawDist (0), - dist1 = (m_drawedVerts.size() >= 2) ? getCircleDrawDist (1) : -1; + dist1 = (_drawedVerts.size() >= 2) ? getCircleDrawDist (1) : -1; const int segs = g_lores; const double angleUnit = (2 * pi) / segs; Axis relX, relY; @@ -66,14 +173,14 @@ for (int i = 0; i < segs; ++i) { Vertex v = g_origin; - v.setCoordinate (relX, m_drawedVerts[0][relX] + (cos (i * angleUnit) * dist0)); - v.setCoordinate (relY, m_drawedVerts[0][relY] + (sin (i * angleUnit) * dist0)); + v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist0)); + v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist0)); verts << v; if (dist1 != -1) { - v.setCoordinate (relX, m_drawedVerts[0][relX] + (cos (i * angleUnit) * dist1)); - v.setCoordinate (relY, m_drawedVerts[0][relY] + (sin (i * angleUnit) * dist1)); + v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist1)); + v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist1)); verts2 << v; } } @@ -110,7 +217,7 @@ ringpoints.insert (33, ringpoints[17]); // Draw the ring - painter.setBrush ((m_drawedVerts.size() >= 2) ? _polybrush : Qt::NoBrush); + painter.setBrush ((_drawedVerts.size() >= 2) ? _polybrush : Qt::NoBrush); painter.setPen (Qt::NoPen); painter.drawPolygon (QPolygon (ringpoints)); @@ -121,12 +228,12 @@ painter.drawPolygon (QPolygon (circle2points)); // Draw the current radius in the middle of the circle. - QPoint origin = renderer()->coordconv3_2 (m_drawedVerts[0]); + QPoint origin = renderer()->coordconv3_2 (_drawedVerts[0]); QString label = QString::number (dist0); painter.setPen (renderer()->getTextPen()); painter.drawText (origin.x() - (metrics.width (label) / 2), origin.y(), label); - if (m_drawedVerts.size() >= 2) + if (_drawedVerts.size() >= 2) { painter.drawText (origin.x() - (metrics.width (label) / 2), origin.y() + metrics.height(), QString::number (dist1)); @@ -139,11 +246,11 @@ if (Super::mouseReleased (data)) return true; - if (m_drawedVerts.size() < 3) + if (_drawedVerts.size() < 3) { - addDrawnVertex (m_position3D); + addDrawnVertex (renderer()->position3D()); return; } - Super::mouseReleased (data); + buildCircle(); }