QGIS API Documentation 3.99.0-Master (e9821da5c6b)
Loading...
Searching...
No Matches
qgsdualedgetriangulation.cpp
Go to the documentation of this file.
1/***************************************************************************
2 QgsDualEdgeTriangulation.cpp
3 -------------------------
4 copyright : (C) 2004 by Marco Hugentobler
6 ***************************************************************************/
7
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
18
19#include <map>
20
21#include "MathUtils.h"
22#include "qgsgeometry.h"
23#include "qgsinterpolator.h"
24#include "qgslogger.h"
25#include "qgsvectorfilewriter.h"
26
27#include <QStack>
28#include <QString>
29
30using namespace Qt::StringLiterals;
31
32double leftOfTresh = 0;
33
34static bool inCircle( const QgsPoint &testedPoint, const QgsPoint &point1, const QgsPoint &point2, const QgsPoint &point3 )
35{
36 const double x2 = point2.x() - point1.x();
37 const double y2 = point2.y() - point1.y();
38 const double x3 = point3.x() - point1.x();
39 const double y3 = point3.y() - point1.y();
40
41 const double denom = x2 * y3 - y2 * x3;
42 double frac;
43
44 if ( denom == 0 )
45 return false;
46
47 frac = ( x2 * ( x2 - x3 ) + y2 * ( y2 - y3 ) ) / denom;
48 const double cx = ( x3 + frac * y3 ) / 2;
49 const double cy = ( y3 - frac * x3 ) / 2;
50 const double squaredRadius = ( cx * cx + cy * cy );
51 const QgsPoint center( cx + point1.x(), cy + point1.y() );
52
53 return center.distanceSquared( testedPoint ) < squaredRadius;
54}
55
57{
58 qDeleteAll( mPointVector );
59 qDeleteAll( mHalfEdge );
60}
61
63{
64 QgsDebugMsgLevel( u"performing consistency test"_s, 2 );
65
66 for ( int i = 0; i < mHalfEdge.count(); i++ )
67 {
68 const int a = mHalfEdge[mHalfEdge[i]->getDual()]->getDual();
69 const int b = mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getNext();
70 if ( i != a )
71 {
72 QgsDebugError( u"warning, first test failed"_s );
73 }
74 if ( i != b )
75 {
76 QgsDebugError( u"warning, second test failed"_s );
77 }
78 }
79 QgsDebugMsgLevel( u"consistency test finished"_s, 2 );
80}
81
82void QgsDualEdgeTriangulation::addLine( const QVector<QgsPoint> &points, QgsInterpolator::SourceType lineType )
83{
84 int actpoint = -10; //number of the last point, which has been inserted from the line
85 int currentpoint = -10; //number of the point, which is currently inserted from the line
86
87 int i = 0;
88 for ( const QgsPoint &point : points )
89 {
90 actpoint = addPoint( point );
91 i++;
92 if ( actpoint != -100 )
93 {
94 break;
95 }
96 }
97
98 if ( actpoint == -100 ) //no point of the line could be inserted
99 {
100 return;
101 }
102
103 for ( ; i < points.size(); ++i )
104 {
105 currentpoint = addPoint( points.at( i ) );
106 if ( currentpoint != -100 && actpoint != -100 && currentpoint != actpoint ) //-100 is the return value if the point could not be not inserted
107 {
108 insertForcedSegment( actpoint, currentpoint, lineType );
109 }
110 actpoint = currentpoint;
111 }
112}
113
115{
116 //first update the bounding box
117 if ( mPointVector.isEmpty() ) //update bounding box when the first point is inserted
118 {
119 mXMin = p.x();
120 mYMin = p.y();
121 mXMax = p.x();
122 mYMax = p.y();
123 }
124 else //update bounding box else
125 {
126 mXMin = std::min( p.x(), mXMin );
127 mXMax = std::max( p.x(), mXMax );
128 mYMin = std::min( p.y(), mYMin );
129 mYMax = std::max( p.y(), mYMax );
130 }
131
132 //then update mPointVector
133 mPointVector.append( new QgsPoint( p ) );
134
135 //then update the HalfEdgeStructure
136 if ( mDimension == -1 ) //insert the first point into the triangulation
137 {
138 const unsigned int zedge /* 0 */ = insertEdge( -10, -10, -1, false, false ); //edge pointing from p to the virtual point
139 const unsigned int fedge /* 1 */ = insertEdge( static_cast<int>( zedge ), static_cast<int>( zedge ), 0, false, false ); //edge pointing from the virtual point to p
140 ( mHalfEdge.at( zedge ) )->setDual( static_cast<int>( fedge ) );
141 ( mHalfEdge.at( zedge ) )->setNext( static_cast<int>( fedge ) );
142 mDimension = 0;
143 }
144 else if ( mDimension == 0 ) //insert the second point into the triangulation
145 {
146 //test, if it is the same point as the first point
147 if ( p.x() == mPointVector[0]->x() && p.y() == mPointVector[0]->y() )
148 {
149 //second point is the same as the first point
150 removeLastPoint();
151 return 0;
152 }
153
154 const unsigned int edgeFromPoint0ToPoint1 /* 2 */ = insertEdge( -10, -10, 1, false, false ); //edge pointing from point 0 to point 1
155 const unsigned int edgeFromPoint1ToPoint0 /* 3 */ = insertEdge( edgeFromPoint0ToPoint1, -10, 0, false, false ); //edge pointing from point 1 to point 0
156 const unsigned int edgeFromVirtualToPoint1Side1 /* 4 */ = insertEdge( -10, -10, 1, false, false ); //edge pointing from the virtual point to point 1
157 const unsigned int edgeFromPoint1ToVirtualSide1 /* 5 */ = insertEdge( edgeFromVirtualToPoint1Side1, 1, -1, false, false ); //edge pointing from point 1 to the virtual point
158 const unsigned int edgeFromVirtualToPoint1Side2 /* 6 */ = insertEdge( -10, edgeFromPoint1ToPoint0, 1, false, false );
159 const unsigned int edgeFromPoint1ToVirtualSide2 /* 7 */ = insertEdge( edgeFromVirtualToPoint1Side2, edgeFromVirtualToPoint1Side1, -1, false, false );
160 const unsigned int edgeFromVirtualToPoint0Side2 /* 8 */ = insertEdge( -10, -10, 0, false, false );
161 const unsigned int edgeFromPoint0ToVirtualSide2 /* 9 */ = insertEdge( edgeFromVirtualToPoint0Side2, edgeFromVirtualToPoint1Side2, -1, false, false );
162 mHalfEdge.at( edgeFromPoint1ToPoint0 )->setNext( edgeFromPoint0ToVirtualSide2 );
163 mHalfEdge.at( edgeFromPoint0ToPoint1 )->setDual( edgeFromPoint1ToPoint0 );
164 mHalfEdge.at( edgeFromPoint0ToPoint1 )->setNext( edgeFromPoint1ToVirtualSide1 );
165 mHalfEdge.at( edgeFromVirtualToPoint1Side1 )->setDual( edgeFromPoint1ToVirtualSide1 );
166 mHalfEdge.at( edgeFromVirtualToPoint1Side1 )->setNext( edgeFromPoint1ToVirtualSide2 );
167 mHalfEdge.at( 0 )->setNext( static_cast<int>( edgeFromVirtualToPoint0Side2 ) );
168 mHalfEdge.at( 1 )->setNext( static_cast<int>( edgeFromPoint0ToPoint1 ) );
169 mHalfEdge.at( edgeFromVirtualToPoint1Side2 )->setDual( edgeFromPoint1ToVirtualSide2 );
170 mHalfEdge.at( edgeFromVirtualToPoint0Side2 )->setDual( edgeFromPoint0ToVirtualSide2 );
171 mHalfEdge.at( edgeFromVirtualToPoint0Side2 )->setNext( 0 );
172 mEdgeInside = 3;
173 mEdgeOutside = edgeFromPoint0ToPoint1;
174 mDimension = 1;
175 }
176 else if ( mDimension == 1 )
177 {
178 if ( mEdgeOutside < 0 || mHalfEdge[mEdgeOutside]->getPoint() < 0 || mHalfEdge[mHalfEdge[mEdgeOutside]->getDual()]->getPoint() < 0 )
179 mEdgeOutside = firstEdgeOutSide();
180 if ( mEdgeOutside < 0 || mHalfEdge[mEdgeOutside]->getPoint() < 0 || mHalfEdge[mHalfEdge[mEdgeOutside]->getDual()]->getPoint() < 0 )
181 return -100;
182
183 const double leftOfNumber = MathUtils::leftOf( p, mPointVector[mHalfEdge[mHalfEdge[mEdgeOutside]->getDual()]->getPoint()], mPointVector[mHalfEdge[mEdgeOutside]->getPoint()] );
184 if ( fabs( leftOfNumber ) <= leftOfTresh )
185 {
186 // new point colinear with existing points
187 mDimension = 1;
188 // First find the edge which has the point in or the closest edge if the new point is outside
189 int closestEdge = -1;
190 double distance = std::numeric_limits<double>::max();
191 const int firstEdge = mEdgeOutside;
192 do
193 {
194 const int point1 = mHalfEdge[mEdgeOutside]->getPoint();
195 const int point2 = mHalfEdge[mHalfEdge[mEdgeOutside]->getDual()]->getPoint();
196 const double distance1 = p.distance( *mPointVector[point1] );
197 if ( distance1 <= leftOfTresh ) // point1 == new point
198 {
199 removeLastPoint();
200 return point1;
201 }
202 const double distance2 = p.distance( *mPointVector[point2] );
203 if ( distance2 <= leftOfTresh ) // point2 == new point
204 {
205 removeLastPoint();
206 return point2;
207 }
208
209 const double edgeLength = mPointVector[point1]->distance( *mPointVector[point2] );
210
211 if ( distance1 < edgeLength && distance2 < edgeLength )
212 {
213 //new point include in mEdgeOutside
214 const int newPoint = mPointVector.count() - 1;
215
216 //edges that do not change
217 const int edgeFromNewPointToPoint1 = mEdgeOutside;
218 const int edgeFromNewPointToPoint2 = mHalfEdge[mEdgeOutside]->getDual();
219 //edges to modify
220 const int edgeFromPoint1ToVirtualSide2 = mHalfEdge[edgeFromNewPointToPoint1]->getNext();
221 const int edgeFromVirtualToPoint1Side1 = mHalfEdge[mHalfEdge[edgeFromNewPointToPoint2]->getNext()]->getNext();
222 const int edgeFromPoint2ToVirtualSide1 = mHalfEdge[edgeFromNewPointToPoint2]->getNext();
223 const int edgeFromVirtualToPoint2Side2 = mHalfEdge[mHalfEdge[edgeFromNewPointToPoint1]->getNext()]->getNext();
224 //insert new edges
225 const int edgeFromVirtualToNewPointSide1 = insertEdge( -10, edgeFromNewPointToPoint2, newPoint, false, false );
226 const int edgeFromNewPointToVirtualSide1 = insertEdge( edgeFromVirtualToNewPointSide1, edgeFromVirtualToPoint1Side1, -1, false, false );
227 const int edgeFromVirtualToNewPointSide2 = insertEdge( -10, edgeFromNewPointToPoint1, newPoint, false, false );
228 const int edgeFromNewPointToVirtualSide2 = insertEdge( edgeFromVirtualToNewPointSide2, edgeFromVirtualToPoint2Side2, -1, false, false );
229 const int edgeFromPoint1ToNewPoint = insertEdge( edgeFromNewPointToPoint1, edgeFromNewPointToVirtualSide1, newPoint, false, false );
230 const int edgeFromPoint2ToNewPoint = insertEdge( edgeFromNewPointToPoint2, edgeFromNewPointToVirtualSide2, newPoint, false, false );
231 mHalfEdge.at( edgeFromVirtualToNewPointSide1 )->setDual( edgeFromNewPointToVirtualSide1 );
232 mHalfEdge.at( edgeFromVirtualToNewPointSide2 )->setDual( edgeFromNewPointToVirtualSide2 );
233 //modify existing edges
234 mHalfEdge.at( edgeFromPoint1ToVirtualSide2 )->setNext( edgeFromVirtualToNewPointSide2 );
235 mHalfEdge.at( edgeFromVirtualToPoint1Side1 )->setNext( edgeFromPoint1ToNewPoint );
236 mHalfEdge.at( edgeFromPoint2ToVirtualSide1 )->setNext( edgeFromVirtualToNewPointSide1 );
237 mHalfEdge.at( edgeFromVirtualToPoint2Side2 )->setNext( edgeFromPoint2ToNewPoint );
238 mHalfEdge.at( edgeFromNewPointToPoint1 )->setDual( edgeFromPoint1ToNewPoint );
239 mHalfEdge.at( edgeFromNewPointToPoint2 )->setDual( edgeFromPoint2ToNewPoint );
240 return newPoint;
241 }
242 else
243 {
244 if ( distance1 < distance )
245 {
246 closestEdge = mEdgeOutside;
247 distance = distance1;
248 }
249 else if ( distance2 < distance )
250 {
251 closestEdge = mHalfEdge[mEdgeOutside]->getDual();
252 distance = distance2;
253 }
254 }
255 mEdgeOutside = mHalfEdge[mHalfEdge[mHalfEdge[mEdgeOutside]->getNext()]->getDual()]->getNext();
256 } while ( mEdgeOutside != firstEdge && mHalfEdge[mEdgeOutside]->getPoint() != -1 && mHalfEdge[mHalfEdge[mEdgeOutside]->getDual()]->getPoint() != -1 );
257
258 if ( closestEdge < 0 )
259 return -100; //something gets wrong
260
261 //add the new colinear point linking it to the extremity of closest edge
262 const int extremePoint = mHalfEdge[closestEdge]->getPoint();
263 const int newPoint = mPointVector.count() - 1;
264 //edges that do not change
265 const int edgeFromExtremeToOpposite = mHalfEdge[closestEdge]->getDual();
266 //edges to modify
267 const int edgeFromVirtualToExtremeSide1 = mHalfEdge[mHalfEdge[closestEdge]->getNext()]->getDual();
268 const int edgeFromVirtualToExtremeSide2 = mHalfEdge[mHalfEdge[mHalfEdge[closestEdge]->getDual()]->getNext()]->getNext();
269 const int edgeFromExtremeToVirtualSide2 = mHalfEdge[edgeFromVirtualToExtremeSide2]->getDual();
270 //insert new edge
271 const int edgeFromExtremeToNewPoint = insertEdge( -10, -10, newPoint, false, false );
272 const int edgeFromNewPointToExtreme = insertEdge( edgeFromExtremeToNewPoint, edgeFromExtremeToVirtualSide2, extremePoint, false, false );
273 const int edgeFromNewPointToVirtualSide1 = insertEdge( -10, edgeFromVirtualToExtremeSide1, -1, false, false );
274 const int edgeFromVirtualToNewPointSide1 = insertEdge( edgeFromNewPointToVirtualSide1, -10, newPoint, false, false );
275 const int edgeFromNewPointToVirtualSide2 = insertEdge( -10, edgeFromVirtualToNewPointSide1, -1, false, false );
276 const int edgeFromVirtualToNewPointSide2 = insertEdge( edgeFromNewPointToVirtualSide2, edgeFromNewPointToExtreme, newPoint, false, false );
277 mHalfEdge.at( edgeFromExtremeToNewPoint )->setDual( edgeFromNewPointToExtreme );
278 mHalfEdge.at( edgeFromExtremeToNewPoint )->setNext( edgeFromNewPointToVirtualSide1 );
279 mHalfEdge.at( edgeFromNewPointToVirtualSide1 )->setDual( edgeFromVirtualToNewPointSide1 );
280 mHalfEdge.at( edgeFromNewPointToVirtualSide2 )->setDual( edgeFromVirtualToNewPointSide2 );
281 mHalfEdge.at( edgeFromVirtualToNewPointSide1 )->setNext( edgeFromNewPointToVirtualSide2 );
282 //modify existing edges
283 mHalfEdge.at( edgeFromVirtualToExtremeSide1 )->setNext( edgeFromExtremeToNewPoint );
284 mHalfEdge.at( edgeFromVirtualToExtremeSide2 )->setNext( edgeFromExtremeToOpposite );
285 mHalfEdge.at( edgeFromExtremeToVirtualSide2 )->setNext( edgeFromVirtualToNewPointSide2 );
286
287 return newPoint;
288 }
289 else if ( leftOfNumber >= leftOfTresh )
290 {
291 // new point on the right of mEdgeOutside
292 mEdgeOutside = mHalfEdge[mEdgeOutside]->getDual();
293 }
294 mDimension = 2;
295 const int newPoint = mPointVector.count() - 1;
296 //build the 2D dimension triangulation
297 //First clock wise
298 int cwEdge = mEdgeOutside;
299 while ( mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[cwEdge]->getNext()]->getDual()]->getNext()]->getPoint() != -1 )
300 {
301 mHalfEdge[mHalfEdge[cwEdge]->getNext()]->setPoint( newPoint );
302 cwEdge = mHalfEdge[mHalfEdge[mHalfEdge[cwEdge]->getNext()]->getDual()]->getNext();
303 }
304
305 const int edgeFromLastCwPointToVirtualPoint = mHalfEdge[mHalfEdge[mHalfEdge[cwEdge]->getNext()]->getDual()]->getNext();
306 const int edgeFromLastCwPointToNewPointPoint = mHalfEdge[cwEdge]->getNext();
307 const int edgeFromNewPointPointToLastCwPoint = mHalfEdge[edgeFromLastCwPointToNewPointPoint]->getDual();
308 //connect the new point
309 const int edgeFromNewPointtoVirtualPoint = insertEdge( -10, -10, -1, false, false );
310 const int edgeFromVirtualPointToNewPoint = insertEdge( edgeFromNewPointtoVirtualPoint, edgeFromNewPointPointToLastCwPoint, newPoint, false, false );
311 mHalfEdge.at( edgeFromLastCwPointToNewPointPoint )->setPoint( newPoint );
312 mHalfEdge.at( edgeFromNewPointtoVirtualPoint )->setDual( edgeFromVirtualPointToNewPoint );
313 mHalfEdge.at( edgeFromLastCwPointToVirtualPoint )->setNext( edgeFromVirtualPointToNewPoint );
314
315 //First counter clock wise
316 int ccwEdge = mEdgeOutside;
317 while ( mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getDual()]->getNext()]->getDual()]->getNext()]->getPoint() != -1 )
318 {
319 mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getNext()]->getNext()]->getDual()]->setPoint( newPoint );
320 ccwEdge = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getDual()]->getNext()]->getDual()]->getNext()]->getDual();
321 }
322
323 const int edgeToLastCcwPoint = mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getDual()]->getNext()]->getDual();
324 const int edgeFromLastCcwPointToNewPoint = mHalfEdge[edgeToLastCcwPoint]->getNext();
325 mHalfEdge.at( edgeFromNewPointtoVirtualPoint )->setNext( edgeToLastCcwPoint );
326 mHalfEdge.at( edgeFromLastCcwPointToNewPoint )->setNext( edgeFromNewPointtoVirtualPoint );
327 mHalfEdge.at( edgeFromLastCcwPointToNewPoint )->setPoint( newPoint );
328 }
329 else
330 {
331 const int number = baseEdgeOfTriangle( p );
332
333 //point is outside the convex hull----------------------------------------------------
334 if ( number == -10 )
335 {
336 unsigned int cwEdge = mEdgeOutside; //the last visible edge clockwise from mEdgeOutside
337 unsigned int ccwEdge = mEdgeOutside; //the last visible edge counterclockwise from mEdgeOutside
338
339 //mEdgeOutside is in each case visible
340 mHalfEdge[mHalfEdge[mEdgeOutside]->getNext()]->setPoint( mPointVector.count() - 1 );
341
342 //find cwEdge and replace the virtual point with the new point when necessary (equivalent to while the hull is not convex going clock wise)
343 while ( MathUtils::leftOf( *mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[cwEdge]->getNext()]->getDual()]->getNext()]->getPoint()], &p, mPointVector[mHalfEdge[cwEdge]->getPoint()] ) < ( -leftOfTresh ) )
344 {
345 //set the point number of the necessary edge to the actual point instead of the virtual point
346 mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[cwEdge]->getNext()]->getDual()]->getNext()]->getNext()]->setPoint( mPointVector.count() - 1 );
347 //advance cwedge one edge further clockwise
348 cwEdge = ( unsigned int ) mHalfEdge[mHalfEdge[mHalfEdge[cwEdge]->getNext()]->getDual()]->getNext();
349 }
350
351 //build the necessary connections with the virtual point
352 const unsigned int edge1 = insertEdge( mHalfEdge[cwEdge]->getNext(), -10, mHalfEdge[cwEdge]->getPoint(), false, false ); //edge pointing from the new point to the last visible point clockwise
353 const unsigned int edge2 = insertEdge( mHalfEdge[mHalfEdge[cwEdge]->getNext()]->getDual(), -10, -1, false, false ); //edge pointing from the last visible point to the virtual point
354 const unsigned int edge3 = insertEdge( -10, edge1, mPointVector.count() - 1, false, false ); //edge pointing from the virtual point to new point
355
356 //adjust the other pointers
357 mHalfEdge[mHalfEdge[mHalfEdge[cwEdge]->getNext()]->getDual()]->setDual( edge2 );
358 mHalfEdge[mHalfEdge[cwEdge]->getNext()]->setDual( edge1 );
359 mHalfEdge[edge1]->setNext( edge2 );
360 mHalfEdge[edge2]->setNext( edge3 );
361
362 //find ccwedge and replace the virtual point with the new point when necessary
363 while ( MathUtils::leftOf( *mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getNext()]->getNext()]->getPoint()], mPointVector[mPointVector.count() - 1], mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getNext()]->getNext()]->getDual()]->getNext()]->getPoint()] ) < ( -leftOfTresh ) )
364 {
365 //set the point number of the necessary edge to the actual point instead of the virtual point
366 mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getNext()]->getNext()]->getDual()]->setPoint( mPointVector.count() - 1 );
367 //advance ccwedge one edge further counterclockwise
368 ccwEdge = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getNext()]->getNext()]->getDual()]->getNext()]->getNext();
369 }
370
371 //build the necessary connections with the virtual point
372 const unsigned int edge4 = insertEdge( mHalfEdge[mHalfEdge[ccwEdge]->getNext()]->getNext(), -10, mPointVector.count() - 1, false, false ); //points from the last visible point counterclockwise to the new point
373 const unsigned int edge5 = insertEdge( edge3, -10, -1, false, false ); //points from the new point to the virtual point
374 const unsigned int edge6 = insertEdge( mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getNext()]->getNext()]->getDual(), edge4, mHalfEdge[mHalfEdge[ccwEdge]->getDual()]->getPoint(), false, false ); //points from the virtual point to the last visible point counterclockwise
375
376
377 //adjust the other pointers
378 mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getNext()]->getNext()]->getDual()]->setDual( edge6 );
379 mHalfEdge[mHalfEdge[mHalfEdge[ccwEdge]->getNext()]->getNext()]->setDual( edge4 );
380 mHalfEdge[edge4]->setNext( edge5 );
381 mHalfEdge[edge5]->setNext( edge6 );
382 mHalfEdge[edge3]->setDual( edge5 );
383
384 //now test the HalfEdge at the former convex hull for swappint
385 unsigned int index = ccwEdge;
386 unsigned int toswap;
387 while ( true )
388 {
389 toswap = index;
390 index = mHalfEdge[mHalfEdge[mHalfEdge[index]->getNext()]->getDual()]->getNext();
391 checkSwapRecursively( toswap, 0 );
392 if ( toswap == cwEdge )
393 {
394 break;
395 }
396 }
397 }
398 else if ( number >= 0 ) //point is inside the convex hull------------------------------------------------------
399 {
400 const int nextnumber = mHalfEdge[number]->getNext();
401 const int nextnextnumber = mHalfEdge[mHalfEdge[number]->getNext()]->getNext();
402
403 //insert 6 new HalfEdges for the connections to the vertices of the triangle
404 const unsigned int edge1 = insertEdge( -10, nextnumber, mHalfEdge[number]->getPoint(), false, false );
405 const unsigned int edge2 = insertEdge( static_cast<int>( edge1 ), -10, mPointVector.count() - 1, false, false );
406 const unsigned int edge3 = insertEdge( -10, nextnextnumber, mHalfEdge[nextnumber]->getPoint(), false, false );
407 const unsigned int edge4 = insertEdge( static_cast<int>( edge3 ), static_cast<int>( edge1 ), mPointVector.count() - 1, false, false );
408 const unsigned int edge5 = insertEdge( -10, number, mHalfEdge[nextnextnumber]->getPoint(), false, false );
409 const unsigned int edge6 = insertEdge( static_cast<int>( edge5 ), static_cast<int>( edge3 ), mPointVector.count() - 1, false, false );
410
411
412 mHalfEdge.at( edge1 )->setDual( static_cast<int>( edge2 ) );
413 mHalfEdge.at( edge2 )->setNext( static_cast<int>( edge5 ) );
414 mHalfEdge.at( edge3 )->setDual( static_cast<int>( edge4 ) );
415 mHalfEdge.at( edge5 )->setDual( static_cast<int>( edge6 ) );
416 mHalfEdge.at( number )->setNext( static_cast<int>( edge2 ) );
417 mHalfEdge.at( nextnumber )->setNext( static_cast<int>( edge4 ) );
418 mHalfEdge.at( nextnextnumber )->setNext( static_cast<int>( edge6 ) );
419
420 //check, if there are swaps necessary
421 checkSwapRecursively( number, 0 );
422 checkSwapRecursively( nextnumber, 0 );
423 checkSwapRecursively( nextnextnumber, 0 );
424 }
425 //the point is exactly on an existing edge (the number of the edge is stored in the variable 'mEdgeWithPoint'---------------
426 else if ( number == -20 )
427 {
428 //point exactly on edge;
429
430 //check if new point is the same than one extremity
431 const int point1 = mHalfEdge[mEdgeWithPoint]->getPoint();
432 const int point2 = mHalfEdge[mHalfEdge[mEdgeWithPoint]->getDual()]->getPoint();
433 const double distance1 = p.distance( *mPointVector[point1] );
434 if ( distance1 <= leftOfTresh ) // point1 == new point
435 {
436 removeLastPoint();
437 return point1;
438 }
439 const double distance2 = p.distance( *mPointVector[point2] );
440 if ( distance2 <= leftOfTresh ) // point2 == new point
441 {
442 removeLastPoint();
443 return point2;
444 }
445
446 const int edgea = mEdgeWithPoint;
447 const int edgeb = mHalfEdge[mEdgeWithPoint]->getDual();
448 const int edgec = mHalfEdge[edgea]->getNext();
449 const int edged = mHalfEdge[edgec]->getNext();
450 const int edgee = mHalfEdge[edgeb]->getNext();
451 const int edgef = mHalfEdge[edgee]->getNext();
452
453 //insert the six new edges
454 const int nedge1 = insertEdge( -10, mHalfEdge[edgea]->getNext(), mHalfEdge[edgea]->getPoint(), false, false );
455 const int nedge2 = insertEdge( nedge1, -10, mPointVector.count() - 1, false, false );
456 const int nedge3 = insertEdge( -10, edged, mHalfEdge[edgec]->getPoint(), false, false );
457 const int nedge4 = insertEdge( nedge3, nedge1, mPointVector.count() - 1, false, false );
458 const int nedge5 = insertEdge( -10, edgef, mHalfEdge[edgee]->getPoint(), false, false );
459 const int nedge6 = insertEdge( nedge5, edgeb, mPointVector.count() - 1, false, false );
460
461 //adjust the triangular structure
462 mHalfEdge[nedge1]->setDual( nedge2 );
463 mHalfEdge[nedge2]->setNext( nedge5 );
464 mHalfEdge[nedge3]->setDual( nedge4 );
465 mHalfEdge[nedge5]->setDual( nedge6 );
466 mHalfEdge[edgea]->setPoint( mPointVector.count() - 1 );
467 mHalfEdge[edgea]->setNext( nedge3 );
468 mHalfEdge[edgec]->setNext( nedge4 );
469 mHalfEdge[edgee]->setNext( nedge6 );
470 mHalfEdge[edgef]->setNext( nedge2 );
471
472 //swap edges if necessary
473 checkSwapRecursively( edgec, 0 );
474 checkSwapRecursively( edged, 0 );
475 checkSwapRecursively( edgee, 0 );
476 checkSwapRecursively( edgef, 0 );
477 }
478
479 else if ( number == -100 || number == -5 ) //this means unknown problems or a numerical error occurred in 'baseEdgeOfTriangle'
480 {
481 //QgsDebugError( "point has not been inserted because of unknown problems" );
482 removeLastPoint();
483 return -100;
484 }
485 else if ( number == -25 ) //this means that the point has already been inserted in the triangulation
486 {
487 //Take the higher z-Value in case of two equal points
488 QgsPoint *newPoint = mPointVector[mPointVector.count() - 1];
489 QgsPoint *existingPoint = mPointVector[mTwiceInsPoint];
490 existingPoint->setZ( std::max( newPoint->z(), existingPoint->z() ) );
491
492 removeLastPoint();
493 return mTwiceInsPoint;
494 }
495 }
496
497 return ( mPointVector.count() - 1 );
498}
499
500int QgsDualEdgeTriangulation::baseEdgeOfPoint( int point )
501{
502 unsigned int actedge = mEdgeInside; //starting edge
503
504 if ( mPointVector.count() < 4 || point == -1 || mDimension == 1 ) //at the beginning, mEdgeInside is not defined yet
505 {
506 int fromVirtualPoint = -1;
507 //first find pointingedge(an edge pointing to p1, priority to edge that no come from virtual point)
508 for ( int i = 0; i < mHalfEdge.count(); i++ )
509 {
510 if ( mHalfEdge[i]->getPoint() == point ) //we found one
511 {
512 if ( mHalfEdge[mHalfEdge[i]->getDual()]->getPoint() != -1 )
513 return i;
514 else
515 fromVirtualPoint = i;
516 }
517 }
518 return fromVirtualPoint;
519 }
520
521 int control = 0;
522
523 while ( true ) //otherwise, start the search
524 {
525 control += 1;
526 if ( control > 1000000 )
527 {
528 //QgsDebugError( u"warning, endless loop"_s );
529
530 //use the secure and slow method
531 //qWarning( "******************warning, using the slow method in baseEdgeOfPoint****************************************" );
532 for ( int i = 0; i < mHalfEdge.count(); i++ )
533 {
534 if ( mHalfEdge[i]->getPoint() == point && mHalfEdge[mHalfEdge[i]->getNext()]->getPoint() != -1 ) //we found it
535 {
536 return i;
537 }
538 }
539 }
540
541 const int fromPoint = mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint();
542 const int toPoint = mHalfEdge[actedge]->getPoint();
543
544 if ( fromPoint == -1 || toPoint == -1 ) //this would cause a crash. Therefore we use the slow method in this case
545 {
546 for ( int i = 0; i < mHalfEdge.count(); i++ )
547 {
548 if ( mHalfEdge[i]->getPoint() == point && mHalfEdge[mHalfEdge[i]->getNext()]->getPoint() != -1 ) //we found it
549 {
550 mEdgeInside = i;
551 return i;
552 }
553 }
554 }
555
556 const double leftOfNumber = MathUtils::leftOf( *mPointVector[point], mPointVector[mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[actedge]->getPoint()] );
557
558
559 if ( mHalfEdge[actedge]->getPoint() == point && mHalfEdge[mHalfEdge[actedge]->getNext()]->getPoint() != -1 ) //we found the edge
560 {
561 mEdgeInside = actedge;
562 return actedge;
563 }
564 else if ( leftOfNumber <= 0.0 )
565 {
566 actedge = mHalfEdge[actedge]->getNext();
567 }
568 else
569 {
570 actedge = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[actedge]->getDual()]->getNext()]->getNext()]->getDual();
571 }
572 }
573}
574
575int QgsDualEdgeTriangulation::baseEdgeOfTriangle( const QgsPoint &point )
576{
577 unsigned int actEdge = mEdgeInside; //start with an edge which does not point to the virtual point
578 if ( mHalfEdge.at( actEdge )->getPoint() < 0 )
579 actEdge = mHalfEdge.at( mHalfEdge.at( mHalfEdge.at( actEdge )->getDual() )->getNext() )->getDual(); //get an real inside edge
580 if ( mHalfEdge.at( mHalfEdge.at( actEdge )->getDual() )->getPoint() < 0 )
581 actEdge = mHalfEdge.at( mHalfEdge.at( actEdge )->getNext() )->getDual();
582
583 int counter = 0; //number of consecutive successful left-of-tests
584 int nulls = 0; //number of left-of-tests, which returned 0. 1 means, that the point is on a line, 2 means that it is on an existing point
585 int numInstabs = 0; //number of suspect left-of-tests due to 'leftOfTresh'
586 int runs = 0; //counter for the number of iterations in the loop to prevent an endless loop
587 int firstEndPoint = 0, secEndPoint = 0, thEndPoint = 0, fouEndPoint = 0; //four numbers of endpoints in cases when two left-of-test are 0
588
589 while ( true )
590 {
591 if ( runs > MAX_BASE_ITERATIONS ) //prevents endless loops
592 {
593 //QgsDebugError( "warning, probable endless loop detected" );
594 return -100;
595 }
596
597 const double leftOfValue = MathUtils::leftOf( point, mPointVector.at( mHalfEdge.at( mHalfEdge.at( actEdge )->getDual() )->getPoint() ), mPointVector.at( mHalfEdge.at( actEdge )->getPoint() ) );
598
599 if ( leftOfValue < ( -leftOfTresh ) ) //point is on the left side
600 {
601 counter += 1;
602 if ( counter == 3 ) //three successful passes means that we have found the triangle
603 {
604 break;
605 }
606 }
607 else if ( fabs( leftOfValue ) <= leftOfTresh ) //point is exactly in the line of the edge
608 {
609 if ( nulls == 0 )
610 {
611 //store the numbers of the two endpoints of the line
612 firstEndPoint = mHalfEdge.at( mHalfEdge.at( actEdge )->getDual() )->getPoint();
613 secEndPoint = mHalfEdge.at( actEdge )->getPoint();
614 }
615 else if ( nulls == 1 )
616 {
617 //store the numbers of the two endpoints of the line
618 thEndPoint = mHalfEdge.at( mHalfEdge.at( actEdge )->getDual() )->getPoint();
619 fouEndPoint = mHalfEdge.at( actEdge )->getPoint();
620 }
621 counter += 1;
622 mEdgeWithPoint = actEdge;
623 nulls += 1;
624 if ( counter == 3 ) //three successful passes means that we have found the triangle
625 {
626 break;
627 }
628 }
629 else //point is on the right side
630 {
631 actEdge = mHalfEdge.at( actEdge )->getDual();
632 counter = 1;
633 nulls = 0;
634 numInstabs = 0;
635 }
636 actEdge = mHalfEdge.at( actEdge )->getNext();
637 if ( mHalfEdge.at( actEdge )->getPoint() == -1 ) //the half edge points to the virtual point
638 {
639 if ( nulls == 1 ) //point is exactly on the convex hull
640 {
641 return -20;
642 }
643 mEdgeOutside = ( unsigned int ) mHalfEdge.at( mHalfEdge.at( actEdge )->getNext() )->getNext();
644 mEdgeInside = mHalfEdge.at( mHalfEdge.at( mEdgeOutside )->getDual() )->getNext();
645 return -10; //the point is outside the convex hull
646 }
647 runs++;
648 }
649
650 if ( numInstabs > 0 ) //we hit an existing point or a numerical instability occurred
651 {
652 // QgsDebugError("numerical instability occurred");
653 mUnstableEdge = actEdge;
654 return -5;
655 }
656
657 if ( nulls == 2 )
658 {
659 //find out the number of the point, which has already been inserted
660 if ( firstEndPoint == thEndPoint || firstEndPoint == fouEndPoint )
661 {
662 //firstendp is the number of the point which has been inserted twice
663 mTwiceInsPoint = firstEndPoint;
664 // QgsDebugError(QString("point nr %1 already inserted").arg(firstendp));
665 }
666 else if ( secEndPoint == thEndPoint || secEndPoint == fouEndPoint )
667 {
668 //secendp is the number of the point which has been inserted twice
669 mTwiceInsPoint = secEndPoint;
670 // QgsDebugError(QString("point nr %1 already inserted").arg(secendp));
671 }
672
673 return -25; //return the code for a point that is already contained in the triangulation
674 }
675
676 if ( nulls == 1 ) //point is on an existing edge
677 {
678 return -20;
679 }
680
681 mEdgeInside = actEdge;
682
683 int nr1, nr2, nr3;
684 nr1 = mHalfEdge.at( actEdge )->getPoint();
685 nr2 = mHalfEdge.at( mHalfEdge.at( actEdge )->getNext() )->getPoint();
686 nr3 = mHalfEdge.at( mHalfEdge.at( mHalfEdge.at( actEdge )->getNext() )->getNext() )->getPoint();
687 const double x1 = mPointVector.at( nr1 )->x();
688 const double y1 = mPointVector.at( nr1 )->y();
689 const double x2 = mPointVector.at( nr2 )->x();
690 const double y2 = mPointVector.at( nr2 )->y();
691 const double x3 = mPointVector.at( nr3 )->x();
692 const double y3 = mPointVector.at( nr3 )->y();
693
694 //now make sure that always the same edge is returned
695 if ( x1 < x2 && x1 < x3 ) //return the edge which points to the point with the lowest x-coordinate
696 {
697 return actEdge;
698 }
699 else if ( x2 < x1 && x2 < x3 )
700 {
701 return mHalfEdge.at( actEdge )->getNext();
702 }
703 else if ( x3 < x1 && x3 < x2 )
704 {
705 return mHalfEdge.at( mHalfEdge.at( actEdge )->getNext() )->getNext();
706 }
707 //in case two x-coordinates are the same, the edge pointing to the point with the lower y-coordinate is returned
708 else if ( x1 == x2 )
709 {
710 if ( y1 < y2 )
711 {
712 return actEdge;
713 }
714 else if ( y2 < y1 )
715 {
716 return mHalfEdge.at( actEdge )->getNext();
717 }
718 }
719 else if ( x2 == x3 )
720 {
721 if ( y2 < y3 )
722 {
723 return mHalfEdge.at( actEdge )->getNext();
724 }
725 else if ( y3 < y2 )
726 {
727 return mHalfEdge.at( mHalfEdge.at( actEdge )->getNext() )->getNext();
728 }
729 }
730 else if ( x1 == x3 )
731 {
732 if ( y1 < y3 )
733 {
734 return actEdge;
735 }
736 else if ( y3 < y1 )
737 {
738 return mHalfEdge.at( mHalfEdge.at( actEdge )->getNext() )->getNext();
739 }
740 }
741 return -100; //this means a bug happened
742}
743
744bool QgsDualEdgeTriangulation::calcNormal( double x, double y, QgsPoint &result )
745{
746 if ( mTriangleInterpolator )
747 {
748 return mTriangleInterpolator->calcNormVec( x, y, result );
749 }
750 else
751 {
752 QgsDebugError( u"warning, null pointer"_s );
753 return false;
754 }
755}
756
757bool QgsDualEdgeTriangulation::calcPoint( double x, double y, QgsPoint &result )
758{
759 if ( mTriangleInterpolator )
760 {
761 return mTriangleInterpolator->calcPoint( x, y, result );
762 }
763 else
764 {
765 QgsDebugError( u"warning, null pointer"_s );
766 return false;
767 }
768}
769
770bool QgsDualEdgeTriangulation::checkSwapRecursively( unsigned int edge, unsigned int recursiveDeep )
771{
772 if ( swapPossible( edge ) )
773 {
774 QgsPoint *pta = mPointVector.at( mHalfEdge.at( edge )->getPoint() );
775 QgsPoint *ptb = mPointVector.at( mHalfEdge.at( mHalfEdge.at( edge )->getNext() )->getPoint() );
776 QgsPoint *ptc = mPointVector.at( mHalfEdge.at( mHalfEdge.at( mHalfEdge.at( edge )->getNext() )->getNext() )->getPoint() );
777 QgsPoint *ptd = mPointVector.at( mHalfEdge.at( mHalfEdge.at( mHalfEdge.at( edge )->getDual() )->getNext() )->getPoint() );
778 if ( inCircle( *ptd, *pta, *ptb, *ptc ) /*&& recursiveDeep < 100*/ ) //empty circle criterion violated
779 {
780 doSwapRecursively( edge, recursiveDeep ); //swap the edge (recursive)
781 return true;
782 }
783 }
784 return false;
785}
786
787bool QgsDualEdgeTriangulation::isEdgeNeedSwap( unsigned int edge ) const
788{
789 if ( swapPossible( edge ) )
790 {
791 QgsPoint *pta = mPointVector[mHalfEdge[edge]->getPoint()];
792 QgsPoint *ptb = mPointVector[mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint()];
793 QgsPoint *ptc = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[edge]->getNext()]->getNext()]->getPoint()];
794 QgsPoint *ptd = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint()];
795 return inCircle( *ptd, *pta, *ptb, *ptc );
796 }
797
798 return false;
799}
800
801void QgsDualEdgeTriangulation::doOnlySwap( unsigned int edge )
802{
803 const unsigned int edge1 = edge;
804 const unsigned int edge2 = mHalfEdge[edge]->getDual();
805 const unsigned int edge3 = mHalfEdge[edge]->getNext();
806 const unsigned int edge4 = mHalfEdge[mHalfEdge[edge]->getNext()]->getNext();
807 const unsigned int edge5 = mHalfEdge[mHalfEdge[edge]->getDual()]->getNext();
808 const unsigned int edge6 = mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getNext();
809 mHalfEdge[edge1]->setNext( edge4 ); //set the necessary nexts
810 mHalfEdge[edge2]->setNext( edge6 );
811 mHalfEdge[edge3]->setNext( edge2 );
812 mHalfEdge[edge4]->setNext( edge5 );
813 mHalfEdge[edge5]->setNext( edge1 );
814 mHalfEdge[edge6]->setNext( edge3 );
815 mHalfEdge[edge1]->setPoint( mHalfEdge[edge3]->getPoint() ); //change the points to which edge1 and edge2 point
816 mHalfEdge[edge2]->setPoint( mHalfEdge[edge5]->getPoint() );
817}
818
819void QgsDualEdgeTriangulation::doSwapRecursively( unsigned int edge, unsigned int recursiveDeep )
820{
821 const unsigned int edge1 = edge;
822 const unsigned int edge2 = mHalfEdge.at( edge )->getDual();
823 const unsigned int edge3 = mHalfEdge.at( edge )->getNext();
824 const unsigned int edge4 = mHalfEdge.at( mHalfEdge.at( edge )->getNext() )->getNext();
825 const unsigned int edge5 = mHalfEdge.at( mHalfEdge.at( edge )->getDual() )->getNext();
826 const unsigned int edge6 = mHalfEdge.at( mHalfEdge.at( mHalfEdge.at( edge )->getDual() )->getNext() )->getNext();
827 mHalfEdge.at( edge1 )->setNext( edge4 ); //set the necessary nexts
828 mHalfEdge.at( edge2 )->setNext( edge6 );
829 mHalfEdge.at( edge3 )->setNext( edge2 );
830 mHalfEdge.at( edge4 )->setNext( edge5 );
831 mHalfEdge.at( edge5 )->setNext( edge1 );
832 mHalfEdge.at( edge6 )->setNext( edge3 );
833 mHalfEdge.at( edge1 )->setPoint( mHalfEdge.at( edge3 )->getPoint() ); //change the points to which edge1 and edge2 point
834 mHalfEdge.at( edge2 )->setPoint( mHalfEdge.at( edge5 )->getPoint() );
835 recursiveDeep++;
836
837 if ( recursiveDeep < 100 )
838 {
839 checkSwapRecursively( edge3, recursiveDeep );
840 checkSwapRecursively( edge6, recursiveDeep );
841 checkSwapRecursively( edge4, recursiveDeep );
842 checkSwapRecursively( edge5, recursiveDeep );
843 }
844 else
845 {
846 QStack<int> edgesToSwap;
847 edgesToSwap.push( edge3 );
848 edgesToSwap.push( edge6 );
849 edgesToSwap.push( edge4 );
850 edgesToSwap.push( edge5 );
851 int loopCount = 0;
852 while ( !edgesToSwap.isEmpty() && loopCount < 10000 )
853 {
854 loopCount++;
855 const unsigned int e1 = edgesToSwap.pop();
856 if ( isEdgeNeedSwap( e1 ) )
857 {
858 const unsigned int e2 = mHalfEdge.at( e1 )->getDual();
859 const unsigned int e3 = mHalfEdge.at( e1 )->getNext();
860 const unsigned int e4 = mHalfEdge.at( mHalfEdge.at( e1 )->getNext() )->getNext();
861 const unsigned int e5 = mHalfEdge.at( mHalfEdge.at( e1 )->getDual() )->getNext();
862 const unsigned int e6 = mHalfEdge.at( mHalfEdge.at( mHalfEdge.at( e1 )->getDual() )->getNext() )->getNext();
863 mHalfEdge.at( e1 )->setNext( e4 ); //set the necessary nexts
864 mHalfEdge.at( e2 )->setNext( e6 );
865 mHalfEdge.at( e3 )->setNext( e2 );
866 mHalfEdge.at( e4 )->setNext( e5 );
867 mHalfEdge.at( e5 )->setNext( e1 );
868 mHalfEdge.at( e6 )->setNext( e3 );
869 mHalfEdge.at( e1 )->setPoint( mHalfEdge.at( e3 )->getPoint() ); //change the points to which edge1 and edge2 point
870 mHalfEdge.at( e2 )->setPoint( mHalfEdge.at( e5 )->getPoint() );
871
872 edgesToSwap.push( e3 );
873 edgesToSwap.push( e6 );
874 edgesToSwap.push( e4 );
875 edgesToSwap.push( e5 );
876 }
877 }
878 }
879}
880
881#if 0
882void DualEdgeTriangulation::draw( QPainter *p, double xlowleft, double ylowleft, double xupright, double yupright, double width, double height ) const
883{
884 //if mPointVector is empty, there is nothing to do
885 if ( mPointVector.isEmpty() )
886 {
887 return;
888 }
889
890 p->setPen( mEdgeColor );
891
892 bool *control = new bool[mHalfEdge.count()];//controllarray that no edge is painted twice
893 bool *control2 = new bool[mHalfEdge.count()];//controllarray for the flat triangles
894
895 for ( unsigned int i = 0; i <= mHalfEdge.count() - 1; i++ )
896 {
897 control[i] = false;
898 control2[i] = false;
899 }
900
901 if ( ( ( xupright - xlowleft ) / width ) > ( ( yupright - ylowleft ) / height ) )
902 {
903 double lowerborder = -( height * ( xupright - xlowleft ) / width - yupright );//real world coordinates of the lower widget border. This is useful to know because of the HalfEdge bounding box test
904 for ( unsigned int i = 0; i < mHalfEdge.count() - 1; i++ )
905 {
906 if ( mHalfEdge[i]->getPoint() == -1 || mHalfEdge[mHalfEdge[i]->getDual()]->getPoint() == -1 )
907 {continue;}
908
909 //check, if the edge belongs to a flat triangle, remove this later
910 if ( !control2[i] )
911 {
912 double p1, p2, p3;
913 if ( mHalfEdge[i]->getPoint() != -1 && mHalfEdge[mHalfEdge[i]->getNext()]->getPoint() != -1 && mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint() != -1 )
914 {
915 p1 = mPointVector[mHalfEdge[i]->getPoint()]->getZ();
916 p2 = mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getZ();
917 p3 = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getZ();
918 if ( p1 == p2 && p2 == p3 && halfEdgeBBoxTest( i, xlowleft, lowerborder, xupright, yupright ) && halfEdgeBBoxTest( mHalfEdge[i]->getNext(), xlowleft, lowerborder, xupright, yupright ) && halfEdgeBBoxTest( mHalfEdge[mHalfEdge[i]->getNext()]->getNext(), xlowleft, lowerborder, xupright, yupright ) )//draw the triangle
919 {
920 QPointArray pa( 3 );
921 pa.setPoint( 0, ( mPointVector[mHalfEdge[i]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[i]->getPoint()]->getY() ) / ( xupright - xlowleft )*width );
922 pa.setPoint( 1, ( mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getY() ) / ( xupright - xlowleft )*width );
923 pa.setPoint( 2, ( mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getY() ) / ( xupright - xlowleft )*width );
924 QColor c( 255, 0, 0 );
925 p->setBrush( c );
926 p->drawPolygon( pa );
927 }
928 }
929
930 control2[i] = true;
931 control2[mHalfEdge[i]->getNext()] = true;
932 control2[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()] = true;
933 }//end of the section, which has to be removed later
934
935 if ( control[i] )//check, if edge has already been drawn
936 {continue;}
937
938 //draw the edge;
939 if ( halfEdgeBBoxTest( i, xlowleft, lowerborder, xupright, yupright ) )//only draw the halfedge if its bounding box intersects the painted area
940 {
941 if ( mHalfEdge[i]->getBreak() )//change the color it the edge is a breakline
942 {
943 p->setPen( mBreakEdgeColor );
944 }
945 else if ( mHalfEdge[i]->getForced() )//change the color if the edge is forced
946 {
947 p->setPen( mForcedEdgeColor );
948 }
949
950
951 p->drawLine( ( mPointVector[mHalfEdge[i]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[i]->getPoint()]->getY() ) / ( xupright - xlowleft )*width, ( mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()]->getX() - xlowleft ) / ( xupright - xlowleft )*width, ( yupright - mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()]->getY() ) / ( xupright - xlowleft )*width );
952
953 if ( mHalfEdge[i]->getForced() )
954 {
955 p->setPen( mEdgeColor );
956 }
957
958
959 }
960 control[i] = true;
961 control[mHalfEdge[i]->getDual()] = true;
962 }
963 }
964 else
965 {
966 double rightborder = width * ( yupright - ylowleft ) / height + xlowleft;//real world coordinates of the right widget border. This is useful to know because of the HalfEdge bounding box test
967 for ( unsigned int i = 0; i < mHalfEdge.count() - 1; i++ )
968 {
969 if ( mHalfEdge[i]->getPoint() == -1 || mHalfEdge[mHalfEdge[i]->getDual()]->getPoint() == -1 )
970 {continue;}
971
972 //check, if the edge belongs to a flat triangle, remove this section later
973 if ( !control2[i] )
974 {
975 double p1, p2, p3;
976 if ( mHalfEdge[i]->getPoint() != -1 && mHalfEdge[mHalfEdge[i]->getNext()]->getPoint() != -1 && mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint() != -1 )
977 {
978 p1 = mPointVector[mHalfEdge[i]->getPoint()]->getZ();
979 p2 = mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getZ();
980 p3 = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getZ();
981 if ( p1 == p2 && p2 == p3 && halfEdgeBBoxTest( i, xlowleft, ylowleft, rightborder, yupright ) && halfEdgeBBoxTest( mHalfEdge[i]->getNext(), xlowleft, ylowleft, rightborder, yupright ) && halfEdgeBBoxTest( mHalfEdge[mHalfEdge[i]->getNext()]->getNext(), xlowleft, ylowleft, rightborder, yupright ) )//draw the triangle
982 {
983 QPointArray pa( 3 );
984 pa.setPoint( 0, ( mPointVector[mHalfEdge[i]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[i]->getPoint()]->getY() ) / ( yupright - ylowleft )*height );
985 pa.setPoint( 1, ( mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[mHalfEdge[i]->getNext()]->getPoint()]->getY() ) / ( yupright - ylowleft )*height );
986 pa.setPoint( 2, ( mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()]->getPoint()]->getY() ) / ( yupright - ylowleft )*height );
987 QColor c( 255, 0, 0 );
988 p->setBrush( c );
989 p->drawPolygon( pa );
990 }
991 }
992
993 control2[i] = true;
994 control2[mHalfEdge[i]->getNext()] = true;
995 control2[mHalfEdge[mHalfEdge[i]->getNext()]->getNext()] = true;
996 }//end of the section, which has to be removed later
997
998
999 if ( control[i] )//check, if edge has already been drawn
1000 {continue;}
1001
1002 //draw the edge
1003 if ( halfEdgeBBoxTest( i, xlowleft, ylowleft, rightborder, yupright ) )//only draw the edge if its bounding box intersects with the painted area
1004 {
1005 if ( mHalfEdge[i]->getBreak() )//change the color if the edge is a breakline
1006 {
1007 p->setPen( mBreakEdgeColor );
1008 }
1009 else if ( mHalfEdge[i]->getForced() )//change the color if the edge is forced
1010 {
1011 p->setPen( mForcedEdgeColor );
1012 }
1013
1014 p->drawLine( ( mPointVector[mHalfEdge[i]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[i]->getPoint()]->getY() ) / ( yupright - ylowleft )*height, ( mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()]->getX() - xlowleft ) / ( yupright - ylowleft )*height, ( yupright - mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()]->getY() ) / ( yupright - ylowleft )*height );
1015
1016 if ( mHalfEdge[i]->getForced() )
1017 {
1018 p->setPen( mEdgeColor );
1019 }
1020
1021 }
1022 control[i] = true;
1023 control[mHalfEdge[i]->getDual()] = true;
1024 }
1025 }
1026
1027 delete[] control;
1028 delete[] control2;
1029}
1030#endif
1031
1033{
1034 //first find a half edge which points to p2
1035 const int firstedge = baseEdgeOfPoint( p2 );
1036
1037 //then find the edge which comes from p1 or print an error message if there isn't any
1038 int theedge = -10;
1039 int nextnextedge = firstedge;
1040 int edge, nextedge;
1041 do
1042 {
1043 edge = mHalfEdge[nextnextedge]->getDual();
1044 if ( mHalfEdge[edge]->getPoint() == p1 )
1045 {
1046 theedge = nextnextedge;
1047 break;
1048 } //we found the edge
1049 nextedge = mHalfEdge[edge]->getNext();
1050 nextnextedge = mHalfEdge[nextedge]->getNext();
1051 } while ( nextnextedge != firstedge );
1052
1053 if ( theedge == -10 ) //there is no edge between p1 and p2
1054 {
1055 //QgsDebugError( u"warning, error: the points are: %1 and %2"_s.arg( p1 ).arg( p2 ) );
1056 return -10;
1057 }
1058
1059 //finally find the opposite point
1060 return mHalfEdge[mHalfEdge[mHalfEdge[theedge]->getDual()]->getNext()]->getPoint();
1061}
1062
1064{
1065 const int firstedge = baseEdgeOfPoint( pointno );
1066
1067 QList<int> vlist;
1068 if ( firstedge == -1 ) //an error occurred
1069 {
1070 return vlist;
1071 }
1072
1073 int actedge = firstedge;
1074 int edge, nextedge, nextnextedge;
1075 do
1076 {
1077 edge = mHalfEdge[actedge]->getDual();
1078 vlist.append( mHalfEdge[edge]->getPoint() ); //add the number of the endpoint of the first edge to the value list
1079 nextedge = mHalfEdge[edge]->getNext();
1080 vlist.append( mHalfEdge[nextedge]->getPoint() ); //add the number of the endpoint of the second edge to the value list
1081 nextnextedge = mHalfEdge[nextedge]->getNext();
1082 vlist.append( mHalfEdge[nextnextedge]->getPoint() ); //add the number of endpoint of the third edge to the value list
1083 if ( mHalfEdge[nextnextedge]->getBreak() ) //add, whether the third edge is a breakline or not
1084 {
1085 vlist.append( -10 );
1086 }
1087 else
1088 {
1089 vlist.append( -20 );
1090 }
1091 actedge = nextnextedge;
1092 } while ( nextnextedge != firstedge );
1093
1094 return vlist;
1095}
1096
1097bool QgsDualEdgeTriangulation::triangleVertices( double x, double y, QgsPoint &p1, int &n1, QgsPoint &p2, int &n2, QgsPoint &p3, int &n3 )
1098{
1099 if ( mPointVector.size() < 3 )
1100 {
1101 return false;
1102 }
1103
1104 const QgsPoint point( x, y, 0 );
1105 const int edge = baseEdgeOfTriangle( point );
1106 if ( edge == -10 ) //the point is outside the convex hull
1107 {
1108 return false;
1109 }
1110
1111 else if ( edge >= 0 ) //the point is inside the convex hull
1112 {
1113 const int ptnr1 = mHalfEdge[edge]->getPoint();
1114 const int ptnr2 = mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint();
1115 const int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[edge]->getNext()]->getNext()]->getPoint();
1116 p1.setX( mPointVector[ptnr1]->x() );
1117 p1.setY( mPointVector[ptnr1]->y() );
1118 p1.setZ( mPointVector[ptnr1]->z() );
1119 p2.setX( mPointVector[ptnr2]->x() );
1120 p2.setY( mPointVector[ptnr2]->y() );
1121 p2.setZ( mPointVector[ptnr2]->z() );
1122 p3.setX( mPointVector[ptnr3]->x() );
1123 p3.setY( mPointVector[ptnr3]->y() );
1124 p3.setZ( mPointVector[ptnr3]->z() );
1125 n1 = ptnr1;
1126 n2 = ptnr2;
1127 n3 = ptnr3;
1128 return true;
1129 }
1130 else if ( edge == -20 ) //the point is exactly on an edge
1131 {
1132 const int ptnr1 = mHalfEdge[mEdgeWithPoint]->getPoint();
1133 const int ptnr2 = mHalfEdge[mHalfEdge[mEdgeWithPoint]->getNext()]->getPoint();
1134 const int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[mEdgeWithPoint]->getNext()]->getNext()]->getPoint();
1135 if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 )
1136 {
1137 return false;
1138 }
1139 p1.setX( mPointVector[ptnr1]->x() );
1140 p1.setY( mPointVector[ptnr1]->y() );
1141 p1.setZ( mPointVector[ptnr1]->z() );
1142 p2.setX( mPointVector[ptnr2]->x() );
1143 p2.setY( mPointVector[ptnr2]->y() );
1144 p2.setZ( mPointVector[ptnr2]->z() );
1145 p3.setX( mPointVector[ptnr3]->x() );
1146 p3.setY( mPointVector[ptnr3]->y() );
1147 p3.setZ( mPointVector[ptnr3]->z() );
1148 n1 = ptnr1;
1149 n2 = ptnr2;
1150 n3 = ptnr3;
1151 return true;
1152 }
1153 else if ( edge == -25 ) //x and y are the coordinates of an existing point
1154 {
1155 const int edge1 = baseEdgeOfPoint( mTwiceInsPoint );
1156 const int edge2 = mHalfEdge[edge1]->getNext();
1157 const int edge3 = mHalfEdge[edge2]->getNext();
1158 const int ptnr1 = mHalfEdge[edge1]->getPoint();
1159 const int ptnr2 = mHalfEdge[edge2]->getPoint();
1160 const int ptnr3 = mHalfEdge[edge3]->getPoint();
1161 p1.setX( mPointVector[ptnr1]->x() );
1162 p1.setY( mPointVector[ptnr1]->y() );
1163 p1.setZ( mPointVector[ptnr1]->z() );
1164 p2.setX( mPointVector[ptnr2]->x() );
1165 p2.setY( mPointVector[ptnr2]->y() );
1166 p2.setZ( mPointVector[ptnr2]->z() );
1167 p3.setX( mPointVector[ptnr3]->x() );
1168 p3.setY( mPointVector[ptnr3]->y() );
1169 p3.setZ( mPointVector[ptnr3]->z() );
1170 n1 = ptnr1;
1171 n2 = ptnr2;
1172 n3 = ptnr3;
1173 return true;
1174 }
1175 else if ( edge == -5 ) //numerical problems in 'baseEdgeOfTriangle'
1176 {
1177 const int ptnr1 = mHalfEdge[mUnstableEdge]->getPoint();
1178 const int ptnr2 = mHalfEdge[mHalfEdge[mUnstableEdge]->getNext()]->getPoint();
1179 const int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[mUnstableEdge]->getNext()]->getNext()]->getPoint();
1180 if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 )
1181 {
1182 return false;
1183 }
1184 p1.setX( mPointVector[ptnr1]->x() );
1185 p1.setY( mPointVector[ptnr1]->y() );
1186 p1.setZ( mPointVector[ptnr1]->z() );
1187 p2.setX( mPointVector[ptnr2]->x() );
1188 p2.setY( mPointVector[ptnr2]->y() );
1189 p2.setZ( mPointVector[ptnr2]->z() );
1190 p3.setX( mPointVector[ptnr3]->x() );
1191 p3.setY( mPointVector[ptnr3]->y() );
1192 p3.setZ( mPointVector[ptnr3]->z() );
1193 n1 = ptnr1;
1194 n2 = ptnr2;
1195 n3 = ptnr3;
1196 return true;
1197 }
1198 else //problems
1199 {
1200 //QgsDebugError( u"problem: the edge is: %1"_s.arg( edge ) );
1201 return false;
1202 }
1203}
1204
1206{
1207 if ( mPointVector.size() < 3 )
1208 {
1209 return false;
1210 }
1211
1212 const QgsPoint point( x, y, 0 );
1213 const int edge = baseEdgeOfTriangle( point );
1214 if ( edge == -10 ) //the point is outside the convex hull
1215 {
1216 return false;
1217 }
1218 else if ( edge >= 0 ) //the point is inside the convex hull
1219 {
1220 const int ptnr1 = mHalfEdge[edge]->getPoint();
1221 const int ptnr2 = mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint();
1222 const int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[edge]->getNext()]->getNext()]->getPoint();
1223 p1.setX( mPointVector[ptnr1]->x() );
1224 p1.setY( mPointVector[ptnr1]->y() );
1225 p1.setZ( mPointVector[ptnr1]->z() );
1226 p2.setX( mPointVector[ptnr2]->x() );
1227 p2.setY( mPointVector[ptnr2]->y() );
1228 p2.setZ( mPointVector[ptnr2]->z() );
1229 p3.setX( mPointVector[ptnr3]->x() );
1230 p3.setY( mPointVector[ptnr3]->y() );
1231 p3.setZ( mPointVector[ptnr3]->z() );
1232 return true;
1233 }
1234 else if ( edge == -20 ) //the point is exactly on an edge
1235 {
1236 const int ptnr1 = mHalfEdge[mEdgeWithPoint]->getPoint();
1237 const int ptnr2 = mHalfEdge[mHalfEdge[mEdgeWithPoint]->getNext()]->getPoint();
1238 const int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[mEdgeWithPoint]->getNext()]->getNext()]->getPoint();
1239 if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 )
1240 {
1241 return false;
1242 }
1243 p1.setX( mPointVector[ptnr1]->x() );
1244 p1.setY( mPointVector[ptnr1]->y() );
1245 p1.setZ( mPointVector[ptnr1]->z() );
1246 p2.setX( mPointVector[ptnr2]->x() );
1247 p2.setY( mPointVector[ptnr2]->y() );
1248 p2.setZ( mPointVector[ptnr2]->z() );
1249 p3.setX( mPointVector[ptnr3]->x() );
1250 p3.setY( mPointVector[ptnr3]->y() );
1251 p3.setZ( mPointVector[ptnr3]->z() );
1252 return true;
1253 }
1254 else if ( edge == -25 ) //x and y are the coordinates of an existing point
1255 {
1256 const int edge1 = baseEdgeOfPoint( mTwiceInsPoint );
1257 const int edge2 = mHalfEdge[edge1]->getNext();
1258 const int edge3 = mHalfEdge[edge2]->getNext();
1259 const int ptnr1 = mHalfEdge[edge1]->getPoint();
1260 const int ptnr2 = mHalfEdge[edge2]->getPoint();
1261 const int ptnr3 = mHalfEdge[edge3]->getPoint();
1262 if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 )
1263 {
1264 return false;
1265 }
1266 p1.setX( mPointVector[ptnr1]->x() );
1267 p1.setY( mPointVector[ptnr1]->y() );
1268 p1.setZ( mPointVector[ptnr1]->z() );
1269 p2.setX( mPointVector[ptnr2]->x() );
1270 p2.setY( mPointVector[ptnr2]->y() );
1271 p2.setZ( mPointVector[ptnr2]->z() );
1272 p3.setX( mPointVector[ptnr3]->x() );
1273 p3.setY( mPointVector[ptnr3]->y() );
1274 p3.setZ( mPointVector[ptnr3]->z() );
1275 return true;
1276 }
1277 else if ( edge == -5 ) //numerical problems in 'baseEdgeOfTriangle'
1278 {
1279 const int ptnr1 = mHalfEdge[mUnstableEdge]->getPoint();
1280 const int ptnr2 = mHalfEdge[mHalfEdge[mUnstableEdge]->getNext()]->getPoint();
1281 const int ptnr3 = mHalfEdge[mHalfEdge[mHalfEdge[mUnstableEdge]->getNext()]->getNext()]->getPoint();
1282 if ( ptnr1 == -1 || ptnr2 == -1 || ptnr3 == -1 )
1283 {
1284 return false;
1285 }
1286 p1.setX( mPointVector[ptnr1]->x() );
1287 p1.setY( mPointVector[ptnr1]->y() );
1288 p1.setZ( mPointVector[ptnr1]->z() );
1289 p2.setX( mPointVector[ptnr2]->x() );
1290 p2.setY( mPointVector[ptnr2]->y() );
1291 p2.setZ( mPointVector[ptnr2]->z() );
1292 p3.setX( mPointVector[ptnr3]->x() );
1293 p3.setY( mPointVector[ptnr3]->y() );
1294 p3.setZ( mPointVector[ptnr3]->z() );
1295 return true;
1296 }
1297 else //problems
1298 {
1299 return false;
1300 }
1301}
1302
1303unsigned int QgsDualEdgeTriangulation::insertEdge( int dual, int next, int point, bool mbreak, bool forced )
1304{
1305 HalfEdge *edge = new HalfEdge( dual, next, point, mbreak, forced );
1306 mHalfEdge.append( edge );
1307 return mHalfEdge.count() - 1;
1308}
1309
1310static bool altitudeTriangleIsSmall( const QgsPoint &pointBase1, const QgsPoint &pointBase2, const QgsPoint &pt3, double tolerance )
1311{
1312 // Compare the altitude of the triangle defined by base points and a third point with tolerance. Return true if the altitude < tolerance
1313 const double x1 = pointBase1.x();
1314 const double y1 = pointBase1.y();
1315 const double x2 = pointBase2.x();
1316 const double y2 = pointBase2.y();
1317 const double X = pt3.x();
1318 const double Y = pt3.y();
1319 QgsPoint projectedPoint;
1320
1321 double nx, ny; //normal vector
1322
1323 nx = y2 - y1;
1324 ny = -( x2 - x1 );
1325
1326 double t;
1327 t = ( X * ny - Y * nx - x1 * ny + y1 * nx ) / ( ( x2 - x1 ) * ny - ( y2 - y1 ) * nx );
1328 projectedPoint.setX( x1 + t * ( x2 - x1 ) );
1329 projectedPoint.setY( y1 + t * ( y2 - y1 ) );
1330
1331 return pt3.distance( projectedPoint ) < tolerance;
1332}
1333
1334int QgsDualEdgeTriangulation::insertForcedSegment( int p1, int p2, QgsInterpolator::SourceType segmentType )
1335{
1336 if ( p1 == p2 )
1337 {
1338 return 0;
1339 }
1340
1341 QgsPoint *point1 = mPointVector.at( p1 );
1342 QgsPoint *point2 = mPointVector.at( p2 );
1343
1344 //list with (half of) the crossed edges
1345 QList<int> crossedEdges;
1346
1347 //an edge pointing to p1
1348 int pointingEdge = 0;
1349
1350 pointingEdge = baseEdgeOfPoint( p1 );
1351
1352 if ( pointingEdge == -1 )
1353 {
1354 return -100; //return an error code
1355 }
1356
1357 //go around p1 and find out, if the segment already exists and if not, which is the first cut edge
1358 int actEdge = mHalfEdge[pointingEdge]->getDual();
1359 const int firstActEdge = actEdge;
1360 //number to prevent endless loops
1361 int control = 0;
1362
1363 do //if it's an endless loop, something went wrong
1364 {
1365 control += 1;
1366 if ( control > 100 )
1367 {
1368 //QgsDebugError( u"warning, endless loop"_s );
1369 return -100; //return an error code
1370 }
1371
1372 if ( mHalfEdge[actEdge]->getPoint() == -1 ) //actEdge points to the virtual point
1373 {
1374 actEdge = mHalfEdge[mHalfEdge[mHalfEdge[actEdge]->getNext()]->getNext()]->getDual();
1375 continue;
1376 }
1377
1378 //test, if actEdge is already the forced edge
1379 if ( mHalfEdge[actEdge]->getPoint() == p2 )
1380 {
1381 mHalfEdge[actEdge]->setForced( true );
1382 mHalfEdge[actEdge]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1383 mHalfEdge[mHalfEdge[actEdge]->getDual()]->setForced( true );
1384 mHalfEdge[mHalfEdge[actEdge]->getDual()]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1385 return actEdge;
1386 }
1387
1388 //test, if the forced segment is a multiple of actEdge and if the direction is the same
1389 if ( /*lines are parallel*/ ( point2->y() - point1->y() ) / ( mPointVector[mHalfEdge[actEdge]->getPoint()]->y() - point1->y() ) == ( point2->x() - point1->x() ) / ( mPointVector[mHalfEdge[actEdge]->getPoint()]->x() - point1->x() )
1390 && ( ( point2->y() - point1->y() ) >= 0 ) == ( ( mPointVector[mHalfEdge[actEdge]->getPoint()]->y() - point1->y() ) > 0 )
1391 && ( ( point2->x() - point1->x() ) >= 0 ) == ( ( mPointVector[mHalfEdge[actEdge]->getPoint()]->x() - point1->x() ) > 0 ) )
1392 {
1393 //mark actedge and Dual(actedge) as forced, reset p1 and start the method from the beginning
1394 mHalfEdge[actEdge]->setForced( true );
1395 mHalfEdge[actEdge]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1396 mHalfEdge[mHalfEdge[actEdge]->getDual()]->setForced( true );
1397 mHalfEdge[mHalfEdge[actEdge]->getDual()]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1398 const int a = insertForcedSegment( mHalfEdge[actEdge]->getPoint(), p2, segmentType );
1399 return a;
1400 }
1401
1402 //test, if the forced segment intersects Next(actEdge)
1403 const int oppositeEdge = mHalfEdge[actEdge]->getNext();
1404
1405 if ( mHalfEdge[oppositeEdge]->getPoint() == -1 || mHalfEdge[mHalfEdge[oppositeEdge]->getDual()]->getPoint() == -1 ) //intersection with line to the virtual point makes no sense
1406 {
1407 actEdge = mHalfEdge[mHalfEdge[oppositeEdge]->getNext()]->getDual(); //continue with the next edge around p1
1408 continue;
1409 }
1410
1411 QgsPoint *oppositePoint1 = mPointVector[mHalfEdge[oppositeEdge]->getPoint()];
1412 QgsPoint *oppositePoint2 = mPointVector[mHalfEdge[mHalfEdge[oppositeEdge]->getDual()]->getPoint()];
1413
1414 if ( altitudeTriangleIsSmall( *oppositePoint1, *oppositePoint2, *point1, oppositePoint1->distance( *oppositePoint2 ) / 500 ) )
1415 {
1416 // to much risks to do something, go away
1417 return -100;
1418 }
1419
1420 if ( MathUtils::lineIntersection( point1, point2, mPointVector[mHalfEdge[oppositeEdge]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[oppositeEdge]->getDual()]->getPoint()] ) )
1421 {
1422 if ( mHalfEdge[mHalfEdge[actEdge]->getNext()]->getForced() && mForcedCrossBehavior == QgsTriangulation::ForcedCrossBehavior::SnappingTypeVertex ) //if the crossed edge is a forced edge, we have to snap the forced line to the next node
1423 {
1424 QgsPoint crosspoint( 0, 0, 0 );
1425 int p3, p4;
1426 p3 = mHalfEdge[mHalfEdge[actEdge]->getNext()]->getPoint();
1427 p4 = mHalfEdge[mHalfEdge[mHalfEdge[actEdge]->getNext()]->getDual()]->getPoint();
1428 MathUtils::lineIntersection( point1, point2, mPointVector[p3], mPointVector[p4], &crosspoint );
1429 const double dista = crosspoint.distance( *mPointVector[p3] );
1430 const double distb = crosspoint.distance( *mPointVector[p4] );
1431 if ( dista <= distb )
1432 {
1433 insertForcedSegment( p1, p3, segmentType );
1434 const int e = insertForcedSegment( p3, p2, segmentType );
1435 return e;
1436 }
1437 else if ( distb <= dista )
1438 {
1439 insertForcedSegment( p1, p4, segmentType );
1440 const int e = insertForcedSegment( p4, p2, segmentType );
1441 return e;
1442 }
1443 }
1444
1445 if ( mHalfEdge[mHalfEdge[actEdge]->getNext()]->getForced() && mForcedCrossBehavior == QgsTriangulation::ForcedCrossBehavior::InsertVertex ) //if the crossed edge is a forced edge, we have to insert a new vertice on this edge
1446 {
1447 QgsPoint crosspoint( 0, 0, 0 );
1448 int p3, p4;
1449 p3 = mHalfEdge[mHalfEdge[actEdge]->getNext()]->getPoint();
1450 p4 = mHalfEdge[mHalfEdge[mHalfEdge[actEdge]->getNext()]->getDual()]->getPoint();
1451 MathUtils::lineIntersection( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p4], &crosspoint );
1452 const double distpart = crosspoint.distance( *mPointVector[p4] );
1453 const double disttot = mPointVector[p3]->distance( *mPointVector[p4] );
1454 const float frac = distpart / disttot;
1455
1456 if ( frac == 0 || frac == 1 ) //just in case MathUtils::lineIntersection does not work as expected
1457 {
1458 if ( frac == 0 )
1459 {
1460 //mark actEdge and Dual(actEdge) as forced, reset p1 and start the method from the beginning
1461 mHalfEdge[actEdge]->setForced( true );
1462 mHalfEdge[actEdge]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1463 mHalfEdge[mHalfEdge[actEdge]->getDual()]->setForced( true );
1464 mHalfEdge[mHalfEdge[actEdge]->getDual()]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1465 const int a = insertForcedSegment( p4, p2, segmentType );
1466 return a;
1467 }
1468 else if ( frac == 1 )
1469 {
1470 //mark actEdge and Dual(actEdge) as forced, reset p1 and start the method from the beginning
1471 mHalfEdge[actEdge]->setForced( true );
1472 mHalfEdge[actEdge]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1473 mHalfEdge[mHalfEdge[actEdge]->getDual()]->setForced( true );
1474 mHalfEdge[mHalfEdge[actEdge]->getDual()]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1475 if ( p3 != p2 )
1476 {
1477 const int a = insertForcedSegment( p3, p2, segmentType );
1478 return a;
1479 }
1480 else
1481 {
1482 return actEdge;
1483 }
1484 }
1485 }
1486 else
1487 {
1488 const int newpoint = splitHalfEdge( mHalfEdge[actEdge]->getNext(), frac );
1489 insertForcedSegment( p1, newpoint, segmentType );
1490 const int e = insertForcedSegment( newpoint, p2, segmentType );
1491 return e;
1492 }
1493 }
1494
1495 //add the first HalfEdge to the list of crossed edges
1496 crossedEdges.append( oppositeEdge );
1497 break;
1498 }
1499 actEdge = mHalfEdge[mHalfEdge[oppositeEdge]->getNext()]->getDual(); //continue with the next edge around p1
1500 } while ( actEdge != firstActEdge );
1501
1502 if ( crossedEdges.isEmpty() ) //nothing found due to rounding error, better to go away!
1503 return -100;
1504 int lastEdgeOppositePointIndex = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint();
1505
1506 //we found the first edge, terminated the method or called the method with other points. Lets search for all the other crossed edges
1507 while ( lastEdgeOppositePointIndex != p2 )
1508 {
1509 QgsPoint *lastEdgePoint1 = mPointVector[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getPoint()];
1510 QgsPoint *lastEdgePoint2 = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getPoint()];
1511 QgsPoint *lastEdgeOppositePoint = mPointVector[lastEdgeOppositePointIndex];
1512
1513 if ( MathUtils::lineIntersection( lastEdgePoint1, lastEdgeOppositePoint, point1, point2 ) )
1514 {
1515 if ( mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getForced() && mForcedCrossBehavior == QgsTriangulation::ForcedCrossBehavior::SnappingTypeVertex ) //if the crossed edge is a forced edge and mForcedCrossBehavior is SnappingType_VERTICE, we have to snap the forced line to the next node
1516 {
1517 QgsPoint crosspoint( 0, 0, 0 );
1518 int p3, p4;
1519 p3 = mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getPoint();
1520 p4 = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint();
1521 MathUtils::lineIntersection( point1, point2, mPointVector[p3], mPointVector[p4], &crosspoint );
1522 const double dista = crosspoint.distance( *mPointVector[p3] );
1523 const double distb = crosspoint.distance( *mPointVector[p4] );
1524 if ( dista <= distb )
1525 {
1526 insertForcedSegment( p1, p3, segmentType );
1527 const int e = insertForcedSegment( p3, p2, segmentType );
1528 return e;
1529 }
1530 else if ( distb <= dista )
1531 {
1532 insertForcedSegment( p1, p4, segmentType );
1533 const int e = insertForcedSegment( p4, p2, segmentType );
1534 return e;
1535 }
1536 }
1537 else if ( mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getForced() && mForcedCrossBehavior == QgsTriangulation::ForcedCrossBehavior::InsertVertex ) //if the crossed edge is a forced edge, we have to insert a new vertice on this edge
1538 {
1539 QgsPoint crosspoint( 0, 0, 0 );
1540 int p3, p4;
1541 p3 = mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getPoint();
1542 p4 = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint();
1543 MathUtils::lineIntersection( point1, point2, mPointVector[p3], mPointVector[p4], &crosspoint );
1544 const double distpart = crosspoint.distance( *mPointVector[p3] );
1545 const double disttot = mPointVector[p3]->distance( *mPointVector[p4] );
1546 const float frac = distpart / disttot;
1547 if ( frac == 0 || frac == 1 )
1548 {
1549 break; //seems that a roundoff error occurred. We found the endpoint
1550 }
1551 const int newpoint = splitHalfEdge( mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext(), frac );
1552 insertForcedSegment( p1, newpoint, segmentType );
1553 const int e = insertForcedSegment( newpoint, p2, segmentType );
1554 return e;
1555 }
1556
1557 crossedEdges.append( mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext() );
1558 }
1559 else if ( MathUtils::lineIntersection( lastEdgePoint2, lastEdgeOppositePoint, point1, point2 ) )
1560 {
1561 if ( mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getForced() && mForcedCrossBehavior == QgsTriangulation::ForcedCrossBehavior::SnappingTypeVertex ) //if the crossed edge is a forced edge and mForcedCrossBehavior is SnappingType_VERTICE, we have to snap the forced line to the next node
1562 {
1563 QgsPoint crosspoint( 0, 0, 0 );
1564 int p3, p4;
1565 p3 = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint();
1566 p4 = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getPoint();
1567 MathUtils::lineIntersection( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p4], &crosspoint );
1568 const double dista = crosspoint.distance( *mPointVector[p3] );
1569 const double distb = crosspoint.distance( *mPointVector[p4] );
1570 if ( dista <= distb )
1571 {
1572 insertForcedSegment( p1, p3, segmentType );
1573 const int e = insertForcedSegment( p3, p2, segmentType );
1574 return e;
1575 }
1576 else if ( distb <= dista )
1577 {
1578 insertForcedSegment( p1, p4, segmentType );
1579 const int e = insertForcedSegment( p4, p2, segmentType );
1580 return e;
1581 }
1582 }
1583 else if ( mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getForced() && mForcedCrossBehavior == QgsTriangulation::ForcedCrossBehavior::InsertVertex ) //if the crossed edge is a forced edge, we have to insert a new vertice on this edge
1584 {
1585 QgsPoint crosspoint( 0, 0, 0 );
1586 int p3, p4;
1587 p3 = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint();
1588 p4 = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getPoint();
1589 MathUtils::lineIntersection( point1, point2, mPointVector[p3], mPointVector[p4], &crosspoint );
1590 const double distpart = crosspoint.distance( *mPointVector[p3] );
1591 const double disttot = mPointVector[p3]->distance( *mPointVector[p4] );
1592 const float frac = distpart / disttot;
1593 if ( frac == 0 || frac == 1 )
1594 {
1595 break; //seems that a roundoff error occurred. We found the endpoint
1596 }
1597 const int newpoint = splitHalfEdge( mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext(), frac );
1598 insertForcedSegment( p1, newpoint, segmentType );
1599 const int e = insertForcedSegment( newpoint, p2, segmentType );
1600 return e;
1601 }
1602
1603 crossedEdges.append( mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext() );
1604 }
1605 else
1606 {
1607 //no intersection found, surely due to rounding error or something else wrong, better to give up!
1608 return -100;
1609 }
1610 lastEdgeOppositePointIndex = mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getPoint();
1611 }
1612
1613 // Last check before construct the breakline
1614 QgsPoint *lastEdgePoint1 = mPointVector[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getPoint()];
1615 QgsPoint *lastEdgePoint2 = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext()]->getNext()]->getPoint()];
1616 QgsPoint *lastEdgeOppositePoint = mPointVector[lastEdgeOppositePointIndex];
1617 if ( altitudeTriangleIsSmall( *lastEdgePoint1, *lastEdgePoint2, *lastEdgeOppositePoint, lastEdgePoint1->distance( *lastEdgePoint2 ) / 500 ) )
1618 return -100;
1619
1620 //set the flags 'forced' and 'break' to false for every edge and dualedge of 'crossEdges'
1621 QList<int>::const_iterator iter;
1622 for ( iter = crossedEdges.constBegin(); iter != crossedEdges.constEnd(); ++iter )
1623 {
1624 mHalfEdge[( *( iter ) )]->setForced( false );
1625 mHalfEdge[( *( iter ) )]->setBreak( false );
1626 mHalfEdge[mHalfEdge[( *( iter ) )]->getDual()]->setForced( false );
1627 mHalfEdge[mHalfEdge[( *( iter ) )]->getDual()]->setBreak( false );
1628 }
1629
1630 //crossed edges is filled, now the two polygons to be retriangulated can be build
1631
1632 QList<int> freelist = crossedEdges; //copy the list with the crossed edges to remove the edges already reused
1633
1634 //create the left polygon as a list of the numbers of the halfedges
1635 QList<int> leftPolygon;
1636 QList<int> rightPolygon;
1637
1638 //insert the forced edge and enter the corresponding halfedges as the first edges in the left and right polygons. The nexts and points are set later because of the algorithm to build two polygons from 'crossedEdges'
1639 const int firstedge = freelist.first(); //edge pointing from p1 to p2
1640 mHalfEdge[firstedge]->setForced( true );
1641 mHalfEdge[firstedge]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1642 leftPolygon.append( firstedge );
1643 const int dualfirstedge = mHalfEdge[freelist.first()]->getDual(); //edge pointing from p2 to p1
1644 mHalfEdge[dualfirstedge]->setForced( true );
1645 mHalfEdge[dualfirstedge]->setBreak( segmentType == QgsInterpolator::SourceType::BreakLines );
1646 rightPolygon.append( dualfirstedge );
1647 freelist.pop_front(); //delete the first entry from the freelist
1648
1649 //finish the polygon on the left side
1650 int actpointl = p2;
1651 QList<int>::const_iterator leftiter; //todo: is there a better way to set an iterator to the last list element?
1652 leftiter = crossedEdges.constEnd();
1653 --leftiter;
1654 while ( true )
1655 {
1656 const int newpoint = mHalfEdge[mHalfEdge[mHalfEdge[mHalfEdge[( *leftiter )]->getDual()]->getNext()]->getNext()]->getPoint();
1657 if ( newpoint != actpointl )
1658 {
1659 //insert the edge into the leftPolygon
1660 actpointl = newpoint;
1661 const int theedge = mHalfEdge[mHalfEdge[mHalfEdge[( *leftiter )]->getDual()]->getNext()]->getNext();
1662 leftPolygon.append( theedge );
1663 }
1664 if ( leftiter == crossedEdges.constBegin() )
1665 {
1666 break;
1667 }
1668 --leftiter;
1669 }
1670
1671 //insert the last element into leftPolygon
1672 leftPolygon.append( mHalfEdge[crossedEdges.first()]->getNext() );
1673
1674 //finish the polygon on the right side
1675 QList<int>::const_iterator rightiter;
1676 int actpointr = p1;
1677 for ( rightiter = crossedEdges.constBegin(); rightiter != crossedEdges.constEnd(); ++rightiter )
1678 {
1679 const int newpoint = mHalfEdge[mHalfEdge[mHalfEdge[( *rightiter )]->getNext()]->getNext()]->getPoint();
1680 if ( newpoint != actpointr )
1681 {
1682 //insert the edge into the right polygon
1683 actpointr = newpoint;
1684 const int theedge = mHalfEdge[mHalfEdge[( *rightiter )]->getNext()]->getNext();
1685 rightPolygon.append( theedge );
1686 }
1687 }
1688
1689
1690 //insert the last element into rightPolygon
1691 rightPolygon.append( mHalfEdge[mHalfEdge[crossedEdges.last()]->getDual()]->getNext() );
1692 mHalfEdge[rightPolygon.last()]->setNext( dualfirstedge ); //set 'Next' of the last edge to dualfirstedge
1693
1694 //set the necessary nexts of leftPolygon(except the first)
1695 int actedgel = leftPolygon[1];
1696 leftiter = leftPolygon.constBegin();
1697 leftiter += 2;
1698 for ( ; leftiter != leftPolygon.constEnd(); ++leftiter )
1699 {
1700 mHalfEdge[actedgel]->setNext( ( *leftiter ) );
1701 actedgel = ( *leftiter );
1702 }
1703
1704 //set all the necessary nexts of rightPolygon
1705 int actedger = rightPolygon[1];
1706 rightiter = rightPolygon.constBegin();
1707 rightiter += 2;
1708 for ( ; rightiter != rightPolygon.constEnd(); ++rightiter )
1709 {
1710 mHalfEdge[actedger]->setNext( ( *rightiter ) );
1711 actedger = ( *( rightiter ) );
1712 }
1713
1714
1715 //setNext and setPoint for the forced edge because this would disturb the building of 'leftpoly' and 'rightpoly' otherwise
1716 mHalfEdge[leftPolygon.first()]->setNext( ( *( ++( leftiter = leftPolygon.constBegin() ) ) ) );
1717 mHalfEdge[leftPolygon.first()]->setPoint( p2 );
1718 mHalfEdge[leftPolygon.last()]->setNext( firstedge );
1719 mHalfEdge[rightPolygon.first()]->setNext( ( *( ++( rightiter = rightPolygon.constBegin() ) ) ) );
1720 mHalfEdge[rightPolygon.first()]->setPoint( p1 );
1721 mHalfEdge[rightPolygon.last()]->setNext( dualfirstedge );
1722
1723 triangulatePolygon( &leftPolygon, &freelist, firstedge );
1724 triangulatePolygon( &rightPolygon, &freelist, dualfirstedge );
1725
1726 //optimisation of the new edges
1727 for ( iter = crossedEdges.constBegin(); iter != crossedEdges.constEnd(); ++iter )
1728 {
1729 checkSwapRecursively( ( *( iter ) ), 0 );
1730 }
1731
1732 return leftPolygon.first();
1733}
1734
1739
1741{
1742 mTriangleInterpolator = interpolator;
1743}
1744
1746{
1747 //QgsDebugMsgLevel( u"am in eliminateHorizontalTriangles"_s, 2 );
1748 const double minangle = 0; //minimum angle for swapped triangles. If triangles generated by a swap would have a minimum angle (in degrees) below that value, the swap will not be done.
1749
1750 while ( true )
1751 {
1752 bool swapped = false; //flag which allows exiting the loop
1753 bool *control = new bool[mHalfEdge.count()]; //controlarray
1754
1755 for ( int i = 0; i <= mHalfEdge.count() - 1; i++ )
1756 {
1757 control[i] = false;
1758 }
1759
1760
1761 for ( int i = 0; i <= mHalfEdge.count() - 1; i++ )
1762 {
1763 if ( control[i] ) //edge has already been examined
1764 {
1765 continue;
1766 }
1767
1768 int e1, e2, e3; //numbers of the three edges
1769 e1 = i;
1770 e2 = mHalfEdge[e1]->getNext();
1771 e3 = mHalfEdge[e2]->getNext();
1772
1773 int p1, p2, p3; //numbers of the three points
1774 p1 = mHalfEdge[e1]->getPoint();
1775 p2 = mHalfEdge[e2]->getPoint();
1776 p3 = mHalfEdge[e3]->getPoint();
1777
1778 //skip the iteration, if one point is the virtual point
1779 if ( p1 == -1 || p2 == -1 || p3 == -1 )
1780 {
1781 control[e1] = true;
1782 control[e2] = true;
1783 control[e3] = true;
1784 continue;
1785 }
1786
1787 double el1, el2, el3; //elevations of the points
1788 el1 = mPointVector[p1]->z();
1789 el2 = mPointVector[p2]->z();
1790 el3 = mPointVector[p3]->z();
1791
1792 if ( el1 == el2 && el2 == el3 ) //we found a horizontal triangle
1793 {
1794 //swap edges if it is possible, if it would remove the horizontal triangle and if the minimum angle generated by the swap is high enough
1795 if ( swapPossible( ( uint ) e1 ) && mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[e1]->getDual()]->getNext()]->getPoint()]->z() != el1 && swapMinAngle( e1 ) > minangle )
1796 {
1797 doOnlySwap( ( uint ) e1 );
1798 swapped = true;
1799 }
1800 else if ( swapPossible( ( uint ) e2 ) && mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[e2]->getDual()]->getNext()]->getPoint()]->z() != el2 && swapMinAngle( e2 ) > minangle )
1801 {
1802 doOnlySwap( ( uint ) e2 );
1803 swapped = true;
1804 }
1805 else if ( swapPossible( ( uint ) e3 ) && mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[e3]->getDual()]->getNext()]->getPoint()]->z() != el3 && swapMinAngle( e3 ) > minangle )
1806 {
1807 doOnlySwap( ( uint ) e3 );
1808 swapped = true;
1809 }
1810 control[e1] = true;
1811 control[e2] = true;
1812 control[e3] = true;
1813 continue;
1814 }
1815 else //no horizontal triangle, go to the next one
1816 {
1817 control[e1] = true;
1818 control[e2] = true;
1819 control[e3] = true;
1820 continue;
1821 }
1822 }
1823 if ( !swapped )
1824 {
1825 delete[] control;
1826 break;
1827 }
1828 delete[] control;
1829 }
1830
1831 //QgsDebugMsgLevel( u"end of method"_s, 2 );
1832}
1833
1835{
1836 //minimum angle
1837 const double mintol = 17; //refinement stops after the minimum angle reached this tolerance
1838
1839 //data structures
1840 std::map<int, double> edge_angle; //search tree with the edge number as key
1841 std::multimap<double, int> angle_edge; //multimap (map with not unique keys) with angle as key
1842 QSet<int> dontexamine; //search tree containing the edges which do not have to be examined (because of numerical problems)
1843
1844
1845 //first, go through all the forced edges and subdivide if they are encroached by a point
1846 bool stop = false; //flag to ensure that the for-loop is repeated until no half edge is split any more
1847
1848 while ( !stop )
1849 {
1850 stop = true;
1851 const int nhalfedges = mHalfEdge.count();
1852
1853 for ( int i = 0; i < nhalfedges - 1; i++ )
1854 {
1855 const int next = mHalfEdge[i]->getNext();
1856 const int nextnext = mHalfEdge[next]->getNext();
1857
1858 if ( mHalfEdge[next]->getPoint() != -1 && ( mHalfEdge[i]->getForced() || mHalfEdge[mHalfEdge[mHalfEdge[i]->getDual()]->getNext()]->getPoint() == -1 ) ) //check for encroached points on forced segments and segments on the inner side of the convex hull, but don't consider edges on the outer side of the convex hull
1859 {
1860 if ( !( ( mHalfEdge[next]->getForced() || edgeOnConvexHull( next ) ) || ( mHalfEdge[nextnext]->getForced() || edgeOnConvexHull( nextnext ) ) ) ) //don't consider triangles where all three edges are forced edges or hull edges
1861 {
1862 //test for encroachment
1863 while ( MathUtils::inDiametral( mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()], mPointVector[mHalfEdge[i]->getPoint()], mPointVector[mHalfEdge[next]->getPoint()] ) )
1864 {
1865 //split segment
1866 const int pointno = splitHalfEdge( i, 0.5 );
1867 Q_UNUSED( pointno )
1868 stop = false;
1869 }
1870 }
1871 }
1872 }
1873 }
1874
1875 //examine the triangulation for angles below the minimum and insert the edges into angle_edge and edge_angle, except the small angle is between forced segments or convex hull edges
1876 double angle; //angle between edge i and the consecutive edge
1877 int p1, p2, p3; //numbers of the triangle points
1878 for ( int i = 0; i < mHalfEdge.count() - 1; i++ )
1879 {
1880 p1 = mHalfEdge[mHalfEdge[i]->getDual()]->getPoint();
1881 p2 = mHalfEdge[i]->getPoint();
1882 p3 = mHalfEdge[mHalfEdge[i]->getNext()]->getPoint();
1883
1884 if ( p1 == -1 || p2 == -1 || p3 == -1 ) //don't consider triangles with the virtual point
1885 {
1886 continue;
1887 }
1888 angle = MathUtils::angle( mPointVector[p1], mPointVector[p2], mPointVector[p3], mPointVector[p2] );
1889
1890 bool twoforcededges; //flag to decide, if edges should be added to the maps. Do not add them if true
1891
1892
1893 twoforcededges = ( mHalfEdge[i]->getForced() || edgeOnConvexHull( i ) ) && ( mHalfEdge[mHalfEdge[i]->getNext()]->getForced() || edgeOnConvexHull( mHalfEdge[i]->getNext() ) );
1894
1895 if ( angle < mintol && !twoforcededges )
1896 {
1897 edge_angle.insert( std::make_pair( i, angle ) );
1898 angle_edge.insert( std::make_pair( angle, i ) );
1899 }
1900 }
1901
1902 //debugging: print out all the angles below the minimum for a test
1903 for ( std::multimap<double, int>::const_iterator it = angle_edge.begin(); it != angle_edge.end(); ++it )
1904 {
1905 QgsDebugMsgLevel( u"angle: %1"_s.arg( it->first ), 2 );
1906 }
1907
1908
1909 double minangle = 0; //actual minimum angle
1910 int minedge; //first edge adjacent to the minimum angle
1911 int minedgenext;
1912 int minedgenextnext;
1913
1914 QgsPoint circumcenter( 0, 0, 0 );
1915
1916 while ( !edge_angle.empty() )
1917 {
1918 minangle = angle_edge.begin()->first;
1919 QgsDebugMsgLevel( u"minangle: %1"_s.arg( minangle ), 2 );
1920 minedge = angle_edge.begin()->second;
1921 minedgenext = mHalfEdge[minedge]->getNext();
1922 minedgenextnext = mHalfEdge[minedgenext]->getNext();
1923
1924 //calculate the circumcenter
1925 if ( !MathUtils::circumcenter( mPointVector[mHalfEdge[minedge]->getPoint()], mPointVector[mHalfEdge[minedgenext]->getPoint()], mPointVector[mHalfEdge[minedgenextnext]->getPoint()], &circumcenter ) )
1926 {
1927 QgsDebugError( u"warning, calculation of circumcenter failed"_s );
1928 //put all three edges to dontexamine and remove them from the other maps
1929 dontexamine.insert( minedge );
1930 edge_angle.erase( minedge );
1931 std::multimap<double, int>::iterator minedgeiter = angle_edge.find( minangle );
1932 while ( minedgeiter->second != minedge )
1933 {
1934 ++minedgeiter;
1935 }
1936 angle_edge.erase( minedgeiter );
1937 continue;
1938 }
1939
1940 if ( !pointInside( circumcenter.x(), circumcenter.y() ) )
1941 {
1942 //put all three edges to dontexamine and remove them from the other maps
1943 QgsDebugError( u"put circumcenter %1//%2 on dontexamine list because it is outside the convex hull"_s
1944 .arg( circumcenter.x() )
1945 .arg( circumcenter.y() ) );
1946 dontexamine.insert( minedge );
1947 edge_angle.erase( minedge );
1948 std::multimap<double, int>::iterator minedgeiter = angle_edge.find( minangle );
1949 while ( minedgeiter->second != minedge )
1950 {
1951 ++minedgeiter;
1952 }
1953 angle_edge.erase( minedgeiter );
1954 continue;
1955 }
1956
1957 /*******find out, if any forced segment or convex hull segment is in the influence region of the circumcenter. In this case, split the segment********************/
1958
1959 bool encroached = false;
1960
1961#if 0 //slow version
1962 int numhalfedges = mHalfEdge.count();//begin slow version
1963 for ( int i = 0; i < numhalfedges; i++ )
1964 {
1965 if ( mHalfEdge[i]->getForced() || edgeOnConvexHull( i ) )
1966 {
1967 if ( MathUtils::inDiametral( mPointVector[mHalfEdge[i]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[i]->getDual()]->getPoint()], &circumcenter ) )
1968 {
1969 encroached = true;
1970 //split segment
1971 QgsDebugMsgLevel( u"segment split"_s, 2 );
1972 int pointno = splitHalfEdge( i, 0.5 );
1973
1974 //update dontexmine, angle_edge, edge_angle
1975 int pointingedge = baseEdgeOfPoint( pointno );
1976
1977 int actedge = pointingedge;
1978 int ed1, ed2, ed3;//numbers of the three edges
1979 int pt1, pt2, pt3;//numbers of the three points
1980 double angle1, angle2, angle3;
1981
1982 do
1983 {
1984 ed1 = mHalfEdge[actedge]->getDual();
1985 pt1 = mHalfEdge[ed1]->getPoint();
1986 ed2 = mHalfEdge[ed1]->getNext();
1987 pt2 = mHalfEdge[ed2]->getPoint();
1988 ed3 = mHalfEdge[ed2]->getNext();
1989 pt3 = mHalfEdge[ed3]->getPoint();
1990 actedge = ed3;
1991
1992 if ( pt1 == -1 || pt2 == -1 || pt3 == -1 )//don't consider triangles with the virtual point
1993 {
1994 continue;
1995 }
1996
1997 angle1 = MathUtils::angle( mPointVector[pt3], mPointVector[pt1], mPointVector[pt2], mPointVector[pt1] );
1998 angle2 = MathUtils::angle( mPointVector[pt1], mPointVector[pt2], mPointVector[pt3], mPointVector[pt2] );
1999 angle3 = MathUtils::angle( mPointVector[pt2], mPointVector[pt3], mPointVector[pt1], mPointVector[pt3] );
2000
2001 //don't put the edges on the maps if two segments are forced or on a hull
2002 bool twoforcededges1, twoforcededges2, twoforcededges3;//flag to indicate, if angle1, angle2 and angle3 are between forced edges or hull edges
2003
2004 if ( ( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) && ( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) )
2005 {
2006 twoforcededges1 = true;
2007 }
2008 else
2009 {
2010 twoforcededges1 = false;
2011 }
2012
2013 if ( ( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) && ( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) )
2014 {
2015 twoforcededges2 = true;
2016 }
2017 else
2018 {
2019 twoforcededges2 = false;
2020 }
2021
2022 if ( ( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) && ( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) )
2023 {
2024 twoforcededges3 = true;
2025 }
2026 else
2027 {
2028 twoforcededges3 = false;
2029 }
2030
2031 //update the settings related to ed1
2032 QSet<int>::iterator ed1iter = dontexamine.find( ed1 );
2033 if ( ed1iter != dontexamine.end() )
2034 {
2035 //edge number is on dontexamine list
2036 dontexamine.erase( ed1iter );
2037 }
2038 else
2039 {
2040 //test, if it is on edge_angle and angle_edge and erase them if yes
2041 std::map<int, double>::iterator tempit1;
2042 tempit1 = edge_angle.find( ed1 );
2043 if ( tempit1 != edge_angle.end() )
2044 {
2045 //erase the entries
2046 double angle = tempit1->second;
2047 edge_angle.erase( ed1 );
2048 std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle );
2049 while ( tempit2->second != ed1 )
2050 {
2051 ++tempit2;
2052 }
2053 angle_edge.erase( tempit2 );
2054 }
2055 }
2056
2057 if ( angle1 < mintol && !twoforcededges1 )
2058 {
2059 edge_angle.insert( std::make_pair( ed1, angle1 ) );
2060 angle_edge.insert( std::make_pair( angle1, ed1 ) );
2061 }
2062
2063 //update the settings related to ed2
2064 QSet<int>::iterator ed2iter = dontexamine.find( ed2 );
2065 if ( ed2iter != dontexamine.end() )
2066 {
2067 //edge number is on dontexamine list
2068 dontexamine.erase( ed2iter );
2069 }
2070 else
2071 {
2072 //test, if it is on edge_angle and angle_edge and erase them if yes
2073 std::map<int, double>::iterator tempit1;
2074 tempit1 = edge_angle.find( ed2 );
2075 if ( tempit1 != edge_angle.end() )
2076 {
2077 //erase the entries
2078 double angle = tempit1->second;
2079 edge_angle.erase( ed2 );
2080 std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle );
2081 while ( tempit2->second != ed2 )
2082 {
2083 ++tempit2;
2084 }
2085 angle_edge.erase( tempit2 );
2086 }
2087 }
2088
2089 if ( angle2 < mintol && !twoforcededges2 )
2090 {
2091 edge_angle.insert( std::make_pair( ed2, angle2 ) );
2092 angle_edge.insert( std::make_pair( angle2, ed2 ) );
2093 }
2094
2095 //update the settings related to ed3
2096 QSet<int>::iterator ed3iter = dontexamine.find( ed3 );
2097 if ( ed3iter != dontexamine.end() )
2098 {
2099 //edge number is on dontexamine list
2100 dontexamine.erase( ed3iter );
2101 }
2102 else
2103 {
2104 //test, if it is on edge_angle and angle_edge and erase them if yes
2105 std::map<int, double>::iterator tempit1;
2106 tempit1 = edge_angle.find( ed3 );
2107 if ( tempit1 != edge_angle.end() )
2108 {
2109 //erase the entries
2110 double angle = tempit1->second;
2111 edge_angle.erase( ed3 );
2112 std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle );
2113 while ( tempit2->second != ed3 )
2114 {
2115 ++tempit2;
2116 }
2117 angle_edge.erase( tempit2 );
2118 }
2119 }
2120
2121 if ( angle3 < mintol && !twoforcededges3 )
2122 {
2123 edge_angle.insert( std::make_pair( ed3, angle3 ) );
2124 angle_edge.insert( std::make_pair( angle3, ed3 ) );
2125 }
2126
2127
2128 }
2129 while ( actedge != pointingedge );
2130 }
2131 }
2132 }
2133#endif //end slow version
2134
2135
2136 //fast version. Maybe this does not work
2137 QSet<int> influenceedges; //begin fast method
2138 int baseedge = baseEdgeOfTriangle( circumcenter );
2139 if ( baseedge == -5 ) //a numerical instability occurred or the circumcenter already exists in the triangulation
2140 {
2141 //delete minedge from edge_angle and minangle from angle_edge
2142 edge_angle.erase( minedge );
2143 std::multimap<double, int>::iterator minedgeiter = angle_edge.find( minangle );
2144 while ( minedgeiter->second != minedge )
2145 {
2146 ++minedgeiter;
2147 }
2148 angle_edge.erase( minedgeiter );
2149 continue;
2150 }
2151 else if ( baseedge == -25 ) //circumcenter already exists in the triangulation
2152 {
2153 //delete minedge from edge_angle and minangle from angle_edge
2154 edge_angle.erase( minedge );
2155 std::multimap<double, int>::iterator minedgeiter = angle_edge.find( minangle );
2156 while ( minedgeiter->second != minedge )
2157 {
2158 ++minedgeiter;
2159 }
2160 angle_edge.erase( minedgeiter );
2161 continue;
2162 }
2163 else if ( baseedge == -20 )
2164 {
2165 baseedge = mEdgeWithPoint;
2166 }
2167
2168 evaluateInfluenceRegion( &circumcenter, baseedge, influenceedges );
2169 evaluateInfluenceRegion( &circumcenter, mHalfEdge[baseedge]->getNext(), influenceedges );
2170 evaluateInfluenceRegion( &circumcenter, mHalfEdge[mHalfEdge[baseedge]->getNext()]->getNext(), influenceedges );
2171
2172 for ( QSet<int>::iterator it = influenceedges.begin(); it != influenceedges.end(); ++it )
2173 {
2174 if ( ( mHalfEdge[*it]->getForced() || edgeOnConvexHull( *it ) ) && MathUtils::inDiametral( mPointVector[mHalfEdge[*it]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[*it]->getDual()]->getPoint()], &circumcenter ) )
2175 {
2176 //split segment
2177 QgsDebugMsgLevel( u"segment split"_s, 2 );
2178 const int pointno = splitHalfEdge( *it, 0.5 );
2179 encroached = true;
2180
2181 //update dontexmine, angle_edge, edge_angle
2182 const int pointingedge = baseEdgeOfPoint( pointno );
2183
2184 int actedge = pointingedge;
2185 int ed1, ed2, ed3; //numbers of the three edges
2186 int pt1, pt2, pt3; //numbers of the three points
2187 double angle1, angle2, angle3;
2188
2189 do
2190 {
2191 ed1 = mHalfEdge[actedge]->getDual();
2192 pt1 = mHalfEdge[ed1]->getPoint();
2193 ed2 = mHalfEdge[ed1]->getNext();
2194 pt2 = mHalfEdge[ed2]->getPoint();
2195 ed3 = mHalfEdge[ed2]->getNext();
2196 pt3 = mHalfEdge[ed3]->getPoint();
2197 actedge = ed3;
2198
2199 if ( pt1 == -1 || pt2 == -1 || pt3 == -1 ) //don't consider triangles with the virtual point
2200 {
2201 continue;
2202 }
2203
2204 angle1 = MathUtils::angle( mPointVector[pt3], mPointVector[pt1], mPointVector[pt2], mPointVector[pt1] );
2205 angle2 = MathUtils::angle( mPointVector[pt1], mPointVector[pt2], mPointVector[pt3], mPointVector[pt2] );
2206 angle3 = MathUtils::angle( mPointVector[pt2], mPointVector[pt3], mPointVector[pt1], mPointVector[pt3] );
2207
2208 //don't put the edges on the maps if two segments are forced or on a hull
2209 bool twoforcededges1, twoforcededges2, twoforcededges3; //flag to decide, if edges should be added to the maps. Do not add them if true
2210
2211
2212 twoforcededges1 = ( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) && ( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) );
2213
2214 twoforcededges2 = ( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) && ( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) );
2215
2216 twoforcededges3 = ( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) && ( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) );
2217
2218
2219 //update the settings related to ed1
2220 const QSet<int>::iterator ed1iter = dontexamine.find( ed1 );
2221 if ( ed1iter != dontexamine.end() )
2222 {
2223 //edge number is on dontexamine list
2224 dontexamine.erase( ed1iter );
2225 }
2226 else
2227 {
2228 //test, if it is on edge_angle and angle_edge and erase them if yes
2229 std::map<int, double>::iterator tempit1;
2230 tempit1 = edge_angle.find( ed1 );
2231 if ( tempit1 != edge_angle.end() )
2232 {
2233 //erase the entries
2234 const double angle = tempit1->second;
2235 edge_angle.erase( ed1 );
2236 std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle );
2237 while ( tempit2->second != ed1 )
2238 {
2239 ++tempit2;
2240 }
2241 angle_edge.erase( tempit2 );
2242 }
2243 }
2244
2245 if ( angle1 < mintol && !twoforcededges1 )
2246 {
2247 edge_angle.insert( std::make_pair( ed1, angle1 ) );
2248 angle_edge.insert( std::make_pair( angle1, ed1 ) );
2249 }
2250
2251 //update the settings related to ed2
2252 const QSet<int>::iterator ed2iter = dontexamine.find( ed2 );
2253 if ( ed2iter != dontexamine.end() )
2254 {
2255 //edge number is on dontexamine list
2256 dontexamine.erase( ed2iter );
2257 }
2258 else
2259 {
2260 //test, if it is on edge_angle and angle_edge and erase them if yes
2261 std::map<int, double>::iterator tempit1;
2262 tempit1 = edge_angle.find( ed2 );
2263 if ( tempit1 != edge_angle.end() )
2264 {
2265 //erase the entries
2266 const double angle = tempit1->second;
2267 edge_angle.erase( ed2 );
2268 std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle );
2269 while ( tempit2->second != ed2 )
2270 {
2271 ++tempit2;
2272 }
2273 angle_edge.erase( tempit2 );
2274 }
2275 }
2276
2277 if ( angle2 < mintol && !twoforcededges2 )
2278 {
2279 edge_angle.insert( std::make_pair( ed2, angle2 ) );
2280 angle_edge.insert( std::make_pair( angle2, ed2 ) );
2281 }
2282
2283 //update the settings related to ed3
2284 const QSet<int>::iterator ed3iter = dontexamine.find( ed3 );
2285 if ( ed3iter != dontexamine.end() )
2286 {
2287 //edge number is on dontexamine list
2288 dontexamine.erase( ed3iter );
2289 }
2290 else
2291 {
2292 //test, if it is on edge_angle and angle_edge and erase them if yes
2293 std::map<int, double>::iterator tempit1;
2294 tempit1 = edge_angle.find( ed3 );
2295 if ( tempit1 != edge_angle.end() )
2296 {
2297 //erase the entries
2298 const double angle = tempit1->second;
2299 edge_angle.erase( ed3 );
2300 std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle );
2301 while ( tempit2->second != ed3 )
2302 {
2303 ++tempit2;
2304 }
2305 angle_edge.erase( tempit2 );
2306 }
2307 }
2308
2309 if ( angle3 < mintol && !twoforcededges3 )
2310 {
2311 edge_angle.insert( std::make_pair( ed3, angle3 ) );
2312 angle_edge.insert( std::make_pair( angle3, ed3 ) );
2313 }
2314
2315
2316 } while ( actedge != pointingedge );
2317 }
2318 } //end fast method
2319
2320
2321 if ( encroached )
2322 {
2323 continue;
2324 }
2325
2326 /*******otherwise, try to add the circumcenter to the triangulation************************************************************************************************/
2327
2328 QgsPoint p( 0, 0, 0 );
2329 calcPoint( circumcenter.x(), circumcenter.y(), p );
2330 const int pointno = addPoint( p );
2331
2332 if ( pointno == -100 || pointno == mTwiceInsPoint )
2333 {
2334 if ( pointno == -100 )
2335 {
2336 QgsDebugError( u"put circumcenter %1//%2 on dontexamine list because of numerical instabilities"_s
2337 .arg( circumcenter.x() )
2338 .arg( circumcenter.y() ) );
2339 }
2340 else if ( pointno == mTwiceInsPoint )
2341 {
2342 QgsDebugError( u"put circumcenter %1//%2 on dontexamine list because it is already inserted"_s
2343 .arg( circumcenter.x() )
2344 .arg( circumcenter.y() ) );
2345 //test, if the point is present in the triangulation
2346 bool flag = false;
2347 for ( int i = 0; i < mPointVector.count(); i++ )
2348 {
2349 if ( mPointVector[i]->x() == circumcenter.x() && mPointVector[i]->y() == circumcenter.y() )
2350 {
2351 flag = true;
2352 }
2353 }
2354 if ( !flag )
2355 {
2356 QgsDebugError( u"point is not present in the triangulation"_s );
2357 }
2358 }
2359 //put all three edges to dontexamine and remove them from the other maps
2360 dontexamine.insert( minedge );
2361 edge_angle.erase( minedge );
2362 std::multimap<double, int>::iterator minedgeiter = angle_edge.lower_bound( minangle );
2363 while ( minedgeiter->second != minedge )
2364 {
2365 ++minedgeiter;
2366 }
2367 angle_edge.erase( minedgeiter );
2368 continue;
2369 }
2370 else //insertion successful
2371 {
2372 QgsDebugMsgLevel( u"circumcenter added"_s, 2 );
2373
2374 //update the maps
2375 //go around the inserted point and make changes for every half edge
2376 const int pointingedge = baseEdgeOfPoint( pointno );
2377
2378 int actedge = pointingedge;
2379 int ed1, ed2, ed3; //numbers of the three edges
2380 int pt1, pt2, pt3; //numbers of the three points
2381 double angle1, angle2, angle3;
2382
2383 do
2384 {
2385 ed1 = mHalfEdge[actedge]->getDual();
2386 pt1 = mHalfEdge[ed1]->getPoint();
2387 ed2 = mHalfEdge[ed1]->getNext();
2388 pt2 = mHalfEdge[ed2]->getPoint();
2389 ed3 = mHalfEdge[ed2]->getNext();
2390 pt3 = mHalfEdge[ed3]->getPoint();
2391 actedge = ed3;
2392
2393 if ( pt1 == -1 || pt2 == -1 || pt3 == -1 ) //don't consider triangles with the virtual point
2394 {
2395 continue;
2396 }
2397
2398 angle1 = MathUtils::angle( mPointVector[pt3], mPointVector[pt1], mPointVector[pt2], mPointVector[pt1] );
2399 angle2 = MathUtils::angle( mPointVector[pt1], mPointVector[pt2], mPointVector[pt3], mPointVector[pt2] );
2400 angle3 = MathUtils::angle( mPointVector[pt2], mPointVector[pt3], mPointVector[pt1], mPointVector[pt3] );
2401
2402 //todo: put all three edges on the dontexamine list if two edges are forced or convex hull edges
2403 bool twoforcededges1, twoforcededges2, twoforcededges3;
2404
2405 twoforcededges1 = ( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) ) && ( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) );
2406
2407 twoforcededges2 = ( mHalfEdge[ed2]->getForced() || edgeOnConvexHull( ed2 ) ) && ( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) );
2408
2409 twoforcededges3 = ( mHalfEdge[ed3]->getForced() || edgeOnConvexHull( ed3 ) ) && ( mHalfEdge[ed1]->getForced() || edgeOnConvexHull( ed1 ) );
2410
2411
2412 //update the settings related to ed1
2413 const QSet<int>::iterator ed1iter = dontexamine.find( ed1 );
2414 if ( ed1iter != dontexamine.end() )
2415 {
2416 //edge number is on dontexamine list
2417 dontexamine.erase( ed1iter );
2418 }
2419 else
2420 {
2421 //test, if it is on edge_angle and angle_edge and erase them if yes
2422 std::map<int, double>::iterator tempit1;
2423 tempit1 = edge_angle.find( ed1 );
2424 if ( tempit1 != edge_angle.end() )
2425 {
2426 //erase the entries
2427 const double angle = tempit1->second;
2428 edge_angle.erase( ed1 );
2429 std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle );
2430 while ( tempit2->second != ed1 )
2431 {
2432 ++tempit2;
2433 }
2434 angle_edge.erase( tempit2 );
2435 }
2436 }
2437
2438 if ( angle1 < mintol && !twoforcededges1 )
2439 {
2440 edge_angle.insert( std::make_pair( ed1, angle1 ) );
2441 angle_edge.insert( std::make_pair( angle1, ed1 ) );
2442 }
2443
2444
2445 //update the settings related to ed2
2446 const QSet<int>::iterator ed2iter = dontexamine.find( ed2 );
2447 if ( ed2iter != dontexamine.end() )
2448 {
2449 //edge number is on dontexamine list
2450 dontexamine.erase( ed2iter );
2451 }
2452 else
2453 {
2454 //test, if it is on edge_angle and angle_edge and erase them if yes
2455 std::map<int, double>::iterator tempit1;
2456 tempit1 = edge_angle.find( ed2 );
2457 if ( tempit1 != edge_angle.end() )
2458 {
2459 //erase the entries
2460 const double angle = tempit1->second;
2461 edge_angle.erase( ed2 );
2462 std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle );
2463 while ( tempit2->second != ed2 )
2464 {
2465 ++tempit2;
2466 }
2467 angle_edge.erase( tempit2 );
2468 }
2469 }
2470
2471 if ( angle2 < mintol && !twoforcededges2 )
2472 {
2473 edge_angle.insert( std::make_pair( ed2, angle2 ) );
2474 angle_edge.insert( std::make_pair( angle2, ed2 ) );
2475 }
2476
2477 //update the settings related to ed3
2478 const QSet<int>::iterator ed3iter = dontexamine.find( ed3 );
2479 if ( ed3iter != dontexamine.end() )
2480 {
2481 //edge number is on dontexamine list
2482 dontexamine.erase( ed3iter );
2483 }
2484 else
2485 {
2486 //test, if it is on edge_angle and angle_edge and erase them if yes
2487 std::map<int, double>::iterator tempit1;
2488 tempit1 = edge_angle.find( ed3 );
2489 if ( tempit1 != edge_angle.end() )
2490 {
2491 //erase the entries
2492 const double angle = tempit1->second;
2493 edge_angle.erase( ed3 );
2494 std::multimap<double, int>::iterator tempit2 = angle_edge.lower_bound( angle );
2495 while ( tempit2->second != ed3 )
2496 {
2497 ++tempit2;
2498 }
2499 angle_edge.erase( tempit2 );
2500 }
2501 }
2502
2503 if ( angle3 < mintol && !twoforcededges3 )
2504 {
2505 edge_angle.insert( std::make_pair( ed3, angle3 ) );
2506 angle_edge.insert( std::make_pair( angle3, ed3 ) );
2507 }
2508
2509
2510 } while ( actedge != pointingedge );
2511 }
2512 }
2513
2514#if 0
2515 //debugging: print out all edge of dontexamine
2516 for ( QSet<int>::iterator it = dontexamine.begin(); it != dontexamine.end(); ++it )
2517 {
2518 QgsDebugMsgLevel( u"edge nr. %1 is in dontexamine"_s.arg( *it ), 2 );
2519 }
2520#endif
2521}
2522
2523
2524bool QgsDualEdgeTriangulation::swapPossible( unsigned int edge ) const
2525{
2526 //test, if edge belongs to a forced edge
2527 if ( mHalfEdge[edge]->getForced() )
2528 {
2529 return false;
2530 }
2531
2532 //test, if the edge is on the convex hull or is connected to the virtual point
2533 if ( mHalfEdge[edge]->getPoint() == -1 || mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint() == -1 || mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint() == -1 || mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint() == -1 )
2534 {
2535 return false;
2536 }
2537 //then, test, if the edge is in the middle of a not convex quad
2538 QgsPoint *pta = mPointVector[mHalfEdge[edge]->getPoint()];
2539 QgsPoint *ptb = mPointVector[mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint()];
2540 QgsPoint *ptc = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[edge]->getNext()]->getNext()]->getPoint()];
2541 QgsPoint *ptd = mPointVector[mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint()];
2542 if ( MathUtils::leftOf( *ptc, pta, ptb ) > leftOfTresh )
2543 {
2544 return false;
2545 }
2546 else if ( MathUtils::leftOf( *ptd, ptb, ptc ) > leftOfTresh )
2547 {
2548 return false;
2549 }
2550 else if ( MathUtils::leftOf( *pta, ptc, ptd ) > leftOfTresh )
2551 {
2552 return false;
2553 }
2554 else if ( MathUtils::leftOf( *ptb, ptd, pta ) > leftOfTresh )
2555 {
2556 return false;
2557 }
2558 return true;
2559}
2560
2561void QgsDualEdgeTriangulation::triangulatePolygon( QList<int> *poly, QList<int> *free, int mainedge )
2562{
2563 if ( poly && free )
2564 {
2565 if ( poly->count() == 3 ) //polygon is already a triangle
2566 {
2567 return;
2568 }
2569
2570 //search for the edge pointing on the closest point(distedge) and for the next(nextdistedge)
2571 QList<int>::const_iterator iterator = ++( poly->constBegin() ); //go to the second edge
2572 double distance = MathUtils::distPointFromLine( mPointVector[mHalfEdge[( *iterator )]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[mainedge]->getPoint()] );
2573 int distedge = ( *iterator );
2574 int nextdistedge = mHalfEdge[( *iterator )]->getNext();
2575 ++iterator;
2576
2577 while ( iterator != --( poly->constEnd() ) )
2578 {
2579 if ( MathUtils::distPointFromLine( mPointVector[mHalfEdge[( *iterator )]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[mainedge]->getPoint()] ) < distance )
2580 {
2581 distedge = ( *iterator );
2582 nextdistedge = mHalfEdge[( *iterator )]->getNext();
2583 distance = MathUtils::distPointFromLine( mPointVector[mHalfEdge[( *iterator )]->getPoint()], mPointVector[mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[mainedge]->getPoint()] );
2584 }
2585 ++iterator;
2586 }
2587
2588 if ( nextdistedge == ( *( --poly->end() ) ) ) //the nearest point is connected to the endpoint of mainedge
2589 {
2590 const int inserta = free->first(); //take an edge from the freelist
2591 const int insertb = mHalfEdge[inserta]->getDual();
2592 free->pop_front();
2593
2594 mHalfEdge[inserta]->setNext( ( poly->at( 1 ) ) );
2595 mHalfEdge[inserta]->setPoint( mHalfEdge[mainedge]->getPoint() );
2596 mHalfEdge[insertb]->setNext( nextdistedge );
2597 mHalfEdge[insertb]->setPoint( mHalfEdge[distedge]->getPoint() );
2598 mHalfEdge[distedge]->setNext( inserta );
2599 mHalfEdge[mainedge]->setNext( insertb );
2600
2601 QList<int> polya;
2602 for ( iterator = ( ++( poly->constBegin() ) ); ( *iterator ) != nextdistedge; ++iterator )
2603 {
2604 polya.append( ( *iterator ) );
2605 }
2606 polya.prepend( inserta );
2607
2608#if 0
2609 //print out all the elements of polya for a test
2610 for ( iterator = polya.begin(); iterator != polya.end(); ++iterator )
2611 {
2612 QgsDebugMsgLevel( *iterator, 2 );
2613 }
2614#endif
2615
2616 triangulatePolygon( &polya, free, inserta );
2617 }
2618
2619 else if ( distedge == ( *( ++poly->begin() ) ) ) //the nearest point is connected to the beginpoint of mainedge
2620 {
2621 const int inserta = free->first(); //take an edge from the freelist
2622 const int insertb = mHalfEdge[inserta]->getDual();
2623 free->pop_front();
2624
2625 mHalfEdge[inserta]->setNext( ( poly->at( 2 ) ) );
2626 mHalfEdge[inserta]->setPoint( mHalfEdge[distedge]->getPoint() );
2627 mHalfEdge[insertb]->setNext( mainedge );
2628 mHalfEdge[insertb]->setPoint( mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint() );
2629 mHalfEdge[distedge]->setNext( insertb );
2630 mHalfEdge[( *( --poly->end() ) )]->setNext( inserta );
2631
2632 QList<int> polya;
2633 iterator = poly->constBegin();
2634 iterator += 2;
2635 while ( iterator != poly->constEnd() )
2636 {
2637 polya.append( ( *iterator ) );
2638 ++iterator;
2639 }
2640 polya.prepend( inserta );
2641
2642 triangulatePolygon( &polya, free, inserta );
2643 }
2644
2645 else //the nearest point is not connected to an endpoint of mainedge
2646 {
2647 const int inserta = free->first(); //take an edge from the freelist
2648 const int insertb = mHalfEdge[inserta]->getDual();
2649 free->pop_front();
2650
2651 const int insertc = free->first();
2652 const int insertd = mHalfEdge[insertc]->getDual();
2653 free->pop_front();
2654
2655 mHalfEdge[inserta]->setNext( ( poly->at( 1 ) ) );
2656 mHalfEdge[inserta]->setPoint( mHalfEdge[mainedge]->getPoint() );
2657 mHalfEdge[insertb]->setNext( insertd );
2658 mHalfEdge[insertb]->setPoint( mHalfEdge[distedge]->getPoint() );
2659 mHalfEdge[insertc]->setNext( nextdistedge );
2660 mHalfEdge[insertc]->setPoint( mHalfEdge[distedge]->getPoint() );
2661 mHalfEdge[insertd]->setNext( mainedge );
2662 mHalfEdge[insertd]->setPoint( mHalfEdge[mHalfEdge[mainedge]->getDual()]->getPoint() );
2663
2664 mHalfEdge[distedge]->setNext( inserta );
2665 mHalfEdge[mainedge]->setNext( insertb );
2666 mHalfEdge[( *( --poly->end() ) )]->setNext( insertc );
2667
2668 //build two new polygons for recursive triangulation
2669 QList<int> polya;
2670 QList<int> polyb;
2671
2672 for ( iterator = ++( poly->constBegin() ); ( *iterator ) != nextdistedge; ++iterator )
2673 {
2674 polya.append( ( *iterator ) );
2675 }
2676 polya.prepend( inserta );
2677
2678
2679 while ( iterator != poly->constEnd() )
2680 {
2681 polyb.append( ( *iterator ) );
2682 ++iterator;
2683 }
2684 polyb.prepend( insertc );
2685
2686 triangulatePolygon( &polya, free, inserta );
2687 triangulatePolygon( &polyb, free, insertc );
2688 }
2689 }
2690
2691 else
2692 {
2693 QgsDebugError( u"warning, null pointer"_s );
2694 }
2695}
2696
2698{
2699 const QgsPoint point( x, y, 0 );
2700 unsigned int actedge = mEdgeInside; //start with an edge which does not point to the virtual point
2701 int counter = 0; //number of consecutive successful left-of-tests
2702 int nulls = 0; //number of left-of-tests, which returned 0. 1 means, that the point is on a line, 2 means that it is on an existing point
2703 int numinstabs = 0; //number of suspect left-of-tests due to 'leftOfTresh'
2704 int runs = 0; //counter for the number of iterations in the loop to prevent an endless loop
2705
2706 while ( true )
2707 {
2708 if ( runs > MAX_BASE_ITERATIONS ) //prevents endless loops
2709 {
2710 QgsDebugError( u"warning, instability detected: Point coordinates: %1//%2"_s.arg( x ).arg( y ) );
2711 return false;
2712 }
2713
2714 if ( MathUtils::leftOf( point, mPointVector[mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[actedge]->getPoint()] ) < ( -leftOfTresh ) ) //point is on the left side
2715 {
2716 counter += 1;
2717 if ( counter == 3 ) //three successful passes means that we have found the triangle
2718 {
2719 break;
2720 }
2721 }
2722
2723 else if ( fabs( MathUtils::leftOf( point, mPointVector[mHalfEdge[mHalfEdge[actedge]->getDual()]->getPoint()], mPointVector[mHalfEdge[actedge]->getPoint()] ) ) <= leftOfTresh ) //point is exactly in the line of the edge
2724 {
2725 counter += 1;
2726 mEdgeWithPoint = actedge;
2727 nulls += 1;
2728 if ( counter == 3 ) //three successful passes means that we have found the triangle
2729 {
2730 break;
2731 }
2732 }
2733
2734 else //point is on the right side
2735 {
2736 actedge = mHalfEdge[actedge]->getDual();
2737 counter = 1;
2738 nulls = 0;
2739 numinstabs = 0;
2740 }
2741
2742 actedge = mHalfEdge[actedge]->getNext();
2743 if ( mHalfEdge[actedge]->getPoint() == -1 ) //the half edge points to the virtual point
2744 {
2745 if ( nulls == 1 ) //point is exactly on the convex hull
2746 {
2747 return true;
2748 }
2749 mEdgeOutside = ( unsigned int ) mHalfEdge[mHalfEdge[actedge]->getNext()]->getNext();
2750 return false; //the point is outside the convex hull
2751 }
2752 runs++;
2753 }
2754
2755 if ( nulls == 2 ) //we hit an existing point
2756 {
2757 return true;
2758 }
2759 if ( numinstabs > 0 ) //a numerical instability occurred
2760 {
2761 QgsDebugError( u"numerical instabilities"_s );
2762 return true;
2763 }
2764
2765 if ( nulls == 1 ) //point is on an existing edge
2766 {
2767 return true;
2768 }
2769 mEdgeInside = actedge;
2770 return true;
2771}
2772
2773#if 0
2774bool DualEdgeTriangulation::readFromTAFF( QString filename )
2775{
2776 QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );//change the cursor
2777
2778 QFile file( filename );//the file to be read
2779 file.open( IO_Raw | IO_ReadOnly );
2780 QBuffer buffer( file.readAll() );//the buffer to copy the file to
2781 file.close();
2782
2783 QTextStream textstream( &buffer );
2784 buffer.open( IO_ReadOnly );
2785
2786 QString buff;
2787 int numberofhalfedges;
2788 int numberofpoints;
2789
2790 //edge section
2791 while ( buff.mid( 0, 4 ) != "TRIA" )//search for the TRIA-section
2792 {
2793 buff = textstream.readLine();
2794 }
2795 while ( buff.mid( 0, 4 ) != "NEDG" )
2796 {
2797 buff = textstream.readLine();
2798 }
2799 numberofhalfedges = buff.section( ' ', 1, 1 ).toInt();
2800 mHalfEdge.resize( numberofhalfedges );
2801
2802
2803 while ( buff.mid( 0, 4 ) != "DATA" )//search for the data section
2804 {
2805 textstream >> buff;
2806 }
2807
2808 int nr1, nr2, dual1, dual2, point1, point2, next1, next2, fo1, fo2, b1, b2;
2809 bool forced1, forced2, break1, break2;
2810
2811
2812 //import all the DualEdges
2813 QProgressBar *edgebar = new QProgressBar();//use a progress dialog so that it is not boring for the user
2814 edgebar->setCaption( tr( "Reading edges…" ) );
2815 edgebar->setTotalSteps( numberofhalfedges / 2 );
2816 edgebar->setMinimumWidth( 400 );
2817 edgebar->move( 500, 500 );
2818 edgebar->show();
2819
2820 for ( int i = 0; i < numberofhalfedges / 2; i++ )
2821 {
2822 if ( i % 1000 == 0 )
2823 {
2824 edgebar->setProgress( i );
2825 }
2826
2827 textstream >> nr1;
2828 textstream >> point1;
2829 textstream >> next1;
2830 textstream >> fo1;
2831
2832 if ( fo1 == 0 )
2833 {
2834 forced1 = false;
2835 }
2836 else
2837 {
2838 forced1 = true;
2839 }
2840
2841 textstream >> b1;
2842
2843 if ( b1 == 0 )
2844 {
2845 break1 = false;
2846 }
2847 else
2848 {
2849 break1 = true;
2850 }
2851
2852 textstream >> nr2;
2853 textstream >> point2;
2854 textstream >> next2;
2855 textstream >> fo2;
2856
2857 if ( fo2 == 0 )
2858 {
2859 forced2 = false;
2860 }
2861 else
2862 {
2863 forced2 = true;
2864 }
2865
2866 textstream >> b2;
2867
2868 if ( b2 == 0 )
2869 {
2870 break2 = false;
2871 }
2872 else
2873 {
2874 break2 = true;
2875 }
2876
2877 HalfEdge *hf1 = new HalfEdge();
2878 hf1->setDual( nr2 );
2879 hf1->setNext( next1 );
2880 hf1->setPoint( point1 );
2881 hf1->setBreak( break1 );
2882 hf1->setForced( forced1 );
2883
2884 HalfEdge *hf2 = new HalfEdge();
2885 hf2->setDual( nr1 );
2886 hf2->setNext( next2 );
2887 hf2->setPoint( point2 );
2888 hf2->setBreak( break2 );
2889 hf2->setForced( forced2 );
2890
2891 // QgsDebugMsgLevel( u"inserting half edge pair %1"_s.arg( i ), 2 );
2892 mHalfEdge.insert( nr1, hf1 );
2893 mHalfEdge.insert( nr2, hf2 );
2894
2895 }
2896
2897 edgebar->setProgress( numberofhalfedges / 2 );
2898 delete edgebar;
2899
2900 //set mEdgeInside to a reasonable value
2901 for ( int i = 0; i < numberofhalfedges; i++ )
2902 {
2903 int a, b, c, d;
2904 a = mHalfEdge[i]->getPoint();
2905 b = mHalfEdge[mHalfEdge[i]->getDual()]->getPoint();
2906 c = mHalfEdge[mHalfEdge[i]->getNext()]->getPoint();
2907 d = mHalfEdge[mHalfEdge[mHalfEdge[i]->getDual()]->getNext()]->getPoint();
2908 if ( a != -1 && b != -1 && c != -1 && d != -1 )
2909 {
2910 mEdgeInside = i;
2911 break;
2912 }
2913 }
2914
2915 //point section
2916 while ( buff.mid( 0, 4 ) != "POIN" )
2917 {
2918 buff = textstream.readLine();
2919 QgsDebugMsgLevel( buff, 2 );
2920 }
2921 while ( buff.mid( 0, 4 ) != "NPTS" )
2922 {
2923 buff = textstream.readLine();
2924 QgsDebugMsgLevel( buff, 2 );
2925 }
2926 numberofpoints = buff.section( ' ', 1, 1 ).toInt();
2927 mPointVector.resize( numberofpoints );
2928
2929 while ( buff.mid( 0, 4 ) != "DATA" )
2930 {
2931 textstream >> buff;
2932 }
2933
2934 QProgressBar *pointbar = new QProgressBar();
2935 pointbar->setCaption( tr( "Reading points…" ) );
2936 pointbar->setTotalSteps( numberofpoints );
2937 pointbar->setMinimumWidth( 400 );
2938 pointbar->move( 500, 500 );
2939 pointbar->show();
2940
2941
2942 double x, y, z;
2943 for ( int i = 0; i < numberofpoints; i++ )
2944 {
2945 if ( i % 1000 == 0 )
2946 {
2947 pointbar->setProgress( i );
2948 }
2949
2950 textstream >> x;
2951 textstream >> y;
2952 textstream >> z;
2953
2954 QgsPoint *p = new QgsPoint( x, y, z );
2955
2956 // QgsDebugMsgLevel( u"inserting point %1"_s.arg( i ), 2 );
2957 mPointVector.insert( i, p );
2958
2959 if ( i == 0 )
2960 {
2961 xMin = x;
2962 xMax = x;
2963 yMin = y;
2964 yMax = y;
2965 }
2966 else
2967 {
2968 //update the bounding box
2969 if ( x < xMin )
2970 {
2971 xMin = x;
2972 }
2973 else if ( x > xMax )
2974 {
2975 xMax = x;
2976 }
2977
2978 if ( y < yMin )
2979 {
2980 yMin = y;
2981 }
2982 else if ( y > yMax )
2983 {
2984 yMax = y;
2985 }
2986 }
2987 }
2988
2989 pointbar->setProgress( numberofpoints );
2990 delete pointbar;
2991 QApplication::restoreOverrideCursor();
2992
2993}
2994
2995bool DualEdgeTriangulation::saveToTAFF( QString filename ) const
2996{
2997 QFile outputfile( filename );
2998 if ( !outputfile.open( IO_WriteOnly ) )
2999 {
3000 QMessageBox::warning( 0, tr( "Warning" ), tr( "File could not be written." ), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton );
3001 return false;
3002 }
3003
3004 QTextStream outstream( &outputfile );
3005 outstream.precision( 9 );
3006
3007 //export the edges. Attention, dual edges must be adjacent in the TAFF-file
3008 outstream << "TRIA" << std::endl << std::flush;
3009 outstream << "NEDG " << mHalfEdge.count() << std::endl << std::flush;
3010 outstream << "PANO 1" << std::endl << std::flush;
3011 outstream << "DATA ";
3012
3013 bool *cont = new bool[mHalfEdge.count()];
3014 for ( unsigned int i = 0; i <= mHalfEdge.count() - 1; i++ )
3015 {
3016 cont[i] = false;
3017 }
3018
3019 for ( unsigned int i = 0; i < mHalfEdge.count(); i++ )
3020 {
3021 if ( cont[i] )
3022 {
3023 continue;
3024 }
3025
3026 int dual = mHalfEdge[i]->getDual();
3027 outstream << i << " " << mHalfEdge[i]->getPoint() << " " << mHalfEdge[i]->getNext() << " " << mHalfEdge[i]->getForced() << " " << mHalfEdge[i]->getBreak() << " ";
3028 outstream << dual << " " << mHalfEdge[dual]->getPoint() << " " << mHalfEdge[dual]->getNext() << " " << mHalfEdge[dual]->getForced() << " " << mHalfEdge[dual]->getBreak() << " ";
3029 cont[i] = true;
3030 cont[dual] = true;
3031 }
3032 outstream << std::endl << std::flush;
3033 outstream << std::endl << std::flush;
3034
3035 delete[] cont;
3036
3037 //export the points to the file
3038 outstream << "POIN" << std::endl << std::flush;
3039 outstream << "NPTS " << getNumberOfPoints() << std::endl << std::flush;
3040 outstream << "PATT 3" << std::endl << std::flush;
3041 outstream << "DATA ";
3042
3043 for ( int i = 0; i < getNumberOfPoints(); i++ )
3044 {
3045 QgsPoint *p = mPointVector[i];
3046 outstream << p->getX() << " " << p->getY() << " " << p->getZ() << " ";
3047 }
3048 outstream << std::endl << std::flush;
3049 outstream << std::endl << std::flush;
3050
3051 return true;
3052}
3053#endif //0
3054
3055bool QgsDualEdgeTriangulation::swapEdge( double x, double y )
3056{
3057 QgsPoint p( x, y, 0 );
3058 const int edge1 = baseEdgeOfTriangle( p );
3059 if ( edge1 >= 0 )
3060 {
3061 int edge2, edge3;
3062 QgsPoint *point1 = nullptr;
3063 QgsPoint *point2 = nullptr;
3064 QgsPoint *point3 = nullptr;
3065 edge2 = mHalfEdge[edge1]->getNext();
3066 edge3 = mHalfEdge[edge2]->getNext();
3067 point1 = point( mHalfEdge[edge1]->getPoint() );
3068 point2 = point( mHalfEdge[edge2]->getPoint() );
3069 point3 = point( mHalfEdge[edge3]->getPoint() );
3070 if ( point1 && point2 && point3 )
3071 {
3072 //find out the closest edge to the point and swap this edge
3073 double dist1, dist2, dist3;
3074 dist1 = MathUtils::distPointFromLine( &p, point3, point1 );
3075 dist2 = MathUtils::distPointFromLine( &p, point1, point2 );
3076 dist3 = MathUtils::distPointFromLine( &p, point2, point3 );
3077 if ( dist1 <= dist2 && dist1 <= dist3 )
3078 {
3079 //qWarning("edge "+QString::number(edge1)+" is closest");
3080 if ( swapPossible( edge1 ) )
3081 {
3082 doOnlySwap( edge1 );
3083 }
3084 }
3085 else if ( dist2 <= dist1 && dist2 <= dist3 )
3086 {
3087 //qWarning("edge "+QString::number(edge2)+" is closest");
3088 if ( swapPossible( edge2 ) )
3089 {
3090 doOnlySwap( edge2 );
3091 }
3092 }
3093 else if ( dist3 <= dist1 && dist3 <= dist2 )
3094 {
3095 //qWarning("edge "+QString::number(edge3)+" is closest");
3096 if ( swapPossible( edge3 ) )
3097 {
3098 doOnlySwap( edge3 );
3099 }
3100 }
3101 return true;
3102 }
3103 else
3104 {
3105 // QgsDebugError("warning: null pointer");
3106 return false;
3107 }
3108 }
3109 else
3110 {
3111 // QgsDebugError("Edge number negative");
3112 return false;
3113 }
3114}
3115
3116QList<int> QgsDualEdgeTriangulation::pointsAroundEdge( double x, double y )
3117{
3118 QgsPoint p( x, y, 0 );
3119 QList<int> list;
3120 const int edge1 = baseEdgeOfTriangle( p );
3121 if ( edge1 >= 0 )
3122 {
3123 const int edge2 = mHalfEdge[edge1]->getNext();
3124 const int edge3 = mHalfEdge[edge2]->getNext();
3125 QgsPoint *point1 = point( mHalfEdge[edge1]->getPoint() );
3126 QgsPoint *point2 = point( mHalfEdge[edge2]->getPoint() );
3127 QgsPoint *point3 = point( mHalfEdge[edge3]->getPoint() );
3128 if ( point1 && point2 && point3 )
3129 {
3130 int p1, p2, p3, p4;
3131 const double dist1 = MathUtils::distPointFromLine( &p, point3, point1 );
3132 const double dist2 = MathUtils::distPointFromLine( &p, point1, point2 );
3133 const double dist3 = MathUtils::distPointFromLine( &p, point2, point3 );
3134 if ( dist1 <= dist2 && dist1 <= dist3 )
3135 {
3136 p1 = mHalfEdge[edge1]->getPoint();
3137 p2 = mHalfEdge[mHalfEdge[edge1]->getNext()]->getPoint();
3138 p3 = mHalfEdge[mHalfEdge[edge1]->getDual()]->getPoint();
3139 p4 = mHalfEdge[mHalfEdge[mHalfEdge[edge1]->getDual()]->getNext()]->getPoint();
3140 }
3141 else if ( dist2 <= dist1 && dist2 <= dist3 )
3142 {
3143 p1 = mHalfEdge[edge2]->getPoint();
3144 p2 = mHalfEdge[mHalfEdge[edge2]->getNext()]->getPoint();
3145 p3 = mHalfEdge[mHalfEdge[edge2]->getDual()]->getPoint();
3146 p4 = mHalfEdge[mHalfEdge[mHalfEdge[edge2]->getDual()]->getNext()]->getPoint();
3147 }
3148 else /* if ( dist3 <= dist1 && dist3 <= dist2 ) */
3149 {
3150 p1 = mHalfEdge[edge3]->getPoint();
3151 p2 = mHalfEdge[mHalfEdge[edge3]->getNext()]->getPoint();
3152 p3 = mHalfEdge[mHalfEdge[edge3]->getDual()]->getPoint();
3153 p4 = mHalfEdge[mHalfEdge[mHalfEdge[edge3]->getDual()]->getNext()]->getPoint();
3154 }
3155
3156
3157 list.append( p1 );
3158 list.append( p2 );
3159 list.append( p3 );
3160 list.append( p4 );
3161 }
3162 else
3163 {
3164 QgsDebugError( u"warning: null pointer"_s );
3165 }
3166 }
3167 else
3168 {
3169 QgsDebugError( u"Edge number negative"_s );
3170 }
3171 return list;
3172}
3173
3175{
3176 if ( !sink )
3177 {
3178 return false;
3179 }
3180
3181 bool *alreadyVisitedEdges = new bool[mHalfEdge.size()];
3182 if ( !alreadyVisitedEdges )
3183 {
3184 QgsDebugError( u"out of memory"_s );
3185 return false;
3186 }
3187
3188 for ( int i = 0; i < mHalfEdge.size(); ++i )
3189 {
3190 alreadyVisitedEdges[i] = false;
3191 }
3192
3193 for ( int i = 0; i < mHalfEdge.size(); ++i )
3194 {
3195 if ( feedback && feedback->isCanceled() )
3196 break;
3197
3198 HalfEdge *currentEdge = mHalfEdge[i];
3199 if ( currentEdge->getPoint() != -1 && mHalfEdge[currentEdge->getDual()]->getPoint() != -1 && !alreadyVisitedEdges[currentEdge->getDual()] )
3200 {
3201 QgsFeature edgeLineFeature;
3202
3203 //geometry
3204 QgsPoint *p1 = mPointVector[currentEdge->getPoint()];
3205 QgsPoint *p2 = mPointVector[mHalfEdge[currentEdge->getDual()]->getPoint()];
3206 QgsPolylineXY lineGeom;
3207 lineGeom.push_back( QgsPointXY( p1->x(), p1->y() ) );
3208 lineGeom.push_back( QgsPointXY( p2->x(), p2->y() ) );
3209 edgeLineFeature.setGeometry( QgsGeometry::fromPolylineXY( lineGeom ) );
3210 edgeLineFeature.initAttributes( 1 );
3211
3212 //attributes
3213 QString attributeString;
3214 if ( currentEdge->getForced() )
3215 {
3216 if ( currentEdge->getBreak() )
3217 {
3218 attributeString = u"break line"_s;
3219 }
3220 else
3221 {
3222 attributeString = u"structure line"_s;
3223 }
3224 }
3225 edgeLineFeature.setAttribute( 0, attributeString );
3226
3227 sink->addFeature( edgeLineFeature, QgsFeatureSink::FastInsert );
3228 }
3229 alreadyVisitedEdges[i] = true;
3230 }
3231
3232 delete[] alreadyVisitedEdges;
3233
3234 return !feedback || !feedback->isCanceled();
3235}
3236
3238{
3239 if ( feedback )
3240 feedback->setProgress( 0 );
3241
3242 QVector<bool> edgeToTreat( mHalfEdge.count(), true );
3243 QHash<HalfEdge *, int> edgesHash;
3244 for ( int i = 0; i < mHalfEdge.count(); ++i )
3245 {
3246 edgesHash.insert( mHalfEdge[i], i );
3247 }
3248
3249 QgsMesh mesh;
3250 for ( const QgsPoint *point : mPointVector )
3251 {
3252 mesh.vertices.append( *point );
3253 }
3254
3255 const int edgeCount = edgeToTreat.count();
3256 for ( int i = 0; i < edgeCount; ++i )
3257 {
3258 bool containVirtualPoint = false;
3259 if ( edgeToTreat[i] )
3260 {
3261 HalfEdge *currentEdge = mHalfEdge[i];
3262 HalfEdge *firstEdge = currentEdge;
3263 QgsMeshFace face;
3264 do
3265 {
3266 edgeToTreat[edgesHash.value( currentEdge )] = false;
3267 face.append( currentEdge->getPoint() );
3268 containVirtualPoint |= currentEdge->getPoint() == -1;
3269 currentEdge = mHalfEdge.at( currentEdge->getNext() );
3270 } while ( currentEdge != firstEdge && !containVirtualPoint && ( !feedback || !feedback->isCanceled() ) );
3271 if ( !containVirtualPoint )
3272 mesh.faces.append( face );
3273 }
3274 if ( feedback )
3275 {
3276 feedback->setProgress( ( 100 * i ) / edgeCount );
3277 }
3278 }
3279
3280 return mesh;
3281}
3282
3283double QgsDualEdgeTriangulation::swapMinAngle( int edge ) const
3284{
3285 QgsPoint *p1 = point( mHalfEdge[edge]->getPoint() );
3286 QgsPoint *p2 = point( mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint() );
3287 QgsPoint *p3 = point( mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint() );
3288 QgsPoint *p4 = point( mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint() );
3289
3290 //search for the minimum angle (it is important, which directions the lines have!)
3291 double minangle;
3292 const double angle1 = MathUtils::angle( p1, p2, p4, p2 );
3293 minangle = angle1;
3294 const double angle2 = MathUtils::angle( p3, p2, p4, p2 );
3295 if ( angle2 < minangle )
3296 {
3297 minangle = angle2;
3298 }
3299 const double angle3 = MathUtils::angle( p2, p3, p4, p3 );
3300 if ( angle3 < minangle )
3301 {
3302 minangle = angle3;
3303 }
3304 const double angle4 = MathUtils::angle( p3, p4, p2, p4 );
3305 if ( angle4 < minangle )
3306 {
3307 minangle = angle4;
3308 }
3309 const double angle5 = MathUtils::angle( p2, p4, p1, p4 );
3310 if ( angle5 < minangle )
3311 {
3312 minangle = angle5;
3313 }
3314 const double angle6 = MathUtils::angle( p4, p1, p2, p1 );
3315 if ( angle6 < minangle )
3316 {
3317 minangle = angle6;
3318 }
3319
3320 return minangle;
3321}
3322
3323int QgsDualEdgeTriangulation::splitHalfEdge( int edge, float position )
3324{
3325 //just a short test if position is between 0 and 1
3326 if ( position < 0 || position > 1 )
3327 {
3328 QgsDebugError( u"warning, position is not between 0 and 1"_s );
3329 }
3330
3331 //create the new point on the heap
3332 QgsPoint *p = new QgsPoint( mPointVector[mHalfEdge[edge]->getPoint()]->x() * position + mPointVector[mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint()]->x() * ( 1 - position ), mPointVector[mHalfEdge[edge]->getPoint()]->y() * position + mPointVector[mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint()]->y() * ( 1 - position ), 0 );
3333
3334 //calculate the z-value of the point to insert
3335 QgsPoint zvaluepoint( 0, 0, 0 );
3336 calcPoint( p->x(), p->y(), zvaluepoint );
3337 p->setZ( zvaluepoint.z() );
3338
3339 //insert p into mPointVector
3340 if ( mPointVector.count() >= mPointVector.size() )
3341 {
3342 mPointVector.resize( mPointVector.count() + 1 );
3343 }
3344 QgsDebugMsgLevel( u"inserting point nr. %1, %2//%3//%4"_s.arg( mPointVector.count() ).arg( p->x() ).arg( p->y() ).arg( p->z() ), 2 );
3345 mPointVector.insert( mPointVector.count(), p );
3346
3347 //insert the six new halfedges
3348 const int dualedge = mHalfEdge[edge]->getDual();
3349 const int edge1 = insertEdge( -10, -10, mPointVector.count() - 1, false, false );
3350 const int edge2 = insertEdge( edge1, mHalfEdge[mHalfEdge[edge]->getNext()]->getNext(), mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint(), false, false );
3351 const int edge3 = insertEdge( -10, mHalfEdge[mHalfEdge[dualedge]->getNext()]->getNext(), mHalfEdge[mHalfEdge[dualedge]->getNext()]->getPoint(), false, false );
3352 const int edge4 = insertEdge( edge3, dualedge, mPointVector.count() - 1, false, false );
3353 const int edge5 = insertEdge( -10, mHalfEdge[edge]->getNext(), mHalfEdge[edge]->getPoint(), mHalfEdge[edge]->getBreak(), mHalfEdge[edge]->getForced() );
3354 const int edge6 = insertEdge( edge5, edge3, mPointVector.count() - 1, mHalfEdge[dualedge]->getBreak(), mHalfEdge[dualedge]->getForced() );
3355 mHalfEdge[edge1]->setDual( edge2 );
3356 mHalfEdge[edge1]->setNext( edge5 );
3357 mHalfEdge[edge3]->setDual( edge4 );
3358 mHalfEdge[edge5]->setDual( edge6 );
3359
3360 //adjust the already existing halfedges
3361 mHalfEdge[mHalfEdge[edge]->getNext()]->setNext( edge1 );
3362 mHalfEdge[mHalfEdge[dualedge]->getNext()]->setNext( edge4 );
3363 mHalfEdge[edge]->setNext( edge2 );
3364 mHalfEdge[edge]->setPoint( mPointVector.count() - 1 );
3365 mHalfEdge[mHalfEdge[edge3]->getNext()]->setNext( edge6 );
3366
3367 //test four times recursively for swapping
3368 checkSwapRecursively( mHalfEdge[edge5]->getNext(), 0 );
3369 checkSwapRecursively( mHalfEdge[edge2]->getNext(), 0 );
3370 checkSwapRecursively( mHalfEdge[dualedge]->getNext(), 0 );
3371 checkSwapRecursively( mHalfEdge[edge3]->getNext(), 0 );
3372
3373 addPoint( QgsPoint( p->x(), p->y(), 0 ) ); //dirty hack to enforce update of decorators
3374
3375 return mPointVector.count() - 1;
3376}
3377
3378bool QgsDualEdgeTriangulation::edgeOnConvexHull( int edge )
3379{
3380 return ( mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint() == -1 || mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getPoint() == -1 );
3381}
3382
3383void QgsDualEdgeTriangulation::evaluateInfluenceRegion( QgsPoint *point, int edge, QSet<int> &set )
3384{
3385 if ( set.find( edge ) == set.end() )
3386 {
3387 set.insert( edge );
3388 }
3389 else //prevent endless loops
3390 {
3391 return;
3392 }
3393
3394 if ( !mHalfEdge[edge]->getForced() && !edgeOnConvexHull( edge ) )
3395 {
3396 //test, if point is in the circle through both endpoints of edge and the endpoint of edge->dual->next->point
3397 if ( inCircle( *point, *mPointVector[mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint()], *mPointVector[mHalfEdge[edge]->getPoint()], *mPointVector[mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint()] ) )
3398 {
3399 evaluateInfluenceRegion( point, mHalfEdge[mHalfEdge[edge]->getDual()]->getNext(), set );
3400 evaluateInfluenceRegion( point, mHalfEdge[mHalfEdge[mHalfEdge[edge]->getDual()]->getNext()]->getNext(), set );
3401 }
3402 }
3403}
3404
3405int QgsDualEdgeTriangulation::firstEdgeOutSide()
3406{
3407 int edge = 0;
3408 while ( ( mHalfEdge[mHalfEdge[edge]->getNext()]->getPoint() != -1 || mHalfEdge[edge]->getPoint() == -1 || mHalfEdge[mHalfEdge[edge]->getDual()]->getPoint() == -1 ) && edge < mHalfEdge.count() )
3409 {
3410 edge++;
3411 }
3412
3413 if ( edge >= mHalfEdge.count() )
3414 return -1;
3415 else
3416 return edge;
3417}
3418
3419void QgsDualEdgeTriangulation::removeLastPoint()
3420{
3421 if ( mPointVector.isEmpty() )
3422 return;
3423 QgsPoint *p = mPointVector.takeLast();
3424 delete p;
3425}
Represents a half edge in a triangulation.
Definition HalfEdge.h:31
bool getForced() const
Returns, whether the HalfEdge belongs to a constrained edge or not.
Definition HalfEdge.h:98
int getNext() const
Returns the number of the next HalfEdge.
Definition HalfEdge.h:83
void setNext(int n)
Sets the number of the next HalfEdge.
Definition HalfEdge.h:108
void setPoint(int p)
Sets the number of point at which this HalfEdge points.
Definition HalfEdge.h:113
int getPoint() const
Returns the number of the point at which this HalfEdge points.
Definition HalfEdge.h:88
int getDual() const
Returns the number of the dual HalfEdge.
Definition HalfEdge.h:78
void setDual(int d)
Sets the number of the dual HalfEdge.
Definition HalfEdge.h:103
void setForced(bool f)
Sets the forced flag.
Definition HalfEdge.h:123
bool getBreak() const
Returns, whether the HalfEdge belongs to a break line or not.
Definition HalfEdge.h:93
void setBreak(bool b)
Sets the break flag.
Definition HalfEdge.h:118
bool saveTriangulation(QgsFeatureSink *sink, QgsFeedback *feedback=nullptr) const override
Saves the triangulation features to a feature sink.
QgsPoint * point(int i) const override
Draws the points, edges and the forced lines.
QList< int > surroundingTriangles(int pointno) override
Returns a value list with the information of the triangles surrounding (counterclockwise) a point.
void ruppertRefinement() override
Adds points to make the triangles better shaped (algorithm of ruppert).
bool pointInside(double x, double y) override
Returns true, if the point with coordinates x and y is inside the convex hull and false otherwise.
void setTriangleInterpolator(TriangleInterpolator *interpolator) override
Sets an interpolator object.
void performConsistencyTest() override
Performs a consistency check, remove this later.
int oppositePoint(int p1, int p2) override
Returns the number of the point opposite to the triangle points p1, p2 (which have to be on a halfedg...
int addPoint(const QgsPoint &p) override
Adds a point to the triangulation.
QgsMesh triangulationToMesh(QgsFeedback *feedback=nullptr) const override
Returns a QgsMesh corresponding to the triangulation.
void setForcedCrossBehavior(QgsTriangulation::ForcedCrossBehavior b) override
Sets the behavior of the triangulation in case of crossing forced lines.
bool calcNormal(double x, double y, QgsPoint &result) override
Calculates the normal at a point on the surface.
void addLine(const QVector< QgsPoint > &points, QgsInterpolator::SourceType lineType) override
Adds a line (e.g.
bool calcPoint(double x, double y, QgsPoint &result) override
Calculates x-, y and z-value of the point on the surface and assigns it to 'result'.
void eliminateHorizontalTriangles() override
Eliminates the horizontal triangles by swapping or by insertion of new points.
bool triangleVertices(double x, double y, QgsPoint &p1, int &n1, QgsPoint &p2, int &n2, QgsPoint &p3, int &n3) override
Finds out in which triangle the point with coordinates x and y is and assigns the numbers of the vert...
bool swapEdge(double x, double y) override
Swaps the edge which is closest to the point with x and y coordinates (if this is possible).
QList< int > pointsAroundEdge(double x, double y) override
Returns a value list with the numbers of the four points, which would be affected by an edge swap....
An interface for objects which accept features via addFeature(s) methods.
virtual bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags())
Adds a single feature to the sink.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:55
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:63
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
SourceType
Describes the type of input data.
Represents a 2D point.
Definition qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
void setY(double y)
Sets the point's y-coordinate.
Definition qgspoint.h:341
void setX(double x)
Sets the point's x-coordinate.
Definition qgspoint.h:330
double z
Definition qgspoint.h:58
double x
Definition qgspoint.h:56
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition qgspoint.h:391
void setZ(double z)
Sets the point's z-coordinate.
Definition qgspoint.h:354
double distanceSquared(double x, double y) const
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
Definition qgspoint.h:413
double y
Definition qgspoint.h:57
ForcedCrossBehavior
Enumeration describing the behavior, if two forced lines cross.
@ SnappingTypeVertex
The second inserted forced line is snapped to the closest vertice of the first inserted forced line.
An interface for interpolator classes for triangulations.
bool ANALYSIS_EXPORT inDiametral(QgsPoint *p1, QgsPoint *p2, QgsPoint *point)
Tests, whether 'point' is inside the diametral circle through 'p1' and 'p2'.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored).
bool ANALYSIS_EXPORT lineIntersection(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Returns true, if line1 (p1 to p2) and line2 (p3 to p4) intersect. If the lines have an endpoint in co...
bool ANALYSIS_EXPORT circumcenter(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *result)
Calculates the center of the circle passing through p1, p2 and p3. Returns true in case of success an...
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
double ANALYSIS_EXPORT distPointFromLine(QgsPoint *thepoint, QgsPoint *p1, QgsPoint *p2)
Calculates the (2 dimensional) distance from 'thepoint' to the line defined by p1 and p2.
bool ANALYSIS_EXPORT inCircle(QgsPoint *testp, QgsPoint *p1, QgsPoint *p2, QgsPoint *p3)
Tests, whether 'testp' is inside the circle through 'p1', 'p2' and 'p3'.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
double leftOfTresh
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition qgsgeometry.h:63
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
QVector< int > QgsMeshFace
List of vertex indexes.
Mesh - vertices, edges and faces.
QVector< QgsMeshVertex > vertices
QVector< QgsMeshFace > faces