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