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