Wed, 30 May 2018 22:31:06 +0300
added draw plane feature (doesn't work with circle draw quite right yet)
--- a/CMakeLists.txt Sat May 26 17:28:15 2018 +0300 +++ b/CMakeLists.txt Wed May 30 22:31:06 2018 +0300 @@ -76,6 +76,7 @@ src/editmodes/rectangleMode.cpp src/editmodes/selectMode.cpp src/geometry/linesegment.cpp + src/geometry/plane.cpp src/linetypes/comment.cpp src/linetypes/conditionaledge.cpp src/linetypes/edgeline.cpp @@ -153,6 +154,7 @@ src/generics/ring.h src/generics/transform.h src/geometry/linesegment.h + src/geometry/plane.h src/linetypes/comment.h src/linetypes/conditionaledge.h src/linetypes/edgeline.h
--- a/src/basics.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/basics.cpp Wed May 30 22:31:06 2018 +0300 @@ -192,3 +192,70 @@ function(); object->blockSignals(wasBlockingSignals); } + +/* + * Returns the angle between two vectors + */ +qreal vectorAngle(const QVector3D& vec_1, const QVector3D& vec_2) +{ + return acos(QVector3D::dotProduct(vec_1, vec_2) / vec_1.length() / vec_2.length()); +} + +/* + * Computes the determinant of a 2×2 matrix with each variable passed in row-major order. + */ +qreal determinant(qreal a, qreal b, qreal c, qreal d) +{ + return a * d - b * c; +} + +/* + * Computes the determinant of a 3×3 matrix with each variable passed in row-major order. + */ +qreal determinant(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f, qreal g, qreal h, qreal i) +{ + return a*e*i + b*f*g + c*d*h - a*f*h - b*d*i - c*e*g; +} + +/* + * Computes the determinant of a 2×2 matrix. + */ +qreal determinant(const QMatrix2x2& matrix) +{ + return matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0); +} + +/* + * Computes the determinant of a 3×3 matrix. + */ +qreal determinant(const QMatrix3x3& matrix) +{ + return sum( + +matrix(0, 0) * matrix(1, 1) * matrix(2, 2), + -matrix(0, 0) * matrix(1, 2) * matrix(2, 1), + -matrix(0, 1) * matrix(1, 0) * matrix(2, 2), + +matrix(0, 1) * matrix(1, 2) * matrix(2, 0), + +matrix(0, 2) * matrix(1, 0) * matrix(2, 1), + -matrix(0, 2) * matrix(1, 1) * matrix(2, 0)); +} + +/* + * Computes the determinant of a 4×4 matrix. + */ +qreal determinant(const QMatrix4x4& matrix) +{ + qreal sum = 0; + + for (int column : {0, 1, 2, 3}) + { + int column_1 = (column >= 1) ? 0 : 1; + int column_2 = (column >= 2) ? 1 : 2; + int column_3 = (column >= 3) ? 2 : 3; + sum += ((column % 1) ? -1 : 1) * determinant( + matrix(1, column_1), matrix(1, column_2), matrix(1, column_3), + matrix(2, column_1), matrix(2, column_2), matrix(2, column_3), + matrix(3, column_1), matrix(3, column_2), matrix(3, column_3)); + } + + return sum; +}
--- a/src/basics.h Sat May 26 17:28:15 2018 +0300 +++ b/src/basics.h Wed May 30 22:31:06 2018 +0300 @@ -89,6 +89,11 @@ return vector.length(); } +qreal determinant(qreal a, qreal b, qreal c, qreal d); +qreal determinant(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f, qreal g, qreal h, qreal i); +qreal determinant(const QMatrix2x2& matrix); +qreal determinant(const QMatrix3x3& matrix); +qreal determinant(const QMatrix4x4& matrix); QString formatFileSize(qint64 size); int gcd(int a, int b); QString joinStrings(const QList<class StringFormatArg>& values, QString delimeter = " "); @@ -100,4 +105,5 @@ QString superscript(int number); QString subscript(int number); QString fractionRep(int numerator, int denominator); +qreal vectorAngle(const QVector3D& vec_1, const QVector3D& vec_2); void withSignalsBlocked(QObject* object, std::function<void()> function);
--- a/src/canvas.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/canvas.cpp Wed May 30 22:31:06 2018 +0300 @@ -347,20 +347,16 @@ // ============================================================================= // -void Canvas::setDepthValue (double depth) +void Canvas::setDrawPlane(const Plane& plane) { - if (camera() < Camera::Free) - m_depthValues[static_cast<int>(camera())] = depth; + m_drawPlane = plane; } // ============================================================================= // -double Canvas::getDepthValue() const +const Plane& Canvas::drawPlane() const { - if (camera() < Camera::Free) - return m_depthValues[static_cast<int>(camera())]; - else - return 0.0; + return m_drawPlane; } void Canvas::contextMenuEvent(QContextMenuEvent* event)
--- a/src/canvas.h Sat May 26 17:28:15 2018 +0300 +++ b/src/canvas.h Wed May 30 22:31:06 2018 +0300 @@ -19,6 +19,7 @@ #pragma once #include "glrenderer.h" #include "editmodes/abstractEditMode.h" +#include "geometry/plane.h" class Canvas : public GLRenderer { @@ -27,6 +28,7 @@ ~Canvas(); EditModeType currentEditModeType() const; + const Plane& drawPlane() const; int depthNegateFactor() const; LDDocument* document() const; void drawPoint(QPainter& painter, QPointF pos, QColor color = QColor (64, 192, 0)) const; @@ -34,12 +36,11 @@ void drawBlipCoordinates(QPainter& painter, const Vertex& pos3d, QPointF pos) const; void clearCurrentCullValue(); double currentCullValue() const; - double getDepthValue() const; void getRelativeAxes(Axis& relX, Axis& relY) const; Axis getRelativeZ() const; QPen linePen() const; const Vertex& position3D() const; - void setDepthValue(double depth); + void setDrawPlane(const Plane& plane); void setCullValue(double value); void setEditMode(EditModeType type); @@ -60,6 +61,6 @@ LDDocument& m_document; AbstractEditMode* m_currentEditMode = nullptr; Vertex m_position3D; - double m_depthValues[6] = {0}; + Plane m_drawPlane; double cullValues[6] = {0}; };
--- a/src/editmodes/abstractEditMode.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/editmodes/abstractEditMode.cpp Wed May 30 22:31:06 2018 +0300 @@ -314,7 +314,7 @@ result.setCoordinate(relativeY, point.y()); } - return result; + return projectToDrawPlane(result); } /* @@ -349,3 +349,23 @@ * TODO: the two method names are too similar and should be renamed. */ void AbstractDrawMode::endDraw() {} + +/* + * Sets the depth value of the vertex so that it's in the draw plane. + */ +Vertex AbstractDrawMode::projectToDrawPlane(const Vertex& vertex) const +{ + Axis localx, localy; + renderer()->getRelativeAxes(localx, localy); + Axis localz = renderer()->getRelativeZ(); + Line line; + line.v_1 = line.v_2 = vertex; + line.v_1[localz] = 1; + line.v_2[localz] = -1; + Plane::IntersectionResult intersection = renderer()->drawPlane().intersection(line); + + if (intersection.intersected) + return intersection.vertex; + else + return vertex; +}
--- a/src/editmodes/abstractEditMode.h Sat May 26 17:28:15 2018 +0300 +++ b/src/editmodes/abstractEditMode.h Wed May 30 22:31:06 2018 +0300 @@ -95,6 +95,7 @@ virtual int maxVertices() const; bool mouseReleased(const AbstractEditMode::MouseEventData& data) override; virtual bool preAddVertex(Vertex const&); + Vertex projectToDrawPlane(const Vertex& vertex) const; void renderPolygon(QPainter& painter, const QVector<Vertex>& poly3d, bool withlengths, bool withangles) const; };
--- a/src/editmodes/circleMode.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/editmodes/circleMode.cpp Wed May 30 22:31:06 2018 +0300 @@ -60,6 +60,28 @@ return 0.0; } +static Matrix shearMatrixForPlane(Canvas* renderer) +{ + const Plane& plane = renderer->drawPlane(); + Axis localx, localy; + renderer->getRelativeAxes(localx, localy); + Axis localz = renderer->getRelativeZ(); + Matrix shearMatrix = Matrix::identity; + Vertex normalAsVertex = Vertex::fromVector(plane.normal); + + // Compute shear matrix values. The (Y, X) cell means a slope for Y in regard to X. + // If x grows by 2, y grows by 2 times this value. In the circle primitives, + // depth is Y, but in the orthogonal view, depth is Z. So Y and Z must be swapped. + if (not qFuzzyCompare(normalAsVertex[localz], 0.0)) + { + // The slope of the vector is 90° offset from the normal vector. So Y/X slope is + // -X/Y from the normal vector. + shearMatrix(Y, X) = -normalAsVertex[localx] / normalAsVertex[localz]; + shearMatrix(Y, Z) = -normalAsVertex[localy] / normalAsVertex[localz]; + } + + return shearMatrix; +} void CircleMode::endDraw() { @@ -72,28 +94,33 @@ double dist1 (getCircleDrawDist (1)); LDDocument* primitiveFile; Matrix transform; + bool circleOrDisc = false; if (dist1 < dist0) qSwap(dist0, dist1); - if (dist0 == dist1) + if (qFuzzyCompare(dist0, dist1)) { - // If the radii are the same, there's no ring space to fill. Use a circle. + // Special case: radii are the same, there's no area. Use a circle. primitiveModel.type = PrimitiveModel::Circle; primitiveFile = primitives()->getPrimitive(primitiveModel); - transform = Matrix::fromRotationMatrix(renderer()->currentCamera().transformationMatrix(dist0)); + // transform = shearMatrixForPlane(renderer()); + transform = Matrix::fromQMatrix(renderer()->currentCamera().transformationMatrix(1)); + transform *= Matrix::scaleMatrix(dist0); circleOrDisc = true; } - else if (dist0 == 0 or dist1 == 0) + else if (qFuzzyCompare(dist0, 0) or qFuzzyCompare(dist1, 0)) { - // If either radii is 0, use a disc. + // Special case #2: one radius is 0, so use a disc. primitiveModel.type = PrimitiveModel::Disc; primitiveFile = primitives()->getPrimitive(primitiveModel); - transform = Matrix::fromRotationMatrix(renderer()->currentCamera().transformationMatrix((dist0 != 0) ? dist0 : dist1)); + //transform = shearMatrixForPlane(renderer()); + transform = Matrix::fromQMatrix(renderer()->currentCamera().transformationMatrix(1)); + transform *= Matrix::scaleMatrix(max(dist0, dist1)); circleOrDisc = true; } - else if (g_RingFinder.findRings(dist0, dist1)) + else if (g_RingFinder.findRings(dist0, dist1)) // Consult the ring finder now { // The ring finder found a solution, use that. Add the component rings to the file. primitiveModel.type = PrimitiveModel::Ring; @@ -102,7 +129,8 @@ { primitiveModel.ringNumber = component.num; primitiveFile = primitives()->getPrimitive(primitiveModel); - Matrix matrix = Matrix::fromRotationMatrix(renderer()->currentCamera().transformationMatrix(component.scale)); + Matrix matrix = Matrix::fromQMatrix(renderer()->currentCamera().transformationMatrix(component.scale)); + // matrix = shearMatrixForPlane(renderer()) * matrix; model.emplace<LDSubfileReference>(primitiveFile->name(), matrix, m_drawedVerts.first()); } } @@ -118,7 +146,6 @@ Vertex templ; templ.setCoordinate(localx, x0); templ.setCoordinate(localy, y0); - templ.setCoordinate(localz, renderer()->getDepthValue()); // Calculate circle coords QVector<QLineF> c0 = makeCircle(primitiveModel.segments, primitiveModel.divisions, dist0); @@ -141,13 +168,19 @@ if (static_cast<int>(renderer()->camera()) % 3 <= 0) qSwap(v1, v3); + // Project the vertices onto the draw plane. + for (Vertex* vertex : {&v0, &v1, &v2, &v3}) + *vertex = projectToDrawPlane(*vertex); + LDQuadrilateral* quad = model.emplace<LDQuadrilateral>(v0, v1, v2, v3); quad->setColor(MainColor); } } if (circleOrDisc and primitiveFile) + { model.emplace<LDSubfileReference>(primitiveFile->name(), transform, m_drawedVerts.first()); + } finishDraw (model); }
--- a/src/editmodes/rectangleMode.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/editmodes/rectangleMode.cpp Wed May 30 22:31:06 2018 +0300 @@ -78,16 +78,16 @@ Axis localx, localy, localz; renderer()->getRelativeAxes(localx, localy); localz = renderer()->getRelativeZ(); - - for (int i = 0; i < 4; ++i) - m_rectangleVerts[i].setCoordinate (localz, renderer()->getDepthValue()); + m_rectangleVerts[0].setCoordinate(localx, v0[localx]); + m_rectangleVerts[0].setCoordinate(localy, v0[localy]); + m_rectangleVerts[1].setCoordinate(localx, v1[localx]); + m_rectangleVerts[1].setCoordinate(localy, v0[localy]); + m_rectangleVerts[2].setCoordinate(localx, v1[localx]); + m_rectangleVerts[2].setCoordinate(localy, v1[localy]); + m_rectangleVerts[3].setCoordinate(localx, v0[localx]); + m_rectangleVerts[3].setCoordinate(localy, v1[localy]); - m_rectangleVerts[0].setCoordinate (localx, v0[localx]); - m_rectangleVerts[0].setCoordinate (localy, v0[localy]); - m_rectangleVerts[1].setCoordinate (localx, v1[localx]); - m_rectangleVerts[1].setCoordinate (localy, v0[localy]); - m_rectangleVerts[2].setCoordinate (localx, v1[localx]); - m_rectangleVerts[2].setCoordinate (localy, v1[localy]); - m_rectangleVerts[3].setCoordinate (localx, v0[localx]); - m_rectangleVerts[3].setCoordinate (localy, v1[localy]); + // Compute local z from the draw plane + for (int i = 0; i < 4; ++i) + m_rectangleVerts[i] = projectToDrawPlane(m_rectangleVerts[i]); }
--- a/src/generics/functions.h Sat May 26 17:28:15 2018 +0300 +++ b/src/generics/functions.h Wed May 30 22:31:06 2018 +0300 @@ -224,6 +224,24 @@ return static_cast<T>(round(value / interval) * interval); } +/* + * Returns the empty sum. (recursion base) + */ +template<typename T> +T sum() +{ + return {}; +} + +/* + * Returns the sum of n arguments. + */ +template<typename T, typename... Rest> +T sum(const T& arg, Rest&&... rest) +{ + return arg + sum<T>(rest...); +} + // Copy of qOverload so as to drop Qt version requirement from 5.7 to 5.5. #if (QT_VERSION < QT_VERSION_CHECK(5, 7, 0)) template <typename... Args>
--- a/src/geometry/linesegment.h Sat May 26 17:28:15 2018 +0300 +++ b/src/geometry/linesegment.h Wed May 30 22:31:06 2018 +0300 @@ -35,3 +35,5 @@ unsigned int qHash(const LineSegment& segment); bool operator==(const LineSegment& one, const LineSegment& other); bool operator<(const LineSegment& one, const LineSegment& other); + +using Line = LineSegment;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/geometry/plane.cpp Wed May 30 22:31:06 2018 +0300 @@ -0,0 +1,73 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2018 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "plane.h" + +/* + * Constructs a plane from three points + */ +Plane Plane::fromPoints(const Vertex& v1, const Vertex& v2, const Vertex& v3) +{ + Plane result; + result.normal = QVector3D::crossProduct(v2 - v1, v3 - v1); + result.point = v1; + return result; +} + +/* + * Returns whether or not this plane is valid. + */ +bool Plane::isValid() const +{ + return not normal.isNull(); +} + +/* + * Finds the intersection of a line and a plane. Returns a structure containing whether or not + * there was an intersection as well as the intersected vertex if there was one. Can return a point + * outside of the line segment. + * + * C.f. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection#Algebraic_form + */ +Plane::IntersectionResult Plane::intersection(const Line& line) const +{ + if (isValid()) + { + QVector3D lineVector = line.v_2 - line.v_1; + qreal dot = QVector3D::dotProduct(lineVector, normal); + + if (not qFuzzyCompare(dot, 0.0)) + { + qreal factor = QVector3D::dotProduct(point - line.v_1, normal) / dot; + IntersectionResult result; + result.intersected = true; + result.vertex = Vertex::fromVector(lineVector * factor + (line.v_1 - Vertex {0, 0, 0})); + return result; + } + else + { + // did not intersect + return {}; + } + } + else + { + // plane is invalid + return {}; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/geometry/plane.h Wed May 30 22:31:06 2018 +0300 @@ -0,0 +1,42 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2018 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include "../basics.h" +#include "../types/vertex.h" +#include "linesegment.h" + +/* + * Models a plane in 3D space. + */ +struct Plane +{ + struct IntersectionResult + { + bool intersected = false; + Vertex vertex; + }; + + QVector3D normal; + Vertex point; + + IntersectionResult intersection(const Line& line) const; + bool isValid() const; + + static Plane fromPoints(const Vertex& v1, const Vertex& v2, const Vertex& v3); +};
--- a/src/linetypes/quadrilateral.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/linetypes/quadrilateral.cpp Wed May 30 22:31:06 2018 +0300 @@ -55,3 +55,21 @@ { return LDObjectType::Quadrilateral; } + +/* + * Returns whether or not this quadrilateral is co-planar. + */ +bool LDQuadrilateral::isCoPlanar() const +{ + return planeAngle() < 0.001745329; +} + +/* + * Returns the angle between the two planes in this quadrilateral. + */ +qreal LDQuadrilateral::planeAngle() const +{ + QVector3D vec_1 = QVector3D::crossProduct(vertex(2) - vertex(1), vertex(0) - vertex(1)); + QVector3D vec_2 = QVector3D::crossProduct(vertex(0) - vertex(3), vertex(2) - vertex(3)); + return vectorAngle(vec_1, vec_2); +}
--- a/src/linetypes/quadrilateral.h Sat May 26 17:28:15 2018 +0300 +++ b/src/linetypes/quadrilateral.h Wed May 30 22:31:06 2018 +0300 @@ -31,6 +31,8 @@ LDQuadrilateral(const Vertex& v1, const Vertex& v2, const Vertex& v3, const Vertex& v4); QString asText() const override; + bool isCoPlanar() const; + qreal planeAngle() const; int numVertices() const override; int triangleCount(DocumentManager*) const override; LDObjectType type() const override;
--- a/src/mainwindow.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/mainwindow.cpp Wed May 30 22:31:06 2018 +0300 @@ -497,7 +497,8 @@ if (renderer()->camera() != Camera::Free) { contextMenu->addSeparator(); - contextMenu->addAction (ui.actionSetDrawDepth); + contextMenu->addAction(ui.actionSetDrawPlane); + contextMenu->addAction(ui.actionClearDrawPlane); contextMenu->addAction(ui.actionSetCullDepth); contextMenu->addAction(ui.actionClearCullDepth); }
--- a/src/mainwindow.ui Sat May 26 17:28:15 2018 +0300 +++ b/src/mainwindow.ui Wed May 30 22:31:06 2018 +0300 @@ -332,7 +332,8 @@ <addaction name="actionModeCircle"/> <addaction name="actionModeLinePath"/> <addaction name="separator"/> - <addaction name="actionSetDrawDepth"/> + <addaction name="actionSetDrawPlane"/> + <addaction name="actionClearDrawPlane"/> <addaction name="separator"/> <addaction name="actionJumpTo"/> </widget> @@ -1029,9 +1030,12 @@ <string>D</string> </property> </action> - <action name="actionSetDrawDepth"> + <action name="actionSetDrawPlane"> <property name="text"> - <string>Set Draw Dept&h</string> + <string>Set draw plane</string> + </property> + <property name="toolTip"> + <string>Locks draw tools into a plane defined by a triangle or a coplanar quadrilateral.</string> </property> </action> <action name="actionSetColor"> @@ -1769,6 +1773,14 @@ <string>Clear cull depth</string> </property> </action> + <action name="actionClearDrawPlane"> + <property name="text"> + <string>Clear draw plane</string> + </property> + <property name="toolTip"> + <string>Resets the drawing plane</string> + </property> + </action> </widget> <customwidgets> <customwidget>
--- a/src/toolsets/viewtoolset.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/toolsets/viewtoolset.cpp Wed May 30 22:31:06 2018 +0300 @@ -26,6 +26,7 @@ #include "../colors.h" #include "../glcompiler.h" #include "../documentmanager.h" +#include "../linetypes/quadrilateral.h" #include "viewtoolset.h" ViewToolset::ViewToolset (MainWindow *parent) : @@ -168,28 +169,53 @@ m_window->renderer()->update(); } -void ViewToolset::setDrawDepth() +/* + * If the given object is within a single plane, returns that plane. + * Should probably be smarter than this. + */ +static Plane drawPlaneFromObject(LDObject* object) { - if (m_window->renderer()->camera() == Camera::Free) - return; + switch (object->type()) + { + case LDObjectType::Quadrilateral: + if (not static_cast<LDQuadrilateral*>(object)->isCoPlanar()) + return {}; + case LDObjectType::Triangle: + return Plane::fromPoints(object->vertex(0), object->vertex(1), object->vertex(2)); + + default: + return {}; + } +} + +void ViewToolset::setDrawPlane() +{ + QSet<LDObject*> objects = selectedObjects(); - bool ok; - double depth = QInputDialog::getDouble( - m_window, - tr("Set draw depth"), - format( - tr("Depth value for %1:"), - m_window->renderer()->currentCamera().name() - ), - m_window->renderer()->getDepthValue(), - -10000.0f, - 10000.0f, - 4, - &ok - ); + if (objects.size() == 1) + { + LDObject* object = *objects.begin(); + Plane plane = drawPlaneFromObject(object); - if (ok) - m_window->renderer()->setDepthValue(depth); + if (plane.isValid()) + { + m_window->renderer()->setDrawPlane(plane); + } + else + { + QMessageBox::critical( + m_window, + tr("Error"), + tr("This object does not define a single plane"), + QMessageBox::Ok, + QMessageBox::Ok); + } + } +} + +void ViewToolset::clearDrawPlane() +{ + m_window->renderer()->setDrawPlane({}); } void ViewToolset::setCullDepth()
--- a/src/toolsets/viewtoolset.h Sat May 26 17:28:15 2018 +0300 +++ b/src/toolsets/viewtoolset.h Wed May 30 22:31:06 2018 +0300 @@ -29,6 +29,7 @@ Q_INVOKABLE void axes(); Q_INVOKABLE void bfcView(); Q_INVOKABLE void clearCullDepth(); + Q_INVOKABLE void clearDrawPlane(); Q_INVOKABLE void drawAngles(); Q_INVOKABLE void drawConditionalLines(); Q_INVOKABLE void drawEdgeLines(); @@ -41,8 +42,8 @@ Q_INVOKABLE void selectAll(); Q_INVOKABLE void selectByColor(); Q_INVOKABLE void selectByType(); + Q_INVOKABLE void setDrawPlane(); Q_INVOKABLE void setCullDepth(); - Q_INVOKABLE void setDrawDepth(); Q_INVOKABLE void visibilityHide(); Q_INVOKABLE void visibilityReveal(); Q_INVOKABLE void visibilityToggle();
--- a/src/types/matrix.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/types/matrix.cpp Wed May 30 22:31:06 2018 +0300 @@ -238,13 +238,28 @@ return _row; } -Matrix Matrix::fromRotationMatrix(const GLRotationMatrix& rotationMatrix) +Matrix Matrix::fromQMatrix(const QMatrix4x4& matrix) { Matrix result; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) - result(i, j) = rotationMatrix(i, j); + result(i, j) = matrix(i, j); return result; } + +Matrix Matrix::scaleMatrix(qreal scalar) +{ + return { + scalar, 0, 0, + 0, scalar, 0, + 0, 0, scalar + }; +} + +Matrix& Matrix::operator*=(const Matrix& other) +{ + *this = *this * other; + return *this; +}
--- a/src/types/matrix.h Sat May 26 17:28:15 2018 +0300 +++ b/src/types/matrix.h Wed May 30 22:31:06 2018 +0300 @@ -51,9 +51,11 @@ ConstRowView operator[](int row) const; double& operator()(int row, int column); const double& operator()(int row, int column) const; + Matrix& operator*=(const Matrix& other); static const Matrix identity; - static Matrix fromRotationMatrix(const GLRotationMatrix& rotationMatrix); + static Matrix fromQMatrix(const QMatrix4x4& matrix); + static Matrix scaleMatrix(qreal scalar); private: double m_values[9];
--- a/src/types/vertex.cpp Sat May 26 17:28:15 2018 +0300 +++ b/src/types/vertex.cpp Wed May 30 22:31:06 2018 +0300 @@ -92,6 +92,11 @@ return ::format("%1 %2 %3", this->x, this->y, this->z); } +Vertex Vertex::fromVector(const QVector3D& vector) +{ + return {vector.x(), vector.y(), vector.z()}; +} + Vertex Vertex::operator*(qreal scalar) const { return {this->x * scalar, this->y * scalar, this->z * scalar};
--- a/src/types/vertex.h Sat May 26 17:28:15 2018 +0300 +++ b/src/types/vertex.h Wed May 30 22:31:06 2018 +0300 @@ -48,6 +48,8 @@ double operator[](Axis ax) const; bool operator==(const Vertex& other) const; bool operator!=(const Vertex& other) const; + + static Vertex fromVector(const QVector3D& vector); }; inline Vertex operator*(qreal scalar, const Vertex& vertex)