1 /***************************************************************************
2   qgsmeshforcebypolylines.h - QgsMeshForceByPolylines
3 
4  ---------------------
5  begin                : 5.9.2021
6  copyright            : (C) 2021 by Vincent Cloarec
7  email                : vcloarec at gmail dot com
8  ***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16 #ifndef QGSMESHFORCEBYPOLYLINES_H
17 #define QGSMESHFORCEBYPOLYLINES_H
18 
19 
20 #include "qgis_core.h"
21 #include "qgstopologicalmesh.h"
22 #include "qgstriangularmesh.h"
23 #include "qgsabstractgeometry.h"
24 #include "qgsmeshadvancedediting.h"
25 
26 /**
27  * \ingroup core
28  *
29  * \brief Class derived from QgsMeshAdvancedEditing that forces mesh based on a line
30  *
31  * Forcing lines consist of line that the faces are forced to follow, that is edges of encountered faces have to be on theses lines.
32  *
33  * Caller of this class has to set the line with setInputLine() before applying the edition with QgsMeshEditor::advancedEdit()
34  *
35  * Other option has also to be set before calling QgsMeshEditor::advancedEdit()
36  *
37  * \since QGIS 3.22
38  */
39 class CORE_EXPORT QgsMeshEditForceByLine : public QgsMeshAdvancedEditing
40 {
41   public:
42 
43     //! Constructor
44     QgsMeshEditForceByLine() = default;
45 
46     //! Sets the input forcing line in rendering coordinates
47     void setInputLine( const QgsPoint &pt1, const QgsPoint &pt2, double tolerance, bool newVertexOnIntersection );
48 
49     //! Sets the tolerance in redering coordinate system unit
50     void setTolerance( double tolerance );
51 
52     //! Sets whether vertices will be added when the lines will intersect internal edges of faces, default is FALSE
53     void setAddVertexOnIntersection( bool addVertex );
54 
55     //! Sets the default value of Z coordinate to use for new vertices, this value will be used if the Z value
56     void setDefaultZValue( double defaultZValue );
57 
58     /**
59      * Sets whether the new created vertices will have their value interpolated from the existing mesh.
60      * If not, Z value will be interpolated from the lines,
61      * in case these line are not 3D, the default value will be used (\see setDefaultZValue())
62      */
63     void setInterpolateZValueOnMesh( bool interpolateZValueOnMesh );
64 
65   private:
66     QgsPoint mPoint1;
67     QgsPoint mPoint2;
68     bool mNewVertexOnIntersection = false;
69     double mTolerance = 1e-8;
70     double mDefaultZValue = 0;
71     bool mInterpolateZValueOnMesh = false;
72 
73     QgsTopologicalMesh::Changes apply( QgsMeshEditor *meshEditor ) override;
74 
75     virtual void finish();
76 
77     //members and method used for the calculation
78     QgsMeshEditor *mEditor = nullptr;
79     QList<int> mRemovedFaces;
80     QList<int> mHoleOnLeft; // contains the border vertices of hole to fill on the right of the line (line go up)
81     QList<int> mNeighborOnLeft; //contains the neighbor face on the right of the line (line go up)
82     QList<int> mHoleOnRight; // contains the border vertices of hole to fill on the right of the line (line go up)
83     QList<int> mNeighborOnRight; // contains the neighbor face on the right of the line (line go up)
84     QList<int> mNewVerticesIndexesOnLine; //the new vertices intersecting edges except
85     bool mEndOnPoint2 = false;
86     int mPoint2VertexIndex = -1;
87     int mCurrentSnappedVertex = -1; // Last snapped point
88     QgsPoint mCurrentPointPosition;
89 
90     bool mFirstPointChecked = false;
91     bool mSecondPointChecked = false;
92 
93     void interpolateZValueOnMesh( QgsPoint &point ) const;
94     void interpolateZValueOnMesh( int faceIndex, QgsPoint &point ) const;
95     void interpolateZValue( QgsMeshVertex &point, const QgsPoint &otherPoint1, const QgsPoint &otherPoint2 );
96 
97 
98     bool buildForcedElements();
99 
100     bool edgeIntersection( int vertex1,
101                            int vertex2,
102                            int &closestSnappedVertex,
103                            QgsPoint &intersectionPoint,
104                            bool outAllowed );
105 
106     bool searchIntersectionEdgeFromSnappedVertex(
107       int &intersectionFaceIndex,
108       int &previousSnappedVertex,
109       int &currentSnappedVertexIndex,
110       QgsPoint &intersectionPoint,
111       int &edgePosition,
112       QSet<int> &treatedFaces );
113 
114     // Insert a new vertex and returns its local index (0 is first index in th
115     int insertNewVertex( const QgsMeshVertex &vertex );
116 
117     bool triangulateHoles( const QList<int> &holeOnLeft,
118                            const QList<int> &neighborOnLeft,
119                            bool isLeftHole,
120                            QList<std::array<int, 2> > &newFacesOnLine,
121                            std::array<int, 2> &extremeFaces );
122 
123     bool finishForcingLine();
124 
125     friend class TestQgsMeshEditor;
126     friend class QgsMeshEditForceByPolylines;
127 };
128 
129 
130 
131 /**
132  * \ingroup core
133  *
134  * \brief Class derived from QgsMeshEditForceByLine that forces mesh based on polyline.
135  *
136  * Forcing lines consist of line that the faces are forced to follow, that is edges of encountered faces have to be on theses lines.
137  *
138  * Caller of this class has to add the lines from QgsGeometry instances with addLineFromGeometry() or addLinesFromGeometries()
139  * before applying the edition with QgsMeshEditor::advancedEdit()
140  *
141  *
142  * \since QGIS 3.22
143  */
144 class CORE_EXPORT QgsMeshEditForceByPolylines : public QgsMeshEditForceByLine
145 {
146   public:
147 
148     //! Constructor
149     QgsMeshEditForceByPolylines() = default;
150 
151     QString text() const override;
152     bool isFinished() const override;
153 
154     /**
155      * Adds a input forcing line geometry in rendering coordinates
156      *
157      * \note if the geometry is not 3D, the default Z value will be used for the Z value of the geometry's vertices.
158      *       This default Z value has to be set before adding the geometry (\see setDefaultZValue()
159      */
160     void addLineFromGeometry( const QgsGeometry &geom );
161 
162     /**
163      * Adds a list of input forcing lines geometry in rendering coordinates
164      *
165      * \note if the geometry is not 3D, the default Z value will be used for the Z value of the geometry's vertices.
166      *       This default Z value has to be set before adding the geometry (\see setDefaultZValue()
167      */
168     void addLinesFromGeometries( const QList<QgsGeometry> geometries );
169 
170   private:
171     QList<QgsPointSequence> mPolylines;
172     int mCurrentPolyline = 0;
173     int mCurrentSegment = 0;
174 
175     void incrementSegment();
176 
177     using QgsMeshEditForceByLine::setInputLine;
178     QgsTopologicalMesh::Changes apply( QgsMeshEditor *meshEditor ) override;
179 
180 };
181 
182 #endif // QGSMESHFORCEBYPOLYLINES_H
183