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