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