├── res ├── string │ └── number.txt ├── qml │ └── GeometryShape.qml ├── icon │ ├── geometry2d │ │ ├── rectangle.svg │ │ ├── righttriangle.svg │ │ ├── isoscelestriangle.svg │ │ ├── square.svg │ │ ├── diamond.svg │ │ ├── isopopetrapezoid.svg │ │ ├── parallelogram.svg │ │ ├── line.svg │ │ ├── righttrapezoid.svg │ │ ├── regularpolygon.5.svg │ │ ├── sector.svg │ │ ├── circle.svg │ │ ├── line.so-.svg │ │ ├── line.so-so.svg │ │ ├── arbitrarypolygon.svg │ │ └── dotline.svg │ ├── geometry3d │ │ ├── cuboid.svg │ │ ├── cube.svg │ │ ├── cylinder.svg │ │ └── cone.svg │ └── ruler │ │ ├── delete.svg │ │ ├── adjust.svg │ │ └── rotate.svg └── Geometry.qrc ├── doc ├── cone.png ├── cube.png ├── line.png ├── linear.png ├── sector.png ├── sphere.png ├── diamond.png ├── ellipse.png ├── triangle.png ├── protractor.png ├── iso_triangle.png ├── arbitrarypolygon.png ├── regularprismoid.png └── isoscelestriangle.png ├── algorithm ├── algorithm.pri └── approxgeometry.h ├── conanfile.txt ├── .gitlab-ci.yml ├── geometry3ds ├── cone.cpp ├── cone.h ├── regularprism.h ├── regularprism.cpp ├── cube.h ├── cylinder.h ├── sphere.h ├── cylinder.cpp ├── qrthoprism.h ├── cuboid.h ├── ellipsoid.h ├── frustumcone.h ├── geometry3ds.pri ├── geometry3ds.h ├── polyhedron.h ├── qrthoprism.cpp ├── cube.cpp ├── regularprismoid.h ├── sphere.cpp ├── geometry3d.h ├── cuboid.cpp ├── ellipsoid.cpp ├── geometry3d.cpp ├── polyhedron.cpp └── regularprismoid.cpp ├── geometryplugin.cpp ├── Geometry_global.h ├── base ├── base.pri ├── geometryitem.h ├── geometrycontrol.h ├── geometry.h ├── geometryhelper.h ├── geometryitem.cpp └── geometry.cpp ├── rulers ├── compasses.h ├── rulers.h ├── rulerline.h ├── compasses.cpp ├── linearruler.h ├── rulers.pri ├── protractor.h ├── triangleruler.h ├── rulertriangle.h ├── rulertool.h ├── linearruler.cpp ├── ruleritem.h ├── rulertool.cpp ├── rulerline.cpp ├── ruler.h ├── protractor.cpp ├── triangleruler.cpp ├── ruler.cpp ├── rulertriangle.cpp └── ruleritem.cpp ├── geometry2ds ├── square.h ├── ellipse.h ├── diamond.h ├── righttriangle.h ├── righttrapezoid.h ├── righttrapezoid.cpp ├── isoscelestriangle.h ├── circle.h ├── arc.h ├── triangle.h ├── rectangle.h ├── parallelogram.h ├── isopopetrapezoid.h ├── trapezoid.h ├── sector.h ├── arbitrarypolygon.h ├── triangle.cpp ├── rectangle.cpp ├── geometry2ds.pri ├── righttriangle.cpp ├── ellipse.cpp ├── geometry2ds.h ├── regularpolygon.h ├── geometry2d.h ├── parallelogram.cpp ├── diamond.cpp ├── isopopetrapezoid.cpp ├── square.cpp ├── isoscelestriangle.cpp ├── polygon.h ├── circle.cpp ├── line.h ├── trapezoid.cpp ├── arc.cpp ├── arbitrarypolygon.cpp ├── geometry2d.cpp ├── regularpolygon.cpp ├── polygon.cpp └── sector.cpp ├── exports.h ├── geometryplugin.h ├── README.md ├── geometrytool.h ├── .gitignore ├── conanfile.py ├── Geometry.pro └── geometrytool.cpp /res/string/number.txt: -------------------------------------------------------------------------------- 1 | 零一二三四五六七八九十 -------------------------------------------------------------------------------- /doc/cone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/cone.png -------------------------------------------------------------------------------- /doc/cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/cube.png -------------------------------------------------------------------------------- /doc/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/line.png -------------------------------------------------------------------------------- /doc/linear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/linear.png -------------------------------------------------------------------------------- /doc/sector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/sector.png -------------------------------------------------------------------------------- /doc/sphere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/sphere.png -------------------------------------------------------------------------------- /doc/diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/diamond.png -------------------------------------------------------------------------------- /doc/ellipse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/ellipse.png -------------------------------------------------------------------------------- /doc/triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/triangle.png -------------------------------------------------------------------------------- /doc/protractor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/protractor.png -------------------------------------------------------------------------------- /doc/iso_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/iso_triangle.png -------------------------------------------------------------------------------- /doc/arbitrarypolygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/arbitrarypolygon.png -------------------------------------------------------------------------------- /doc/regularprismoid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/regularprismoid.png -------------------------------------------------------------------------------- /doc/isoscelestriangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmguo/Geometry/HEAD/doc/isoscelestriangle.png -------------------------------------------------------------------------------- /algorithm/algorithm.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/approxgeometry.h 3 | 4 | SOURCES += \ 5 | $$PWD/approxgeometry.cpp 6 | -------------------------------------------------------------------------------- /res/qml/GeometryShape.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Shapes 1.0 3 | 4 | Shape 5 | { 6 | ShapePath // Fix pathElements property not list 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | QtComposition/master@cmguo/stable 3 | qtpromise/v0.5.0@cmguo/stable 4 | ShowBoard/develop@cmguo/test 5 | 6 | [generators] 7 | qmake 8 | 9 | [options] 10 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - deploy 3 | 4 | deploy-job: 5 | stage: deploy 6 | tags: 7 | - "qt-conan" 8 | script: 9 | - echo "deploy-to-conan" 10 | - git rev-parse HEAD 11 | - py conanfile.py 12 | -------------------------------------------------------------------------------- /geometry3ds/cone.cpp: -------------------------------------------------------------------------------- 1 | #include "cone.h" 2 | 3 | Cone::Cone(Resource * res) 4 | : FrustumCone(res) 5 | { 6 | } 7 | 8 | Cone::Cone(Cone const & o) 9 | : FrustumCone(o) 10 | { 11 | } 12 | 13 | qreal Cone::r2(qreal r) 14 | { 15 | (void)r; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /geometryplugin.cpp: -------------------------------------------------------------------------------- 1 | #include "geometryplugin.h" 2 | #include "exports.h" 3 | 4 | GeometryPlugin::GeometryPlugin(QObject *parent) 5 | : QGenericPlugin(parent) 6 | { 7 | } 8 | 9 | QObject *GeometryPlugin::create(const QString &, const QString &) 10 | { 11 | return nullptr; 12 | } 13 | -------------------------------------------------------------------------------- /Geometry_global.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRY_GLOBAL_H 2 | #define GEOMETRY_GLOBAL_H 3 | 4 | #include 5 | 6 | #if defined(GEOMETRY_LIBRARY) 7 | # define GEOMETRY_EXPORT Q_DECL_EXPORT 8 | #else 9 | # define GEOMETRY_EXPORT Q_DECL_IMPORT 10 | #endif 11 | 12 | #endif // GEOMETRY_GLOBAL_H 13 | -------------------------------------------------------------------------------- /base/base.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/geometry.h \ 3 | $$PWD/geometrycontrol.h \ 4 | $$PWD/geometryhelper.h \ 5 | $$PWD/geometryitem.h 6 | 7 | SOURCES += \ 8 | $$PWD/geometry.cpp \ 9 | $$PWD/geometrycontrol.cpp \ 10 | $$PWD/geometryhelper.cpp \ 11 | $$PWD/geometryitem.cpp 12 | -------------------------------------------------------------------------------- /geometry3ds/cone.h: -------------------------------------------------------------------------------- 1 | #ifndef CONE_H 2 | #define CONE_H 3 | 4 | #include "frustumcone.h" 5 | 6 | class Cone : public FrustumCone 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Cone(Resource * res); 11 | 12 | Q_INVOKABLE Cone(Cone const & o); 13 | 14 | protected: 15 | virtual qreal r2(qreal r) override; 16 | }; 17 | 18 | #endif // CONE_H 19 | -------------------------------------------------------------------------------- /geometry3ds/regularprism.h: -------------------------------------------------------------------------------- 1 | #ifndef REGULARPRISM_H 2 | #define REGULARPRISM_H 3 | 4 | #include "regularprismoid.h" 5 | 6 | class RegularPrism : public RegularPrismoid 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE RegularPrism(Resource * res); 11 | 12 | Q_INVOKABLE RegularPrism(RegularPrism const & o); 13 | }; 14 | 15 | #endif // REGULARPRISM_H 16 | -------------------------------------------------------------------------------- /geometry3ds/regularprism.cpp: -------------------------------------------------------------------------------- 1 | #include "regularprism.h" 2 | 3 | static EdgesToolButtons edgesButtons("正%1棱柱"); 4 | REGISTER_OPTION_BUTTONS(RegularPrism, edges, edgesButtons) 5 | 6 | RegularPrism::RegularPrism(Resource * res) 7 | : RegularPrismoid(res, 1.0) 8 | { 9 | ratio_ = 1.0; 10 | } 11 | 12 | RegularPrism::RegularPrism(RegularPrism const & o) 13 | : RegularPrismoid(o) 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /geometry3ds/cube.h: -------------------------------------------------------------------------------- 1 | #ifndef CUBE_H 2 | #define CUBE_H 3 | 4 | #include "cuboid.h" 5 | 6 | class Cube : public Cuboid 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Cube(Resource * res); 11 | 12 | Q_INVOKABLE Cube(Cube const & o); 13 | 14 | public: 15 | virtual void movePoint(const QPointF &pt) override; 16 | 17 | virtual bool moveElememt(int elem, const QPointF &pt) override; 18 | }; 19 | 20 | #endif // CUBE_H 21 | -------------------------------------------------------------------------------- /rulers/compasses.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPASSES_H 2 | #define COMPASSES_H 3 | 4 | #include "ruler.h" 5 | 6 | // 圆规 7 | class Compasses : public Ruler 8 | { 9 | public: 10 | explicit Compasses(Resource * res); 11 | 12 | protected: 13 | virtual QPointF adjustDirection(QRectF &adjust) override; 14 | 15 | virtual QVector getControlPositions() override; 16 | 17 | virtual void updateShape() override; 18 | }; 19 | 20 | #endif // COMPASSES_H 21 | -------------------------------------------------------------------------------- /geometry3ds/cylinder.h: -------------------------------------------------------------------------------- 1 | #ifndef CYLINDER_H 2 | #define CYLINDER_H 3 | 4 | #include "frustumcone.h" 5 | 6 | class Cylinder : public FrustumCone 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Cylinder(Resource * res); 11 | 12 | Q_INVOKABLE Cylinder(Cylinder const & o); 13 | 14 | public: 15 | virtual bool moveElememt(int elem, QPointF const & pt) override; 16 | 17 | protected: 18 | virtual qreal r2(qreal r) override; 19 | }; 20 | 21 | #endif // CYLINDER_H 22 | -------------------------------------------------------------------------------- /rulers/rulers.h: -------------------------------------------------------------------------------- 1 | #ifndef RULERS_H 2 | #define RULERS_H 3 | 4 | #include "rulertool.h" 5 | #include "linearruler.h" 6 | #include "triangleruler.h" 7 | #include "protractor.h" 8 | 9 | #include 10 | 11 | REGISTER_CONTROL(RulerTool, "rulertool") 12 | REGISTER_RESOURCE_VIEW_FACTORY(RulerFactory, Ruler, "rulertool") 13 | REGISTER_RULER(LinearRuler, "linear") 14 | REGISTER_RULER(TriangleRuler, "triangle,iso_triangle") 15 | REGISTER_RULER(Protractor, "protractor") 16 | 17 | #endif // RULERS_H 18 | -------------------------------------------------------------------------------- /geometry2ds/square.h: -------------------------------------------------------------------------------- 1 | #ifndef SQUARE_H 2 | #define SQUARE_H 3 | 4 | #include "rectangle.h" 5 | 6 | class Square : public Rectangle 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Square(Resource * res); 11 | 12 | Q_INVOKABLE Square(Square const & o); 13 | 14 | Square(QPointF const & vec1, QPointF const & vec2); 15 | 16 | public: 17 | virtual void movePoint(QPointF const & pt) override; 18 | 19 | virtual bool moveElememt(int elem, const QPointF &pt) override; 20 | }; 21 | 22 | #endif // SQUARE_H 23 | -------------------------------------------------------------------------------- /rulers/rulerline.h: -------------------------------------------------------------------------------- 1 | #ifndef RULERLINE_H 2 | #define RULERLINE_H 3 | 4 | #include "geometry2ds/line.h" 5 | 6 | class RulerLine : public Line 7 | { 8 | public: 9 | RulerLine(QLineF const & line); 10 | 11 | virtual void addPoint(QPointF const & pt); 12 | 13 | virtual void movePoint(QPointF const & pt); 14 | 15 | virtual bool commitPoint(QPointF const & pt); 16 | 17 | private: 18 | QPointF attachToLine(QPointF const & pt); 19 | 20 | private: 21 | QLineF line_; 22 | }; 23 | 24 | 25 | #endif // RULERLINE_H 26 | -------------------------------------------------------------------------------- /rulers/compasses.cpp: -------------------------------------------------------------------------------- 1 | #include "compasses.h" 2 | 3 | Compasses::Compasses(Resource * res) 4 | : Ruler(res) 5 | { 6 | } 7 | 8 | QPointF Compasses::adjustDirection(QRectF &) 9 | { 10 | return {0, 1}; 11 | } 12 | 13 | QVector Compasses::getControlPositions() 14 | { 15 | QVector points; 16 | points.insert(0,QPointF(0,0)); 17 | points.insert(1,QPointF(100,100)); 18 | points.insert(2,QPointF(200,200)); 19 | return points; 20 | } 21 | 22 | void Compasses::updateShape() 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /geometry3ds/sphere.h: -------------------------------------------------------------------------------- 1 | #ifndef SPHERE_H 2 | #define SPHERE_H 3 | 4 | #include "ellipsoid.h" 5 | 6 | class Sphere : public Ellipsoid 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Sphere(Resource * res); 11 | 12 | Q_INVOKABLE Sphere(Sphere const & o); 13 | 14 | public: 15 | virtual void sync() override; 16 | 17 | virtual QVector movePoints() override; 18 | 19 | virtual int hit(QPointF & pt) override; 20 | 21 | virtual bool moveElememt(int elem, QPointF const & pt) override; 22 | 23 | }; 24 | 25 | #endif // SPHERE_H 26 | -------------------------------------------------------------------------------- /rulers/linearruler.h: -------------------------------------------------------------------------------- 1 | #ifndef LINEARRULER_H 2 | #define LINEARRULER_H 3 | 4 | #include "ruler.h" 5 | 6 | class LinearRuler : public Ruler 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE explicit LinearRuler(Resource * res); 11 | 12 | protected: 13 | virtual QVector getControlPositions() override; 14 | 15 | virtual void updateShape() override; 16 | 17 | virtual void onDraw(QPainter *painter) override; 18 | 19 | virtual Geometry * createGeometry() override; 20 | }; 21 | 22 | #endif // LINEARRULER_H 23 | -------------------------------------------------------------------------------- /geometry2ds/ellipse.h: -------------------------------------------------------------------------------- 1 | #ifndef ELLIPSE_H 2 | #define ELLIPSE_H 3 | 4 | #include "geometry2d.h" 5 | 6 | class Ellipse : public Geometry2D 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Ellipse(Resource * res); 11 | 12 | Q_INVOKABLE Ellipse(Ellipse const & o); 13 | 14 | Ellipse(QPointF const & center, QSizeF const & radius); 15 | 16 | public: 17 | virtual QPainterPath graphPath() override; 18 | 19 | virtual QVector movePoints() override; 20 | 21 | virtual int hit(QPointF &pt) override; 22 | }; 23 | 24 | #endif // ELLIPSE_H 25 | -------------------------------------------------------------------------------- /geometry2ds/diamond.h: -------------------------------------------------------------------------------- 1 | #ifndef DIAMOND_H 2 | #define DIAMOND_H 3 | 4 | #include "polygon.h" 5 | 6 | class Diamond : public Polygon 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Diamond(Resource * res); 11 | 12 | Q_INVOKABLE Diamond(Diamond const & o); 13 | 14 | Diamond(QPointF const & vec1, QPointF const & vec2); 15 | 16 | public: 17 | virtual int pointCount() override; 18 | 19 | virtual QPointF point(int index) override; 20 | 21 | virtual bool setPoint(int index, const QPointF &pt) override; 22 | }; 23 | 24 | 25 | #endif // DIAMOND_H 26 | -------------------------------------------------------------------------------- /geometry2ds/righttriangle.h: -------------------------------------------------------------------------------- 1 | #ifndef RIGHTTRIANGLE_H 2 | #define RIGHTTRIANGLE_H 3 | 4 | #include "triangle.h" 5 | 6 | class RightTriangle : public Triangle 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE RightTriangle(Resource * res); 11 | 12 | Q_INVOKABLE RightTriangle(RightTriangle const & o); 13 | 14 | RightTriangle(QPointF const & vec1, QPointF const & vec2); 15 | 16 | public: 17 | virtual QPointF point(int index) override; 18 | 19 | virtual bool moveElememt(int elem, const QPointF &pt) override; 20 | }; 21 | 22 | #endif // RIGHTTRIANGLE_H 23 | -------------------------------------------------------------------------------- /exports.h: -------------------------------------------------------------------------------- 1 | #ifndef EXPORTS_H 2 | #define EXPORTS_H 3 | 4 | #include "geometry2ds/geometry2ds.h" 5 | #include "geometry3ds/geometry3ds.h" 6 | #include "rulers/rulers.h" 7 | #include "base/geometrycontrol.h" 8 | #include "base/geometryhelper.h" 9 | #include "geometrytool.h" 10 | 11 | REGISTER_CONTROL(GeometryControl, "geometry2d,geometry3d") 12 | REGISTER_CONTROL(GeometryTool, "geometry2dtool,geometry3dtool,rulertooltool"); 13 | 14 | static QExport export_tools(QPart::shared); 15 | static QExport export_helper(QPart::shared); 16 | 17 | #endif // EXPORTS_H 18 | -------------------------------------------------------------------------------- /geometry2ds/righttrapezoid.h: -------------------------------------------------------------------------------- 1 | #ifndef RIGHTTRAPEZOID_H 2 | #define RIGHTTRAPEZOID_H 3 | 4 | #include "trapezoid.h" 5 | 6 | class RightTrapezoid : public Trapezoid 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE RightTrapezoid(Resource * res); 11 | 12 | Q_INVOKABLE RightTrapezoid(RightTrapezoid const & o); 13 | 14 | RightTrapezoid(QPointF const & vec1, QPointF const & vec2, QPointF const & vec3); 15 | 16 | protected: 17 | virtual QPointF point4(QPointF const & pt1, QPointF const & pt2, QPointF const & pt3) override; 18 | }; 19 | 20 | #endif // RIGHTTRAPEZOID_H 21 | -------------------------------------------------------------------------------- /geometry2ds/righttrapezoid.cpp: -------------------------------------------------------------------------------- 1 | #include "righttrapezoid.h" 2 | 3 | RightTrapezoid::RightTrapezoid(Resource * res) 4 | : Trapezoid(res) 5 | { 6 | } 7 | 8 | RightTrapezoid::RightTrapezoid(RightTrapezoid const & o) 9 | : Trapezoid(o) 10 | { 11 | } 12 | 13 | RightTrapezoid::RightTrapezoid(const QPointF &vec1, const QPointF &vec2, const QPointF &vec3) 14 | : Trapezoid(vec1, vec2, vec3) 15 | { 16 | } 17 | 18 | QPointF RightTrapezoid::point4(QPointF const & pt1, QPointF const & pt2, QPointF const & pt3) 19 | { 20 | (void) pt2; 21 | return QPointF(pt1.x(), pt3.y()); 22 | } 23 | -------------------------------------------------------------------------------- /res/icon/geometry2d/rectangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic9 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /geometry2ds/isoscelestriangle.h: -------------------------------------------------------------------------------- 1 | #ifndef ISOSCELESTRIANGLE_H 2 | #define ISOSCELESTRIANGLE_H 3 | 4 | #include "triangle.h" 5 | 6 | class IsoscelesTriangle : public Triangle 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE IsoscelesTriangle(Resource * res); 11 | 12 | Q_INVOKABLE IsoscelesTriangle(IsoscelesTriangle const & o); 13 | 14 | IsoscelesTriangle(QPointF const & vec1, QPointF const & vec2); 15 | 16 | public: 17 | virtual QPointF point(int index) override; 18 | 19 | virtual bool moveElememt(int elem, QPointF const & pt) override; 20 | }; 21 | #endif // ISOSCELESTRIANGLE_H 22 | -------------------------------------------------------------------------------- /geometry3ds/cylinder.cpp: -------------------------------------------------------------------------------- 1 | #include "cylinder.h" 2 | 3 | Cylinder::Cylinder(Resource * res) 4 | : FrustumCone(res) 5 | { 6 | } 7 | 8 | Cylinder::Cylinder(Cylinder const & o) 9 | : FrustumCone(o) 10 | { 11 | } 12 | 13 | qreal Cylinder::r2(qreal r) 14 | { 15 | return r; 16 | } 17 | 18 | bool Cylinder::moveElememt(int elem, QPointF const & pt) 19 | { 20 | if (elem == 4 || elem == 5) { 21 | points_[0].setY(pt.y()); 22 | QPointF p(pt.x(), points_[1].y()); 23 | return FrustumCone::moveElememt(1, p); 24 | } 25 | return FrustumCone::moveElememt(elem, pt); 26 | } 27 | -------------------------------------------------------------------------------- /geometry3ds/qrthoprism.h: -------------------------------------------------------------------------------- 1 | #ifndef QRTHOPRISM_H 2 | #define QRTHOPRISM_H 3 | 4 | #include "regularprismoid.h" 5 | 6 | class Qrthoprism : public RegularPrismoid 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Qrthoprism(Resource * res); 11 | 12 | Q_INVOKABLE Qrthoprism(Qrthoprism const & o); 13 | 14 | public: 15 | virtual int pointCount() override; 16 | 17 | virtual QVector3D point(int index) override; 18 | 19 | virtual bool moveElememt(int elem, const QPointF &pt) override; 20 | 21 | protected: 22 | virtual void makeLines() override; 23 | }; 24 | 25 | #endif // QRTHOPRISM_H 26 | -------------------------------------------------------------------------------- /res/icon/geometry2d/righttriangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic7 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /geometry2ds/circle.h: -------------------------------------------------------------------------------- 1 | #ifndef CIRCLE_H 2 | #define CIRCLE_H 3 | 4 | #include "ellipse.h" 5 | 6 | class Circle : public Ellipse 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Circle(Resource * res); 11 | 12 | Q_INVOKABLE Circle(Circle const & o); 13 | 14 | Circle(QPointF const & center, qreal radius); 15 | 16 | public: 17 | virtual QPainterPath graphPath() override; 18 | 19 | virtual QVector movePoints() override; 20 | 21 | virtual int hit(QPointF &pt) override; 22 | 23 | virtual bool moveElememt(int elem, QPointF const & pt) override; 24 | }; 25 | 26 | #endif // CIRCLE_H 27 | -------------------------------------------------------------------------------- /geometryplugin.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRYPLUGIN_H 2 | #define GEOMETRYPLUGIN_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | class GeometryPlugin : public QGenericPlugin 9 | , public QComponentFactoryInterface 10 | { 11 | Q_OBJECT 12 | Q_PLUGIN_METADATA(IID ComponentFactory_iid FILE "Geometry.json") 13 | Q_INTERFACES(QComponentFactoryInterface) 14 | 15 | public: 16 | explicit GeometryPlugin(QObject *parent = nullptr); 17 | 18 | private: 19 | QObject *create(const QString &name, const QString &spec) override; 20 | }; 21 | 22 | #endif // GEOMETRYPLUGIN_H 23 | -------------------------------------------------------------------------------- /res/icon/geometry2d/isoscelestriangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic6 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/icon/geometry2d/square.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic8 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /geometry2ds/arc.h: -------------------------------------------------------------------------------- 1 | #ifndef ARC_H 2 | #define ARC_H 3 | 4 | #include "geometry2d.h" 5 | 6 | class Arc : public Geometry2D 7 | { 8 | Q_OBJECT 9 | 10 | Q_PROPERTY(QSizeF radius MEMBER radius_) 11 | 12 | public: 13 | Q_INVOKABLE Arc(Resource * res); 14 | 15 | Q_INVOKABLE Arc(Arc const & o); 16 | 17 | public: 18 | virtual QPainterPath graphPath() override; 19 | 20 | private: 21 | void arcTo(QPainterPath & graphPath, const QPointF &point, const QSizeF &size, double rotationAngle, bool isLargeArc, bool sweepDirection); 22 | 23 | private: 24 | QSizeF radius_ { 200, 200}; 25 | }; 26 | 27 | #endif // ARC_H 28 | -------------------------------------------------------------------------------- /geometry2ds/triangle.h: -------------------------------------------------------------------------------- 1 | #ifndef TRIANGLE_H 2 | #define TRIANGLE_H 3 | 4 | #include "polygon.h" 5 | 6 | class Triangle : public Polygon 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Triangle(Resource * res); 11 | 12 | Triangle(Triangle const & o); 13 | 14 | Triangle(QPointF const & vec1, QPointF const & vec2); 15 | 16 | public: 17 | virtual int pointCount() override; 18 | 19 | virtual bool setPoint(int index, const QPointF &pt) override; 20 | 21 | virtual bool moveElememt(int elem, const QPointF &pt) override; 22 | 23 | private: 24 | qreal angles_[3]; 25 | }; 26 | 27 | #endif // TRIANGLE_H 28 | -------------------------------------------------------------------------------- /res/icon/geometry2d/diamond.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic10 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /rulers/rulers.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/compasses.h \ 3 | $$PWD/linearruler.h \ 4 | $$PWD/protractor.h \ 5 | $$PWD/ruler.h \ 6 | $$PWD/ruleritem.h \ 7 | $$PWD/rulerline.h \ 8 | $$PWD/rulers.h \ 9 | $$PWD/rulertool.h \ 10 | $$PWD/rulertriangle.h \ 11 | $$PWD/triangleruler.h 12 | 13 | SOURCES += \ 14 | $$PWD/compasses.cpp \ 15 | $$PWD/linearruler.cpp \ 16 | $$PWD/protractor.cpp \ 17 | $$PWD/ruler.cpp \ 18 | $$PWD/ruleritem.cpp \ 19 | $$PWD/rulerline.cpp \ 20 | $$PWD/rulertool.cpp \ 21 | $$PWD/rulertriangle.cpp \ 22 | $$PWD/triangleruler.cpp 23 | -------------------------------------------------------------------------------- /res/icon/geometry2d/isopopetrapezoid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic11 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/icon/geometry2d/parallelogram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic14 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /rulers/protractor.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef PROTRACTOR_H 3 | #define PROTRACTOR_H 4 | 5 | #include "ruler.h" 6 | 7 | // 量角器 8 | class Protractor : public Ruler 9 | { 10 | Q_OBJECT 11 | public: 12 | Q_INVOKABLE explicit Protractor(Resource * res); 13 | 14 | protected: 15 | virtual QPointF adjustDirection(QRectF &adjust) override; 16 | 17 | virtual QVector getControlPositions() override; 18 | 19 | virtual void updateShape() override; 20 | 21 | virtual void onDraw(QPainter *painter) override; 22 | 23 | virtual Geometry * createGeometry() override; 24 | }; 25 | 26 | 27 | #endif // PROTRACTOR_H 28 | -------------------------------------------------------------------------------- /res/icon/geometry2d/line.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic0 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /geometry2ds/rectangle.h: -------------------------------------------------------------------------------- 1 | #ifndef RECTANGLE_H 2 | #define RECTANGLE_H 3 | 4 | #include "polygon.h" 5 | 6 | class Rectangle : public Polygon 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Rectangle(Resource * res); 11 | 12 | Q_INVOKABLE Rectangle(Rectangle const & o); 13 | 14 | Rectangle(QPointF const & vec1, QPointF const & vec2); 15 | 16 | public: 17 | virtual int pointCount() override; 18 | 19 | virtual bool setPoint(int index, const QPointF &pt) override; 20 | 21 | virtual QPointF point(int index) override; 22 | 23 | virtual bool moveElememt(int elem, const QPointF &pt) override; 24 | }; 25 | 26 | #endif // RECTANGLE_H 27 | -------------------------------------------------------------------------------- /res/icon/geometry2d/righttrapezoid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic12 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/icon/geometry2d/regularpolygon.5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic13 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /rulers/triangleruler.h: -------------------------------------------------------------------------------- 1 | #ifndef TRIANGLERULER_H 2 | #define TRIANGLERULER_H 3 | 4 | #include "ruler.h" 5 | 6 | class TriangleRuler : public Ruler 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE explicit TriangleRuler(Resource * res); 11 | 12 | protected: 13 | virtual QPointF adjustDirection(QRectF &adjust) override; 14 | 15 | virtual QVector getControlPositions() override; 16 | 17 | virtual void updateShape() override; 18 | 19 | virtual void onDraw(QPainter *painter) override; 20 | 21 | virtual Geometry * createGeometry() override; 22 | 23 | private: 24 | bool isosceles_; //是否等腰三角尺 25 | }; 26 | 27 | #endif // TRIANGLERULER_H 28 | -------------------------------------------------------------------------------- /geometry3ds/cuboid.h: -------------------------------------------------------------------------------- 1 | #ifndef CUBOID_H 2 | #define CUBOID_H 3 | 4 | #include "polyhedron.h" 5 | 6 | class Cuboid : public Polyhedron 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Cuboid(Resource * res); 11 | 12 | Q_INVOKABLE Cuboid(Cuboid const & o); 13 | 14 | public: 15 | virtual int pointCount() override; 16 | 17 | virtual QVector3D point(int index) override; 18 | 19 | virtual bool moveElememt(int elem, const QPointF &pt) override; 20 | 21 | virtual void sync() override; 22 | 23 | protected: 24 | void setMoveElem(int elem); 25 | 26 | protected: 27 | int moveElem_ = 1; 28 | bool inner_ = false; // inner control point 2,3,5,6 29 | }; 30 | 31 | #endif // CUBOID_H 32 | -------------------------------------------------------------------------------- /geometry2ds/parallelogram.h: -------------------------------------------------------------------------------- 1 | #ifndef PARALLELOGRAM_H 2 | #define PARALLELOGRAM_H 3 | 4 | #include "trapezoid.h" 5 | 6 | class Parallelogram : public Trapezoid 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Parallelogram(Resource * res); 11 | 12 | Q_INVOKABLE Parallelogram(Parallelogram const & o); 13 | 14 | Parallelogram(QPointF const & vec1, QPointF const & vec2, QPointF const & vec3); 15 | 16 | protected: 17 | virtual bool setPoint(int index, const QPointF &pt) override; 18 | 19 | virtual QPointF point4(QPointF const & pt1, QPointF const & pt2, QPointF const & pt3) override; 20 | 21 | virtual bool moveElememt(int elem, const QPointF &pt) override; 22 | }; 23 | 24 | #endif // PARALLELOGRAM_H 25 | -------------------------------------------------------------------------------- /geometry3ds/ellipsoid.h: -------------------------------------------------------------------------------- 1 | #ifndef ELLIPSOID_H 2 | #define ELLIPSOID_H 3 | 4 | #include "geometry3d.h" 5 | 6 | class Ellipsoid : public Geometry3D 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE Ellipsoid(Resource * res); 11 | 12 | Q_INVOKABLE Ellipsoid(Ellipsoid const & o); 13 | 14 | public: 15 | virtual void sync() override; 16 | 17 | virtual QPainterPath visualPath() override; 18 | 19 | virtual QPainterPath contour() override; 20 | 21 | virtual QVector movePoints() override; 22 | 23 | virtual int hit(QPointF & pt) override; 24 | 25 | virtual bool moveElememt(int elem, QPointF const & pt) override; 26 | 27 | protected: 28 | QVector3D radius_; 29 | }; 30 | 31 | #endif // ELLIPSOID_H 32 | -------------------------------------------------------------------------------- /geometry2ds/isopopetrapezoid.h: -------------------------------------------------------------------------------- 1 | #ifndef ISOPOPETRAPEZOID_H 2 | #define ISOPOPETRAPEZOID_H 3 | 4 | #include "trapezoid.h" 5 | 6 | class IsopopeTrapezoid : public Trapezoid 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE IsopopeTrapezoid(Resource * res); 11 | 12 | Q_INVOKABLE IsopopeTrapezoid(IsopopeTrapezoid const & o); 13 | 14 | IsopopeTrapezoid(QPointF const & vec1, QPointF const & vec2, QPointF const & vec3); 15 | 16 | protected: 17 | virtual bool setPoint(int index, const QPointF &pt) override; 18 | 19 | virtual QPointF point4(QPointF const & pt1, QPointF const & pt2, QPointF const & pt3) override; 20 | 21 | virtual bool moveElememt(int elem, const QPointF &pt) override; 22 | }; 23 | 24 | #endif // ISOPOPETRAPEZOID_H 25 | -------------------------------------------------------------------------------- /res/icon/geometry2d/sector.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic5 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /geometry3ds/frustumcone.h: -------------------------------------------------------------------------------- 1 | #ifndef FRUSTUMCONE_H 2 | #define FRUSTUMCONE_H 3 | 4 | #include "geometry3d.h" 5 | 6 | class FrustumCone : public Geometry3D 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE FrustumCone(Resource * res); 11 | 12 | Q_INVOKABLE FrustumCone(FrustumCone const & o); 13 | 14 | public: 15 | virtual QPainterPath visualPath() override; 16 | 17 | virtual QPainterPath contour() override; 18 | 19 | virtual QVector movePoints() override; 20 | 21 | virtual int hit(QPointF & pt) override; 22 | 23 | virtual bool moveElememt(int elem, QPointF const & pt) override; 24 | 25 | public slots: 26 | bool contains(QPointF const & pt); 27 | 28 | protected: 29 | virtual qreal r2(qreal r); 30 | }; 31 | 32 | #endif // FRUSTUMCONE_H 33 | -------------------------------------------------------------------------------- /geometry3ds/geometry3ds.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/cone.h \ 3 | $$PWD/cube.h \ 4 | $$PWD/cuboid.h \ 5 | $$PWD/cylinder.h \ 6 | $$PWD/ellipsoid.h \ 7 | $$PWD/frustumcone.h \ 8 | $$PWD/geometry3d.h \ 9 | $$PWD/geometry3ds.h \ 10 | $$PWD/polyhedron.h \ 11 | $$PWD/qrthoprism.h \ 12 | $$PWD/regularprism.h \ 13 | $$PWD/regularprismoid.h \ 14 | $$PWD/sphere.h 15 | 16 | SOURCES += \ 17 | $$PWD/cone.cpp \ 18 | $$PWD/cube.cpp \ 19 | $$PWD/cuboid.cpp \ 20 | $$PWD/cylinder.cpp \ 21 | $$PWD/ellipsoid.cpp \ 22 | $$PWD/frustumcone.cpp \ 23 | $$PWD/geometry3d.cpp \ 24 | $$PWD/polyhedron.cpp \ 25 | $$PWD/qrthoprism.cpp \ 26 | $$PWD/regularprism.cpp \ 27 | $$PWD/regularprismoid.cpp \ 28 | $$PWD/sphere.cpp 29 | -------------------------------------------------------------------------------- /res/icon/geometry2d/circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic4 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /rulers/rulertriangle.h: -------------------------------------------------------------------------------- 1 | #ifndef RULERTRIANGLE_H 2 | #define RULERTRIANGLE_H 3 | 4 | #include "geometry2ds/polygon.h" 5 | 6 | class RulerTriangle : public Polygon 7 | { 8 | public: 9 | RulerTriangle(QVector const & stuns); 10 | 11 | virtual void addPoint(QPointF const & pt); 12 | 13 | virtual void movePoint(QPointF const & pt); 14 | 15 | virtual bool commitPoint(QPointF const & pt); 16 | 17 | virtual bool canClose() override; 18 | 19 | private: 20 | QPointF attachToLine(QPointF const & pt); 21 | 22 | private: 23 | QVector stuns_; 24 | int curLine_ = 0; // update by attachToLine 25 | int lastLine_ = 0; 26 | int startLine_ = 0; 27 | int endLine_ = 0; 28 | QPointF start_; 29 | QPointF end_; 30 | }; 31 | 32 | #endif // RULERTRIANGLE_H 33 | -------------------------------------------------------------------------------- /res/icon/geometry3d/cuboid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic17 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /res/icon/geometry3d/cube.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic16 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /res/icon/ruler/delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /rulers/rulertool.h: -------------------------------------------------------------------------------- 1 | #ifndef RULERTOOL_H 2 | #define RULERTOOL_H 3 | 4 | #include 5 | 6 | class Geometry; 7 | 8 | class RulerTool: public Control 9 | { 10 | Q_OBJECT 11 | public: 12 | Q_INVOKABLE RulerTool(ResourceView *res); 13 | 14 | virtual QString toolsString(QByteArray const & parent) const override; 15 | 16 | using :: Control::sizeChanged; 17 | 18 | public: 19 | Control * addGeometry(Geometry * geometry); 20 | 21 | void finishGeometry(Control * geometry); 22 | 23 | protected: 24 | virtual ControlView * create(ControlView * parent) override; 25 | 26 | virtual void attaching() override; 27 | 28 | virtual void attached() override; 29 | 30 | virtual SelectMode selectTest(ControlView *child, ControlView *parent, const QPointF &point, bool onlyAssist) override; 31 | }; 32 | 33 | #endif // RULERTOOL_H 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Geometry 2 | 在电子白板中进行几何图形创作 3 | 4 | ![image](doc/arbitrarypolygon.png) 5 | ![image](doc/regularprismoid.png) 6 | ![image](doc/diamond.png) 7 | ![image](doc/isoscelestriangle.png) 8 | ![image](doc/sector.png) 9 | ![image](doc/ellipse.png) 10 | ![image](doc/line.png) 11 | 12 | ![image](doc/cone.png) 13 | ![image](doc/cube.png) 14 | ![image](doc/sphere.png) 15 | 16 | ![image](doc/linear.png) 17 | ![image](doc/triangle.png) 18 | ![image](doc/iso_triangle.png) 19 | ![image](doc/protractor.png) 20 | 21 | # 特性: 22 | - 一笔画:大部分图形通过鼠标按下、移动、抬起一笔完成 23 | - 手绘图形:通过画笔即可绘制大部分 2D 图形(自动识别) 24 | - 可调节:一笔画完,可以进一步拖拽顶点、边进行调节 25 | - 角度标注:自动标注特殊角度(30,45,60,90等) 26 | - 圆角特效:所有二维图形的顶点都可以圆角化 27 | - 角度吸附:一笔画、调节过程中,会自动吸附到特殊角度,方便创建规整的几何图形 28 | - 导出图形:导出为图片(PNG,SVG 等格式),将创作成果在其他地方使用 29 | 30 | # 技术方案: 31 | - 基于 C++ 实现几何算法(目前基于 Qt,规划会将核心算法与 Qt 解耦) 32 | - 利用[电子白板](https://github.com/cmguo/ShowBoard)的功能框架,可实现平移、缩放、选择;拷贝、删除;复制、粘贴等功能 33 | -------------------------------------------------------------------------------- /res/icon/geometry2d/line.so-.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic2 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /geometrytool.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRYTOOL_H 2 | #define GEOMETRYTOOL_H 3 | 4 | #include 5 | 6 | class GeometryTools : QObject 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE GeometryTools(); 11 | 12 | public slots: 13 | static void getToolButtons(QList & result, QByteArray const & type); 14 | 15 | static void handleToolButton(ToolButton* button, QByteArray const & type); 16 | }; 17 | 18 | class GeometryTool : public MenuTool 19 | { 20 | Q_OBJECT 21 | public: 22 | Q_INVOKABLE GeometryTool(ResourceView *res = nullptr); 23 | 24 | private: 25 | virtual void getToolButtons(QList & buttons, 26 | ToolButton * parent) override; 27 | 28 | using ToolButtonProvider::handleToolButton; 29 | 30 | virtual bool handleToolButton(ToolButton * button, QStringList const & args) override; 31 | 32 | private: 33 | QList buttons_; 34 | }; 35 | 36 | #endif // GRAPHTOOL_H 37 | -------------------------------------------------------------------------------- /geometry2ds/trapezoid.h: -------------------------------------------------------------------------------- 1 | #ifndef TRAPEZOID_H 2 | #define TRAPEZOID_H 3 | 4 | #include "polygon.h" 5 | 6 | class Trapezoid : public Polygon 7 | { 8 | Q_OBJECT 9 | public: 10 | Trapezoid(Resource * res); 11 | 12 | Trapezoid(Trapezoid const & o); 13 | 14 | Trapezoid(QPointF const & vec1, QPointF const & vec2); 15 | 16 | Trapezoid(QPointF const & vec1, QPointF const & vec2, QPointF const & vec3); 17 | 18 | public: 19 | virtual void movePoint(QPointF const & pt) override; 20 | 21 | virtual bool commitPoint(QPointF const & pt) override; 22 | 23 | virtual int pointCount() override; 24 | 25 | virtual bool setPoint(int index, const QPointF &pt) override; 26 | 27 | virtual QPointF point(int index) override; 28 | 29 | virtual bool moveElememt(int elem, const QPointF &pt) override; 30 | 31 | protected: 32 | virtual QPointF point4(QPointF const & pt1, QPointF const & pt2, QPointF const & pt3) = 0; 33 | }; 34 | 35 | #endif // TRAPEZOID_H 36 | -------------------------------------------------------------------------------- /geometry3ds/geometry3ds.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRY3DS_H 2 | #define GEOMETRY3DS_H 3 | 4 | #include 5 | 6 | #include "geometry3d.h" 7 | #include "cuboid.h" 8 | #include "cube.h" 9 | #include "frustumcone.h" 10 | #include "cone.h" 11 | #include "cylinder.h" 12 | #include "ellipsoid.h" 13 | #include "sphere.h" 14 | #include "regularprism.h" 15 | #include "regularprismoid.h" 16 | #include "qrthoprism.h" 17 | 18 | REGISTER_RESOURCE_VIEW_FACTORY(Geometry3DFactory, Geometry3D, "geometry3d") 19 | REGISTER_GEOMETRY_3D(Cuboid, "cuboid") 20 | REGISTER_GEOMETRY_3D(Cube, "cube") 21 | REGISTER_GEOMETRY_3D(FrustumCone, "frustumcone") 22 | REGISTER_GEOMETRY_3D(Cone, "cone") 23 | REGISTER_GEOMETRY_3D(Cylinder, "cylinder") 24 | REGISTER_GEOMETRY_3D(Sphere, "sphere") 25 | REGISTER_GEOMETRY_3D(Ellipsoid, "ellipsoid") 26 | REGISTER_GEOMETRY_3D(RegularPrism, "regularprism") 27 | REGISTER_GEOMETRY_3D(RegularPrismoid, "regularprismoid") 28 | REGISTER_GEOMETRY_3D(Qrthoprism, "qrthoprism") 29 | 30 | #endif // GEOMETRY3DS_H 31 | -------------------------------------------------------------------------------- /res/icon/geometry2d/line.so-so.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic3 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /geometry2ds/sector.h: -------------------------------------------------------------------------------- 1 | #ifndef SECTOR_H 2 | #define SECTOR_H 3 | 4 | #include "geometry2d.h" 5 | 6 | class Sector : public Geometry2D 7 | { 8 | Q_OBJECT 9 | 10 | Q_CLASSINFO("toolsString", "angle|角度|Popup,OptionsGroup,NeedUpdate|;") 11 | 12 | Q_PROPERTY(qreal angle READ angle WRITE setAngle) 13 | 14 | public: 15 | Q_INVOKABLE Sector(Resource * res); 16 | 17 | Q_INVOKABLE Sector(Sector const & o); 18 | 19 | public: 20 | virtual QPainterPath graphPath() override; 21 | 22 | virtual QPainterPath textPath() override; 23 | 24 | virtual QVector movePoints() override; 25 | 26 | virtual int hit(QPointF &pt) override; 27 | 28 | virtual bool moveElememt(int elem, QPointF const & pt) override; 29 | 30 | virtual void sync() override; 31 | 32 | public: 33 | qreal angle(); 34 | 35 | void setAngle(qreal angle); 36 | 37 | private: 38 | qreal angle_ = 0.0; 39 | QPainterPath graphPath_; 40 | QPainterPath textPath_; 41 | }; 42 | 43 | #endif // SECTOR_H 44 | -------------------------------------------------------------------------------- /algorithm/approxgeometry.h: -------------------------------------------------------------------------------- 1 | #ifndef APPROXGEOMETRY_H 2 | #define APPROXGEOMETRY_H 3 | 4 | #include 5 | 6 | class Geometry; 7 | class QObject; 8 | 9 | class ApproxGeometry 10 | { 11 | public: 12 | ApproxGeometry(qreal epsilon = 0); 13 | 14 | bool addPoints(QVector points); 15 | 16 | QObject * finish(QPointF const & offset); 17 | 18 | private: 19 | Geometry * approxGeometry3(); 20 | 21 | Geometry * approxGeometry4(); 22 | 23 | Geometry * approxGeometryRegular(); 24 | 25 | Geometry * approxGeometryEllipse(); 26 | 27 | private: 28 | static void RamerDouglasPeucker(const QVector &pointList, qreal epsilon, QVector &out); 29 | 30 | static QVector edgeLengths(QVector const & points); 31 | 32 | static QVector edgeAngles(QVector const & points, QVector const & lengths); 33 | 34 | private: 35 | qreal epsilon_; 36 | QVector points_; 37 | qreal rotate_ = 0; 38 | }; 39 | 40 | #endif // APPROXGEOMETRY_H 41 | -------------------------------------------------------------------------------- /geometry2ds/arbitrarypolygon.h: -------------------------------------------------------------------------------- 1 | #ifndef ARBITRARYPOLYGON_H 2 | #define ARBITRARYPOLYGON_H 3 | 4 | #include "polygon.h" 5 | 6 | class ArbitraryPolygon : public Polygon 7 | { 8 | Q_OBJECT 9 | public: 10 | Q_INVOKABLE ArbitraryPolygon(Resource * res); 11 | 12 | Q_INVOKABLE ArbitraryPolygon(ArbitraryPolygon const & o); 13 | 14 | public: 15 | virtual bool canClose() override; 16 | 17 | virtual void addPoint(QPointF const & pt) override; 18 | 19 | virtual void movePoint(QPointF const & pt) override; 20 | 21 | virtual bool commitPoint(QPointF const & pt) override; 22 | 23 | virtual bool moveTempPoint(const QPointF &pt) override; 24 | 25 | virtual bool canFinish() override; 26 | 27 | virtual void finish(const QPointF &c) override; 28 | 29 | virtual int pointCount() override; 30 | 31 | virtual QPointF point(int index) override; 32 | 33 | virtual bool moveElememt(int elem, const QPointF &pt) override; 34 | 35 | private: 36 | bool tempValid_ = false; 37 | QPointF temp_; 38 | }; 39 | 40 | #endif // ARBITRARYPOLYGON_H 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | -------------------------------------------------------------------------------- /geometry2ds/triangle.cpp: -------------------------------------------------------------------------------- 1 | #include "triangle.h" 2 | 3 | Triangle::Triangle(Resource * res) 4 | : Polygon(res, DrawAttach) 5 | { 6 | } 7 | 8 | Triangle::Triangle(Triangle const & o) 9 | : Polygon(o) 10 | { 11 | } 12 | 13 | Triangle::Triangle(const QPointF &vec1, const QPointF &vec2) 14 | : Polygon({vec1, vec2}) 15 | { 16 | } 17 | 18 | int Triangle::pointCount() 19 | { 20 | return points_.size() == 2 ? 3 : 1; 21 | } 22 | 23 | bool Triangle::setPoint(int index, const QPointF &pt) 24 | { 25 | if (index < 2) { 26 | Polygon::setPoint(index, pt); 27 | } 28 | return true; 29 | } 30 | 31 | bool Triangle::moveElememt(int elem, const QPointF &pt) 32 | { 33 | bool result = Polygon::moveElememt(elem, pt); 34 | /* 35 | if (result && elem < 3) { 36 | QPointF lpt = points_.back(); 37 | for (int i = 0; i < 3; ++i) { 38 | QPointF pt = points_[i]; 39 | QPointF npt = i == 2 ? points_.front() : points_[i + 1]; 40 | angles_[i] = angle(lpt, pt, npt); 41 | lpt = pt; 42 | } 43 | } 44 | */ 45 | return result; 46 | } 47 | -------------------------------------------------------------------------------- /rulers/linearruler.cpp: -------------------------------------------------------------------------------- 1 | #include "linearruler.h" 2 | #include "rulerline.h" 3 | 4 | LinearRuler::LinearRuler(Resource * res) 5 | : Ruler(res) 6 | { 7 | width_ = 500; 8 | height_ = 115; 9 | } 10 | 11 | QVector LinearRuler::getControlPositions() 12 | { 13 | return QVector{ 14 | {40, 85}, 15 | {width_ - 100, 85}, 16 | {width_ - 40, 85}, 17 | }; 18 | } 19 | 20 | void LinearRuler::updateShape() 21 | { 22 | shape_ = QPainterPath(); 23 | shape_.addRoundedRect({0, 0, width_, height_}, Unit, Unit); 24 | shape1_ = QPainterPath(); 25 | shape1_.addRect({0, Unit * 3, width_, Unit * 3}); 26 | shape2_ = QPainterPath(); 27 | shape2_.addRect({0, Unit * 6, width_, height_ - Unit * 6}); 28 | shape2_ = shape2_ & shape_; 29 | } 30 | 31 | void LinearRuler::onDraw(QPainter *painter) 32 | { 33 | QPointF corner{Unit / 2 * 5, Unit * 7 / 2}; 34 | drawTickMarks(painter, corner, {width_ - corner.x(), corner.y()}, 0); 35 | } 36 | 37 | Geometry *LinearRuler::createGeometry() 38 | { 39 | return new RulerLine(QLineF(0, 0, width_, 0).translated(0, Unit * 3)); 40 | } 41 | -------------------------------------------------------------------------------- /res/icon/geometry2d/arbitrarypolygon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic15 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /geometry2ds/rectangle.cpp: -------------------------------------------------------------------------------- 1 | #include "rectangle.h" 2 | 3 | Rectangle::Rectangle(Resource * res) 4 | : Polygon(res) 5 | { 6 | } 7 | 8 | Rectangle::Rectangle(Rectangle const & o) 9 | : Polygon(o) 10 | { 11 | } 12 | 13 | Rectangle::Rectangle(const QPointF &vec1, const QPointF &vec2) 14 | : Polygon({vec1, vec2}) 15 | { 16 | } 17 | 18 | int Rectangle::pointCount() 19 | { 20 | return points_.size() == 2 ? 4 : 1; 21 | } 22 | 23 | bool Rectangle::setPoint(int index, const QPointF &pt) 24 | { 25 | if ((index & 1) == 0) { 26 | Polygon::setPoint(index >> 1, pt); 27 | } 28 | return true; 29 | } 30 | 31 | QPointF Rectangle::point(int index) 32 | { 33 | if ((index & 1) == 0) { 34 | return points_[index >> 1]; 35 | } 36 | QPointF const & st = points_.first(); 37 | QPointF const & pt = points_[1]; 38 | if (index == 1) { 39 | return QPointF(pt.x(), st.y()); 40 | } else { 41 | return QPointF(st.x(), pt.y()); 42 | } 43 | } 44 | 45 | bool Rectangle::moveElememt(int elem, const QPointF &pt) 46 | { 47 | if (elem < 4) 48 | return moveKeepAngle(elem, pt); 49 | return Polygon::moveElememt(elem, pt); 50 | } 51 | -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from QtToolsFish import conans_tools 4 | from QtToolsFish.Conans import QtConanFile 5 | from conans import tools 6 | 7 | package_name = "Geometry" 8 | package_version = "develop" 9 | 10 | package_user_channel = "cmguo/test" 11 | 12 | 13 | class ConanConfig(QtConanFile): 14 | name = package_name 15 | version = package_version 16 | 17 | git_url = "git@git.100tal.com:epg_xhb_solution/talcloud_khaos_geometry.git" 18 | git_branch = "develop/master" 19 | 20 | description = "Geometry Library" 21 | 22 | requires = "QtComposition/master@cmguo/stable", "qtpromise/v0.5.0@cmguo/stable", "ShowBoard/develop@cmguo/test" 23 | 24 | exports_sources = "*" 25 | 26 | def source(self): 27 | conans_tools.move_dir_files_to_folder(self.get_library_name()) 28 | super(ConanConfig, self).source() 29 | 30 | 31 | if __name__ == '__main__': 32 | conans_tools.remove_cache(package_version=f"{package_name}/{package_version}", user_channel=package_user_channel) 33 | conans_tools.create(user_channel=package_user_channel) 34 | conans_tools.upload(package_version=f"{package_name}/{package_version}", user_channel=package_user_channel) 35 | -------------------------------------------------------------------------------- /geometry3ds/polyhedron.h: -------------------------------------------------------------------------------- 1 | #ifndef POLYHEDRON_H 2 | #define POLYHEDRON_H 3 | 4 | #include "geometry3d.h" 5 | 6 | //#define POLYHEDRON_ISOMETRIC_PROJECTION 7 | 8 | class Polyhedron : public Geometry3D 9 | { 10 | Q_OBJECT 11 | public: 12 | Q_INVOKABLE Polyhedron(Resource * res); 13 | 14 | Polyhedron(Polyhedron const & o); 15 | 16 | public: 17 | virtual bool commitPoint(const QPointF &pt) override; 18 | 19 | virtual bool canFinish() override; 20 | 21 | virtual QPainterPath visualPath() override; 22 | 23 | virtual QPainterPath contour() override; 24 | 25 | virtual QVector movePoints() override; 26 | 27 | virtual int hit(QPointF &pt) override; 28 | 29 | virtual bool moveElememt(int elem, const QPointF &pt) override; 30 | 31 | protected: 32 | virtual int pointCount(); 33 | 34 | virtual QVector3D point(int index); 35 | 36 | virtual bool setPoint(int index, QVector3D const & pt); 37 | 38 | protected: 39 | void clearLines(); 40 | 41 | void makeLine(int startIndex, int endIndex); 42 | 43 | void collect(QVector & points, QVector & hidden); 44 | 45 | protected: 46 | QVector lines_; 47 | }; 48 | 49 | #endif // POLYHEDRON_H 50 | -------------------------------------------------------------------------------- /geometry2ds/geometry2ds.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/arbitrarypolygon.h \ 3 | $$PWD/arc.h \ 4 | $$PWD/geometry2d.h \ 5 | $$PWD/circle.h \ 6 | $$PWD/diamond.h \ 7 | $$PWD/ellipse.h \ 8 | $$PWD/geometry2ds.h \ 9 | $$PWD/isopopetrapezoid.h \ 10 | $$PWD/isoscelestriangle.h \ 11 | $$PWD/line.h \ 12 | $$PWD/parallelogram.h \ 13 | $$PWD/polygon.h \ 14 | $$PWD/rectangle.h \ 15 | $$PWD/regularpolygon.h \ 16 | $$PWD/righttrapezoid.h \ 17 | $$PWD/righttriangle.h \ 18 | $$PWD/sector.h \ 19 | $$PWD/square.h \ 20 | $$PWD/trapezoid.h \ 21 | $$PWD/triangle.h 22 | 23 | SOURCES += \ 24 | $$PWD/arbitrarypolygon.cpp \ 25 | $$PWD/arc.cpp \ 26 | $$PWD/circle.cpp \ 27 | $$PWD/diamond.cpp \ 28 | $$PWD/ellipse.cpp \ 29 | $$PWD/geometry2d.cpp \ 30 | $$PWD/isopopetrapezoid.cpp \ 31 | $$PWD/isoscelestriangle.cpp \ 32 | $$PWD/line.cpp \ 33 | $$PWD/parallelogram.cpp \ 34 | $$PWD/polygon.cpp \ 35 | $$PWD/rectangle.cpp \ 36 | $$PWD/regularpolygon.cpp \ 37 | $$PWD/righttrapezoid.cpp \ 38 | $$PWD/righttriangle.cpp \ 39 | $$PWD/sector.cpp \ 40 | $$PWD/square.cpp \ 41 | $$PWD/trapezoid.cpp \ 42 | $$PWD/triangle.cpp 43 | -------------------------------------------------------------------------------- /geometry2ds/righttriangle.cpp: -------------------------------------------------------------------------------- 1 | #include "righttriangle.h" 2 | #include "base/geometryhelper.h" 3 | 4 | RightTriangle::RightTriangle(Resource * res) 5 | : Triangle(res) 6 | { 7 | } 8 | 9 | RightTriangle::RightTriangle(RightTriangle const & o) 10 | : Triangle(o) 11 | { 12 | } 13 | 14 | RightTriangle::RightTriangle(const QPointF &vec1, const QPointF &vec2) 15 | : Triangle(vec1, vec2) 16 | { 17 | } 18 | 19 | QPointF RightTriangle::point(int index) 20 | { 21 | if (index < 2) { 22 | return points_[index]; 23 | } 24 | return QPointF(points_.first().x(), points_[1].y()); 25 | } 26 | 27 | bool RightTriangle::moveElememt(int elem, const QPointF &pt) 28 | { 29 | if (elem == 0) { 30 | QPointF p(pt); 31 | GeometryHelper::attachToLines(points_[1], p); 32 | Triangle::moveElememt(3, p); 33 | return Triangle::moveElememt(0, p); 34 | } else if (elem == 1) { 35 | QPointF p(pt); 36 | GeometryHelper::attachToLines(points_[0], p); 37 | Triangle::moveElememt(5, p); 38 | return Triangle::moveElememt(1, p); 39 | } else if (elem == 2) { 40 | return moveKeepAngle(elem, pt); 41 | } else { 42 | return Triangle::moveElememt(elem, pt); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /geometry3ds/qrthoprism.cpp: -------------------------------------------------------------------------------- 1 | #include "qrthoprism.h" 2 | 3 | static EdgesToolButtons edgesButtons("正%1棱锥"); 4 | REGISTER_OPTION_BUTTONS(Qrthoprism, edges, edgesButtons) 5 | 6 | Qrthoprism::Qrthoprism(Resource * res) 7 | : RegularPrismoid(res, 0) 8 | { 9 | } 10 | 11 | Qrthoprism::Qrthoprism(Qrthoprism const & o) 12 | : RegularPrismoid(o) 13 | { 14 | } 15 | 16 | int Qrthoprism::pointCount() 17 | { 18 | return points_.size() == 2 ? 1 + nEdges_ : 0; 19 | } 20 | 21 | QVector3D Qrthoprism::point(int index) 22 | { 23 | if (index == 0) { 24 | QVector3D pt = origin_; 25 | pt.setZ(pt.z() + size_.z()); 26 | return pt; 27 | } 28 | return RegularPrismoid::point(index + nEdges_ - 1); 29 | } 30 | 31 | // @see RegularPrismoid::movePoints() 32 | bool Qrthoprism::moveElememt(int elem, const QPointF &pt) 33 | { 34 | if (elem == 0) 35 | elem = nEdges_ * 2; 36 | else if (elem <= nEdges_) 37 | elem = elem + nEdges_ - 1; 38 | else 39 | elem = nEdges_ * 2 + 1; 40 | return RegularPrismoid::moveElememt(elem, pt); 41 | } 42 | 43 | void Qrthoprism::makeLines() 44 | { 45 | for (int i = 1; i <= nEdges_; ++i) { 46 | int j = i % nEdges_ + 1; 47 | makeLine(0, i); 48 | makeLine(i, j); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rulers/ruleritem.h: -------------------------------------------------------------------------------- 1 | #ifndef RULERITEM_H 2 | #define RULERITEM_H 3 | 4 | #include 5 | 6 | class Ruler; 7 | class Control; 8 | 9 | class RulerItem : public QGraphicsItem 10 | { 11 | public: 12 | explicit RulerItem(Ruler * ruler, QGraphicsItem *parent = nullptr); 13 | 14 | virtual ~RulerItem() override; 15 | 16 | protected: 17 | virtual QRectF boundingRect()const override; 18 | 19 | virtual QPainterPath shape() const override; 20 | 21 | virtual bool sceneEvent(QEvent *event) override; 22 | 23 | virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override; 24 | 25 | virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; 26 | 27 | private: 28 | void updateShape(); 29 | 30 | void adjustControlPositions(); 31 | 32 | QGraphicsItem * iconItem(QString const & url); 33 | 34 | protected: 35 | Ruler * ruler_; 36 | // drawing 37 | Control * geometry_ = nullptr; 38 | 39 | private: 40 | QGraphicsItem * deleteItem_ = nullptr; 41 | QGraphicsItem * adjustItem_ = nullptr; 42 | QGraphicsItem * rotateItem_ = nullptr; 43 | bool isPressed = false; 44 | QPointF lastPoint_; 45 | }; 46 | #endif // RULERITEM_H 47 | -------------------------------------------------------------------------------- /res/icon/geometry3d/cylinder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic18 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /geometry3ds/cube.cpp: -------------------------------------------------------------------------------- 1 | #include "cube.h" 2 | 3 | Cube::Cube(Resource * res) 4 | : Cuboid(res) 5 | { 6 | } 7 | 8 | Cube::Cube(Cube const & o) 9 | : Cuboid(o) 10 | { 11 | } 12 | 13 | void Cube::movePoint(const QPointF &pt) 14 | { 15 | if (points_.size() == 1) { 16 | points_.append(pt); 17 | } 18 | moveElememt(1, pt); 19 | } 20 | 21 | bool Cube::moveElememt(int elem, const QPointF &pt) 22 | { 23 | setMoveElem(elem); 24 | points_[1] = pt; 25 | QPointF & pt1 = points_[0]; 26 | QPointF & pt2 = points_[1]; 27 | if (inner_) { 28 | qreal h = (pt2.y() - pt1.y()) / (1 - CO); 29 | qreal w = pt2.x() - pt1.x() - h * CO; 30 | if (qAbs(w) < qAbs(h)) { 31 | w = w > 0 ? qAbs(h) : -qAbs(h); 32 | } else { 33 | h = h > 0 ? qAbs(w) : -qAbs(w); 34 | } 35 | pt2.setX(pt1.x() + CO * h + w); 36 | pt2.setY(h * (1 - CO) + pt1.y()); 37 | } else { 38 | qreal h = (pt2.y() - pt1.y()) / (1 + CO); 39 | qreal x0 = pt1.x() - CO * h; 40 | qreal w = pt2.x() - x0; 41 | if (qAbs(w) < qAbs(h)) { 42 | w = w > 0 ? qAbs(h) : -qAbs(h); 43 | } else { 44 | h = h > 0 ? qAbs(w) : -qAbs(w); 45 | } 46 | pt2.setX(pt1.x() - CO * h + w); 47 | pt2.setY(h * (1 + CO) + pt1.y()); 48 | } 49 | dirty_ = true; 50 | return true; 51 | } 52 | -------------------------------------------------------------------------------- /geometry2ds/ellipse.cpp: -------------------------------------------------------------------------------- 1 | #include "ellipse.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | 6 | Ellipse::Ellipse(Resource * res) 7 | : Geometry2D(res) 8 | { 9 | } 10 | 11 | Ellipse::Ellipse(Ellipse const & o) 12 | : Geometry2D(o) 13 | { 14 | } 15 | 16 | Ellipse::Ellipse(const QPointF ¢er, const QSizeF &radius) 17 | : Geometry2D({center, center + QPointF(radius.width(), radius.height()) / sqrt(2.0)}) 18 | { 19 | } 20 | 21 | QPainterPath Ellipse::graphPath() 22 | { 23 | QPainterPath ph; 24 | if (points_.size() > 1) 25 | { 26 | QPointF off(points_.back() - points_.front()); 27 | off.setX(qAbs(off.x()) * sqrt(2.0)); 28 | off.setY(qAbs(off.y()) * sqrt(2.0)); 29 | ph.addEllipse(points_.front(), off.x(), off.y()); 30 | } 31 | return ph; 32 | } 33 | 34 | QVector Ellipse::movePoints() 35 | { 36 | return QVector(); 37 | } 38 | 39 | int Ellipse::hit(QPointF &pt) 40 | { 41 | QPointF center = (points_.back() + points_.front()) / 2.0; 42 | QPointF off(points_.back() - center); 43 | qreal prod = GeometryHelper::length2(off); 44 | QPointF off2(pt - center); 45 | qreal prod2 = GeometryHelper::length2(off2); 46 | off = off2 * sqrt(prod / prod2); 47 | off2 -= off; 48 | if (GeometryHelper::length2(off2) < 25.0) { 49 | pt = center + off; 50 | return 1; 51 | } 52 | return -1; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /geometry3ds/regularprismoid.h: -------------------------------------------------------------------------------- 1 | #ifndef REGULARPRISMOID_H 2 | #define REGULARPRISMOID_H 3 | 4 | #include "polyhedron.h" 5 | 6 | #include 7 | 8 | class RegularPrismoid : public Polyhedron 9 | { 10 | Q_OBJECT 11 | Q_PROPERTY(int edges READ edges WRITE setEdges) 12 | 13 | public: 14 | Q_INVOKABLE RegularPrismoid(Resource * res); 15 | 16 | Q_INVOKABLE RegularPrismoid(RegularPrismoid const & o); 17 | 18 | public slots: 19 | void setEdges(int n); 20 | 21 | int edges() { return nEdges_; } 22 | 23 | public: 24 | virtual int pointCount() override; 25 | 26 | virtual QVector3D point(int index) override; 27 | 28 | virtual bool moveElememt(int elem, const QPointF &pt) override; 29 | 30 | virtual void sync() override; 31 | 32 | virtual QVector movePoints() override; 33 | 34 | protected: 35 | RegularPrismoid(Resource * res, qreal ratio); 36 | 37 | virtual void makeLines(); 38 | 39 | protected: 40 | int nEdges_ = 0; 41 | qreal ratio_ = 0.5; 42 | QPointF vAngleStep_; 43 | QPointF vAngleInit_; 44 | }; 45 | 46 | class EdgesToolButtons : public OptionToolButtons 47 | { 48 | public: 49 | EdgesToolButtons(QString const & title); 50 | protected: 51 | virtual QString buttonTitle(const QVariant &value) override; 52 | private: 53 | static QString buttonTitle(QString const & title, int n); 54 | private: 55 | QString title_; 56 | }; 57 | 58 | #endif // REGULARPRISMOID_H 59 | -------------------------------------------------------------------------------- /res/Geometry.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | icon/geometry2d/arbitrarypolygon.svg 4 | icon/geometry2d/circle.svg 5 | icon/geometry2d/isopopetrapezoid.svg 6 | icon/geometry2d/isoscelestriangle.svg 7 | icon/geometry2d/line.svg 8 | icon/geometry2d/parallelogram.svg 9 | icon/geometry2d/righttrapezoid.svg 10 | icon/geometry2d/righttriangle.svg 11 | icon/geometry2d/square.svg 12 | icon/geometry3d/cone.svg 13 | icon/geometry3d/cube.svg 14 | icon/geometry3d/cuboid.svg 15 | icon/geometry3d/cylinder.svg 16 | icon/geometry3d/sphere.svg 17 | icon/geometry2d/line.so-.svg 18 | icon/geometry2d/line.so-so.svg 19 | icon/geometry2d/dotline.svg 20 | string/number.txt 21 | icon/geometry2d/regularpolygon.5.svg 22 | icon/geometry2d/sector.svg 23 | icon/geometry2d/diamond.svg 24 | icon/geometry2d/rectangle.svg 25 | qml/GeometryShape.qml 26 | icon/ruler/adjust.svg 27 | icon/ruler/rotate.svg 28 | icon/ruler/delete.svg 29 | 30 | 31 | -------------------------------------------------------------------------------- /geometry2ds/geometry2ds.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRY2DS_H 2 | #define GEOMETRY2DS_H 3 | 4 | #include "geometry2d.h" 5 | #include "circle.h" 6 | #include "ellipse.h" 7 | #include "sector.h" 8 | #include "isoscelestriangle.h" 9 | #include "righttriangle.h" 10 | #include "rectangle.h" 11 | #include "square.h" 12 | #include "polygon.h" 13 | #include "arbitrarypolygon.h" 14 | #include "regularpolygon.h" 15 | #include "righttrapezoid.h" 16 | #include "isopopetrapezoid.h" 17 | #include "parallelogram.h" 18 | #include "diamond.h" 19 | #include "line.h" 20 | #include "arc.h" 21 | 22 | #include 23 | 24 | REGISTER_RESOURCE_VIEW_FACTORY(Geometry2DFactory, Geometry2D, "geometry2d") 25 | REGISTER_GEOMETRY_2D(Ellipse, "ellipse") 26 | REGISTER_GEOMETRY_2D(Circle, "circle") 27 | REGISTER_GEOMETRY_2D(Arc, "arc") 28 | REGISTER_GEOMETRY_2D(Sector, "sector") 29 | REGISTER_GEOMETRY_2D(IsoscelesTriangle, "isoscelestriangle") 30 | REGISTER_GEOMETRY_2D(RightTriangle, "righttriangle") 31 | REGISTER_GEOMETRY_2D(IsopopeTrapezoid, "isopopetrapezoid") 32 | REGISTER_GEOMETRY_2D(RightTrapezoid, "righttrapezoid") 33 | REGISTER_GEOMETRY_2D(Parallelogram, "parallelogram") 34 | REGISTER_GEOMETRY_2D(Diamond, "diamond") 35 | REGISTER_GEOMETRY_2D(Rectangle, "rectangle") 36 | REGISTER_GEOMETRY_2D(Square, "square") 37 | REGISTER_GEOMETRY_2D(ArbitraryPolygon, "arbitrarypolygon") 38 | REGISTER_GEOMETRY_2D(Line, "line,dashline,dotline,dashdotline"); 39 | REGISTER_GEOMETRY_2D(RegularPolygon, "regularpolygon") 40 | 41 | #endif // GEOMETRY2DS_H 42 | -------------------------------------------------------------------------------- /base/geometryitem.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRY_ITEM_H 2 | #define GEOMETRY_ITEM_H 3 | 4 | #include "core/controlview.h" 5 | 6 | #ifdef SHOWBOARD_QUICK 7 | #include 8 | #else 9 | #include 10 | #endif 11 | #include 12 | 13 | class Geometry; 14 | 15 | #ifdef SHOWBOARD_QUICK 16 | class GeometryItem : public QQuickItem 17 | #else 18 | class GeometryItem : public QGraphicsPathItem 19 | #endif 20 | { 21 | public: 22 | GeometryItem(Geometry * geometry, ControlView * parent = nullptr); 23 | 24 | void setEditPoints(QVector const & points); 25 | 26 | void showEditor(bool show); 27 | 28 | ControlView * editItem() 29 | { 30 | return editItem_; 31 | } 32 | 33 | void setColor(const QColor & color); 34 | 35 | void setPenWidth(qreal width); 36 | 37 | void setContourPath(const QPainterPath & path); 38 | 39 | private: 40 | virtual bool contains(const QPointF &point) const override; 41 | 42 | #ifdef SHOWBOARD_QUICK 43 | 44 | #else 45 | 46 | virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, 47 | QWidget *widget = nullptr) override; 48 | 49 | virtual bool sceneEvent(QEvent * event) override; 50 | 51 | virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override; 52 | 53 | #endif 54 | 55 | private: 56 | ControlView * editItem_; 57 | Geometry * geometry_; 58 | QMetaMethod methodContains_; 59 | }; 60 | 61 | #endif // GEOMETRY_ITEM_H 62 | -------------------------------------------------------------------------------- /rulers/rulertool.cpp: -------------------------------------------------------------------------------- 1 | #include "rulertool.h" 2 | #include "ruleritem.h" 3 | #include "ruler.h" 4 | #include "base/geometry.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | RulerTool::RulerTool(ResourceView * res) 15 | : Control(res, {KeepAspectRatio}, {CanSelect, CanRotate, CanScale}) 16 | { 17 | } 18 | 19 | ControlView * RulerTool::create(ControlView * parent) 20 | { 21 | (void) parent; 22 | return new RulerItem(qobject_cast(res_)); 23 | } 24 | 25 | void RulerTool::attaching() 26 | { 27 | if (!flags_.testFlag(RestoreSession)) { 28 | qobject_cast(res_)->updateShape(); 29 | } 30 | } 31 | 32 | void RulerTool::attached() 33 | { 34 | loadFinished(true); 35 | } 36 | 37 | Control::SelectMode RulerTool::selectTest(ControlView *child, ControlView *, const QPointF &point, bool) 38 | { 39 | return (child != item_ || qobject_cast(res_)->hitTestTickMark(point)) ? SelectMode::NotSelect : SelectMode::Select; 40 | } 41 | 42 | QString RulerTool::toolsString(QByteArray const &) const 43 | { 44 | return nullptr; 45 | } 46 | 47 | Control * RulerTool::addGeometry(Geometry *geometry) 48 | { 49 | return whiteCanvas()->addResource(geometry); 50 | } 51 | 52 | void RulerTool::finishGeometry(Control *geometry) 53 | { 54 | whiteCanvas()->selector()->unselect(geometry); 55 | } 56 | -------------------------------------------------------------------------------- /geometry2ds/regularpolygon.h: -------------------------------------------------------------------------------- 1 | #ifndef REGULARPOLYGON_H 2 | #define REGULARPOLYGON_H 3 | 4 | #include "polygon.h" 5 | 6 | class RegularPolygon : public Polygon 7 | { 8 | Q_OBJECT 9 | 10 | Q_CLASSINFO("toolsString", "edgeSpan|边数|Popup,OptionsGroup,NeedUpdate|;") 11 | 12 | Q_PROPERTY(int edges READ edges WRITE setEdges) 13 | Q_PROPERTY(int span READ span WRITE setSpan) 14 | Q_PROPERTY(int edgeSpan READ edgeSpan WRITE setEdges) 15 | 16 | public: 17 | Q_INVOKABLE RegularPolygon(Resource * res); 18 | 19 | Q_INVOKABLE RegularPolygon(RegularPolygon const & o); 20 | 21 | Q_INVOKABLE RegularPolygon(QPointF & center, QPointF const & point, int edges, int span = 1); 22 | 23 | public: 24 | virtual int pointCount() override; 25 | 26 | virtual QPointF iterPoint(int index, QPointF & hint) override; 27 | 28 | virtual QPointF nextPoint(int index, QPointF & hint) override; 29 | 30 | virtual QPointF prevPoint(int index, QPointF & hint) override; 31 | 32 | virtual bool setPoint(int index, const QPointF &pt) override; 33 | 34 | virtual bool moveElememt(int elem, const QPointF &pt) override; 35 | 36 | public slots: 37 | void setEdges(int n); 38 | 39 | int edges() { return nEdges_; } 40 | 41 | void setSpan(int n); 42 | 43 | int span() { return nSpan_; } 44 | 45 | int edgeSpan(); 46 | 47 | private: 48 | int nEdges_; 49 | int nSpan_; 50 | QPointF vAngleStep_; 51 | QPointF vAngleAttach_; 52 | }; 53 | 54 | #endif // REGULARPOLYGON_H 55 | -------------------------------------------------------------------------------- /res/icon/ruler/adjust.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/32px/copy 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /geometry2ds/geometry2d.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRY2D_H 2 | #define GEOMETRY2D_H 3 | 4 | #include "base/geometry.h" 5 | 6 | #include 7 | 8 | #include 9 | 10 | class Geometry2D : public Geometry 11 | { 12 | Q_OBJECT 13 | protected: 14 | Geometry2D(Resource * res, Flags flags = {}, Flags clearFlags = {}); 15 | 16 | Geometry2D(Geometry2D const & o); 17 | 18 | Geometry2D(QVector const & points); 19 | 20 | public: 21 | virtual bool empty() const override; 22 | 23 | protected: 24 | static void moveLine(QPointF const & llpt, QPointF & lpt, QPointF const & pt, 25 | QPointF & npt, QPointF const & nnpt); 26 | 27 | static void addAngleLabeling(QPainterPath & graphPath, QPainterPath &textPath, QPointF const & lpt, QPointF const & pt, 28 | QPointF const & npt); 29 | 30 | static void addAngleLabeling(QPainterPath & graphPath, QPainterPath &textPath, QPointF const & lpt, QPointF const & pt, 31 | QPointF const & npt, qreal angle); 32 | }; 33 | 34 | class Geometry2DFactory : ResourceFactory 35 | { 36 | Q_OBJECT 37 | public: 38 | Q_INVOKABLE Geometry2DFactory(); 39 | 40 | public: 41 | virtual ResourceView * create(Resource * res) override; 42 | 43 | virtual QUrl newUrl(const QByteArray &type) const override; 44 | }; 45 | 46 | #define REGISTER_GEOMETRY_2D(ctype, type) \ 47 | REGISTER_RESOURCE_VIEW_WITH_FACTORY(Geometry2D, ctype, type) 48 | 49 | #endif // GEOMETRY2D_H 50 | -------------------------------------------------------------------------------- /res/icon/geometry2d/dotline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic1 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /rulers/rulerline.cpp: -------------------------------------------------------------------------------- 1 | #include "rulerline.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | 6 | RulerLine::RulerLine(const QLineF &line) 7 | : Line(new Resource("geometry2d", QUrl("geometry2d:line"))) 8 | , line_(line) 9 | { 10 | } 11 | 12 | void RulerLine::addPoint(const QPointF &pt) 13 | { 14 | QPointF dir = line_.p2() - line_.p1(); 15 | GeometryHelper::adjustToLength(dir, width() / 2); 16 | dir = QPointF{dir.y(), -dir.x()}; 17 | line_.translate(dir); 18 | QPointF pt2 = attachToLine(pt); 19 | Line::addPoint(pt2); 20 | } 21 | 22 | void RulerLine::movePoint(const QPointF &pt) 23 | { 24 | QPointF pt2 = attachToLine(pt); 25 | if (points_.size() > 1) { 26 | qreal d = GeometryHelper::dotProduct(pt2 - points_.front(), points_.back() - pt2); 27 | if (d < 0) { 28 | qreal d2 = GeometryHelper::dotProduct(points_.front() - pt2, points_.back() - pt2); 29 | if (d2 > 0) { 30 | points_.front() = pt2; 31 | } else { 32 | points_.back() = pt2; 33 | } 34 | } 35 | } else { 36 | Line::movePoint(pt2); 37 | } 38 | } 39 | 40 | bool RulerLine::commitPoint(const QPointF &pt) 41 | { 42 | movePoint(pt); 43 | return true; 44 | } 45 | 46 | QPointF RulerLine::attachToLine(const QPointF &pt) 47 | { 48 | QPointF d = line_.p2() - line_.p1(); 49 | qreal dot1 = GeometryHelper::dotProduct(d, pt - line_.p1()); 50 | qreal dot2 = GeometryHelper::length2(d); 51 | qreal r = dot1 / dot2; 52 | return line_.p1() + d * r; 53 | } 54 | -------------------------------------------------------------------------------- /res/icon/geometry3d/cone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/48px/graphic19 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /geometry2ds/parallelogram.cpp: -------------------------------------------------------------------------------- 1 | #include "parallelogram.h" 2 | #include "base/geometryhelper.h" 3 | 4 | Parallelogram::Parallelogram(Resource * res) 5 | : Trapezoid(res) 6 | { 7 | } 8 | 9 | Parallelogram::Parallelogram(Parallelogram const & o) 10 | : Trapezoid(o) 11 | { 12 | } 13 | 14 | Parallelogram::Parallelogram(const QPointF &vec1, const QPointF &vec2, const QPointF &vec3) 15 | : Trapezoid(vec1, vec2, vec3) 16 | { 17 | } 18 | 19 | QPointF Parallelogram::point4(QPointF const & pt1, QPointF const & pt2, QPointF const & pt3) 20 | { 21 | return pt1 + pt3 - pt2; 22 | } 23 | 24 | bool Parallelogram::setPoint(int index, const QPointF &pt) 25 | { 26 | if (index == 0) { 27 | QPointF pt2 = point(2); 28 | QPointF pt3 = point(3); 29 | Trapezoid::setPoint(0, pt); 30 | Trapezoid::setPoint(1, QPointF(pt.x() + pt2.x() - pt3.x(), pt.y())); 31 | return true; 32 | } 33 | if (index < 3) { 34 | return Trapezoid::setPoint(index, pt); 35 | } 36 | QPointF st = point(0); 37 | QPointF pt1 = point(1); 38 | return Trapezoid::setPoint(2, QPointF(pt1.x() + pt.x() - st.x(), pt.y())); 39 | } 40 | 41 | bool Parallelogram::moveElememt(int elem, const QPointF &pt) 42 | { 43 | if (elem == 0) { 44 | QPointF p = pt; 45 | GeometryHelper::attachToLines(point(3), p); 46 | return Polygon::moveElememt(elem, p); 47 | } else if (elem == 3) { 48 | QPointF p = pt; 49 | GeometryHelper::attachToLines(point(0), p); 50 | return Polygon::moveElememt(elem, p); 51 | } else { 52 | return Trapezoid::moveElememt(elem, pt); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /geometry2ds/diamond.cpp: -------------------------------------------------------------------------------- 1 | #include "diamond.h" 2 | 3 | Diamond::Diamond(Resource * res) 4 | : Polygon(res) 5 | { 6 | } 7 | 8 | Diamond::Diamond(Diamond const & o) 9 | : Polygon(o) 10 | { 11 | } 12 | 13 | Diamond::Diamond(const QPointF &vec1, const QPointF &vec2) 14 | : Polygon({{vec1.x() * 2 - vec2.x(), vec1.y()}, {vec2.x(), vec2.y() * 2 - vec1.y()}}) 15 | { 16 | } 17 | 18 | int Diamond::pointCount() 19 | { 20 | return points_.size() >= 2 ? 4 : 1; 21 | } 22 | 23 | QPointF Diamond::point(int index) 24 | { 25 | QPointF const & pt1 = points_[0]; 26 | QPointF const & pt2 = points_[1]; 27 | QPointF c = (pt1 + pt2) / 2; 28 | switch (index) { 29 | case 0: 30 | return {c.x(), pt1.y()}; 31 | case 1: 32 | return {pt2.x(), c.y()}; 33 | case 2: 34 | return {c.x(), pt2.y()}; 35 | case 3: 36 | return {pt1.x(), c.y()}; 37 | } 38 | return Polygon::point(index); 39 | } 40 | 41 | bool Diamond::setPoint(int index, const QPointF &pt) 42 | { 43 | QPointF & pt1 = points_[0]; 44 | QPointF & pt2 = points_[1]; 45 | QPointF c = pt1 + pt2; 46 | switch (index) { 47 | case 0: 48 | pt1.setY(pt.y()); 49 | pt2.setY(c.y() - pt.y()); 50 | break; 51 | case 1: 52 | pt1.setX(c.x() - pt.x()); 53 | pt2.setX(pt.x()); 54 | break; 55 | case 2: 56 | pt1.setY(c.y() - pt.y()); 57 | pt2.setY(pt.y()); 58 | break; 59 | case 3: 60 | pt1.setX(pt.x()); 61 | pt2.setX(c.x() - pt.x()); 62 | break; 63 | default: 64 | return false; 65 | } 66 | dirty_ = true; 67 | return true; 68 | } 69 | -------------------------------------------------------------------------------- /geometry3ds/sphere.cpp: -------------------------------------------------------------------------------- 1 | #include "sphere.h" 2 | #include "base/geometryhelper.h" 3 | 4 | Sphere::Sphere(Resource * res) 5 | : Ellipsoid(res) 6 | { 7 | } 8 | 9 | Sphere::Sphere(const Sphere &o) 10 | : Ellipsoid(o) 11 | { 12 | } 13 | 14 | void Sphere::sync() 15 | { 16 | if (dirty_ && points_.size() > 1) { 17 | qreal r = GeometryHelper::length(points_.back() - points_.first()); 18 | radius_.setX(float(r)); 19 | radius_.setY(float(r)); 20 | radius_.setZ(float(r)); 21 | dirty_ = false; 22 | } 23 | } 24 | 25 | QVector Sphere::movePoints() 26 | { 27 | QVector points; 28 | QPointF c(points_.front()); 29 | QPointF off(points_.back() - c); 30 | points.append(points_.back()); 31 | off = QPointF(-off.y(), off.x()); 32 | points.append(c + off); 33 | off = QPointF(-off.y(), off.x()); 34 | points.append(c + off); 35 | off = QPointF(-off.y(), off.x()); 36 | points.append(c + off); 37 | return points; 38 | } 39 | 40 | int Sphere::hit(QPointF &pt) 41 | { 42 | QPointF off(points_.back() - points_.front()); 43 | qreal prod = QPointF::dotProduct(off, off); 44 | QPointF off2(pt - points_.front()); 45 | qreal prod2 = QPointF::dotProduct(off2, off2); 46 | off = off2 * sqrt(prod / prod2); 47 | off2 -= off; 48 | if (GeometryHelper::length2(off2) < GeometryHelper::HIT_DIFF_DIFF) { 49 | pt = points_.front() + off; 50 | return 1; 51 | } 52 | return -1; 53 | } 54 | 55 | bool Sphere::moveElememt(int elem, QPointF const & pt) 56 | { 57 | if (elem < 4) 58 | return Geometry3D::moveElememt(1, pt); 59 | return false; 60 | } 61 | -------------------------------------------------------------------------------- /geometry2ds/isopopetrapezoid.cpp: -------------------------------------------------------------------------------- 1 | #include "isopopetrapezoid.h" 2 | #include "base/geometryhelper.h" 3 | 4 | IsopopeTrapezoid::IsopopeTrapezoid(Resource * res) 5 | : Trapezoid(res) 6 | { 7 | } 8 | 9 | IsopopeTrapezoid::IsopopeTrapezoid(IsopopeTrapezoid const & o) 10 | : Trapezoid(o) 11 | { 12 | } 13 | 14 | IsopopeTrapezoid::IsopopeTrapezoid(const QPointF &vec1, const QPointF &vec2, const QPointF &vec3) 15 | : Trapezoid(vec1, vec2, vec3) 16 | { 17 | } 18 | 19 | QPointF IsopopeTrapezoid::point4(QPointF const & pt1, QPointF const & pt2, QPointF const & pt3) 20 | { 21 | return QPointF(pt1.x() + pt2.x() - pt3.x(), pt3.y()); 22 | } 23 | 24 | bool IsopopeTrapezoid::setPoint(int index, const QPointF &pt) 25 | { 26 | if (index == 0) { 27 | QPointF pt2 = point(2); 28 | QPointF pt3 = point(3); 29 | Trapezoid::setPoint(0, pt); 30 | Trapezoid::setPoint(1, QPointF(pt3.x() + pt2.x() - pt.x(), pt.y())); 31 | return true; 32 | } 33 | if (index < 3) { 34 | return Trapezoid::setPoint(index, pt); 35 | } 36 | QPointF st = point(0); 37 | QPointF pt1 = point(1); 38 | return Trapezoid::setPoint(2, QPointF(st.x() + pt1.x() - pt.x(), pt.y())); 39 | } 40 | 41 | bool IsopopeTrapezoid::moveElememt(int elem, const QPointF &pt) 42 | { 43 | if (elem == 0) { 44 | QPointF p = pt; 45 | GeometryHelper::attachToLines(point(3), p); 46 | return Polygon::moveElememt(elem, p); 47 | } else if (elem == 3) { 48 | QPointF p = pt; 49 | GeometryHelper::attachToLines(point(0), p); 50 | return Polygon::moveElememt(elem, p); 51 | } else { 52 | return Trapezoid::moveElememt(elem, pt); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /geometry2ds/square.cpp: -------------------------------------------------------------------------------- 1 | #include "square.h" 2 | 3 | Square::Square(Resource * res) 4 | : Rectangle(res) 5 | { 6 | } 7 | 8 | Square::Square(Square const & o) 9 | : Rectangle(o) 10 | { 11 | } 12 | 13 | Square::Square(const QPointF &vec1, const QPointF &vec2) 14 | : Rectangle(vec1, vec2) 15 | { 16 | } 17 | 18 | void Square::movePoint(const QPointF &pt) 19 | { 20 | QPointF st = points_.first(); 21 | QSizeF sz = QSizeF(qAbs(pt.x() - st.x()), qAbs(pt.y() - st.y())); 22 | QPointF p(pt); 23 | if (sz.width() > sz.height()) { 24 | p.setY(pt.y() >= st.y() ? st.y() + sz.width() : st.y() - sz.width()); 25 | } else { 26 | p.setX(pt.x() >= st.x() ? st.x() + sz.height() : st.x() - sz.height()); 27 | } 28 | Rectangle::movePoint(p); 29 | } 30 | 31 | bool Square::moveElememt(int elem, QPointF const &pt) 32 | { 33 | QPointF p(pt); 34 | if (elem < 4) { 35 | QPointF st = point((elem + 2) % 4); 36 | QSizeF sz = QSizeF(qAbs(pt.x() - st.x()), qAbs(pt.y() - st.y())); 37 | if (sz.width() > sz.height()) { 38 | p.setY(pt.y() >= st.y() ? st.y() + sz.width() : st.y() - sz.width()); 39 | } else { 40 | p.setX(pt.x() >= st.x() ? st.x() + sz.height() : st.x() - sz.height()); 41 | } 42 | } else { 43 | elem -= 4; 44 | QPointF st = point((elem + 2) % 4); 45 | QSizeF sz = QSizeF(qAbs(pt.x() - st.x()), qAbs(pt.y() - st.y())); 46 | if (elem % 2) { 47 | p.setX(pt.x() >= st.x() ? st.x() + sz.height() : st.x() - sz.height()); 48 | } else { 49 | p.setY(pt.y() >= st.y() ? st.y() + sz.width() : st.y() - sz.width()); 50 | } 51 | } 52 | return Rectangle::moveElememt(elem, p); 53 | } 54 | -------------------------------------------------------------------------------- /geometry2ds/isoscelestriangle.cpp: -------------------------------------------------------------------------------- 1 | #include "isoscelestriangle.h" 2 | #include "base/geometryhelper.h" 3 | 4 | IsoscelesTriangle::IsoscelesTriangle(Resource * res) 5 | : Triangle(res) 6 | { 7 | } 8 | 9 | IsoscelesTriangle::IsoscelesTriangle(IsoscelesTriangle const & o) 10 | : Triangle(o) 11 | { 12 | } 13 | 14 | IsoscelesTriangle::IsoscelesTriangle(const QPointF &vec1, const QPointF &vec2) 15 | : Triangle(vec1, vec2) 16 | { 17 | } 18 | 19 | QPointF IsoscelesTriangle::point(int index) 20 | { 21 | if (index < 2) { 22 | return points_[index]; 23 | } 24 | return QPointF(points_.first().x() * 2 - points_[1].x(), points_[1].y()); 25 | } 26 | 27 | static const qreal SQRT3 = 1.7320508075688772935274463415059; 28 | 29 | bool IsoscelesTriangle::moveElememt(int elem, const QPointF &pt) 30 | { 31 | if (elem == 0) { 32 | QPointF p(pt); 33 | p.setX(0); 34 | QPointF pt1 = points_[1]; 35 | QPointF c(points_[0].x(), points_[1].y()); 36 | qreal d = points_[1].x() - points_[0].x(); 37 | QVector pts; 38 | c.setY(pt1.y() + d); pts.append(c); 39 | c.setY(pt1.y() - d); pts.append(c); 40 | c.setY(pt1.y() + d * SQRT3); pts.append(c); 41 | c.setY(pt1.y() - d * SQRT3); pts.append(c); 42 | c.setY(pt1.y() + d / SQRT3); pts.append(c); 43 | c.setY(pt1.y() - d / SQRT3); pts.append(c); 44 | GeometryHelper::attachToPoints(pts, p); 45 | return Triangle::moveElememt(0, p); 46 | } else if (elem < 3) { 47 | QPointF p(pt); 48 | GeometryHelper::attachToLines(points_[0], p); 49 | if (elem == 2) { 50 | elem = 1; 51 | p.setX(points_[0].x() * 2 - p.x()); 52 | } 53 | return Triangle::moveElememt(elem, p); 54 | } else { 55 | return Triangle::moveElememt(elem, pt); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /geometry2ds/polygon.h: -------------------------------------------------------------------------------- 1 | #ifndef POLYGON_H 2 | #define POLYGON_H 3 | 4 | #include "geometry2d.h" 5 | 6 | class Polygon : public Geometry2D 7 | { 8 | Q_OBJECT 9 | 10 | #ifdef QT_DEBUG 11 | Q_CLASSINFO("toolsString", "radius|圆角|Popup,OptionsGroup,NeedUpdate|;") 12 | #endif 13 | 14 | Q_PROPERTY(qreal radius MEMBER radius_) 15 | public: 16 | Q_INVOKABLE Polygon(Resource * res, Flags flags = {}); 17 | 18 | Polygon(Polygon const & o); 19 | 20 | Polygon(QPolygonF const & polygon); 21 | 22 | Polygon(QVector const & points); 23 | 24 | public: 25 | virtual QPainterPath graphPath() override; 26 | 27 | virtual QPainterPath textPath() override; 28 | 29 | virtual QVector movePoints() override; 30 | 31 | virtual int hit(QPointF &pt) override; 32 | 33 | virtual bool moveElememt(int elem, const QPointF &pt) override; 34 | 35 | virtual void sync() override; 36 | 37 | protected: 38 | virtual bool canClose(); 39 | 40 | virtual int pointCount(); 41 | 42 | virtual QPointF point(int index); 43 | 44 | virtual bool setPoint(int index, QPointF const & pt); 45 | 46 | virtual QPointF lastPoint(QPointF & hint); 47 | 48 | virtual QPointF firstPoint(QPointF & hint); 49 | 50 | virtual QPointF iterPoint(int index, QPointF & hint); 51 | 52 | virtual QPointF prevPoint(int index, QPointF & hint); 53 | 54 | virtual QPointF nextPoint(int index, QPointF & hint); 55 | 56 | protected: 57 | bool moveKeepAngle(int elem, const QPointF &pt); 58 | 59 | qreal angle(int index); 60 | 61 | void addAngleLabeling(QPainterPath & graphPath, QPainterPath &textPath, int index); 62 | 63 | protected: 64 | using Geometry2D::addAngleLabeling; 65 | 66 | private: 67 | QPainterPath graphPath_; 68 | QPainterPath textPath_; 69 | qreal radius_; 70 | }; 71 | 72 | #endif // POLYGON_H 73 | -------------------------------------------------------------------------------- /geometry2ds/circle.cpp: -------------------------------------------------------------------------------- 1 | #include "circle.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | 6 | Circle::Circle(Resource * res) 7 | : Ellipse(res) 8 | { 9 | } 10 | 11 | Circle::Circle(Circle const & o) 12 | : Ellipse(o) 13 | { 14 | } 15 | 16 | Circle::Circle(const QPointF ¢er, qreal radius) 17 | : Ellipse(center, {radius, radius}) 18 | { 19 | } 20 | 21 | QPainterPath Circle::graphPath() 22 | { 23 | QPainterPath ph; 24 | if (points_.size() > 1) 25 | { 26 | QRectF center(-2, -2, 4, 4); 27 | center.moveCenter(points_.front()); 28 | ph.addEllipse(center); 29 | QPointF off(points_.back() - points_.front()); 30 | qreal r = sqrt(QPointF::dotProduct(off, off)); 31 | ph.addEllipse(points_.front(), r, r); 32 | } 33 | return ph; 34 | } 35 | 36 | QVector Circle::movePoints() 37 | { 38 | QVector points; 39 | QPointF c(points_.front()); 40 | QPointF off(points_.back() - c); 41 | points.append(points_[1]); 42 | off = QPointF(-off.y(), off.x()); 43 | points.append(c + off); 44 | off = QPointF(-off.y(), off.x()); 45 | points.append(c + off); 46 | off = QPointF(-off.y(), off.x()); 47 | points.append(c + off); 48 | return points; 49 | } 50 | 51 | int Circle::hit(QPointF &pt) 52 | { 53 | QPointF off(points_.back() - points_.front()); 54 | qreal prod = GeometryHelper::length2(off); 55 | QPointF off2(pt - points_.front()); 56 | qreal prod2 = GeometryHelper::length2(off2); 57 | off = off2 * sqrt(prod / prod2); 58 | off2 -= off; 59 | if (GeometryHelper::length2(off2) < GeometryHelper::HIT_DIFF_DIFF) { 60 | pt = points_.front() + off; 61 | return 1; 62 | } 63 | return -1; 64 | } 65 | 66 | bool Circle::moveElememt(int elem, QPointF const & pt) 67 | { 68 | if (elem < 4) 69 | return Geometry2D::moveElememt(points_.size() - 1, pt); 70 | return false; 71 | } 72 | -------------------------------------------------------------------------------- /geometry2ds/line.h: -------------------------------------------------------------------------------- 1 | #ifndef LINE_H 2 | #define LINE_H 3 | 4 | #include "geometry2d.h" 5 | 6 | class Line : public Geometry2D 7 | { 8 | Q_OBJECT 9 | 10 | Q_PROPERTY(LineType lineType MEMBER lineType_) 11 | Q_PROPERTY(EndianType beginType MEMBER beginType_) 12 | Q_PROPERTY(EndianType endType MEMBER endType_) 13 | 14 | public: 15 | enum LineType 16 | { 17 | Solid, 18 | Dash, 19 | Dot, 20 | DashDot, 21 | DashDotDot, 22 | }; 23 | 24 | Q_ENUM(LineType) 25 | 26 | static constexpr int SolidShape = 1 << 8; 27 | static constexpr int AlignLeft = 1 << 9; 28 | static constexpr int AlignRight = 1 << 10; 29 | static constexpr int AlignBoth = AlignLeft | AlignRight; 30 | 31 | enum EndianType 32 | { 33 | None = 0, 34 | Ball = 1, 35 | SolidBall = 2 | SolidShape, 36 | Arrow = 3 | AlignRight, 37 | SolidArrow = 4 | SolidShape | AlignRight, 38 | HollowArrow = 5 | AlignRight, 39 | SharpArrow = 6 | SolidShape | AlignRight, 40 | Diamond = 7 | AlignBoth, 41 | SolidDiamod = 8 | SolidShape | AlignBoth, 42 | Box = 9, 43 | SolidBox = 10 | SolidShape, 44 | }; 45 | 46 | Q_ENUM(EndianType) 47 | 48 | class LineTypeToolButtons; 49 | class EndianTypeToolButtons; 50 | 51 | public: 52 | Q_INVOKABLE Line(Resource * res); 53 | 54 | Q_INVOKABLE Line(Line const & o); 55 | 56 | public: 57 | virtual bool moveElememt(int elem, QPointF const & pt) override; 58 | 59 | virtual QPainterPath visualPath() override; 60 | 61 | virtual QPainterPath contour() override; 62 | 63 | private: 64 | static void fillEndian(QPainterPath & ph, EndianType type, qreal width, 65 | QPointF & pt, QPointF const & dir, bool & solid); 66 | 67 | private: 68 | LineType lineType_; 69 | EndianType beginType_; 70 | EndianType endType_; 71 | }; 72 | 73 | #endif // LINE_H 74 | -------------------------------------------------------------------------------- /rulers/ruler.h: -------------------------------------------------------------------------------- 1 | #ifndef RULER_H 2 | #define RULER_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | class Geometry; 10 | 11 | class Ruler : public ResourceView 12 | { 13 | Q_OBJECT 14 | Q_CLASSINFO("version", "1.0") 15 | 16 | public: 17 | Ruler(Resource * res, Flags flags = {}, Flags clearFlags = {}); 18 | 19 | public: 20 | // Unit length vector 21 | virtual QPointF adjustDirection(QRectF & adjust); 22 | 23 | virtual void updateShape(); 24 | 25 | virtual QVector getControlPositions() = 0; 26 | 27 | virtual void onDraw(QPainter * painter); 28 | 29 | virtual bool hitTestTickMark(QPointF const & pos); 30 | 31 | virtual Geometry * createGeometry() = 0; 32 | 33 | protected: 34 | enum TickFlags { 35 | Anticlockwise = 1, 36 | CrossLittenEndian = 2, 37 | NeedRotate = 4, 38 | ClipByShape = 8 39 | }; 40 | 41 | QPointF adjust(QPointF const & offset); 42 | 43 | // 刻度线, 44 | QVector tickMarkPoints(QPointF const & from, QPointF const & to, int flags); 45 | 46 | void drawTickMarks(QPainter * painter, QPointF const & from, QPointF const & to, int flags); 47 | 48 | protected: 49 | static constexpr qreal Unit = 5; // 每毫米px 50 | 51 | protected: 52 | friend class RulerItem; 53 | 54 | qreal width_; 55 | qreal height_; 56 | qreal minWidth_ = 300; 57 | QPointF rotateCenter_; 58 | QPainterPath shape_; // whole shape, input area 59 | QPainterPath shape1_; // tick area (dark background) 60 | QPainterPath shape2_; // white background area 61 | }; 62 | 63 | class RulerFactory : ResourceFactory 64 | { 65 | Q_OBJECT 66 | public: 67 | Q_INVOKABLE RulerFactory(); 68 | 69 | public: 70 | virtual ResourceView * create(Resource * res) override; 71 | 72 | virtual QUrl newUrl(const QByteArray &type) const override; 73 | }; 74 | 75 | #define REGISTER_RULER(ctype, type) \ 76 | REGISTER_RESOURCE_VIEW_WITH_FACTORY(Ruler, ctype, type) 77 | 78 | #endif // RULER_H 79 | -------------------------------------------------------------------------------- /res/icon/ruler/rotate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01 通用/01 图标/32px/rotate 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Geometry.pro: -------------------------------------------------------------------------------- 1 | QT += gui widgets quick qml quickwidgets svg 2 | 3 | TEMPLATE = lib 4 | DEFINES += GEOMETRY_LIBRARY 5 | CONFIG += plugin 6 | 7 | CONFIG += c14 8 | 9 | include($$(applyCommonConfig)) 10 | include($$(applyConanPlugin)) 11 | 12 | include(../config.pri) 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any Qt feature that has been marked deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if it uses deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | SOURCES += \ 26 | geometryplugin.cpp \ 27 | geometrytool.cpp 28 | 29 | HEADERS += \ 30 | Geometry_global.h \ 31 | exports.h \ 32 | geometryplugin.h \ 33 | geometrytool.h 34 | 35 | RESOURCES += \ 36 | res/Geometry.qrc 37 | 38 | DISTFILES += \ 39 | Geometry.json 40 | 41 | include(base/base.pri) 42 | include(geometry2ds/geometry2ds.pri) 43 | include(geometry3ds/geometry3ds.pri) 44 | include(rulers/rulers.pri) 45 | include(algorithm/algorithm.pri) 46 | 47 | includes.files = $$PWD/*.h 48 | win32 { 49 | includes.path = $$[QT_INSTALL_HEADERS]/Geometry 50 | target.path = $$[QT_INSTALL_LIBS] 51 | } 52 | INSTALLS += includes 53 | 54 | # Default rules for deployment. 55 | unix { 56 | target.path = /usr/lib 57 | } 58 | !isEmpty(target.path): INSTALLS += target 59 | 60 | exists($$PWD/../OpenCV/opencv/build) { 61 | DEFINES += HAS_OPENCV 62 | win32: { 63 | LIBS += -L$$PWD/../OpenCV/opencv/build/lib 64 | CONFIG(debug, debug|release): -lopencv_world454d 65 | CONFIG(release, debug|release): -lopencv_world454 66 | } 67 | INCLUDEPATH += $$PWD/../OpenCV/opencv/build/include 68 | } 69 | -------------------------------------------------------------------------------- /base/geometrycontrol.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHCONTROL_H 2 | #define GRAPHCONTROL_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class Geometry; 11 | 12 | class GeometryControl : public Control 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | static constexpr Flag ImpliedEditable = CustomFlag; 18 | 19 | Q_INVOKABLE GeometryControl(ResourceView * res, Flags flags = None, Flags clearFlags = None); 20 | 21 | public slots: 22 | void edit(); 23 | 24 | void test(); 25 | 26 | protected: 27 | virtual ControlView * create(ControlView * parent) override; 28 | 29 | virtual void attaching() override; 30 | 31 | virtual void attached() override; 32 | 33 | virtual void resize(QSizeF const & size) override; 34 | 35 | public: 36 | virtual QString toolsString(QByteArray const & parent) const override; 37 | 38 | virtual void getToolButtons(QList &buttons, const QList &parents = {}) override; 39 | 40 | virtual bool setOption(const QByteArray &key, QVariant value) override; 41 | 42 | virtual QVariant getOption(QByteArray const & key) override; 43 | 44 | protected: 45 | using Control::getToolButtons; 46 | 47 | virtual SelectMode selectTest(QPointF const & point) override; 48 | 49 | virtual void select(bool selected) override; 50 | 51 | virtual void captureTo(const QString &file) override; 52 | 53 | protected: 54 | // update new path to item 55 | // also update edit points when editing 56 | void updateGeometry(); 57 | 58 | // finish drawing or adjusting geometry 59 | // will adjust center & update 60 | void finishGeometry(bool valid = false); 61 | 62 | protected: 63 | virtual bool event(QEvent *event) override; 64 | 65 | private: 66 | void updateSettings(); 67 | 68 | void geometryChanged(QByteArray const & key); 69 | 70 | bool beginPoint(QPointF const & point, bool fromHandle); 71 | 72 | void movePoint(QPointF const & point); 73 | 74 | bool endPoint(QPointF const & point); 75 | 76 | private: 77 | int hitElem_; 78 | QPointF hitOffset_; 79 | QPointF hitStart_; 80 | bool hitMoved_; 81 | QVector editPoints_; 82 | bool editing_; 83 | int touchId_; 84 | QPointF touchPos_; 85 | }; 86 | 87 | #endif // GRAPHCONTROL_H 88 | -------------------------------------------------------------------------------- /geometry3ds/geometry3d.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRY3D_H 2 | #define GEOMETRY3D_H 3 | 4 | #include "base/geometry.h" 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | class Geometry3D : public Geometry 13 | { 14 | Q_OBJECT 15 | public: 16 | Geometry3D(Resource * res); 17 | 18 | Geometry3D(Geometry3D const & o); 19 | 20 | public: 21 | virtual bool empty() const override; 22 | 23 | protected: 24 | /* Oblique projection */ 25 | 26 | // sqrt(2.0f) / 4.0f 27 | static constexpr qreal CO = 0.35355339059327376220042218105242; 28 | 29 | static QMatrix4x4 PO; 30 | 31 | /* Isometric projection */ 32 | 33 | // sqrt(2.0f) / 2.0f 34 | static constexpr qreal CIX = 0.70710678118654752440084436210485; 35 | 36 | // sqrt(6.0f) / 6.0f 37 | static constexpr qreal CIY = 0.40824829046386301636621401245098; 38 | 39 | // sqrt(3.0f) / 3.0f 40 | static constexpr qreal CIXY = 0.5;//0.57735026918962576450914878050196; 41 | 42 | static QMatrix4x4 PI; 43 | 44 | protected: 45 | static qreal length(QVector3D const & vec); 46 | 47 | static void adjustToLength(QVector3D const & start, QVector3D & end, qreal length); 48 | 49 | static void addLine(QPainterPath & ph, QPointF const & start, QPointF const & end); 50 | 51 | static void addArc(QPainterPath & ph, QRectF const & rect, qreal startAngle, qreal arcLength); 52 | 53 | static void addDotLine(QPainterPath & ph, QPointF const & start, QPointF const & end, qreal width); 54 | 55 | static void addDotArc(QPainterPath & ph, QRectF const & rect, qreal startAngle, qreal arcLength, qreal width); 56 | 57 | protected: 58 | // ph1: solid, ph2: dash 59 | QPainterPath combine(QPainterPath const & ph1, QPainterPath const & ph2); 60 | 61 | protected: 62 | QVector3D origin_; 63 | QVector3D size_; 64 | }; 65 | 66 | class Geometry3DFactory : ResourceFactory 67 | { 68 | Q_OBJECT 69 | public: 70 | Q_INVOKABLE Geometry3DFactory(); 71 | 72 | public: 73 | virtual ResourceView * create(Resource * res) override; 74 | 75 | virtual QUrl newUrl(const QByteArray &type) const override; 76 | }; 77 | 78 | #define REGISTER_GEOMETRY_3D(ctype, type) \ 79 | REGISTER_RESOURCE_VIEW_WITH_FACTORY(Geometry3D, ctype, type) 80 | 81 | #endif // GEOMETRY3D_H 82 | -------------------------------------------------------------------------------- /geometry2ds/trapezoid.cpp: -------------------------------------------------------------------------------- 1 | #include "trapezoid.h" 2 | #include "base/geometryhelper.h" 3 | 4 | Trapezoid::Trapezoid(Resource * res) 5 | : Polygon(res) 6 | { 7 | } 8 | 9 | Trapezoid::Trapezoid(Trapezoid const & o) 10 | : Polygon(o) 11 | { 12 | } 13 | 14 | Trapezoid::Trapezoid(const QPointF &vec1, const QPointF &vec2) 15 | : Polygon({vec1, vec2}) 16 | { 17 | } 18 | 19 | Trapezoid::Trapezoid(const QPointF &vec1, const QPointF &vec2, const QPointF &vec3) 20 | : Polygon({vec1, vec3, vec2}) 21 | { 22 | } 23 | 24 | static const qreal SQRT3W = 173.20508075688772935274463415059; 25 | 26 | static QVector dirs = { 27 | QPointF(200, 100), QPointF(200, -100), 28 | QPointF(200, SQRT3W), QPointF(200, -SQRT3W), 29 | QPointF(SQRT3W, 50), QPointF(SQRT3W, -50) 30 | }; 31 | 32 | void Trapezoid::movePoint(const QPointF &pt) 33 | { 34 | Polygon::movePoint(pt); 35 | GeometryHelper::attachToLines(points_[0], dirs, points_[1]); 36 | } 37 | 38 | bool Trapezoid::commitPoint(const QPointF &pt) 39 | { 40 | Polygon::commitPoint(pt); 41 | setPoint(1, point(1)); 42 | return true; 43 | } 44 | 45 | int Trapezoid::pointCount() 46 | { 47 | return points_.size() >= 2 ? 4 : 1; 48 | } 49 | 50 | bool Trapezoid::setPoint(int index, const QPointF &pt) 51 | { 52 | if ((index & 1) == 0) { 53 | points_[index >> 1] = pt; 54 | } else if (index == 1) { 55 | if (points_.size() == 3) 56 | points_[2] = pt; 57 | else 58 | points_.append(pt); 59 | } 60 | dirty_ = true; 61 | return true; 62 | } 63 | 64 | QPointF Trapezoid::point(int index) 65 | { 66 | if ((index & 1) == 0) 67 | return points_[index >> 1]; 68 | if (index == 1 && points_.size() == 3) 69 | return points_[2]; 70 | QPointF const & st = points_.first(); 71 | QPointF const & pt = points_[1]; 72 | if (index == 1) { 73 | return QPointF((st.x() + pt.x()) / 2, st.y()); 74 | } else { 75 | return point4(st, point(1), pt); // implemention defined 76 | } 77 | } 78 | 79 | bool Trapezoid::moveElememt(int elem, const QPointF &pt) 80 | { 81 | if (elem == 1) { 82 | QPointF p = pt; 83 | GeometryHelper::attachToLines(points_[1], p); 84 | Polygon::moveElememt(5, p); 85 | Polygon::setPoint(2, p); 86 | return true; 87 | } else if (elem == 2) { 88 | Polygon::setPoint(1, pt); 89 | GeometryHelper::attachToLines(points_[2], points_[1]); 90 | return true; 91 | } else if (elem < 4) { 92 | return moveKeepAngle(elem, pt); 93 | } 94 | return Polygon::moveElememt(elem, pt); 95 | } 96 | -------------------------------------------------------------------------------- /base/geometry.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRY_H 2 | #define GEOMETRY_H 3 | 4 | #include "Geometry_global.h" 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class ToolButton; 14 | 15 | class GEOMETRY_EXPORT Geometry : public ResourceView 16 | { 17 | 18 | Q_OBJECT 19 | Q_CLASSINFO("version", "1.0") 20 | 21 | Q_PROPERTY(QColor color READ color WRITE setColor) 22 | Q_PROPERTY(qreal width READ width WRITE setWidth) 23 | 24 | public: 25 | static constexpr Flag DrawAttach = CustomFlag; 26 | 27 | public: 28 | virtual bool empty() const; 29 | 30 | virtual bool finished() const; 31 | 32 | virtual void clear(); 33 | 34 | virtual void addPoint(QPointF const & pt); 35 | 36 | virtual void movePoint(QPointF const & pt); 37 | 38 | virtual bool commitPoint(QPointF const & pt); 39 | 40 | virtual bool moveTempPoint(QPointF const & pt); 41 | 42 | virtual void sync(); 43 | 44 | virtual bool canFinish(); 45 | 46 | virtual void finish(const QPointF &c); 47 | 48 | void scale(qreal scale); 49 | 50 | public: 51 | QColor color() const 52 | { 53 | return color_; 54 | } 55 | 56 | void setColor(QColor color); 57 | 58 | qreal width() const 59 | { 60 | return width_; 61 | } 62 | 63 | void setWidth(qreal width); 64 | 65 | void init(); 66 | 67 | signals: 68 | void changed(QByteArray const & key); 69 | 70 | public: 71 | /* 72 | * return element (>=0) under point pt 73 | * adjust pt to real element position 74 | */ 75 | virtual int hit(QPointF & pt); 76 | 77 | virtual void beginMove(int elem); 78 | 79 | /* 80 | * move element elem to point pt 81 | * pt is adjusted with some diff as hit() 82 | */ 83 | virtual bool moveElememt(int elem, QPointF const & pt); 84 | 85 | virtual void endMove(int elem); 86 | 87 | public: 88 | virtual QPainterPath graphPath(); 89 | 90 | virtual QPainterPath textPath(); 91 | 92 | virtual QPainterPath contour(); 93 | 94 | // include graphPath & textPath 95 | virtual QPainterPath visualPath(); 96 | 97 | virtual QVector movePoints(); 98 | 99 | // return QQuickShapePath (Qml ShapePath) 100 | virtual QObject * toQuickPath(QObject * context); 101 | 102 | public: 103 | virtual QtPromise::QPromise load(); 104 | 105 | virtual bool setOption(QByteArray const & key, QVariant value) override; 106 | 107 | protected: 108 | Geometry(Resource * res, Flags flags = {}, Flags clearFlags = {}); 109 | 110 | Geometry(Geometry const & o); 111 | 112 | Geometry(QByteArray const & type, QVector const & points); 113 | 114 | protected: 115 | QVector points_; 116 | bool dirty_; 117 | 118 | protected: 119 | QColor color_; 120 | qreal width_; 121 | }; 122 | 123 | #endif // GEOMETRY_H 124 | -------------------------------------------------------------------------------- /geometry3ds/cuboid.cpp: -------------------------------------------------------------------------------- 1 | #include "cuboid.h" 2 | 3 | Cuboid::Cuboid(Resource * res) 4 | : Polyhedron(res) 5 | { 6 | makeLine(0, 1); 7 | makeLine(1, 2); 8 | makeLine(2, 3); 9 | makeLine(3, 0); 10 | makeLine(0, 6); 11 | makeLine(6, 5); 12 | makeLine(5, 4); 13 | makeLine(4, 7); 14 | makeLine(7, 6); 15 | makeLine(7, 3); 16 | makeLine(4, 2); 17 | makeLine(5, 1); 18 | } 19 | 20 | Cuboid::Cuboid(Cuboid const & o) 21 | : Polyhedron(o) 22 | , moveElem_(o.moveElem_) 23 | , inner_(o.inner_) 24 | { 25 | } 26 | 27 | int Cuboid::pointCount() 28 | { 29 | return points_.size() >= 2 ? 8 : 1; 30 | } 31 | 32 | // @see Geometry3D::PO,Geometry3D::PI 33 | 34 | QVector3D Cuboid::point(int index) 35 | { 36 | QVector3D pt(origin_); 37 | if (index >= 4) 38 | #ifndef POLYHEDRON_ISOMETRIC_PROJECTION 39 | pt.setY(size_.y()); 40 | #else 41 | pt.setZ(size_.z()); 42 | #endif 43 | switch (index) { 44 | case 0: 45 | case 6: 46 | break; 47 | case 1: 48 | case 5: 49 | pt.setX(pt.x() + size_.x()); break; 50 | case 2: 51 | case 4: 52 | pt.setX(pt.x() + size_.x()); 53 | #ifndef POLYHEDRON_ISOMETRIC_PROJECTION 54 | pt.setZ(pt.z() + size_.z()); 55 | #else 56 | pt.setY(pt.y() + size_.y()); 57 | #endif 58 | break; 59 | case 3: 60 | case 7: 61 | #ifndef POLYHEDRON_ISOMETRIC_PROJECTION 62 | pt.setZ(pt.z() + size_.z()); 63 | #else 64 | pt.setY(pt.y() + size_.y()); 65 | #endif 66 | break; 67 | } 68 | return pt; 69 | } 70 | 71 | void Cuboid::setMoveElem(int elem) 72 | { 73 | if (moveElem_ != elem) { 74 | int fix = (8 - elem); 75 | if ((fix % 4) == 0) fix -= 4; 76 | points_[0] = PO.map(point(fix)).toPointF(); 77 | moveElem_ = elem; 78 | inner_ = QVector({2,3,5,6}).contains(elem); 79 | } 80 | } 81 | 82 | bool Cuboid::moveElememt(int elem, const QPointF &pt) 83 | { 84 | setMoveElem(elem); 85 | return Polyhedron::moveElememt(1, pt); 86 | } 87 | 88 | void Cuboid::sync() 89 | { 90 | if (dirty_ && points_.size() > 1) { 91 | QPointF pt1 = points_[0]; 92 | QPointF pt2 = points_[1]; 93 | #ifndef POLYHEDRON_ISOMETRIC_PROJECTION 94 | qreal x0, y0, z0; 95 | qreal w, h; 96 | if (inner_) { 97 | x0 = pt1.x(); 98 | y0 = 0; 99 | h = (pt2.y() - pt1.y()) / (1 - CO); 100 | z0 = -pt1.y() - h; 101 | w = pt2.x() - pt1.x() - h * CO; 102 | } else { 103 | y0 = 0; 104 | z0 = -pt2.y(); 105 | h = (pt2.y() - pt1.y()) / (1 + CO); 106 | x0 = pt1.x() - CO * h; 107 | w = pt2.x() - x0; 108 | } 109 | #else 110 | qreal x0 = 0; 111 | qreal y0 = 0; 112 | qreal z0 = 0; 113 | qreal w = 300; 114 | qreal h = 200; 115 | #endif 116 | origin_ = QVector3D(float(x0), float(y0), float(z0)); 117 | #ifndef POLYHEDRON_ISOMETRIC_PROJECTION 118 | size_ = QVector3D(float(w), float(h), float(h)); 119 | #else 120 | size_ = QVector3D(float(h), float(w), float(h)); 121 | #endif 122 | dirty_ = false; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /geometry2ds/arc.cpp: -------------------------------------------------------------------------------- 1 | #include "arc.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | 6 | Arc::Arc(Resource * res) 7 | : Geometry2D(res) 8 | { 9 | } 10 | 11 | Arc::Arc(Arc const & o) 12 | : Geometry2D(o) 13 | { 14 | } 15 | 16 | QPainterPath Arc::graphPath() 17 | { 18 | QPainterPath ph; 19 | if (points_.size() > 1) 20 | { 21 | ph.moveTo(points_[1]); 22 | ph.lineTo(points_[0]); 23 | arcTo(ph, points_[1], radius_, 45, false, false); 24 | } 25 | return ph; 26 | } 27 | 28 | void Arc::arcTo(QPainterPath & path, const QPointF &point, const QSizeF &size, double rotationAngle, bool isLargeArc, bool sweepDirection) 29 | { 30 | // pt1, pt2 are two points in unit circle (location at [0, 0] and with r = 1) 31 | // pt1 = [cos(t1) , sin(t1)] 32 | // pt2 = [cos(t2) , sin(t2)] 33 | // pe1, pe2 are pt1, pt2 scaled by [rx, ry] = size, that is in non-rotate Arc location at [0, 0] 34 | // pe1 = [rx * cos(t1), ry * sin(t1)] 35 | // pe2 = [rx * cos(t2), ry * sin(t2)] 36 | // pa1, pa2 are pe1, pe2 rotate by r = sweepDirection, that is in rotate Arc location at [0, 0] 37 | // |pa1| |cos(t1) sin(t1)| |rx 0| | cos(r) sin(r)| 38 | // | | = | | * | | * | | 39 | // |pa2| |cos(t2) sin(t2)| |0 ry| |-sin(r) cos(r)| 40 | rotationAngle = rotationAngle * M_PI / 180; 41 | QPointF rotate(cos(rotationAngle), sin(rotationAngle)); // [cos(r), sin(r)] 42 | qreal rx = size.width(), ry = size.height(); 43 | QMatrix matrix(rx * rotate.x(), rx * rotate.y(), 44 | -ry * rotate.y(), ry * rotate.x(), 0, 0); 45 | // t = [pt1 - pt2] / 2 = [cos(t1) - cos(t2), sin(t1) - sin(t2)] / 2; 46 | // = [-sin((t1 + t2) / 2) * sin((t1 - t2) / 2), cos((t1 + t2) / 2) * sin((t1 - t2) / 2)] 47 | QPointF t = matrix.inverted().map(path.currentPosition() - point) / 2; 48 | qDebug() << "t" << t; 49 | // a1 = (t1 + t2) / 2, a2 = (t1 - t2) / 2; t1 > t2 50 | qreal a1 = atan(-t.x() / t.y()); 51 | qreal a2 = asin(sqrt(GeometryHelper::length2(t))); 52 | qDebug() << "a1 <-> a2" << (a1 * 180 / M_PI) << (a2 * 180 / M_PI); 53 | if (isLargeArc != sweepDirection) 54 | a2 = -a2; 55 | if (a2 * t.y() <= 0) 56 | a1 += M_PI; 57 | qreal t1 = a1 + a2, t2 = a1 - a2; 58 | qDebug() << "t1 <-> t2" << (t1 * 180 / M_PI) << (t2 * 180 / M_PI); 59 | QPointF pt1(cos(t1), sin(t1)); 60 | QPointF pt2(cos(t2), sin(t2)); 61 | qDebug() << "pt1 <-> pt2" << pt1 << pt2; 62 | qDebug() << "t" << (pt1 - pt2) / 2; 63 | QPointF c = point - matrix.map(pt2); 64 | // 65 | QRectF rect(-rx, -ry, rx * 2, ry * 2); 66 | QPointF pe1(pt1.x() * rx, pt1.y() * ry); 67 | QPointF pe2(pt2.x() * rx, pt2.y() * ry); 68 | qDebug() << "pe1 <-> pe2" << pe1 << pe2; 69 | a1 = 360 - t1 * 180 / M_PI;//angle(pe1); // Y axis is up 70 | a2 = 360 - t2 * 180 / M_PI;//angle(pe2); 71 | qDebug() << "a1 <-> a2" << a1 << a2; 72 | QPainterPath ph(pe1); 73 | a2 -= a1; 74 | if (sweepDirection) { 75 | if (a2 > 0) 76 | a2 -= 360; 77 | } else { 78 | if (a2 < 0) 79 | a2 += 360; 80 | } 81 | ph.arcTo(rect, a1, a2); 82 | path.addPath(QMatrix(rotate.x(), rotate.y(), -rotate.y(), rotate.x(), c.x(), c.y()).map(ph)); 83 | path.addEllipse(c, 4, 4); 84 | qDebug(); 85 | } 86 | 87 | -------------------------------------------------------------------------------- /rulers/protractor.cpp: -------------------------------------------------------------------------------- 1 | #include "protractor.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | #include 6 | 7 | Protractor::Protractor(Resource * res) 8 | : Ruler(res) 9 | { 10 | width_ = 500; 11 | height_ = width_ / 2 + 20; 12 | minWidth_ = 500; 13 | } 14 | 15 | QPointF Protractor::adjustDirection(QRectF &adjust) 16 | { 17 | adjust = {-1, -1, 2, 1}; 18 | return {0, -1}; 19 | } 20 | 21 | QVector Protractor::getControlPositions() 22 | { 23 | return QVector{ 24 | {100, height_ - 40}, 25 | {width_ / 2, 100}, 26 | {width_ - 100, height_ - 40}, 27 | }; 28 | } 29 | 30 | void Protractor::updateShape() 31 | { 32 | QRectF cicle{0, 0, width_, width_}; 33 | shape_ = QPainterPath(); 34 | shape_.addEllipse(cicle); 35 | cicle.adjust(Unit * 4, Unit * 4, -Unit * 4, -Unit * 4); 36 | QPainterPath shape1; 37 | shape1.addEllipse(cicle); 38 | QPainterPath shape2; 39 | cicle.adjust(20, 20, -20, -20); 40 | shape2.addEllipse(cicle); 41 | QPainterPath shape3; 42 | cicle.adjust(20, 20, -20, -20); 43 | shape3.addEllipse(cicle); 44 | shape2_ = shape1 - shape2 + shape3; 45 | QPainterPath bounds; 46 | bounds.addRect({0, 0, width_, height_}); 47 | shape_ = shape_ & bounds; 48 | shape2_ = shape2_ & bounds; 49 | shape1_ = shape_ - shape2_; 50 | rotateCenter_ = {width_ / 2, width_ / 2}; 51 | } 52 | 53 | void Protractor::onDraw(QPainter *painter) 54 | { 55 | qreal r = width_ / 2; 56 | qreal r2 = width_ / 6; 57 | painter->setTransform(QTransform(0, -1, 1, 0, r, r), true); 58 | qreal one = M_PI / 180; 59 | QTransform d(cos(one), sin(one), -sin(one), cos(one), 0, 0); 60 | Qt::Alignment alignment = Qt::AlignTop | Qt::AlignHCenter; 61 | QPen pen = painter->pen(); 62 | QPen pen2 = pen; 63 | pen2.setWidthF(0.5); 64 | for (int i = 0; i <= 180; ++i) { 65 | int l = 0; 66 | if (i % 10 == 0) { // per 10 degree 67 | l = 4; 68 | } else if (i % 5 == 0) { // pre 5 degree 69 | l = 3; 70 | } else { 71 | l = 2; 72 | } 73 | QPointF end{0, -r + Unit * l}; 74 | painter->drawLine(QPointF{0, -r}, end); 75 | if (i % 10 == 0) { 76 | QString t = QString::number(i); 77 | QRectF txtRect = GeometryHelper::textRect(t, end, alignment); 78 | painter->drawText(txtRect, t); 79 | t = QString::number(180 - i); 80 | end.setY(end.y() + 20); 81 | txtRect = GeometryHelper::textRect(t, end, alignment); 82 | painter->drawText(txtRect, t); 83 | end.setY(end.y() + 20); 84 | if (i % 30 == 0) { 85 | painter->drawLine(end, {0, 0}); 86 | } else { 87 | painter->setPen(pen2); 88 | painter->drawLine(end, {0, -r2}); 89 | painter->setPen(pen); 90 | } 91 | } 92 | painter->setTransform(d, true); 93 | } 94 | QRectF cicle{-r2, -r2, r2 * 2, r2 * 2}; 95 | painter->drawArc(cicle, 90 * 16, 180 * 16); 96 | } 97 | 98 | Geometry *Protractor::createGeometry() 99 | { 100 | return nullptr; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /geometry2ds/arbitrarypolygon.cpp: -------------------------------------------------------------------------------- 1 | #include "arbitrarypolygon.h" 2 | #include "base/geometryhelper.h" 3 | 4 | ArbitraryPolygon::ArbitraryPolygon(Resource * res) 5 | : Polygon(res) 6 | { 7 | } 8 | 9 | ArbitraryPolygon::ArbitraryPolygon(ArbitraryPolygon const & o) 10 | : Polygon(o) 11 | { 12 | } 13 | 14 | bool ArbitraryPolygon::canClose() 15 | { 16 | return flags_.testFlag(DrawFinised); 17 | } 18 | 19 | void ArbitraryPolygon::addPoint(QPointF const & pt) 20 | { 21 | if (tempValid_) 22 | Polygon::addPoint(temp_); 23 | else 24 | Polygon::addPoint(pt); 25 | tempValid_ = false; 26 | } 27 | 28 | void ArbitraryPolygon::movePoint(QPointF const & pt) 29 | { 30 | qDebug() << "movePoint"; 31 | if (points_.size() == 1) 32 | points_.append(pt); 33 | else if (!points_.isEmpty()) 34 | points_.back() = pt; 35 | QPointF d = pt - points_.first(); 36 | if (GeometryHelper::length2(d) < GeometryHelper::HIT_DIFF_DIFF) { 37 | points_.back() = points_.first(); 38 | } else { 39 | GeometryHelper::attachToLines(points_[points_.size() - 2], points_.back()); 40 | GeometryHelper::attachToLines(points_.first(), points_.back()); 41 | } 42 | temp_ = pt; 43 | dirty_ = true; 44 | } 45 | 46 | bool ArbitraryPolygon::commitPoint(const QPointF &pt) 47 | { 48 | tempValid_ = false; 49 | if (pointCount() < 4) 50 | return false; 51 | QPointF d = pt - points_.first(); 52 | if (GeometryHelper::length2(d) >= GeometryHelper::HIT_DIFF_DIFF) 53 | return false; 54 | points_.pop_back(); 55 | return true; 56 | } 57 | 58 | bool ArbitraryPolygon::moveTempPoint(const QPointF &pt) 59 | { 60 | if (pt == temp_) 61 | return false; 62 | qDebug() << "moveTempPoint"; 63 | temp_ = pt; 64 | QPointF d = pt - points_.first(); 65 | if (GeometryHelper::length2(d) < GeometryHelper::HIT_DIFF_DIFF) { 66 | temp_ = points_.first(); 67 | } else { 68 | GeometryHelper::attachToLines(points_.back(), temp_); 69 | GeometryHelper::attachToLines(points_.first(), temp_); 70 | } 71 | tempValid_ = true; 72 | dirty_ = true; 73 | return true; 74 | } 75 | 76 | bool ArbitraryPolygon::canFinish() 77 | { 78 | return points_.size() > 2; 79 | } 80 | 81 | void ArbitraryPolygon::finish(const QPointF &c) 82 | { 83 | if (tempValid_) { 84 | tempValid_ = false; 85 | dirty_ = true; 86 | sync(); 87 | QPointF c1 = graphPath().boundingRect().center(); 88 | Polygon::finish(c1); 89 | } else { 90 | Polygon::finish(c); 91 | } 92 | } 93 | 94 | int ArbitraryPolygon::pointCount() 95 | { 96 | return points_.size() + ((!tempValid_ || (flags_ & DrawFinised)) ? 0 : 1); 97 | } 98 | 99 | QPointF ArbitraryPolygon::point(int index) 100 | { 101 | if (index < points_.size()) 102 | return points_[index]; 103 | else 104 | return temp_; 105 | } 106 | 107 | bool ArbitraryPolygon::moveElememt(int elem, const QPointF &pt) 108 | { 109 | QPointF p = pt; 110 | if (elem < points_.size()) { 111 | GeometryHelper::attachToLines( 112 | elem > 0 ? points_[elem - 1] : points_.last(), p); 113 | GeometryHelper::attachToLines( 114 | elem + 1 < points_.size() ? points_[elem + 1] : points_.first(), p); 115 | } 116 | return Polygon::moveElememt(elem, p); 117 | } 118 | -------------------------------------------------------------------------------- /base/geometryhelper.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRYHELPER_H 2 | #define GEOMETRYHELPER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class ResourcePage; 12 | class Geometry; 13 | 14 | class GeometryHelper : public QObject 15 | { 16 | Q_OBJECT 17 | public: 18 | static qreal HIT_DIFF; 19 | 20 | static qreal HIT_DIFF_DIFF; 21 | 22 | static qreal DEFAULT_LINE_WIDTH; 23 | 24 | static QFont TEXT_FONT; 25 | 26 | Q_INVOKABLE GeometryHelper(); 27 | 28 | public: 29 | static QColor defaultColor(ResourcePage * page); 30 | 31 | static void setDefaultColor(ResourcePage * page, QColor color); 32 | 33 | public slots: 34 | static void init(); 35 | 36 | static QPointF textOffset(QString const & text, Qt::Alignment alignment); 37 | 38 | static QRectF textRect(QString const & text, QPointF const & alignTo, Qt::Alignment alignment); 39 | 40 | static QPainterPath toRoundPolygon(QPolygonF const & polygon, qreal radius); 41 | 42 | static QPainterPath toRoundPolygon(QPolygonF const & polygon, QVector const & radiuses); 43 | 44 | static void * approxGeometryBegin(qreal epsilon = 0); 45 | 46 | static bool approxGeometryAddPoints(void * context, QVector pts); 47 | 48 | static QObject * approxGeometryFinish(void * context, QPointF const & offset); 49 | 50 | public slots: 51 | static qreal angle(QPointF const & vec); 52 | 53 | static qreal angle(QPointF const & p1, QPointF const & p2, QPointF const & p3); 54 | 55 | static qreal length(QPointF const & vec); 56 | 57 | static qreal length2(QPointF const & vec); 58 | 59 | static qreal determinant(QPointF const & p1, QPointF const & p2); 60 | 61 | static qreal dotProduct(QPointF const & p1, QPointF const & p2); 62 | 63 | public slots: 64 | static void rotate(QPointF & pt, QPointF const & angle); 65 | 66 | static void reverseRotate(QPointF & pt, QPointF const & angle); 67 | 68 | static void adjustToLength(QPointF & vec, qreal length); 69 | 70 | static void adjustToLength(QPointF const & start, QPointF & end, qreal length); 71 | 72 | public slots: 73 | static int attachToPoints(QVector const & pts, QPointF & p); 74 | 75 | static void attachToLine(QPointF const & p1, QPointF const & p2, QPointF & p); 76 | 77 | static void attachToLines(QPointF const & p1, QPointF & p); 78 | 79 | static void attachToLines(QPointF const & p1, QPointF const & p2, QPointF & p); 80 | 81 | static int attachToLines(QPointF const & p1, QVector const & dirs, QPointF & p); 82 | 83 | static int attachToLines(QPointF const & p1, QPointF const & p2, QVector const & dirs, QPointF & p); 84 | 85 | static int attachLineToPointsAndLines(QVector const & pts, QVector lines, QPointF & lp1, QPointF & lp2); 86 | 87 | public slots: 88 | static qreal dist2PointToSegment(QPointF const & p1, QPointF const & p2, 89 | QPointF const & p, QPointF & rp); 90 | 91 | static QPointF nearestPointAtVerticalBisector(QPointF const & p1, QPointF const & p2, 92 | QPointF const & p); 93 | 94 | static QPointF crossPoint(QPointF const & p1, QPointF const & p2, 95 | QPointF const & q1, QPointF const & q2); 96 | 97 | public slots: 98 | static QPolygonF smallestEnclosingPolygon(QVector const & pts); 99 | }; 100 | 101 | #endif // GEOMETRYHELPER_H 102 | -------------------------------------------------------------------------------- /geometry3ds/ellipsoid.cpp: -------------------------------------------------------------------------------- 1 | #include "ellipsoid.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | Ellipsoid::Ellipsoid(Resource * res) 10 | : Geometry3D(res) 11 | { 12 | } 13 | 14 | Ellipsoid::Ellipsoid(Ellipsoid const & o) 15 | : Geometry3D(o) 16 | ,radius_(o.radius_) 17 | { 18 | } 19 | 20 | void Ellipsoid::sync() 21 | { 22 | if (dirty_ && points_.size() > 1) { 23 | QPointF d = points_.back() - points_.first(); 24 | radius_.setX(float(qAbs(d.x()))); 25 | radius_.setY(float(qAbs(d.y()))); 26 | if (!finished()) 27 | radius_.setZ(float(qAbs(d.y()))); 28 | dirty_ = false; 29 | } 30 | } 31 | 32 | QVector Ellipsoid::movePoints() 33 | { 34 | QVector points; 35 | QPointF ct(points_.front()); 36 | QPointF dx(qreal(radius_.x()), 0); 37 | QPointF dy(0, qreal(radius_.y())); 38 | float a = 6 * pow(radius_.x() * radius_.y() * radius_.z(), 2); 39 | float b = pow(radius_.z(), 4); 40 | float c = b - 36 * pow(radius_.x() * radius_.y(), 2); 41 | QPointF dz(qreal(sqrt((b * pow(radius_.x(), 2) - a) / c)), 42 | qreal(sqrt((b * pow(radius_.y(), 2) - a) / c))); 43 | return QVector{ct - dx, ct + dx, ct - dy, ct + dy, ct - dz, ct + dz}; 44 | } 45 | 46 | int Ellipsoid::hit(QPointF &) 47 | { 48 | return -1; 49 | } 50 | 51 | bool Ellipsoid::moveElememt(int elem, QPointF const & pt) 52 | { 53 | if (elem < 2) { 54 | points_.back().setX(pt.x()); 55 | QPointF d = points_.back() - points_.first(); 56 | radius_.setX(float(qAbs(d.x()))); 57 | } else if (elem < 4) { 58 | points_.back().setY(pt.y()); 59 | QPointF d = points_.back() - points_.first(); 60 | radius_.setY(float(qAbs(d.y()))); 61 | } else if (elem < 6) { 62 | QPointF d = pt - points_.first(); 63 | qreal c2 = 3 * QPointF::dotProduct(d, d) 64 | / (1 - pow(d.x() / qreal(radius_.x()), 2) - pow(d.y() / qreal(radius_.y()), 2)); 65 | radius_.setZ(float(sqrt(c2))); 66 | } 67 | return true; 68 | } 69 | 70 | QPainterPath Ellipsoid::visualPath() 71 | { 72 | QPainterPath ph; 73 | if (points_.size() < 2) 74 | return ph; 75 | QPainterPath ph2; 76 | QPointF center(points_.front()); 77 | // XY circle 78 | QRectF circle(0, 0, qreal(radius_.x()) * 2, qreal(radius_.y()) * 2); 79 | circle.moveCenter(center); 80 | addArc(ph, circle, 0, 360.0); 81 | // XZ cicle 82 | { 83 | QRectF rect(-qreal(radius_.x()), -qreal(radius_.z()) * CIY, 84 | qreal(radius_.x()) * 2, qreal(radius_.z()) * 2 * CIY); 85 | rect.moveCenter(center); 86 | addArc(ph, rect, 180.0, 180.0); 87 | addArc(ph2, rect, 0.0, 180.0); 88 | } 89 | // YZ cicle 90 | { 91 | QRectF rect(-qreal(radius_.z()) * CIY, -qreal(radius_.y()), 92 | qreal(radius_.z()) * CIY * 2, qreal(radius_.y()) * 2); 93 | rect.moveCenter(center); 94 | addArc(ph, rect, 270.0, 180.0); 95 | addArc(ph2, rect, 90.0, 180.0); 96 | } 97 | return combine(ph, ph2); 98 | } 99 | 100 | QPainterPath Ellipsoid::contour() 101 | { 102 | QPainterPath ph; 103 | if (points_.size() < 2) 104 | return ph; 105 | QPointF center(points_.front()); 106 | QRectF circle(0, 0, qreal(radius_.x()) * 2, qreal(radius_.y()) * 2); 107 | circle.moveCenter(center); 108 | ph.addEllipse(circle); 109 | return ph; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /geometrytool.cpp: -------------------------------------------------------------------------------- 1 | #include "geometrytool.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #ifndef QT_DEBUG 15 | 16 | static char const * const geometry2ds[] = { 17 | "line", "dotline", "line.so-", "line.so-so", "", "", 18 | "arbitrarypolygon", "circle", "sector", "isoscelestriangle", "righttriangle", "parallelogram", "diamond", 19 | "square", "rectangle", "isopopetrapezoid", "righttrapezoid", "regularpolygon.5", 20 | }; 21 | 22 | static char const * const geometry3ds[] = { 23 | "cube", "cuboid", "cylinder", "cone", "sphere", 24 | }; 25 | 26 | static char const * const rulertools[] = { 27 | "linear", "triangle", "iso_triangle", "protractor", "compasses", 28 | }; 29 | 30 | #endif 31 | 32 | GeometryTools::GeometryTools() 33 | { 34 | } 35 | 36 | void GeometryTools::getToolButtons(QList & result, QByteArray const & type) 37 | { 38 | GeometryHelper::init(); 39 | static QMap> gButtons; 40 | if (gButtons.contains(type)) { 41 | result = gButtons.value(type); 42 | return; 43 | } 44 | QList names; 45 | ResourceFactory * factory = ResourceManager::instance()->getFactory(type); 46 | #ifdef QT_DEBUG 47 | names = factory->resourceTypes(); 48 | #else 49 | if (type == "geometry2d") { 50 | for (auto g : geometry2ds) 51 | names.append(g); 52 | } else if (type == "geometry3d") { 53 | for (auto g : geometry3ds) 54 | names.append(g); 55 | } 56 | #endif 57 | ToolButton::Flags flags = {ToolButton::Dynamic}; 58 | for (QByteArray & f : names) { 59 | ToolButton * btn = f.isEmpty() ? &ToolButton::PLACE_HOOLDER : new ToolButton( 60 | {factory->newUrl(f).toString().toUtf8(), f, flags, ":geometry/icon/" + type + "/" + f + ".svg"}); 61 | result.append(btn); 62 | } 63 | gButtons.insert(type, result); 64 | } 65 | 66 | void GeometryTools::handleToolButton(ToolButton* button, QByteArray const &) 67 | { 68 | if (button == &ToolButton::PLACE_HOOLDER) 69 | return; 70 | WhiteCanvas * canvas = WhiteCanvasWidget::mainInstance()->canvas(); 71 | Control * drawControl = canvas->getToolControl("drawing"); 72 | QObject::connect(drawControl, SIGNAL(drawFinished(bool)), 73 | button, SIGNAL(delayActive(bool))); 74 | drawControl->setOption("newUrl", button->name()); 75 | canvas->showToolControl(drawControl); 76 | } 77 | 78 | GeometryTool::GeometryTool(ResourceView *res) 79 | : MenuTool(res) 80 | { 81 | } 82 | 83 | void GeometryTool::getToolButtons(QList &buttons, ToolButton *parent) 84 | { 85 | if (parent) 86 | return; 87 | QByteArray type = res_->resource()->type(); 88 | type.remove(type.length() - 4, 4); // "tool" 89 | GeometryTools::getToolButtons(buttons, type); 90 | } 91 | 92 | bool GeometryTool::handleToolButton(ToolButton * button, QStringList const &) 93 | { 94 | WhiteCanvas * canvas = static_cast(item_->parentItem()->parentItem()); 95 | if (button->name().startsWith("rulertool:")) { 96 | Control * control = canvas->addResource(QUrl(button->name())); 97 | control->item()->show(); 98 | return true; 99 | } 100 | canvas->getToolControl("drawing")->setOption("newUrl", button->name()); 101 | canvas->showToolControl("drawing"); 102 | return true; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /rulers/triangleruler.cpp: -------------------------------------------------------------------------------- 1 | #include "rulertriangle.h" 2 | #include "triangleruler.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | static constexpr qreal SQRT2_2 = 0.70710678118654752440084436210485; 10 | static constexpr qreal SQRT3_2 = 0.86602540378443864676372317075294; 11 | 12 | TriangleRuler::TriangleRuler(Resource * res) 13 | : Ruler(res) 14 | { 15 | isosceles_ = res->property(Resource::PROP_SUB_TYPE) == "iso_triangle"; 16 | width_ = 500; 17 | height_ = isosceles_ ? (width_) : (width_ / (SQRT3_2 * 2)); 18 | minWidth_ = isosceles_ ? 300 : 400; 19 | } 20 | 21 | QPointF TriangleRuler::adjustDirection(QRectF &adjust) 22 | { 23 | if (isosceles_) { 24 | adjust = {0, -SQRT2_2 * 2, SQRT2_2 * 2, SQRT2_2 * 2}; 25 | return {SQRT2_2, -SQRT2_2}; 26 | } else { 27 | adjust = {0, -1, SQRT3_2 * 2, 1}; 28 | return {0.5, -SQRT3_2}; 29 | } 30 | } 31 | 32 | QVector TriangleRuler::getControlPositions() 33 | { 34 | qreal offset = Unit * 8 + 40; 35 | qreal ratio1 = isosceles_ ? (SQRT2_2 * 2 + 1.0) : (SQRT3_2 * 2); 36 | qreal ratio2 = isosceles_ ? (SQRT2_2 * 2 + 1.0) : (SQRT3_2 * 2 + 2.0); 37 | return QVector{ 38 | {offset, offset * ratio1}, 39 | {(width_ - offset * (ratio2 - 1)) / 2, (height_ + offset * (ratio1 - 1)) / 2}, 40 | {width_ - offset * ratio2, height_ - offset}, 41 | }; 42 | } 43 | 44 | void TriangleRuler::updateShape() 45 | { 46 | qreal ratio1 = isosceles_ ? (SQRT2_2 * 2 + 1.0) : (SQRT3_2 * 2); 47 | qreal ratio2 = isosceles_ ? (SQRT2_2 * 2 + 1.0) : (SQRT3_2 * 2 + 2.0); 48 | shape_ = QPainterPath(); 49 | // Countor shape 50 | shape_.addPolygon(QVector{ 51 | {0, 0}, 52 | {0, height_}, 53 | {width_, height_}, 54 | }); 55 | qreal offset = Unit * 3; 56 | shape1_ = QPainterPath(); 57 | // Tick outer border, offset 3 Units 58 | shape1_.addPolygon(QVector{ 59 | {offset, offset * ratio1}, 60 | {offset, height_ - offset}, 61 | {width_ - offset * ratio2, height_ - offset}, 62 | }); 63 | offset += Unit * 3; 64 | shape2_ = QPainterPath(); 65 | // Tick inner border, offset 3 Units 66 | shape2_.addPolygon(QVector{ 67 | {offset, offset * ratio1}, 68 | {offset, height_ - offset}, 69 | {width_ - offset * ratio2, height_ - offset}, 70 | }); 71 | shape1_ -= shape2_; 72 | } 73 | 74 | void TriangleRuler::onDraw(QPainter *painter) 75 | { 76 | qreal offset = Unit * 3; 77 | // Bottom tick line, offset 3 Units 78 | drawTickMarks(painter, {offset, height_ - offset}, {offset, offset}, 79 | CrossLittenEndian | NeedRotate | ClipByShape); 80 | drawTickMarks(painter, {offset, height_ - offset}, {width_ - offset, height_ - offset}, 81 | Anticlockwise | CrossLittenEndian | ClipByShape); 82 | qreal offset2 = Unit * 8; 83 | qreal ratio1 = isosceles_ ? (SQRT2_2 * 2 + 1.0) : (SQRT3_2 * 2); 84 | qreal ratio2 = isosceles_ ? (SQRT2_2 * 2 + 1.0) : (SQRT3_2 * 2 + 2.0); 85 | qreal ratio11 = isosceles_ ? (SQRT2_2 + 1.0) : (1.5); 86 | qreal ratio12 = isosceles_ ? (SQRT2_2 + 1.0) : (SQRT3_2); 87 | qreal ratio21 = isosceles_ ? (SQRT2_2 + 1.0) : (SQRT3_2 * 2 + 1.5); 88 | qreal ratio22 = isosceles_ ? (SQRT2_2 + 1.0) : (SQRT3_2 + 1.0); 89 | drawTickMarks(painter, {offset + offset2 * ratio11, offset * ratio1 + offset2 * ratio12}, 90 | {width_ - offset * ratio2 - offset2 * ratio21, height_ - offset - offset2 * ratio22}, 91 | NeedRotate | ClipByShape); 92 | } 93 | 94 | Geometry *TriangleRuler::createGeometry() 95 | { 96 | qreal ratio1 = isosceles_ ? (SQRT2_2 * 2 + 1.0) : (SQRT3_2 * 2); 97 | qreal ratio2 = isosceles_ ? (SQRT2_2 * 2 + 1.0) : (SQRT3_2 * 2 + 2.0); 98 | qreal offset = Unit * 3; 99 | return new RulerTriangle({ 100 | {offset, offset * ratio1}, 101 | {width_ - offset * ratio2, height_ - offset}, 102 | {offset, height_ - offset}, 103 | }); 104 | } 105 | -------------------------------------------------------------------------------- /rulers/ruler.cpp: -------------------------------------------------------------------------------- 1 | #include "ruler.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | 6 | #include 7 | 8 | Ruler::Ruler(Resource * res, Flags flags, Flags clearFlags) 9 | : ResourceView(res, flags, clearFlags | CanCopy) 10 | { 11 | width_ = height_ = 500; 12 | } 13 | 14 | QPointF Ruler::adjustDirection(QRectF &adjust) 15 | { 16 | adjust.setRight(1); 17 | return QPointF(1, 0); 18 | } 19 | 20 | void Ruler::updateShape() 21 | { 22 | } 23 | 24 | void Ruler::onDraw(QPainter *painter) 25 | { 26 | (void) painter; 27 | } 28 | 29 | bool Ruler::hitTestTickMark(const QPointF &pos) 30 | { 31 | return !shape2_.contains(pos); 32 | } 33 | 34 | QPointF Ruler::adjust(QPointF const & offset) 35 | { 36 | QRectF adj; 37 | QPointF dir = adjustDirection(adj); 38 | qreal length = GeometryHelper::dotProduct(offset, dir); 39 | if (width_ + adj.width() * length < minWidth_) 40 | length = (minWidth_ - width_) / adj.width(); 41 | QPointF topLeft = adj.topLeft() * length; 42 | QSizeF size = adj.size() * length; 43 | width_ += size.width(); 44 | height_ += size.height(); 45 | updateShape(); 46 | return topLeft; 47 | } 48 | 49 | QVector Ruler::tickMarkPoints(QPointF const & from, QPointF const & to, int flags) 50 | { 51 | qreal length = GeometryHelper::length(to - from); 52 | QPointF delta = to - from; 53 | GeometryHelper::adjustToLength(delta, Unit); 54 | QPointF scale = delta; 55 | if (flags & Anticlockwise) 56 | GeometryHelper::rotate(scale, QPointF(0, -1)); 57 | else 58 | GeometryHelper::rotate(scale, QPointF(0, 1)); 59 | QVector points; 60 | QPointF cur = from; 61 | while (length > 0) { 62 | int l = 0; 63 | if ((flags & CrossLittenEndian) && points.size() < 10) { 64 | l = points.size() / 2; 65 | } else if (points.size() % 20 == 0) { // per 10mm 66 | l = 4; 67 | } else if (points.size() % 10 == 0) { // pre 5mm 68 | l = 3; 69 | } else { 70 | l = 2; 71 | } 72 | QPointF end = cur + scale * l; 73 | if ((flags & ClipByShape) && l > 0 && !shape1_.contains(end) && !shape2_.contains(end)) 74 | break; 75 | points.append(cur); 76 | points.append(end); 77 | length -= Unit; 78 | cur = cur + delta; 79 | } 80 | return points; 81 | } 82 | 83 | // Ticks with length 2, 3, 4 Units 84 | void Ruler::drawTickMarks(QPainter *painter, const QPointF &from, const QPointF &to, int flags) 85 | { 86 | if (flags & NeedRotate) { 87 | QPointF d = to - from; 88 | if (!qFuzzyIsNull(d.y())) { 89 | GeometryHelper::adjustToLength(d, 1.0); 90 | QTransform t = QTransform(d.x(), d.y(), -d.y(), d.x(), 0, 0) 91 | * QTransform::fromTranslate(from.x(), from.y()); 92 | QTransform t2 = t.inverted(); 93 | QTransform o = painter->transform(); 94 | painter->setTransform(t, true); 95 | if (flags & ClipByShape) { 96 | QPainterPath shape1 = shape1_; 97 | shape1_ = t2.map(shape1); 98 | QPainterPath shape2 = shape2_; 99 | shape2_ = t2.map(shape2); 100 | drawTickMarks(painter, {0, 0}, t2.map(to), flags & ~NeedRotate); 101 | shape2_ = shape2; 102 | shape1_ = shape1; 103 | } else { 104 | drawTickMarks(painter, {0, 0}, t2.map(to), flags & ~NeedRotate); 105 | } 106 | painter->setTransform(o); 107 | return; 108 | } 109 | } 110 | auto marks = tickMarkPoints(from, to, flags); 111 | painter->drawLines(marks); 112 | Qt::Alignment alignment = (flags & Anticlockwise) 113 | ? Qt::AlignBottom | Qt::AlignHCenter : Qt::AlignTop | Qt::AlignHCenter; 114 | for (int i = 0; i < marks.size(); i += 2) { 115 | if (i == 0 && (flags & CrossLittenEndian)) 116 | continue; 117 | if (i % 20 == 0) { 118 | QString mark = QString::number(i / 20); 119 | QRectF txtRect = GeometryHelper::textRect( 120 | mark, marks[i + 1], alignment); 121 | if (!shape2_.contains(txtRect)) 122 | break; 123 | painter->drawText(txtRect, mark); 124 | } 125 | } 126 | } 127 | 128 | /* 129 | * RulerFactory 130 | */ 131 | 132 | RulerFactory::RulerFactory() 133 | { 134 | } 135 | 136 | ResourceView *RulerFactory::create(Resource *res) 137 | { 138 | QString type = res->url().path(); 139 | int n = type.indexOf('/'); 140 | if (n > 0) 141 | type = type.left(n); 142 | return ResourceFactory::create(res, type.toUtf8()); 143 | } 144 | 145 | QUrl RulerFactory::newUrl(const QByteArray &type) const 146 | { 147 | return QUrl("rulertool:" + type); 148 | } 149 | 150 | -------------------------------------------------------------------------------- /geometry2ds/geometry2d.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry2d.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | Geometry2D::Geometry2D(Resource * res, Flags flags, Flags clearFlags) 10 | : Geometry(res, flags, clearFlags) 11 | { 12 | } 13 | 14 | Geometry2D::Geometry2D(Geometry2D const & o) 15 | : Geometry(o) 16 | { 17 | } 18 | 19 | Geometry2D::Geometry2D(const QVector &points) 20 | : Geometry("geometry2d", points) 21 | { 22 | } 23 | 24 | bool Geometry2D::empty() const 25 | { 26 | return Geometry::empty() && res_->url().path().lastIndexOf('/') == -1 27 | && res_->url().query().length() == 0; 28 | } 29 | 30 | /* 31 | * Static functions 32 | */ 33 | 34 | void Geometry2D::moveLine(QPointF const & llpt, QPointF & lpt, QPointF const & pt, 35 | QPointF & npt, QPointF const & nnpt) 36 | { 37 | QPointF lp = GeometryHelper::crossPoint(llpt, lpt, pt, pt + npt - lpt); 38 | QPointF np = GeometryHelper::crossPoint(pt, pt + npt - lpt, npt, nnpt); 39 | lpt = lp; 40 | npt = np; 41 | } 42 | 43 | void Geometry2D::addAngleLabeling(QPainterPath &path, QPainterPath &textPath, QPointF const & lpt, 44 | QPointF const & pt, QPointF const & npt) 45 | { 46 | addAngleLabeling(path, textPath, lpt, pt, npt, GeometryHelper::angle(lpt, pt, npt)); 47 | } 48 | 49 | void Geometry2D::addAngleLabeling(QPainterPath &path, QPainterPath &textPath, QPointF const & lpt, 50 | QPointF const & pt, QPointF const & npt, qreal angle) 51 | { 52 | QPointF lp = lpt; 53 | QPointF np = npt; 54 | GeometryHelper::adjustToLength(pt, lp, GeometryHelper::HIT_DIFF); 55 | GeometryHelper::adjustToLength(pt, np, GeometryHelper::HIT_DIFF); 56 | QPointF rpt = lp + np - pt; 57 | //qDebug() << pt << angle; 58 | QPolygonF polygon({lpt, pt, npt, lpt}); 59 | if (qFuzzyCompare(angle, 90.0)) { 60 | if (polygon.containsPoint(rpt, Qt::OddEvenFill)) { 61 | path.moveTo(lp); 62 | path.lineTo(rpt); 63 | path.lineTo(np); 64 | //path.addText(txt, QFont(), QString("90°")); 65 | } 66 | } else if ((angle < 90) ? (qFuzzyCompare(angle, 30.0) 67 | || qFuzzyCompare(angle, 45.0) || qFuzzyCompare(angle, 60.0)) 68 | : ((angle < 180) ? (qFuzzyCompare(angle, 120.0) 69 | || qFuzzyCompare(angle, 135.0) || qFuzzyCompare(angle, 150.0)) 70 | : (qFuzzyCompare(angle, 180.0) 71 | || qFuzzyCompare(angle, 270.0) || qFuzzyCompare(angle, 360.0)))) { 72 | qreal txtDis = GeometryHelper::HIT_DIFF * 1.5 / sin(angle * M_PI / 360); 73 | if (angle > 90) txtDis += GeometryHelper::HIT_DIFF * 1.5; 74 | GeometryHelper::adjustToLength(pt, rpt, txtDis); 75 | QString text = QString("%1°").arg(qRound(angle)); 76 | QPointF txtOff = GeometryHelper::textOffset(text, Qt::AlignCenter); 77 | QPointF txtPos = rpt + txtOff; 78 | QRectF bound = QRectF(QPointF(), QSizeF(2, 2) * GeometryHelper::HIT_DIFF * 1.5); 79 | bound.moveCenter(pt); 80 | qreal a1 = GeometryHelper::angle(lpt - pt); 81 | qreal a2 = GeometryHelper::angle(npt - pt); 82 | //qDebug() << point << r1 << r2; 83 | qreal start = qMin(a1, a2); 84 | qreal end = qMax(a1, a2); 85 | qreal length = end - start; 86 | if (qFuzzyIsNull(angle - 180)) { 87 | start = a1; 88 | txtPos = lpt - pt; 89 | GeometryHelper::adjustToLength(QPointF(0, 0), txtPos, GeometryHelper::HIT_DIFF * 3); 90 | txtPos = pt - QPointF(-txtPos.y(), txtPos.x()) + txtOff; 91 | if (length < 0) 92 | txtPos = pt * 2 - txtPos + txtOff; 93 | } else if (angle < 180) { 94 | if (length > 180.0) { 95 | length -= 360.0; 96 | } 97 | } else { 98 | if (length < 180.0) { 99 | length -= 360.0; 100 | } 101 | txtPos = pt * 2 - txtPos + txtOff; 102 | } 103 | path.arcMoveTo(bound, start); 104 | path.arcTo(bound, start, length); 105 | if (polygon.containsPoint(txtPos, Qt::OddEvenFill) 106 | && polygon.containsPoint(rpt - txtOff, Qt::OddEvenFill)) 107 | textPath.addText(txtPos, GeometryHelper::TEXT_FONT, text); 108 | } 109 | } 110 | 111 | 112 | Geometry2DFactory::Geometry2DFactory() 113 | { 114 | } 115 | 116 | ResourceView * Geometry2DFactory::create(Resource *res) 117 | { 118 | QString type = res->url().path(); 119 | int n = type.indexOf('/'); 120 | if (n > 0) 121 | type = type.left(n); 122 | return ResourceFactory::create(res, type.toUtf8()); 123 | } 124 | 125 | QUrl Geometry2DFactory::newUrl(const QByteArray &type) const 126 | { 127 | return QUrl("geometry2d:" + type); 128 | } 129 | -------------------------------------------------------------------------------- /geometry3ds/geometry3d.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry3d.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | 6 | #include 7 | 8 | /* 9 | * Z ^ _/ Y 10 | * | _/ 11 | * | _/ 12 | * | / 13 | * o---------------> X 14 | */ 15 | QMatrix4x4 Geometry3D::PO( 16 | 1, float(CO), 0, 0, 17 | 0, -float(CO), -1, 0, 18 | 0, 0, 0, 0, 19 | 0, 0, 0, 1); 20 | 21 | /* 22 | * Z ^ 23 | * | 24 | * | 25 | * | 26 | * o 27 | * / \ 28 | * / \ 29 | * / \ 30 | * X / \ Y 31 | */ 32 | QMatrix4x4 Geometry3D::PI( 33 | -float(CIX), float(CIX), 0, 0, 34 | float(CIY), float(CIY), -float(CIY) * 2, 0, 35 | 0, 0, 0, 0, 36 | 0, 0, 0, 1); 37 | 38 | Geometry3D::Geometry3D(Resource * res) 39 | : Geometry(res) 40 | { 41 | } 42 | 43 | Geometry3D::Geometry3D(Geometry3D const & o) 44 | : Geometry(o) 45 | , origin_(o.origin_) 46 | , size_(o.size_) 47 | { 48 | } 49 | 50 | bool Geometry3D::empty() const 51 | { 52 | return Geometry::empty() && res_->url().path().lastIndexOf('/') == -1 53 | && res_->url().query().length() == 0; 54 | } 55 | 56 | qreal Geometry3D::length(QVector3D const & vec) 57 | { 58 | (void) vec; 59 | return 0;//sqrt(QPointF::dotProduct(vec, vec)); 60 | } 61 | 62 | void Geometry3D::adjustToLength(const QVector3D &, QVector3D &, qreal) 63 | { 64 | } 65 | 66 | void Geometry3D::addLine(QPainterPath &ph, const QPointF &start, const QPointF &end) 67 | { 68 | ph.moveTo(start); 69 | ph.lineTo(end); 70 | } 71 | 72 | void Geometry3D::addArc(QPainterPath &ph, const QRectF &rect, qreal startAngle, qreal arcLength) 73 | { 74 | ph.arcMoveTo(rect, startAngle); 75 | ph.arcTo(rect, startAngle, arcLength); 76 | } 77 | 78 | void Geometry3D::addDotLine(QPainterPath &ph, const QPointF &start, const QPointF &end, qreal width) 79 | { 80 | QPointF u = end - start; 81 | qreal l = GeometryHelper::length(u); 82 | u = u * width / l; 83 | QPointF ps = start; 84 | while (l >= width * 4) { 85 | ph.moveTo(ps); 86 | ph.lineTo(ps + u); 87 | ps = ps + u * 4; 88 | l -= width * 4; 89 | } 90 | if (l > width) 91 | l = width; 92 | if (l > 0) { 93 | ph.moveTo(ps); 94 | ph.lineTo(ps + u * l / width); 95 | } 96 | } 97 | 98 | static qreal dashArc(qreal a, qreal b, qreal t, qreal w) 99 | { 100 | qreal d = b - a; 101 | if (qFuzzyIsNull(d)) 102 | return w / a; 103 | if (t > M_PI_2 * 3) 104 | return dashArc(b, a, M_PI * 2 - t, w); 105 | else if (t > M_PI) 106 | return dashArc(a, b, t - M_PI, w); 107 | else if (t > M_PI_2) 108 | return dashArc(b, a, M_PI - t, w); 109 | d *= M_2_PI; 110 | qreal s = a + d * t; 111 | qreal l = s * s + w * d * 2; 112 | if (l < 0) { 113 | //qDebug() << t * 180 / M_PI; 114 | return w / (a + d * 0.5); 115 | } 116 | return qMin(w / (a + d * 0.5), (sqrt(l) - s) / d); 117 | } 118 | 119 | void Geometry3D::addDotArc(QPainterPath &ph, const QRectF &rect, qreal startAngle, qreal arcLength, qreal width) 120 | { 121 | qreal a = rect.width() * 0.5; 122 | qreal b = rect.height() * 0.5; 123 | //QPointF c = rect.center(); 124 | if (arcLength < 0) width = -width; 125 | while (true) { 126 | qreal r = startAngle * M_PI / 180; 127 | //QPointF p = {a * cos(r), -b * sin(r)}; 128 | //qreal d = sqrt(QPointF::dotProduct(p, p)); 129 | //r = atan(width / d) * 180 / M_PI; 130 | r = dashArc(a, b, r, width) * 180 / M_PI; 131 | //qDebug() << startAngle << r; 132 | if (qAbs(r) > qAbs(arcLength)) 133 | r = arcLength; 134 | ph.arcMoveTo(rect, startAngle); 135 | ph.arcTo(rect, startAngle, r); 136 | if (qAbs(r) >= qAbs(arcLength)) 137 | break; 138 | startAngle += r; 139 | arcLength -= r; 140 | r = startAngle * M_PI / 180; 141 | //p = {a * cos(r), b * sin(r)}; 142 | //d = sqrt(QPointF::dotProduct(p, p)); 143 | //r = atan(width / d * 3) * 180 / M_PI; 144 | r = dashArc(a, b, r, width * 3) * 180 / M_PI; 145 | //qDebug() << startAngle << r; 146 | if (qAbs(r) >= qAbs(arcLength)) 147 | break; 148 | startAngle += r; 149 | arcLength -= r; 150 | } 151 | } 152 | 153 | QPainterPath Geometry3D::combine(QPainterPath const & ph1, QPainterPath const & ph2) 154 | { 155 | QPainterPathStroker ps; 156 | ps.setCapStyle(Qt::RoundCap); 157 | ps.setWidth(width_); 158 | QPainterPath ph = ps.createStroke(ph1); 159 | QVector solid; 160 | ps.setCapStyle(Qt::FlatCap); 161 | ps.setDashPattern(QVector{2.0, 2.0}); 162 | ph |= ps.createStroke(ph2); 163 | return ph; 164 | } 165 | 166 | 167 | Geometry3DFactory::Geometry3DFactory() 168 | { 169 | } 170 | 171 | ResourceView * Geometry3DFactory::create(Resource *res) 172 | { 173 | QString type = res->url().path(); 174 | int n = type.indexOf('/'); 175 | if (n > 0) 176 | type = type.left(n); 177 | return ResourceFactory::create(res, type.toUtf8()); 178 | } 179 | 180 | QUrl Geometry3DFactory::newUrl(const QByteArray &type) const 181 | { 182 | return QUrl("geometry3d:" + type); 183 | } 184 | -------------------------------------------------------------------------------- /geometry2ds/regularpolygon.cpp: -------------------------------------------------------------------------------- 1 | #include "regularpolygon.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | RegularPolygon::RegularPolygon(Resource * res) 12 | : Polygon(res, DrawAttach) 13 | , nEdges_(0) 14 | , nSpan_(0) 15 | { 16 | int edges = 3; 17 | int span = 1; 18 | QByteArray size(res->property(Resource::PROP_SUB_TYPE2).toByteArray()); 19 | int n = size.indexOf('-'); 20 | if (n > 0) { 21 | edges = size.left(n).toInt(); 22 | span = size.mid(n + 1).toInt(); 23 | } else if (!size.isEmpty()){ 24 | edges = size.toInt(); 25 | } 26 | setEdges(edges); 27 | setSpan(span); 28 | } 29 | 30 | RegularPolygon::RegularPolygon(RegularPolygon const & o) 31 | : Polygon(o) 32 | , nEdges_(0) 33 | , nSpan_(0) 34 | { 35 | setEdges(o.nEdges_); 36 | setSpan(o.nSpan_); 37 | } 38 | 39 | RegularPolygon::RegularPolygon(QPointF ¢er, const QPointF &point, int edges, int span) 40 | : Polygon({center, point}) 41 | , nEdges_(0) 42 | , nSpan_(0) 43 | { 44 | setEdges(span == 1 ? edges : (edges << 8 | span)); 45 | } 46 | 47 | class EdgeToolButtons : public OptionToolButtons 48 | { 49 | public: 50 | EdgeToolButtons() 51 | #ifdef QT_DEBUG 52 | : OptionToolButtons({0x501, 0x601, 0x701, 0x801, 0x901, 0xa01, 53 | 0x502, 0x702, 0x703, 0x803, 0x902, 0x904}, 3) 54 | #else 55 | : OptionToolButtons({0x501, 0x601}, 2) 56 | #endif 57 | { 58 | } 59 | protected: 60 | virtual QString buttonTitle(const QVariant &value) override 61 | { 62 | return buttonTitle(value.toInt()); 63 | } 64 | private: 65 | static QString buttonTitle(int n) 66 | { 67 | static QString numberChar; 68 | if (numberChar.isEmpty()) { 69 | QFile file(":/geometry/string/number.txt"); 70 | file.open(QFile::ReadOnly); 71 | numberChar = file.readAll(); 72 | } 73 | int e = n >> 8; 74 | int s = n & 0xff; 75 | return QString("正%1边形").arg(numberChar[e]) + (s == 1 ? "" : QString("%1").arg(s)); 76 | } 77 | }; 78 | static EdgeToolButtons edgeSpanButtons; 79 | REGISTER_OPTION_BUTTONS(RegularPolygon, edgeSpan, edgeSpanButtons) 80 | 81 | void RegularPolygon::setEdges(int n) 82 | { 83 | int s = nSpan_; 84 | if (n > 256) { 85 | s = n & 0xff; 86 | n >>= 8; 87 | } else { 88 | s = 1; 89 | } 90 | if (nEdges_ == n && nSpan_ == s) { 91 | dirty_ = false; 92 | return; 93 | } 94 | nEdges_ = n; 95 | nSpan_ = 0; 96 | qreal radiusAttach = M_PI / 2 - M_PI / nEdges_; 97 | vAngleAttach_ = QPointF(cos(radiusAttach), sin(radiusAttach)); 98 | setSpan(s); 99 | } 100 | 101 | void RegularPolygon::setSpan(int n) 102 | { 103 | if (nSpan_ == n) 104 | return; 105 | nSpan_ = n; 106 | qreal radiusStep = M_PI * 2 * nSpan_ / nEdges_; 107 | vAngleStep_ = QPointF(cos(radiusStep), sin(radiusStep)); 108 | } 109 | 110 | int RegularPolygon::edgeSpan() 111 | { 112 | return nEdges_ << 8 | nSpan_; 113 | } 114 | 115 | int RegularPolygon::pointCount() 116 | { 117 | return points_.size() == 2 ? nEdges_ : 1; 118 | } 119 | 120 | QPointF RegularPolygon::iterPoint(int index, QPointF &hint) 121 | { 122 | QPointF center = points_.front(); 123 | QPointF pt = points_[1]; 124 | hint = pt - center; 125 | if (index == 0) { 126 | return pt; 127 | } else if (index == 1) { 128 | GeometryHelper::reverseRotate(hint, vAngleStep_); 129 | return center + hint; 130 | } else if (index == nEdges_ - 1) { 131 | GeometryHelper::reverseRotate(hint, QPointF(vAngleStep_.x(), -vAngleStep_.y())); 132 | return center + hint; 133 | } else { 134 | qreal radius = M_PI * 2 * nSpan_ * index / nEdges_; 135 | GeometryHelper::reverseRotate(hint, QPointF(cos(radius), sin(radius))); 136 | return center + hint; 137 | } 138 | } 139 | 140 | QPointF RegularPolygon::nextPoint(int index, QPointF &hint) 141 | { 142 | (void) index; 143 | GeometryHelper::reverseRotate(hint, vAngleStep_); 144 | return points_.front() + hint; 145 | } 146 | 147 | QPointF RegularPolygon::prevPoint(int index, QPointF &hint) 148 | { 149 | (void) index; 150 | GeometryHelper::reverseRotate(hint, QPointF(vAngleStep_.x(), -vAngleStep_.y())); 151 | return points_.front() + hint; 152 | } 153 | 154 | bool RegularPolygon::setPoint(int index, const QPointF &pt) 155 | { 156 | (void) index; 157 | Polygon::setPoint(1, pt); 158 | return true; 159 | } 160 | 161 | bool RegularPolygon::moveElememt(int elem, const QPointF &pt) 162 | { 163 | if (elem < nEdges_) { 164 | Polygon::setPoint(1, pt); 165 | QPointF vAngleAttach(-vAngleAttach_.x(), vAngleAttach_.y()); 166 | GeometryHelper::attachToLines(points_[0], {vAngleAttach_, vAngleAttach}, points_[1]); 167 | return true; 168 | } 169 | elem -= nEdges_; 170 | QPointF hint; 171 | QPointF pt0 = points_[0]; 172 | QPointF pt1 = iterPoint(elem, hint); 173 | QPointF pt2 = prevPoint(-1, hint); 174 | QPointF rp; 175 | qreal d = sqrt(GeometryHelper::dist2PointToSegment(pt1, pt2, pt0, rp)); 176 | qreal dd = sqrt(GeometryHelper::dist2PointToSegment(pt1, pt2, pt, rp)); 177 | pt1 = rp - pt0; 178 | pt2 = pt - pt0; 179 | if (GeometryHelper::length2(pt1) < GeometryHelper::length2(pt2)) 180 | dd += d; 181 | else 182 | dd = d - dd; 183 | Polygon::setPoint(1, pt0 + (points_[1] - pt0) * dd / d); 184 | return true; 185 | } 186 | -------------------------------------------------------------------------------- /geometry3ds/polyhedron.cpp: -------------------------------------------------------------------------------- 1 | #include "polyhedron.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | 6 | //#define POLYHEDRON_DEBUG 7 | 8 | Polyhedron::Polyhedron(Resource * res) 9 | : Geometry3D(res) 10 | { 11 | } 12 | 13 | Polyhedron::Polyhedron(Polyhedron const & o) 14 | : Geometry3D(o) 15 | , lines_(o.lines_) 16 | { 17 | } 18 | 19 | bool Polyhedron::commitPoint(const QPointF &pt) 20 | { 21 | if (metaObject() != &Polyhedron::staticMetaObject) { 22 | return Geometry3D::commitPoint(pt); 23 | } 24 | if (pointCount() < 4) 25 | return false; 26 | QPointF d = pt - points_.first(); 27 | if (GeometryHelper::length2(d) >= GeometryHelper::HIT_DIFF_DIFF) 28 | return false; 29 | points_.pop_back(); 30 | return true; 31 | } 32 | 33 | bool Polyhedron::canFinish() 34 | { 35 | return pointCount() > 2; 36 | } 37 | 38 | QPainterPath Polyhedron::visualPath() 39 | { 40 | QPainterPath ph; 41 | if (pointCount() < 4) 42 | return ph; 43 | QVector points(pointCount()); 44 | QVector hidden(pointCount()); 45 | collect(points, hidden); 46 | #ifdef POLYHEDRON_DEBUG 47 | for (int i = 0; i < pointCount(); ++i) { 48 | ph.addText(points[i] + QPointF(10, -5), QString("%1").arg(i)); 49 | } 50 | #endif 51 | QPainterPath ph2; 52 | int last = -1, last2 = -1; 53 | for (int l : lines_) { 54 | int s = l & 0xff; 55 | int e = (l >> 8) & 0xff; 56 | bool h = hidden[s] || hidden[e] || (l >> 16); 57 | if (h) { 58 | if (s != last2) 59 | ph2.moveTo(points[s]); 60 | ph2.lineTo(points[e]); 61 | last2 = e; 62 | } else { 63 | if (s != last) 64 | ph.moveTo(points[s]); 65 | ph.lineTo(points[e]); 66 | last = e; 67 | } 68 | } 69 | return combine(ph, ph2); 70 | } 71 | 72 | QPainterPath Polyhedron::contour() 73 | { 74 | QPainterPath ph; 75 | if (pointCount() < 4) 76 | return ph; 77 | ph.setFillRule(Qt::WindingFill); 78 | QVector points(pointCount()); 79 | QVector hidden(pointCount()); 80 | collect(points, hidden); 81 | /* 82 | int last = -1; 83 | for (int l :lines_) { 84 | int s = l & 0xff; 85 | int e = (l >> 8) & 0xff; 86 | //if (hidden[s] || hidden[e]) continue; 87 | if (s != last) 88 | ph.moveTo(points[s]); 89 | ph.lineTo(points[e]); 90 | last = e; 91 | } 92 | */ 93 | ph.addPolygon(GeometryHelper::smallestEnclosingPolygon(points)); 94 | #ifdef POLYHEDRON_DEBUG 95 | for (int i = 0; i < pointCount(); ++i) { 96 | ph.addText(points[i] + QPointF(10, -5), QFont(), QString("%1").arg(i)); 97 | } 98 | #endif 99 | return ph; 100 | } 101 | 102 | int Polyhedron::pointCount() 103 | { 104 | return points_.size(); 105 | } 106 | 107 | QVector3D Polyhedron::point(int index) 108 | { 109 | return QVector3D(points_[index]); 110 | } 111 | 112 | bool Polyhedron::setPoint(int index, const QVector3D &pt) 113 | { 114 | points_[index] = pt.toPointF(); 115 | return true; 116 | } 117 | 118 | QVector Polyhedron::movePoints() 119 | { 120 | QVector points(pointCount()); 121 | QVector hidden(pointCount()); 122 | collect(points, hidden); 123 | return points; 124 | } 125 | 126 | int Polyhedron::hit(QPointF &pt) 127 | { 128 | QVector points(pointCount()); 129 | QVector hidden(pointCount()); 130 | collect(points, hidden); 131 | return GeometryHelper::attachToPoints(points, pt); 132 | } 133 | 134 | bool Polyhedron::moveElememt(int elem, const QPointF &pt) 135 | { 136 | return Geometry3D::moveElememt(elem, pt); 137 | } 138 | 139 | void Polyhedron::clearLines() 140 | { 141 | lines_.clear(); 142 | dirty_ = true; 143 | } 144 | 145 | void Polyhedron::makeLine(int startIndex, int endIndex) 146 | { 147 | lines_.append(startIndex | endIndex << 8); 148 | } 149 | 150 | void Polyhedron::collect(QVector &points, QVector &hidden) 151 | { 152 | QVector point3ds(pointCount() + lines_.count()); 153 | QVector orders(pointCount() + lines_.count()); 154 | int i = 0; 155 | for (; i < pointCount(); ++i) { 156 | point3ds[i] = point(i); 157 | #ifndef POLYHEDRON_ISOMETRIC_PROJECTION 158 | points[i] = PO.map(point3ds[i]).toPointF(); 159 | #else 160 | points[i] = PI.map(point3ds[i]).toPointF(); 161 | #endif 162 | orders[i] = &point3ds[i]; 163 | hidden[i] = true; 164 | } 165 | for (int j = 0 ; j < lines_.size(); ++j, ++i) { 166 | lines_[j] &= 0xffff; // clear old 167 | int l = lines_[j]; 168 | int r = l >> 8; 169 | l &= 0xff; 170 | point3ds[i] = (point3ds[l] + point3ds[r]) / 2; // line center 171 | orders[i] = &point3ds[i]; 172 | } 173 | i -= lines_.count(); // pointCount() 174 | // sort by y 175 | std::sort(orders.begin(), orders.end(), [](QVector3D*l, QVector3D*r) { 176 | return l->y() < r->y(); 177 | }); 178 | QPolygonF bound; 179 | QVector pts; 180 | for (QVector3D * p : orders) { 181 | QPointF pt(qreal(p->x()) + qreal(p->y()) * CO, qreal(p->z()) + qreal(p->y()) * CO); 182 | int j = int(p - point3ds.data()); 183 | if (bound.containsPoint(pt, Qt::OddEvenFill)) { 184 | if (j >= i) { 185 | int l = lines_[j - i]; 186 | int r = l >> 8; 187 | l &= 0xff; 188 | if (hidden[l] || hidden[r]) 189 | lines_[j - i] |= 0x10000; 190 | } 191 | } else if (j < i) { 192 | hidden[j] = false; 193 | pts.append(pt); 194 | if (pts.size() > 2) 195 | bound = GeometryHelper::smallestEnclosingPolygon(pts); 196 | } 197 | } 198 | } 199 | 200 | /* 201 | * Static functions 202 | */ 203 | 204 | -------------------------------------------------------------------------------- /base/geometryitem.cpp: -------------------------------------------------------------------------------- 1 | #include "geometryitem.h" 2 | #include "geometryhelper.h" 3 | #include "geometry.h" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef SHOWBOARD_QUICK 16 | 17 | #else 18 | 19 | class GeometryEditItem : public QGraphicsPathItem 20 | { 21 | public: 22 | GeometryEditItem(QGraphicsItem * parent) 23 | : QGraphicsPathItem(parent) 24 | { 25 | setPen(QPen(Qt::black, 2.0)); 26 | setBrush(QBrush(Qt::white)); 27 | setAcceptTouchEvents(true); 28 | setCursor(Qt::CrossCursor); 29 | } 30 | 31 | void setEditPoints(QVector const & points) 32 | { 33 | shape_ = QPainterPath(); 34 | shape_.setFillRule(Qt::FillRule::WindingFill); 35 | QPainterPath drawShape; 36 | QRectF circle(0, 0, GeometryHelper::HIT_DIFF * 4, GeometryHelper::HIT_DIFF * 4); 37 | QRectF box(0, 0, GeometryHelper::HIT_DIFF * 1.4, GeometryHelper::HIT_DIFF * 1.4); 38 | for (QPointF const & pt : points) { 39 | circle.moveCenter(pt); 40 | shape_.addEllipse(circle); 41 | box.moveCenter(pt); 42 | drawShape.addEllipse(box); 43 | } 44 | setPath(drawShape); 45 | } 46 | 47 | virtual QPainterPath shape() const override 48 | { 49 | return shape_; 50 | } 51 | 52 | virtual bool sceneEvent(QEvent *event) override 53 | { 54 | switch (event->type()) { 55 | case QEvent::TouchBegin: 56 | case QEvent::TouchUpdate: 57 | case QEvent::TouchEnd: 58 | break; 59 | default: 60 | return QGraphicsPathItem::sceneEvent(event); 61 | } 62 | return event->isAccepted(); 63 | } 64 | 65 | private: 66 | QPainterPath shape_; 67 | }; 68 | 69 | #endif 70 | 71 | GeometryItem::GeometryItem(Geometry * geometry, ControlView * parent) 72 | #ifdef SHOWBOARD_QUICK 73 | : QQuickItem(parent) 74 | #else 75 | : QGraphicsPathItem(parent) 76 | #endif 77 | , geometry_(geometry) 78 | { 79 | #ifdef SHOWBOARD_QUICK 80 | #else 81 | editItem_ = new GeometryEditItem(this); 82 | setFiltersChildEvents(true); 83 | #endif 84 | setAcceptTouchEvents(true); 85 | QMetaObject const * meta = geometry->metaObject(); 86 | int index = meta->indexOfMethod("contains(QPointF)"); 87 | if (index >= 0) 88 | methodContains_ = meta->method(index); 89 | } 90 | 91 | void GeometryItem::setEditPoints(const QVector &points) 92 | { 93 | #ifdef SHOWBOARD_QUICK 94 | (void) points; 95 | #else 96 | static_cast(editItem_)->setEditPoints(points); 97 | #endif 98 | } 99 | 100 | void GeometryItem::showEditor(bool show) 101 | { 102 | editItem_->setVisible(show); 103 | } 104 | 105 | void GeometryItem::setColor(const QColor & color) 106 | { 107 | #ifdef SHOWBOARD_QUICK 108 | (void) color; 109 | #else 110 | QGraphicsPathItem::setBrush(color); 111 | #endif 112 | //editItem_->setPen(QPen(Qt::black, pen.width())); 113 | //editItem_->setBrush(QBrush(pen.color())); 114 | } 115 | 116 | void GeometryItem::setPenWidth(qreal width) 117 | { 118 | #ifdef SHOWBOARD_QUICK 119 | (void) color; 120 | #else 121 | QGraphicsPathItem::setPen(QPen(Qt::black, width)); 122 | #endif 123 | } 124 | 125 | void GeometryItem::setContourPath(const QPainterPath &path) 126 | { 127 | #ifdef SHOWBOARD_QUICK 128 | (void) path; 129 | #else 130 | setPath(path); 131 | update(); // contour may not change 132 | #endif 133 | } 134 | 135 | bool GeometryItem::contains(const QPointF &point) const 136 | { 137 | if (methodContains_.isValid()) { 138 | bool result; 139 | methodContains_.invoke(geometry_, Q_RETURN_ARG(bool, result), Q_ARG(QPointF, point)); 140 | return result; 141 | } 142 | #ifdef SHOWBOARD_QUICK 143 | return false; 144 | #else 145 | return QGraphicsPathItem::contains(point); 146 | #endif 147 | } 148 | 149 | #ifdef SHOWBOARD_QUICK 150 | #else 151 | 152 | void GeometryItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, 153 | QWidget *) 154 | { 155 | painter->save(); 156 | painter->setPen(Qt::NoPen); 157 | painter->setBrush(geometry_->color()); 158 | painter->drawPath(geometry_->visualPath()); 159 | painter->restore(); 160 | } 161 | 162 | bool GeometryItem::sceneEvent(QEvent * event) 163 | { 164 | switch (event->type()) { 165 | case QEvent::GraphicsSceneMousePress: 166 | case QEvent::GraphicsSceneMouseMove: 167 | case QEvent::GraphicsSceneMouseRelease: 168 | case QEvent::TouchBegin: 169 | case QEvent::TouchUpdate: 170 | case QEvent::TouchEnd: 171 | Control::fromItem(this)->event(event); 172 | return event->isAccepted(); 173 | default: 174 | return QGraphicsPathItem::sceneEvent(event); 175 | } 176 | } 177 | 178 | bool GeometryItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event) 179 | { 180 | if (watched != editItem_) { 181 | event->ignore(); 182 | return false; 183 | } 184 | switch (event->type()) { 185 | case QEvent::GraphicsSceneMousePress: 186 | case QEvent::GraphicsSceneMouseMove: 187 | case QEvent::GraphicsSceneMouseRelease: 188 | static_cast(event) 189 | ->setFlags(static_cast(512)); 190 | Control::fromItem(this)->event(event); 191 | return event->isAccepted(); 192 | case QEvent::TouchBegin: 193 | case QEvent::TouchUpdate: 194 | case QEvent::TouchEnd: 195 | static_cast(event) 196 | ->setTouchPointStates(static_cast(512)); 197 | Control::fromItem(this)->event(event); 198 | return false; 199 | default: 200 | return QGraphicsPathItem::sceneEventFilter(watched, event); 201 | } 202 | } 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /rulers/rulertriangle.cpp: -------------------------------------------------------------------------------- 1 | #include "rulertriangle.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | RulerTriangle::RulerTriangle(QVector const & stuns) 10 | : Polygon(new Resource("geometry2d", QUrl("geometry2d:polygon"))) 11 | , stuns_(stuns) 12 | { 13 | } 14 | 15 | void RulerTriangle::addPoint(const QPointF &pt) 16 | { 17 | QPointF stuns[3][2] = { 18 | {stuns_[0], stuns_[1]}, 19 | {stuns_[1], stuns_[2]}, 20 | {stuns_[2], stuns_[0]}, 21 | }; 22 | for (int i = 0; i < 3; ++i) { 23 | QPointF dir = stuns[i][1] - stuns[i][0]; 24 | GeometryHelper::adjustToLength(dir, width() / 2); 25 | dir = QPointF{dir.y(), -dir.x()}; 26 | stuns[i][0] += dir; 27 | stuns[i][1] += dir; 28 | } 29 | for (int i = 0; i < 3; ++i) { 30 | int j = (i + 2) % 3; 31 | stuns_[i] = GeometryHelper::crossPoint(stuns[i][0], stuns[i][1], stuns[j][0], stuns[j][1]); 32 | } 33 | QPointF pt2 = attachToLine(pt); 34 | lastLine_ = curLine_; 35 | startLine_ = endLine_ = curLine_; 36 | Polygon::addPoint(pt2); 37 | } 38 | 39 | void RulerTriangle::movePoint(const QPointF &pt) 40 | { 41 | if (canClose()) 42 | return; 43 | QPointF pt2 = attachToLine(pt); 44 | if (curLine_ < 0) 45 | return; 46 | int diff = (curLine_ - lastLine_ + 4) % 3 - 1; 47 | curLine_ = lastLine_ + diff; 48 | if (curLine_ > startLine_ && curLine_ < endLine_) { 49 | lastLine_ = curLine_; 50 | return; 51 | } 52 | if (curLine_ + 3 < endLine_ || startLine_ + 3 < curLine_) { 53 | startLine_ = 0; 54 | endLine_ = -1; 55 | points_ = stuns_; 56 | dirty_ = true; 57 | qDebug() << "RulerTriangle::movePoint complete" << curLine_; 58 | return; 59 | } 60 | if (diff == 1) { 61 | qDebug() << "RulerTriangle::movePoint inc line" << curLine_; 62 | if (curLine_ > endLine_) { 63 | points_.back() = stuns_[(curLine_ + 3) % 3]; 64 | points_.append(pt2); 65 | endLine_ = lastLine_ = curLine_; 66 | dirty_ = true; 67 | qDebug() << "RulerTriangle::movePoint line range" << startLine_ << endLine_; 68 | return; 69 | } 70 | lastLine_ = curLine_; 71 | } else if (diff == -1) { 72 | qDebug() << "RulerTriangle::movePoint dec line" << curLine_; 73 | if (curLine_ < startLine_) { 74 | points_.front() = stuns_[(lastLine_ + 3) % 3]; 75 | points_.prepend(pt2); 76 | startLine_ = lastLine_ = curLine_; 77 | dirty_ = true; 78 | qDebug() << "RulerTriangle::movePoint line range" << startLine_ << endLine_; 79 | return; 80 | } 81 | lastLine_ = curLine_; 82 | } 83 | // qDebug() << "RulerTriangle::movePoint" << curLine_ << diff << pt; 84 | if (points_.size() > 1) { 85 | QPointF s = startLine_ < curLine_ ? stuns_[(curLine_ + 3) % 3] : points_.front(); 86 | QPointF e = curLine_ < endLine_ ? stuns_[(curLine_ + 4) % 3] : points_.back(); 87 | qreal d = GeometryHelper::dotProduct(pt2 - s, e - pt2); 88 | if (d < 0) { 89 | qreal d2 = GeometryHelper::dotProduct(pt2 - s, e - s); 90 | if (d2 < 0) { 91 | if (curLine_ == startLine_) { 92 | points_.front() = pt2; 93 | } else { 94 | return; 95 | } 96 | } else { 97 | if (curLine_ == endLine_) { 98 | points_.back() = pt2; 99 | } else { 100 | return; 101 | } 102 | } 103 | if (startLine_ + 3 == endLine_) { 104 | s = stuns_[(curLine_ + 3) % 3]; 105 | e = stuns_[(curLine_ + 4) % 3]; 106 | qreal d3 = GeometryHelper::dotProduct(points_.front() - points_.back(), e - s); 107 | if (d3 < 0) { 108 | startLine_ = 0; 109 | endLine_ = -1; 110 | points_ = stuns_; 111 | qDebug() << "RulerTriangle::movePoint complete" << curLine_; 112 | } 113 | } 114 | } else { 115 | return; 116 | } 117 | } else { 118 | QPointF s = stuns_[(curLine_ + 3) % 3]; 119 | QPointF e = stuns_[(curLine_ + 4) % 3]; 120 | qreal d2 = GeometryHelper::dotProduct(e - s, pt2 - points_.front()); 121 | if (d2 < 0) { 122 | points_.prepend(pt2); 123 | } else { 124 | points_.append(pt2); 125 | } 126 | } 127 | dirty_ = true; 128 | // qDebug() << "RulerTriangle::movePoint" << startLine_ << curLine_ << endLine_ << points_; 129 | } 130 | 131 | bool RulerTriangle::commitPoint(const QPointF &pt) 132 | { 133 | movePoint(pt); 134 | return true; 135 | } 136 | 137 | bool RulerTriangle::canClose() 138 | { 139 | return endLine_ < startLine_; 140 | } 141 | 142 | QPointF RulerTriangle::attachToLine(const QPointF &pt) 143 | { 144 | QPointF pts[3]; 145 | qreal len[3] = {0}; 146 | for (int i = 0; i < 3; ++i) { 147 | QPointF d = stuns_[(i + 1) % 3] - stuns_[i]; 148 | qreal dot1 = GeometryHelper::dotProduct(d, pt - stuns_[i]); 149 | qreal dot2 = GeometryHelper::length2(d); 150 | qreal r = dot1 / dot2; 151 | pts[i] = stuns_[i] + d * r; 152 | len[i] = GeometryHelper::length2(pts[i] - pt); 153 | } 154 | int l = len[0]; 155 | curLine_ = 0; 156 | if (len[1] < l) { 157 | l = len[1]; 158 | curLine_ = 1; 159 | } 160 | if (len[2] < l) { 161 | l = len[2]; 162 | curLine_ = 2; 163 | } 164 | QPointF s = stuns_[curLine_]; 165 | QPointF e = stuns_[(curLine_ + 1) % 3]; 166 | QPointF p = pts[curLine_]; 167 | if (GeometryHelper::dotProduct(p - s, e - p) < 0) { 168 | curLine_ = -1; 169 | return pt; 170 | } 171 | // qDebug() << "RulerTriangle::attachToLine" << pt << curLine_ << pts[curLine_]; 172 | return p; 173 | } 174 | -------------------------------------------------------------------------------- /rulers/ruleritem.cpp: -------------------------------------------------------------------------------- 1 | #include "ruleritem.h" 2 | #include "rulertool.h" 3 | #include "ruler.h" 4 | #include "base/geometryhelper.h" 5 | #include "base/geometrycontrol.h" 6 | #include "base/geometry.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | RulerItem::RulerItem(Ruler * ruler, QGraphicsItem *parent) 19 | : QGraphicsItem(parent) 20 | { 21 | GeometryHelper::init(); 22 | ruler_ = ruler; 23 | deleteItem_ = iconItem(":/geometry/icon/ruler/delete.svg"); 24 | adjustItem_ = iconItem(":/geometry/icon/ruler/adjust.svg"); 25 | rotateItem_ = iconItem(":/geometry/icon/ruler/rotate.svg"); 26 | setFiltersChildEvents(true); 27 | adjustControlPositions(); 28 | } 29 | 30 | RulerItem::~RulerItem() 31 | { 32 | } 33 | 34 | QRectF RulerItem::boundingRect() const 35 | { 36 | return QRectF(0, 0, ruler_->width_, ruler_->height_); 37 | } 38 | 39 | QPainterPath RulerItem::shape() const 40 | { 41 | return ruler_->shape_; 42 | } 43 | 44 | bool RulerItem::sceneEvent(QEvent *event) 45 | { 46 | switch (event->type()) { 47 | case QEvent::GraphicsSceneMousePress: { 48 | Geometry * geometry = ruler_->createGeometry(); 49 | if (geometry == nullptr) 50 | break; 51 | geometry->transform() *= ruler_->transform().rotate(); 52 | geometry->transform().translate(scenePos()); 53 | RulerTool *control = qobject_cast(RulerTool::fromItem(this)); 54 | geometry_ = control->addGeometry(geometry); 55 | geometry_->event(event); 56 | break; 57 | } 58 | case QEvent::GraphicsSceneMouseMove: 59 | if (geometry_ != nullptr) { 60 | geometry_->event(event); 61 | } 62 | break; 63 | case QEvent::GraphicsSceneMouseRelease: 64 | if (geometry_ != nullptr) { 65 | geometry_->event(event); 66 | RulerTool *control = qobject_cast(RulerTool::fromItem(this)); 67 | control->finishGeometry(geometry_); 68 | } 69 | geometry_ = nullptr; 70 | break; 71 | default: 72 | return QGraphicsItem::sceneEvent(event); 73 | break; 74 | } 75 | return true; 76 | } 77 | 78 | bool RulerItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event) 79 | { 80 | if (watched != deleteItem_ && watched != rotateItem_ && watched != adjustItem_){ 81 | return false; 82 | } 83 | QGraphicsSceneMouseEvent *mouseEvent = static_cast(event); 84 | switch (event->type()) { 85 | case QEvent::GraphicsSceneHoverEnter: 86 | static_cast(watched)->setBrush(Qt::gray); 87 | break; 88 | case QEvent::GraphicsSceneMousePress: { 89 | static_cast(watched)->setBrush(Qt::gray); 90 | isPressed = true; 91 | QPointF mousePos = mouseEvent->scenePos(); 92 | if (watched == adjustItem_) 93 | mousePos = mapFromScene(mousePos); 94 | lastPoint_ = mousePos; 95 | break; 96 | } 97 | case QEvent::GraphicsSceneMouseMove: { 98 | QPointF mousePos = mouseEvent->scenePos(); 99 | RulerTool *control = qobject_cast(RulerTool::fromItem(this)); 100 | if (watched == rotateItem_) { 101 | control->rotate(mapToParent(ruler_->rotateCenter_), lastPoint_, mousePos); 102 | } else if (watched == adjustItem_) { 103 | mousePos = mapFromScene(mousePos); 104 | QPointF offset = ruler_->adjust(mousePos - lastPoint_); 105 | offset = control->resource()->transform().rotate().map(offset); 106 | mousePos -= offset; 107 | control->move(offset); 108 | control->sizeChanged(); 109 | adjustControlPositions(); 110 | } 111 | lastPoint_ = mousePos; 112 | } 113 | break; 114 | case QEvent::GraphicsSceneMouseRelease: 115 | static_cast(watched)->setBrush(QBrush()); 116 | if (watched == deleteItem_) { 117 | ruler_->removeFromPage(); 118 | } 119 | isPressed = false; 120 | break; 121 | case QEvent::GraphicsSceneHoverLeave: 122 | static_cast(watched)->setBrush(QBrush()); 123 | break; 124 | default: 125 | break; 126 | } 127 | return true; 128 | } 129 | 130 | void RulerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) 131 | { 132 | painter->setPen(Qt::NoPen); 133 | painter->setBrush(QColor(250, 250, 250, 100)); 134 | painter->drawPath(ruler_->shape1_); 135 | painter->setBrush(QColor(250, 250, 250, 160)); 136 | painter->drawPath(ruler_->shape2_); 137 | painter->setPen(QPen(Qt::black, 1)); 138 | painter->setRenderHints(QPainter::TextAntialiasing); 139 | painter->setFont(GeometryHelper::TEXT_FONT); 140 | ruler_->onDraw(painter); 141 | } 142 | 143 | void RulerItem::updateShape() 144 | { 145 | prepareGeometryChange(); 146 | ruler_->updateShape(); 147 | } 148 | 149 | void RulerItem::adjustControlPositions() 150 | { 151 | QVector points = ruler_->getControlPositions(); 152 | deleteItem_->setPos(points[0]); 153 | adjustItem_->setPos(points[1]); 154 | rotateItem_->setPos(points[2]); 155 | } 156 | 157 | QGraphicsItem *RulerItem::iconItem(QString const & url) 158 | { 159 | QPixmap icon(url); 160 | QGraphicsPathItem * back = new QGraphicsPathItem(this); 161 | back->setPen(QPen(Qt::darkGray, 2)); 162 | int add = icon.width() / 4; 163 | QPainterPath path; path.addEllipse({{0, 0}, icon.size() + QSize(add, add) * 2}); 164 | back->setPath(path); 165 | back->setAcceptedMouseButtons(Qt::LeftButton); 166 | back->setAcceptHoverEvents(true); 167 | back->setTransform(QTransform::fromTranslate(-icon.width() / 2 - add, 168 | -icon.height() / 2 - add)); 169 | QGraphicsPixmapItem * item = new QGraphicsPixmapItem(back); 170 | item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); 171 | item->setTransformationMode(Qt::SmoothTransformation); 172 | item->setPixmap(icon); 173 | item->setPos(add, add); 174 | return back; 175 | } 176 | 177 | -------------------------------------------------------------------------------- /base/geometry.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry.h" 2 | #include "geometryhelper.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | using namespace QtPromise; 14 | 15 | Geometry::Geometry(Resource * res, Flags flags, Flags clearFlags) 16 | : ResourceView(res, flags | CanCopy, clearFlags) 17 | , dirty_(false) 18 | , color_("#FFF0F0F0") 19 | , width_(GeometryHelper::DEFAULT_LINE_WIDTH) 20 | { 21 | } 22 | 23 | Geometry::Geometry(Geometry const & o) 24 | : ResourceView(o) 25 | , points_(o.points_) 26 | , dirty_(o.dirty_) 27 | , color_(o.color_) 28 | , width_(o.width_) 29 | { 30 | } 31 | 32 | Geometry::Geometry(QByteArray const & type, const QVector &points) 33 | : Geometry(new Resource(type, QUrl(type + ":"))) 34 | { 35 | points_ = points; 36 | dirty_ = true; 37 | } 38 | 39 | QPromise Geometry::load() 40 | { 41 | if (!Geometry::empty()) 42 | return QPromise::resolve(); 43 | auto life(this->life()); 44 | return res_->getStream().then([this, life](QSharedPointer s) { 45 | if (life.isNull()) 46 | return; 47 | QDataStream ds(s.get()); 48 | int n = 0; 49 | qreal x, y; 50 | ds >> n; 51 | while (n) { 52 | ds >> x >> y; 53 | points_.append(QPointF(x, y)); 54 | ++n; 55 | } 56 | }); 57 | } 58 | 59 | bool Geometry::setOption(const QByteArray &key, QVariant value) 60 | { 61 | QVariant old = getOption(key); 62 | if (!ResourceView::setOption(key, value)) 63 | return false; 64 | QVariant crt = getOption(key); 65 | if (old != crt) { 66 | RecordMergeScope rs(this); 67 | if (rs) 68 | rs.add(MakeFunctionRecord([this, key, old]() { 69 | setOption(key, old); 70 | }, [this, key, crt]() { 71 | setOption(key, crt); 72 | })); 73 | dirty_ = true; 74 | emit changed(key); 75 | } 76 | return true; 77 | } 78 | 79 | bool Geometry::empty() const 80 | { 81 | return points_.isEmpty(); 82 | } 83 | 84 | bool Geometry::finished() const 85 | { 86 | return flags_ & DrawFinised; 87 | } 88 | 89 | void Geometry::clear() 90 | { 91 | points_.clear(); 92 | } 93 | 94 | void Geometry::addPoint(const QPointF &pt) 95 | { 96 | points_.append(pt); 97 | dirty_ = true; 98 | } 99 | 100 | void Geometry::movePoint(const QPointF &pt) 101 | { 102 | if (points_.size() == 1) { 103 | points_.append(pt); 104 | } else { 105 | points_.back() = pt; 106 | if (flags_ & DrawAttach) 107 | moveElememt(points_.size() - 1, pt); 108 | } 109 | dirty_ = true; 110 | } 111 | 112 | bool Geometry::commitPoint(const QPointF & pt) 113 | { 114 | (void) pt; 115 | if (points_.size() == 1) { 116 | movePoint(points_.first() + QPointF(80, 80)); 117 | } 118 | return true; 119 | } 120 | 121 | bool Geometry::moveTempPoint(const QPointF &pt) 122 | { 123 | (void) pt; 124 | return false; 125 | } 126 | 127 | void Geometry::sync() 128 | { 129 | dirty_ = false; 130 | } 131 | 132 | bool Geometry::canFinish() 133 | { 134 | return false; 135 | } 136 | 137 | void Geometry::finish(const QPointF &c) 138 | { 139 | for (int i = 0; i < points_.size(); ++i) 140 | { 141 | QPointF & pt = points_[i]; 142 | pt -= c; 143 | } 144 | // ignore scale transform 145 | transform_->translate(transform_->rotate().map(c)); 146 | flags_ |= DrawFinised; 147 | dirty_ = true; 148 | } 149 | 150 | void Geometry::scale(qreal scale) 151 | { 152 | for (int i = 0; i < points_.size(); ++i) 153 | { 154 | QPointF & pt = points_[i]; 155 | pt *= scale; 156 | } 157 | dirty_ = true; 158 | } 159 | 160 | void Geometry::setColor(QColor color) 161 | { 162 | color_ = color; 163 | GeometryHelper::setDefaultColor(qobject_cast(parent()), color); 164 | } 165 | 166 | void Geometry::setWidth(qreal width) 167 | { 168 | width_ = width; 169 | } 170 | 171 | void Geometry::init() 172 | { 173 | color_ = GeometryHelper::defaultColor(qobject_cast(parent())); 174 | } 175 | 176 | QVector Geometry::movePoints() 177 | { 178 | return points_; 179 | } 180 | 181 | QObject *Geometry::toQuickPath(QObject * context) 182 | { 183 | QQuickShapePath * shape = QQuickShapePath::create(context); 184 | shape->setStrokeColor(QColor(Qt::transparent)); 185 | shape->setStrokeWidth(0); 186 | shape->setFillColor(color_); 187 | shape->addPath(visualPath()); 188 | return shape; 189 | } 190 | 191 | int Geometry::hit(QPointF & pt) 192 | { 193 | for (int i = 0; i < points_.size(); ++i) { 194 | QPointF d = pt - points_[i]; 195 | if (GeometryHelper::length2(d) < GeometryHelper::HIT_DIFF_DIFF) { 196 | pt = points_[i]; 197 | return i; 198 | } 199 | } 200 | return -1; 201 | } 202 | 203 | void Geometry::beginMove(int) 204 | { 205 | setProperty("editStartPoints", QVariant::fromValue(points_)); 206 | setProperty("editStartOffset", transform().offset()); 207 | } 208 | 209 | bool Geometry::moveElememt(int elem, const QPointF &pt) 210 | { 211 | if (elem < points_.size()) { 212 | points_[elem] = pt; 213 | dirty_ = true; 214 | return true; 215 | } 216 | return false; 217 | } 218 | 219 | void Geometry::endMove(int) 220 | { 221 | auto points = property("editStartPoints").value>(); 222 | QPointF off = property("editStartOffset").value() - transform().offset(); 223 | for (auto & p : points) 224 | p += off; 225 | auto points2 = points_; 226 | for (auto & p : points2) 227 | p -= off; 228 | if (!points.isEmpty()) { 229 | RecordMergeScope rs(this); 230 | if (rs) 231 | rs.add(MakeFunctionRecord([this, points]() { 232 | points_ = points; dirty_ = true; emit changed("shape"); 233 | }, [this, points2]() { 234 | points_ = points2; dirty_ = true; emit changed("shape"); 235 | })); 236 | setProperty("editStartPoints", QVariant()); 237 | } 238 | } 239 | 240 | QPainterPath Geometry::graphPath() 241 | { 242 | return QPainterPath(); 243 | } 244 | 245 | QPainterPath Geometry::textPath() 246 | { 247 | return QPainterPath(); 248 | } 249 | 250 | QPainterPath Geometry::contour() 251 | { 252 | QPainterPath ph = graphPath(); 253 | QPainterPath ph2 = textPath(); 254 | if (!ph2.isEmpty() || !ph.contains(ph2)) 255 | ph |= ph2; 256 | return ph; 257 | } 258 | 259 | QPainterPath Geometry::visualPath() 260 | { 261 | QPainterPathStroker ps; 262 | ps.setCapStyle(Qt::RoundCap); 263 | ps.setWidth(width_); 264 | QPainterPath ph = ps.createStroke(graphPath()); 265 | ph |= textPath(); 266 | return ph; 267 | } 268 | -------------------------------------------------------------------------------- /geometry3ds/regularprismoid.cpp: -------------------------------------------------------------------------------- 1 | #include "regularprismoid.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | static EdgesToolButtons edgesButtons("正%1棱台"); 12 | REGISTER_OPTION_BUTTONS(RegularPrismoid, edges, edgesButtons) 13 | 14 | RegularPrismoid::RegularPrismoid(Resource * res) 15 | : RegularPrismoid(res, 0.5) 16 | { 17 | } 18 | 19 | RegularPrismoid::RegularPrismoid(RegularPrismoid const & o) 20 | : Polyhedron(o) 21 | , nEdges_(o.nEdges_) 22 | , ratio_(o.ratio_) 23 | , vAngleStep_(o.vAngleStep_) 24 | , vAngleInit_(o.vAngleInit_) 25 | { 26 | } 27 | 28 | RegularPrismoid::RegularPrismoid(Resource *res, qreal ratio) 29 | : Polyhedron(res) 30 | , ratio_(ratio) 31 | { 32 | setToolsString("edges|边数|Popup,OptionsGroup,NeedUpdate|;"); 33 | 34 | int edges = 3; 35 | QByteArray size(res->property(Resource::PROP_SUB_TYPE2).toByteArray()); 36 | if (!size.isEmpty()) 37 | edges = size.toInt(); 38 | setEdges(edges); 39 | } 40 | 41 | void RegularPrismoid::makeLines() 42 | { 43 | for (int i = 0; i < nEdges_; ++i) { 44 | int j = (i + 1) % nEdges_; 45 | makeLine(i, j); 46 | makeLine(i, i + nEdges_); 47 | makeLine(i + nEdges_, j + nEdges_); 48 | } 49 | } 50 | 51 | void RegularPrismoid::setEdges(int n) 52 | { 53 | if (nEdges_ == n) { 54 | dirty_ = false; 55 | return; 56 | } 57 | nEdges_ = n; 58 | qreal radiusStep = M_PI * 2 / nEdges_; 59 | vAngleStep_ = QPointF(cos(radiusStep), sin(radiusStep)); 60 | qreal radiusInit = M_PI / 2 - M_PI / nEdges_; 61 | if (nEdges_ > 4) 62 | radiusInit -= M_PI * 2 / nEdges_; 63 | vAngleInit_ = QPointF(cos(radiusInit), sin(radiusInit)); 64 | clearLines(); 65 | // delay makeLines, not call from constructor 66 | } 67 | 68 | int RegularPrismoid::pointCount() 69 | { 70 | return points_.size() == 2 ? nEdges_ * 2 : 0; 71 | } 72 | 73 | /* 74 | * p1 -> (x0, y0, z0 + h) 75 | * p2 -> (x0 + r*cos(t), y0 - r*sin(t), z0) 76 | * y0 = 0 77 | * ==> 78 | * X1 = x0 79 | * Y1 = -z0 - h 80 | * X2 = x0 + cos(t)*r - C*sin(t)*r 81 | * Y2 = C*sin(t)*r - z0 82 | * ==> 83 | * x0 = X1 84 | * y0 = 0 (define) 85 | * z0 = C*r*sin(t) - Y2 86 | * h = -Y1 - z0 87 | * r = (X2 - X1) / (cos(t) - C*sin(t)) 88 | */ 89 | 90 | QVector3D RegularPrismoid::point(int index) 91 | { 92 | QVector3D pt3(size_); 93 | if (index < nEdges_) { 94 | pt3.setX(pt3.x() * float(ratio_)); 95 | pt3.setY(pt3.y() * float(ratio_)); 96 | } else { 97 | index -= nEdges_; 98 | pt3.setZ(0); 99 | } 100 | QPointF pt(pt3.toPoint()); 101 | if (index == 1) { 102 | GeometryHelper::reverseRotate(pt, vAngleStep_); 103 | } else if (index == nEdges_ - 1) { 104 | GeometryHelper::rotate(pt, vAngleStep_); 105 | } else { 106 | qreal radius = M_PI * 2 * index / nEdges_; 107 | GeometryHelper::reverseRotate(pt, QPointF(cos(radius), sin(radius))); 108 | } 109 | pt3.setX(float(pt.x())); 110 | pt3.setY(float(pt.y())); 111 | return origin_ + pt3; 112 | } 113 | 114 | QVector RegularPrismoid::movePoints() 115 | { 116 | QVector mpts = Polyhedron::movePoints(); 117 | if (ratio_ > 0) 118 | mpts.append(points_[0]); 119 | mpts.append(points_[0] + QPointF(0, qreal(size_.z()))); 120 | return mpts; 121 | } 122 | 123 | bool RegularPrismoid::moveElememt(int elem, const QPointF &pt) 124 | { 125 | QPointF pt2 = pt; 126 | if (elem < nEdges_ * 2) { 127 | qreal dx = pt.x() - points_[0].x(); // x + Cy 128 | qreal dy = pt.y() - points_[0].y(); // -Cy 129 | if (elem >= nEdges_) 130 | dy -= qreal(size_.z()); 131 | QPointF pt3(dx + dy, -dy / CO); 132 | if (elem > 0) { 133 | qreal radius = M_PI * 2 * elem / nEdges_; 134 | GeometryHelper::rotate(pt3, QPointF(cos(radius), sin(radius))); // reverse 135 | QVector3D ptm = PO.map(QVector3D(pt3) + origin_); 136 | pt2 = ptm.toPointF(); 137 | } else { 138 | pt2.setY(pt2.y() + qreal(size_.z())); 139 | } 140 | vAngleInit_ = QPointF(pt3.x(), -pt3.y()); 141 | GeometryHelper::adjustToLength(vAngleInit_, 1); 142 | if (metaObject() == &staticMetaObject) { 143 | if (elem < nEdges_) { 144 | ratio_ = GeometryHelper::length(pt3) / GeometryHelper::length(size_.toPointF()); 145 | size_.setX(float(pt3.x() / ratio_)); 146 | size_.setY(float(pt3.y() / ratio_)); 147 | pt2 = PO.map(QVector3D(size_.toPointF()) + origin_).toPointF(); 148 | } else { 149 | ratio_ /= GeometryHelper::length(pt3) / GeometryHelper::length(size_.toPointF()); 150 | size_.setX(float(pt3.x())); 151 | size_.setY(float(pt3.y())); 152 | qDebug() << "size_" << __LINE__ << size_; 153 | } 154 | } else { 155 | size_.setX(float(pt3.x())); 156 | size_.setY(float(pt3.y())); 157 | qDebug() << "size_" << __LINE__ << size_; 158 | } 159 | elem = 1; 160 | } else if (elem == nEdges_ * 2) { 161 | size_.setZ(float(-pt.y()) - origin_.z()); 162 | qDebug() << "size_" << __LINE__ << size_; 163 | pt2.setX(points_[0].x()); 164 | elem = 0; 165 | } else { 166 | float d = float(pt.y()) + origin_.z(); 167 | origin_.setZ(float(-pt.y())); 168 | size_.setZ(size_.z() + d); 169 | qDebug() << "size_" << __LINE__ << size_; 170 | pt2.setX(points_[1].x()); 171 | pt2.setY(points_[1].y() + qreal(d)); 172 | elem = 1; 173 | } 174 | Polyhedron::moveElememt(elem, pt2); 175 | dirty_ = false; 176 | return true; 177 | } 178 | 179 | void RegularPrismoid::sync() 180 | { 181 | if (dirty_ && points_.size() > 1) { 182 | if (lines_.empty()) 183 | makeLines(); 184 | qreal x0 = points_[0].x(); 185 | qreal y0 = 0; 186 | qreal r = (points_[1].x() - x0) / (vAngleInit_.x() - CO * vAngleInit_.y()); 187 | qreal z0 = -points_[1].y() + CO * r * vAngleInit_.y(); 188 | qreal h = -points_[0].y() - z0; 189 | origin_ = QVector3D(float(x0), float(y0), float(z0)); 190 | size_ = QVector3D(float(r * vAngleInit_.x()), float(-r * vAngleInit_.y()), float(h)); 191 | dirty_ = false; 192 | } 193 | } 194 | 195 | EdgesToolButtons::EdgesToolButtons(QString const & title) 196 | : OptionToolButtons({3, 4, 5, 6, 7, 8}, 3) 197 | , title_(title) 198 | { 199 | } 200 | 201 | QString EdgesToolButtons::buttonTitle(const QVariant &value) 202 | { 203 | return buttonTitle(title_, value.toInt()); 204 | } 205 | 206 | QString EdgesToolButtons::buttonTitle(QString const & title, int n) 207 | { 208 | static QString numberChar; 209 | if (numberChar.isEmpty()) { 210 | QFile file(":/geometry/string/number.txt"); 211 | file.open(QFile::ReadOnly); 212 | numberChar = file.readAll(); 213 | } 214 | return title.arg(numberChar[n]); 215 | } 216 | -------------------------------------------------------------------------------- /geometry2ds/polygon.cpp: -------------------------------------------------------------------------------- 1 | #include "polygon.h" 2 | #include "base/geometryhelper.h" 3 | #include "regularpolygon.h" 4 | 5 | #include 6 | 7 | #include 8 | 9 | static WidthToolButtons buttonRadius({0, 2.0, 4.0, 8.0, 16.0, 32.0}); 10 | REGISTER_OPTION_BUTTONS(Polygon, radius, buttonRadius); 11 | 12 | Polygon::Polygon(Resource * res, Flags flags) 13 | : Geometry2D(res, flags) 14 | , radius_(0) 15 | { 16 | } 17 | 18 | Polygon::Polygon(Polygon const & o) 19 | : Geometry2D(o) 20 | , graphPath_(o.graphPath_) 21 | , textPath_(o.textPath_) 22 | , radius_(o.radius_) 23 | { 24 | } 25 | 26 | Polygon::Polygon(const QPolygonF &polygon) 27 | : Geometry2D(polygon.mid(0, polygon.size() - 1)) 28 | , radius_(0) 29 | { 30 | } 31 | 32 | Polygon::Polygon(const QVector &points) 33 | : Geometry2D(points) 34 | , radius_(0) 35 | { 36 | } 37 | 38 | QPainterPath Polygon::graphPath() 39 | { 40 | return graphPath_; 41 | } 42 | 43 | QPainterPath Polygon::textPath() 44 | { 45 | return textPath_; 46 | } 47 | 48 | QVector Polygon::movePoints() 49 | { 50 | QVector points(pointCount() * 2); 51 | QPointF hint; 52 | QPointF first = firstPoint(hint); 53 | QPointF pt0 = first; 54 | points[0] = pt0; 55 | for (int i = 1; i < pointCount(); ++i) { 56 | QPointF pt(nextPoint(i, hint)); 57 | points[i] = pt; 58 | points[pointCount() + i] = (pt0 + pt) / 2.0; 59 | pt0 = pt; 60 | } 61 | if (pointCount() > 2) { 62 | if (canClose()) { 63 | points[pointCount()] = (pt0 + first) / 2.0; 64 | } else { 65 | points.removeAt(pointCount()); 66 | } 67 | } else { 68 | points.resize(pointCount()); 69 | } 70 | return points; 71 | } 72 | 73 | int Polygon::hit(QPointF & pt) 74 | { 75 | QPointF hint; 76 | QPointF rp; 77 | QPointF lpt = lastPoint(hint); 78 | int line = -1; 79 | for (int i = 0; i < pointCount(); ++i) { 80 | QPointF cpt = nextPoint(i, hint); 81 | QPointF d = pt - cpt; 82 | if (GeometryHelper::length2(d) < GeometryHelper::HIT_DIFF_DIFF) { 83 | pt = cpt; 84 | return i; 85 | } 86 | if (line == -1 && GeometryHelper::dist2PointToSegment(lpt, cpt, pt, rp) < GeometryHelper::HIT_DIFF_DIFF) { 87 | pt = rp; 88 | line = i + pointCount(); 89 | } 90 | lpt = cpt; 91 | } 92 | if (!canClose()) { 93 | if (line == pointCount()) 94 | line = -1; 95 | else 96 | line -= 1; 97 | } 98 | return line; 99 | } 100 | 101 | bool Polygon::moveElememt(int elem, const QPointF &pt) 102 | { 103 | if (elem < pointCount()) { 104 | return setPoint(elem, pt); 105 | } 106 | elem -= pointCount(); 107 | if (elem >= pointCount()) 108 | return false; 109 | if (!canClose()) 110 | elem += 1; 111 | QPointF hint; 112 | QPointF llpt = iterPoint((pointCount() + elem - 2) % pointCount(), hint); 113 | QPointF lpt = nextPoint((pointCount() + elem - 1) % pointCount(), hint); 114 | QPointF npt = nextPoint(elem, hint); 115 | QPointF nnpt = nextPoint((elem + 1) % pointCount(), hint); 116 | if (!canClose()) { 117 | if (elem == 1) { 118 | llpt = lpt + nnpt - npt; 119 | } else if (elem == pointCount() - 1) { 120 | nnpt = npt + llpt - lpt; 121 | } 122 | } 123 | moveLine(llpt, lpt, pt, npt, nnpt); 124 | setPoint((pointCount() + elem - 1) % pointCount(), lpt); 125 | setPoint(elem, npt); 126 | return true; 127 | } 128 | 129 | void Polygon::sync() 130 | { 131 | if (!dirty_) 132 | return; 133 | dirty_ = false; 134 | int pointCount = this->pointCount(); 135 | if (pointCount < 2) 136 | return; 137 | bool canClose = this->canClose(); 138 | QPainterPath ph; 139 | QPainterPath tph; 140 | QPolygonF polygon; 141 | QPointF hint; 142 | QPointF first = firstPoint(hint); 143 | polygon.append(first); 144 | for (int i = 1; i < pointCount; ++i) 145 | polygon.append(nextPoint(i, hint)); 146 | if (canClose) { 147 | polygon.append(first); 148 | } 149 | if (qFuzzyIsNull(radius_)) 150 | ph.addPolygon(polygon); 151 | else 152 | ph = GeometryHelper::toRoundPolygon(polygon, radius_); 153 | if (pointCount > 2 && qFuzzyIsNull(radius_)) { 154 | QPointF lpt = lastPoint(hint); 155 | QPointF cpt = nextPoint(0, hint); 156 | int i = 0; 157 | if (!canClose) { 158 | lpt = cpt; 159 | cpt = nextPoint(++i, hint); 160 | } 161 | for (; i < pointCount - 1; ++i) { 162 | QPointF npt = nextPoint(i + 1, hint); 163 | addAngleLabeling(ph, tph, lpt, cpt, npt); 164 | lpt = cpt; 165 | cpt = npt; 166 | } 167 | if (canClose) 168 | addAngleLabeling(ph, tph, lpt, cpt, first); 169 | } 170 | graphPath_ = ph; 171 | textPath_ = tph; 172 | } 173 | 174 | bool Polygon::canClose() 175 | { 176 | return true; 177 | } 178 | 179 | bool Polygon::moveKeepAngle(int elem, const QPointF &pt) 180 | { 181 | if (elem >= pointCount()) 182 | return false; 183 | QPointF hint; 184 | QPointF llpt = iterPoint((pointCount() + elem - 2) % pointCount(), hint); 185 | QPointF lpt = nextPoint((pointCount() + elem - 1) % pointCount(), hint); 186 | QPointF npt = nextPoint(elem, hint); 187 | QPointF nnpt = nextPoint((elem + 1) % pointCount(), hint); 188 | moveLine(llpt, lpt, pt, npt, nnpt); 189 | setPoint((pointCount() + elem - 1) % pointCount(), lpt); 190 | QPointF nnnpt = nextPoint((elem + 2) % pointCount(), hint); 191 | moveLine(lpt, npt, pt, nnpt, nnnpt); 192 | setPoint((pointCount() + elem + 1) % pointCount(), nnpt); 193 | setPoint(elem, pt); 194 | return true; 195 | } 196 | 197 | qreal Polygon::angle(int index) 198 | { 199 | QPointF hint; 200 | QPointF lpt = iterPoint((pointCount() + index - 1) % pointCount(), hint); 201 | QPointF pt = nextPoint(index, hint); 202 | QPointF npt = nextPoint((index + 1) % pointCount(), hint); 203 | return GeometryHelper::angle(lpt, pt, npt); 204 | } 205 | 206 | void Polygon::addAngleLabeling(QPainterPath &path, QPainterPath &textPath, int index) 207 | { 208 | QPointF hint; 209 | QPointF lpt = iterPoint((pointCount() + index - 1) % pointCount(), hint); 210 | QPointF pt = nextPoint(index, hint); 211 | QPointF npt = nextPoint((index + 1) % pointCount(), hint); 212 | addAngleLabeling(path, textPath, lpt, pt, npt); 213 | } 214 | 215 | int Polygon::pointCount() 216 | { 217 | return points_.size(); 218 | } 219 | 220 | QPointF Polygon::point(int index) 221 | { 222 | return points_[index]; 223 | } 224 | 225 | bool Polygon::setPoint(int index, const QPointF &pt) 226 | { 227 | points_[index] = pt; 228 | dirty_ = true; 229 | return true; 230 | } 231 | 232 | QPointF Polygon::lastPoint(QPointF & hint) 233 | { 234 | return iterPoint(pointCount() - 1, hint); 235 | } 236 | 237 | QPointF Polygon::firstPoint(QPointF & hint) 238 | { 239 | return iterPoint(0, hint); 240 | } 241 | 242 | QPointF Polygon::iterPoint(int index, QPointF & hint) 243 | { 244 | (void) hint; 245 | return point(index); 246 | } 247 | 248 | QPointF Polygon::prevPoint(int index, QPointF & hint) 249 | { 250 | (void) hint; 251 | return point(index); 252 | } 253 | 254 | QPointF Polygon::nextPoint(int index, QPointF & hint) 255 | { 256 | (void) hint; 257 | return point(index); 258 | } 259 | -------------------------------------------------------------------------------- /geometry2ds/sector.cpp: -------------------------------------------------------------------------------- 1 | #include "sector.h" 2 | #include "base/geometryhelper.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | Sector::Sector(Resource * res) 11 | : Geometry2D(res, DrawAttach) 12 | { 13 | //setToolsString("angle|角度|Popup,OptionsGroup,NeedUpdate|;"); 14 | } 15 | 16 | Sector::Sector(Sector const & o) 17 | : Geometry2D(o),angle_(o.angle_) 18 | , graphPath_(o.graphPath_) 19 | , textPath_(o.textPath_) 20 | { 21 | angle_ = o.angle_; 22 | } 23 | 24 | class AngleToolButtons : public OptionToolButtons 25 | { 26 | public: 27 | AngleToolButtons() 28 | : OptionToolButtons({30, 45, 60, 90, 120, 180, 270, 360}, 4) 29 | { 30 | } 31 | protected: 32 | virtual QString buttonTitle(const QVariant &value) override 33 | { 34 | return QString("%1°").arg(qRound(value.toReal())); 35 | } 36 | }; 37 | 38 | static AngleToolButtons angleButtons; 39 | REGISTER_OPTION_BUTTONS(Sector, angle, angleButtons) 40 | 41 | qreal Sector::angle() 42 | { 43 | return qAbs(qRound(angle_)); 44 | } 45 | 46 | void Sector::setAngle(qreal angle) 47 | { 48 | if (qFuzzyIsNull(angle - angle_)) 49 | return; 50 | qreal la = angle; 51 | //if (la > 0 && la > angle_ + 180.0) 52 | // la -= 360.0; 53 | //else if (la < 0 && la < angle_ - 180.0) 54 | // la += 360.0; 55 | angle_ = la; 56 | la = la * M_PI / 180.0; 57 | QPointF pt3; 58 | qreal r = GeometryHelper::length(points_[1] - points_[0]); 59 | if (points_.size() > 2) { 60 | pt3 = points_[2]; 61 | } else { 62 | pt3 = points_[0] + QPointF(r, 0); 63 | } 64 | QPointF d = pt3 - points_[0]; 65 | GeometryHelper::reverseRotate(d, QPointF(cos(la), -sin(la))); 66 | points_[1] = points_[0] + d; 67 | } 68 | 69 | QPainterPath Sector::graphPath() 70 | { 71 | return graphPath_; 72 | } 73 | 74 | QPainterPath Sector::textPath() 75 | { 76 | return textPath_; 77 | } 78 | 79 | QVector Sector::movePoints() 80 | { 81 | QVector points; 82 | points.append(points_); 83 | qreal r = GeometryHelper::length(points_[1] - points_[0]); 84 | QPointF pt3; 85 | if (points_.size() > 2) { 86 | pt3 = points_[2]; 87 | } else { 88 | pt3 = points_[0] + QPointF(r, 0); 89 | points.append(pt3); 90 | } 91 | points.append((points_[0] + points_[1]) / 2); 92 | points.append((points_[0] + pt3) / 2); 93 | if (qFuzzyIsNull(angle() - 180)) { 94 | pt3 = points_[1] - points_[0]; 95 | pt3 = points_[0] - QPointF(-pt3.y(), pt3.x()); 96 | if (angle_ < 0) 97 | pt3 = points_[0] * 2 - pt3; 98 | } else { 99 | pt3 = (points_[1] + pt3) / 2; 100 | GeometryHelper::adjustToLength(points_[0], pt3, r); 101 | if (angle_ > 180 || angle_ < -180) 102 | pt3 = points_[0] * 2 - pt3; 103 | } 104 | points.append(pt3); 105 | return points; 106 | } 107 | 108 | int Sector::hit(QPointF &pt) 109 | { 110 | int elem = Geometry2D::hit(pt); 111 | if (elem >= 0) 112 | return elem; 113 | QPointF pt1 = points_[0]; 114 | QPointF pt2 = points_[1]; 115 | QPointF pt3; 116 | QPointF d = pt2 - pt1; 117 | qreal r = sqrt(GeometryHelper::length2(d)); 118 | if (points_.size() == 2) { 119 | pt3 = pt1 + QPointF(r, 0); 120 | } else { 121 | pt3 = points_[2]; 122 | } 123 | d = pt3 - pt; 124 | if (GeometryHelper::length2(d) < GeometryHelper::HIT_DIFF_DIFF) { 125 | pt = pt3; 126 | return 2; 127 | } 128 | QPointF rp; 129 | if (GeometryHelper::dist2PointToSegment(pt1, pt2, pt, rp) < GeometryHelper::HIT_DIFF_DIFF) { 130 | pt = rp; 131 | return 3; 132 | } 133 | if (GeometryHelper::dist2PointToSegment(pt1, pt3, pt, rp) < GeometryHelper::HIT_DIFF_DIFF) { 134 | pt = rp; 135 | return 4; 136 | } 137 | QPointF dd = pt - pt1; 138 | qreal rr = sqrt(GeometryHelper::length2(dd)); 139 | if (rr + GeometryHelper::HIT_DIFF > r && rr - GeometryHelper::HIT_DIFF < r) 140 | return 5; 141 | return -1; 142 | } 143 | 144 | bool Sector::moveElememt(int elem, const QPointF &pt) 145 | { 146 | if (elem == 0) { 147 | if (points_.size() == 2) 148 | points_[0] = pt; 149 | else 150 | points_[0] = GeometryHelper::nearestPointAtVerticalBisector(points_[1], points_[2], pt); 151 | } else if (elem == 1) { 152 | points_[1] = pt; 153 | QPointF pt3; 154 | if (points_.size() > 2) { 155 | pt3 = points_[2]; 156 | } else { 157 | qreal r = GeometryHelper::length(points_[1] - points_[0]); 158 | pt3 = points_[0] + QPointF(r, 0); 159 | } 160 | GeometryHelper::attachToLines(points_[0], pt3, points_[1]); 161 | if (points_.size() == 3) 162 | GeometryHelper::adjustToLength(points_[0], points_[2], GeometryHelper::length(points_[0] - points_[1])); 163 | } else if (elem == 2) { 164 | if (points_.size() == 2) 165 | points_.append(pt); 166 | else 167 | points_[2] = pt; 168 | GeometryHelper::attachToLines(points_[0], points_[1], points_[2]); 169 | GeometryHelper::adjustToLength(points_[0], points_[1], GeometryHelper::length(points_[0] - points_[2])); 170 | } else if (elem == 3) { 171 | qreal r = GeometryHelper::length(points_[0] - points_[1]); 172 | points_[1] = pt; 173 | QPointF pt3; 174 | if (points_.size() > 2) { 175 | pt3 = points_[2]; 176 | } else { 177 | pt3 = points_[0] + QPointF(r, 0); 178 | } 179 | GeometryHelper::attachToLines(points_[0], pt3, points_[1]); 180 | GeometryHelper::adjustToLength(points_[0], points_[1], r); 181 | } else if (elem == 4) { 182 | qreal r = GeometryHelper::length(points_[0] - points_[1]); 183 | if (points_.size() == 2) 184 | points_.append(pt); 185 | else 186 | points_[2] = pt; 187 | GeometryHelper::attachToLines(points_[0], points_[1], points_[2]); 188 | GeometryHelper::adjustToLength(points_[0], points_[2], r); 189 | } else if (elem == 5) { 190 | qreal r = GeometryHelper::length(points_[0] - pt); 191 | GeometryHelper::adjustToLength(points_[0], points_[1], r); 192 | if (points_.size() == 3) 193 | GeometryHelper::adjustToLength(points_[0], points_[2], r); 194 | } 195 | dirty_ = true; 196 | return true; 197 | } 198 | 199 | void Sector::sync() 200 | { 201 | if (!dirty_) 202 | return; 203 | dirty_ = false; 204 | if (points_.size() < 2) 205 | return; 206 | QPainterPath ph; 207 | QPainterPath tph; 208 | QPointF pt1 = points_[0]; 209 | QPointF pt2 = points_[1]; 210 | ph.moveTo(pt1); 211 | ph.lineTo(pt2); 212 | qreal r = GeometryHelper::length(pt2 - pt1); 213 | QPointF pt3; 214 | if (points_.size() > 2) { 215 | pt3 = points_[2]; 216 | } else { 217 | pt3 = pt1 + QPointF(r, 0); 218 | } 219 | QRectF rect(-r, -r, r * 2, r * 2); 220 | rect.moveCenter(points_[0]); 221 | qreal a1 = GeometryHelper::angle(pt2 - pt1); 222 | qreal a2 = GeometryHelper::angle(pt3 - pt1); 223 | qreal la = a2 - a1; 224 | if (la > 0 && la > angle_ + 180.0) 225 | la -= 360.0; 226 | else if (la < 0 && la < angle_ - 180.0) 227 | la += 360.0; 228 | if (qFuzzyIsNull(la)) 229 | la = qAbs(angle_) < 180 ? 0 : 360; 230 | angle_ = la; 231 | qDebug() << "sector" << a1 << a2; 232 | qDebug() << "sector angle" << (a2 - a1) << angle_; 233 | ph.arcTo(rect, a1, la); 234 | ph.closeSubpath(); 235 | if (angle_ < 0) 236 | addAngleLabeling(ph, tph, pt3, pt1, pt2, -angle_); 237 | else 238 | addAngleLabeling(ph, tph, pt2, pt1, pt3, angle_); 239 | graphPath_ = ph; 240 | textPath_ = tph; 241 | buttonsChanged(); 242 | } 243 | --------------------------------------------------------------------------------