Mon, 30 Jan 2017 14:30:55 +0200
Some code cleanup in abstract editing modes.
--- a/src/editmodes/abstractEditMode.cpp Mon Jan 30 02:41:45 2017 +0200 +++ b/src/editmodes/abstractEditMode.cpp Mon Jan 30 14:30:55 2017 +0200 @@ -34,13 +34,17 @@ ConfigOption (bool DrawLineLengths = true) ConfigOption (bool DrawAngles = false) +/* + * Base class constructor of the abstract editing mode. + */ AbstractEditMode::AbstractEditMode(GLRenderer* renderer) : QObject(renderer), HierarchyElement(renderer), m_renderer(renderer) {} -AbstractEditMode::~AbstractEditMode() {} - +/* + * Constructs an edit mode by type. + */ AbstractEditMode* AbstractEditMode::createByType(GLRenderer* renderer, EditModeType type) { switch (type) @@ -57,31 +61,41 @@ throw std::logic_error("bad type given to AbstractEditMode::createByType"); } +/* + * Returns the edit mode's corresponding renderer pointer. + */ GLRenderer* AbstractEditMode::renderer() const { return m_renderer; } +/* + * Base class constructor of the abstract drwaing mode. + */ AbstractDrawMode::AbstractDrawMode(GLRenderer* renderer) : - AbstractEditMode(renderer), - m_polybrush{QBrush{QColor{64, 192, 0, 128}}} + AbstractEditMode {renderer}, + m_polybrush {QBrush {QColor {64, 192, 0, 128}}} { - renderer->setContextMenuPolicy (Qt::NoContextMenu); // We need the right mouse button for removing vertices - renderer->setCursor (Qt::CrossCursor); + renderer->setContextMenuPolicy(Qt::NoContextMenu); // We need the right mouse button for removing vertices + renderer->setCursor(Qt::CrossCursor); m_window->currentDocument()->clearSelection(); m_window->updateSelection(); m_drawedVerts.clear(); } -AbstractSelectMode::AbstractSelectMode (GLRenderer* renderer) : - AbstractEditMode (renderer) +/* + * Base class constructor of the abstract selection mode. + */ +AbstractSelectMode::AbstractSelectMode(GLRenderer* renderer) : + AbstractEditMode {renderer} { renderer->unsetCursor(); renderer->setContextMenuPolicy (Qt::DefaultContextMenu); } -// ============================================================================= -// +/* + * Possibly adds this vertex into the list of drawn vertices. + */ void AbstractDrawMode::addDrawnVertex(const Vertex& position) { if (preAddVertex(position)) @@ -90,38 +104,43 @@ m_drawedVerts << position; } +/* + * Handles mouse relese events. + */ bool AbstractDrawMode::mouseReleased(MouseEventData const& data) { if (Super::mouseReleased(data)) return true; + // If the user presses the middle mouse button, seek the closest existing vertex to the cursor and clamp to that. if ((data.releasedButtons & Qt::MidButton) and (countof(m_drawedVerts) < 4) and (not data.mouseMoved)) { // Find the closest vertex to our cursor double minimumDistance = 1024.0; const Vertex* closest = nullptr; - Vertex cursorPosition = renderer()->convert2dTo3d (data.ev->pos(), false); - QPoint cursorPosition2D (data.ev->pos()); + Vertex cursorPosition = renderer()->convert2dTo3d(data.ev->pos(), false); + QPoint cursorPosition2D = data.ev->pos(); const Axis depthAxis = renderer()->getRelativeZ(); QList<Vertex> vertices = renderer()->document()->inlineVertices().toList(); // Sort the vertices in order of distance to camera - std::sort (vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool + std::sort(vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool { - if (renderer()->cameraInfo (renderer()->camera()).negatedDepth) + if (renderer()->cameraInfo(renderer()->camera()).negatedDepth) return a[depthAxis] > b[depthAxis]; else return a[depthAxis] < b[depthAxis]; }); - for (const Vertex& vrt : vertices) + for (const Vertex& vertex : vertices) { // If the vertex in 2d space is very close to the cursor then we use it regardless of depth. - QPoint vect2d = renderer()->convert3dTo2d (vrt) - cursorPosition2D; - const double distance2DSquared = std::pow (vect2d.x(), 2) + std::pow (vect2d.y(), 2); + QPoint vect2d = renderer()->convert3dTo2d(vertex) - cursorPosition2D; + double distance2DSquared = std::pow (vect2d.x(), 2) + std::pow (vect2d.y(), 2); + if (distance2DSquared < 16.0 * 16.0) { - closest = &vrt; + closest = &vertex; break; } @@ -131,49 +150,53 @@ // Not very close to the cursor. Compare using true distance, // including depth. - const double distanceSquared = (vrt - cursorPosition).lengthSquared(); + double distanceSquared = (vertex - cursorPosition).lengthSquared(); if (distanceSquared < minimumDistance) { minimumDistance = distanceSquared; - closest = &vrt; + closest = &vertex; } } if (closest) - addDrawnVertex (*closest); + addDrawnVertex(*closest); return true; } + // If the user presses the right mouse button, remove the previously drawn vertex. if ((data.releasedButtons & Qt::RightButton) and not m_drawedVerts.isEmpty()) { - // Remove the last vertex m_drawedVerts.removeLast(); return true; } + // If the user presses the left mouse button, insert the vertex or stop drawing, whichever is appropriate. if (data.releasedButtons & Qt::LeftButton) { if (maxVertices() and countof(m_drawedVerts) >= maxVertices()) endDraw(); else addDrawnVertex (getCursorVertex()); + return true; } + // Otherwise we did not handle this mouse event. return false; } +/* + * Finalises the draw operation. The provided model is merged into the main document. + */ void AbstractDrawMode::finishDraw(Model& model) { - int pos = m_window->suggestInsertPoint(); + int position = m_window->suggestInsertPoint(); - if (countof(model.objects()) > 0) + if (countof(model) > 0) { - for (LDObject* obj : model) - renderer()->document()->insertObject (pos++, obj); - + renderer()->document()->merge(model, position); m_window->refresh(); m_window->endAction(); } @@ -181,22 +204,33 @@ m_drawedVerts.clear(); } -void AbstractDrawMode::drawLineLength(QPainter &painter, const Vertex &v0, const Vertex &v1, - const QPointF& v0p, const QPointF& v1p) const +/* + * Renders the length of the provided line. + * - v0 and v1 are the line vertices in 3D space. + * - v0p and v1p are the line vertices in 2D space (so that this function does not have to calculate them separately) + */ +void AbstractDrawMode::drawLineLength(QPainter &painter, const Vertex &v0, const Vertex &v1, const QPointF& v0p, const QPointF& v1p) const { if (not m_config->drawLineLengths()) return; const QString label = QString::number(abs(v1 - v0), 'f', 2); - QPoint origin = QLineF (v0p, v1p).pointAt (0.5).toPoint(); + QPoint origin = QLineF {v0p, v1p}.pointAt(0.5).toPoint(); painter.drawText (origin, label); } -void AbstractDrawMode::renderPolygon(QPainter& painter, const QVector<Vertex>& polygon3d, - bool drawLineLengths, bool drawAngles ) const +/* + * Renders a polygon preview. + * + * painter: QPainter instance that is currently being rendered to. + * polygon3d: The polygon as a vector of 3D vertices. + * drawLineLengths: if true, lengths of polygon sides are also previewed, assuming the user has enabled the relevant option. + * drawAngles: if true, the angles between polygon sides are also previewed, assuming the user has enabled the relevant option. + */ +void AbstractDrawMode::renderPolygon(QPainter& painter, const QVector<Vertex>& polygon3d, bool drawLineLengths, bool drawAngles) const { - QVector<QPoint> polygon2d (countof(polygon3d)); - QFontMetrics metrics = QFontMetrics(QFont()); + QVector<QPoint> polygon2d {countof(polygon3d)}; + QFontMetrics metrics {QFont {}}; // Convert to 2D for (int i = 0; i < countof(polygon3d); ++i) @@ -216,7 +250,7 @@ // Draw line lenghts and angle info if appropriate if (countof(polygon3d) >= 2 and (drawLineLengths or drawAngles)) { - painter.setPen (renderer()->textPen()); + painter.setPen(renderer()->textPen()); for (int i = 0; i < countof(polygon3d); ++i) { @@ -244,12 +278,16 @@ } } -bool AbstractDrawMode::keyReleased (QKeyEvent *ev) +/* + * Key release event handler + */ +bool AbstractDrawMode::keyReleased(QKeyEvent *event) { - if (Super::keyReleased (ev)) + if (Super::keyReleased(event)) return true; - if (not m_drawedVerts.isEmpty() and ev->key() == Qt::Key_Backspace) + // Map backspace to removing the previously drawn vertex. + if (not m_drawedVerts.isEmpty() and event->key() == Qt::Key_Backspace) { m_drawedVerts.removeLast(); return true; @@ -258,34 +296,36 @@ return false; } -// -// roundToInterval -// -// Rounds 'a' to the nearest multiple of 'interval'. -// +/* + * Rounds the input value to the nearest multiple of the provided interval. + */ template<typename T> -T roundToInterval (T a, T interval) +T roundToInterval(T value, T interval) { - T remainder = a % interval; + T remainder = value % interval; if (remainder >= interval / 2.0) - a += interval; + value += interval; - a -= remainder; - return a; + value -= remainder; + return value; } +/* + * Computes the position for the vertex currently being drawn. + */ Vertex AbstractDrawMode::getCursorVertex() const { Vertex result = renderer()->position3D(); + // If the Ctrl key is pressed, then the vertex is locked to 45 degree angles relative to the previously drawn vertex. if ((renderer()->keyboardModifiers() & Qt::ControlModifier) and not m_drawedVerts.isEmpty()) { - Vertex const& vertex0 = m_drawedVerts.last(); - Vertex const& vertex1 = result; - Axis relativeX, relativeY; - - renderer()->getRelativeAxes (relativeX, relativeY); + const Vertex& vertex0 = m_drawedVerts.last(); + const Vertex& vertex1 = result; + Axis relativeX; + Axis relativeY; + renderer()->getRelativeAxes(relativeX, relativeY); QLineF line = {vertex0[relativeX], vertex0[relativeY], vertex1[relativeX], vertex1[relativeY]}; line.setAngle(roundToInterval<int>(line.angle(), 45)); result.setCoordinate(relativeX, grid()->snap(line.x2(), Grid::Coordinate)); @@ -293,4 +333,37 @@ } return result; -} \ No newline at end of file +} + +/* + * No draw mode can operate on the free camera, since 3D ⟷ 2D point conversions are not possible with it. + */ +bool AbstractDrawMode::allowFreeCamera() const +{ + return false; +} + +/* + * This virtual method allows drawing modes to specify how many vertices at most can be drawn. Returning 0 means unlimited. + */ +int AbstractDrawMode::maxVertices() const +{ + return 0; +} + +/* + * This virtual method is a hook that allows drawing modes to veto vertex insertion. Returning true means that the vertex insertion + * was handled separately and the vertex will not be added. + */ +bool AbstractDrawMode::preAddVertex (Vertex const&) +{ + return false; +} + +/* + * This virtual method is overridden by subclasses to implement the actions taken by the edit mode. + * The editing mode is to call finishDraw with the prepared model. + * + * TODO: the two method names are too similar and should be renamed. + */ +void AbstractDrawMode::endDraw() {}
--- a/src/editmodes/abstractEditMode.h Mon Jan 30 02:41:45 2017 +0200 +++ b/src/editmodes/abstractEditMode.h Mon Jan 30 14:30:55 2017 +0200 @@ -36,6 +36,9 @@ Curve, }; +/* + * Base class of all editing modes. + */ class AbstractEditMode : public QObject, public HierarchyElement { Q_OBJECT @@ -50,7 +53,6 @@ }; AbstractEditMode (GLRenderer* renderer); - virtual ~AbstractEditMode(); virtual bool allowFreeCamera() const = 0; virtual void render (QPainter&) const {} @@ -68,9 +70,9 @@ GLRenderer* m_renderer; }; -// -// Base class for draw-like edit modes -// +/* + * Base class for draw-like edit modes + */ class AbstractDrawMode : public AbstractEditMode { DEFINE_CLASS (AbstractDrawMode, AbstractEditMode) @@ -82,24 +84,22 @@ public: AbstractDrawMode (GLRenderer* renderer); - void addDrawnVertex (const Vertex& pos); - virtual bool allowFreeCamera() const override final { return false; } - virtual void endDraw() {} - void drawLineLength (QPainter& painter, - const Vertex& v0, const Vertex& v1, - const QPointF& v0p, const QPointF& v1p) const; - void finishDraw (Model& model); + void addDrawnVertex(const Vertex& pos); + bool allowFreeCamera() const override final; + virtual void endDraw(); + void drawLineLength(QPainter& painter, const Vertex& v0, const Vertex& v1, const QPointF& v0p, const QPointF& v1p) const; + void finishDraw(Model& model); Vertex getCursorVertex() const; - bool keyReleased (QKeyEvent* ev) override; - virtual int maxVertices() const { return 0; } - bool mouseReleased (const AbstractEditMode::MouseEventData& data) override; - virtual bool preAddVertex (Vertex const&) { return false; } - void renderPolygon (QPainter& painter, const QVector<Vertex>& poly3d, bool withlengths, bool withangles) const; + bool keyReleased(QKeyEvent* ev) override; + virtual int maxVertices() const; + bool mouseReleased(const AbstractEditMode::MouseEventData& data) override; + virtual bool preAddVertex(Vertex const&); + void renderPolygon(QPainter& painter, const QVector<Vertex>& poly3d, bool withlengths, bool withangles) const; }; -// -// Base class for select-like edit modes -// +/* + * Base class for select-like edit modes + */ class AbstractSelectMode : public AbstractEditMode { DEFINE_CLASS (AbstractSelectMode, AbstractEditMode)