QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
NormVecDecorator.cpp
Go to the documentation of this file.
1/***************************************************************************
2 NormVecDecorator.cpp
3 --------------------
4 copyright : (C) 2004 by Marco Hugentobler
6 ***************************************************************************/
7
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17#include "NormVecDecorator.h"
18
19#include "qgsfeedback.h"
20#include "qgsfields.h"
21#include "qgslogger.h"
22#include "qgspoint.h"
23
24#include <QApplication>
25
27{
28 //remove all the normals
29 if ( !mNormVec->isEmpty() )
30 {
31 for ( int i = 0; i < mNormVec->count(); i++ )
32 {
33 delete ( *mNormVec )[i];
34 }
35 }
36
37 delete mNormVec;
38 delete mPointState;
39 delete mTIN;
40}
41
43{
44 if ( mTIN )
45 {
46 int pointno;
47 pointno = mTIN->addPoint( p );
48
49 if ( pointno == -100 ) //a numerical error occurred
50 {
51 // QgsDebugError("warning, numerical error");
52 return -100;
53 }
54
55 //recalculate the necessary normals
56 if ( alreadyestimated )
57 {
58 estimateFirstDerivative( pointno );
59 //update also the neighbours of the new point
60 const QList<int> list = mTIN->surroundingTriangles( pointno );
61 auto it = list.constBegin(); //iterate through the list and analyze it
62 while ( it != list.constEnd() )
63 {
64 int point;
65 point = *it;
66 if ( point != -1 )
67 {
69 }
70 ++it;
71 ++it;
72 ++it;
73 ++it;
74 }
75 }
76 return pointno;
77 }
78
79 return -1;
80}
81
82bool NormVecDecorator::calcNormal( double x, double y, QgsPoint &result )
83{
84 if ( !alreadyestimated )
85 {
87 alreadyestimated = true;
88 }
89
90 if ( mInterpolator )
91 {
92 const bool b = mInterpolator->calcNormVec( x, y, result );
93 return b;
94 }
95 else
96 {
97 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
98 return false;
99 }
100}
101
102bool NormVecDecorator::calcNormalForPoint( double x, double y, int pointIndex, Vector3D *result )
103{
104 if ( !alreadyestimated )
105 {
107 alreadyestimated = true;
108 }
109
110 if ( result )
111 {
112 int numberofbreaks = 0; //number of breaklines around the point
113 int ffirstbp = -1000; //numbers of the points related to the first breakline
114 int lfirstbp = -1000;
115 bool pointfound = false; //is set to true, if the triangle with the point in is found
116 int numberofruns = 0; //number of runs of the loop. This integer can be used to prevent endless loops
117 const int limit = 100000; //ater this number of iterations, the method is terminated
118
119 result->setX( 0 );
120 result->setY( 0 );
121 result->setZ( 0 );
122
123 const QList<int> vlist = surroundingTriangles( pointIndex ); //get the value list
124 if ( vlist.empty() ) //an error occurred in 'getSurroundingTriangles'
125 {
126 return false;
127 }
128
129 if ( ( ( vlist.count() ) % 4 ) != 0 ) //number of items in vlist has to be a multiple of 4
130 {
131 QgsDebugError( QStringLiteral( "warning, wrong number of items in vlist" ) );
132 return false;
133 }
134
135 auto it = vlist.constBegin();
136
137 bool firstrun;
138
139 while ( true ) //endless loop to analyze vlist
140 {
141 numberofruns++;
142 if ( numberofruns > limit )
143 {
144 QgsDebugError( QStringLiteral( "warning, a probable endless loop is detected" ) );
145 return false;
146 }
147
148 int p1, p2, p3, line;
149 firstrun = false; //flag which tells, if it is the first run with a breakline
150 p1 = ( *it );
151 ++it;
152 p2 = ( *it );
153 ++it;
154 p3 = ( *it );
155 ++it;
156 line = ( *it );
157
158
159 if ( numberofbreaks > 0 )
160 {
161 if ( p1 != -1 && p2 != -1 && p3 != -1 )
162 {
163 if ( MathUtils::pointInsideTriangle( x, y, point( p1 ), point( p2 ), point( p3 ) ) )
164 {
165 pointfound = true;
166 }
167
168 Vector3D addvec( 0, 0, 0 );
169 MathUtils::normalFromPoints( point( p1 ), point( p2 ), point( p3 ), &addvec );
170 result->setX( result->getX() + addvec.getX() );
171 result->setY( result->getY() + addvec.getY() );
172 result->setZ( result->getZ() + addvec.getZ() );
173 }
174 }
175
176 if ( line == -10 ) //we found a breakline
177 {
178 if ( numberofbreaks == 0 ) //it is the first breakline
179 {
180 firstrun = true;
181 ffirstbp = p2; //set the marks to recognize the breakline later
182 lfirstbp = p3;
183 }
184
185 if ( p2 == ffirstbp && p3 == lfirstbp && !firstrun ) //we are back at the first breakline
186 {
187 if ( !pointfound ) //the point with coordinates x, y was in no triangle
188 {
189 QgsDebugError( QStringLiteral( "warning: point (x,y) was in no triangle" ) );
190 return false;
191 }
192 result->standardise();
193 break;
194 }
195
196 if ( numberofbreaks > 0 && pointfound ) //we found the second break line and the point is between the first and the second
197 {
198 result->standardise();
199 numberofbreaks++; //to make the distinction between endpoints and points on a breakline easier
200 break;
201 }
202
203 result->setX( 0 );
204 result->setY( 0 );
205 result->setZ( 0 );
206 numberofbreaks++;
207 }
208
209 ++it;
210 if ( it == vlist.constEnd() ) //restart at the beginning of the loop
211 {
212 it = vlist.constBegin();
213 }
214 }
215 return true;
216 }
217 else
218 {
219 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
220 return false;
221 }
222}
223
224bool NormVecDecorator::calcPoint( double x, double y, QgsPoint &result )
225{
226 if ( !alreadyestimated )
227 {
229 alreadyestimated = true;
230 }
231
232 if ( mInterpolator )
233 {
234 const bool b = mInterpolator->calcPoint( x, y, result );
235 return b;
236 }
237 else
238 {
239 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
240 return false;
241 }
242}
243
244bool NormVecDecorator::getTriangle( double x, double y, QgsPoint &p1, Vector3D *v1, QgsPoint &p2, Vector3D *v2, QgsPoint &p3, Vector3D *v3 )
245{
246 if ( v1 && v2 && v3 )
247 {
248 int nr1 = 0;
249 int nr2 = 0;
250 int nr3 = 0;
251
252 if ( TriDecorator::triangleVertices( x, y, p1, nr1, p2, nr2, p3, nr3 ) ) //everything alright
253 {
254 if ( ( *mNormVec )[nr1] && ( *mNormVec )[nr2] && ( *mNormVec )[nr3] )
255 {
256 v1->setX( ( *mNormVec )[nr1]->getX() );
257 v1->setY( ( *mNormVec )[nr1]->getY() );
258 v1->setZ( ( *mNormVec )[nr1]->getZ() );
259
260 v2->setX( ( *mNormVec )[nr2]->getX() );
261 v2->setY( ( *mNormVec )[nr2]->getY() );
262 v2->setZ( ( *mNormVec )[nr2]->getZ() );
263
264 v3->setX( ( *mNormVec )[nr3]->getX() );
265 v3->setY( ( *mNormVec )[nr3]->getY() );
266 v3->setZ( ( *mNormVec )[nr3]->getZ() );
267 }
268 else
269 {
270 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
271 return false;
272 }
273 return true;
274 }
275 else
276 {
277 return false;
278 }
279 }
280
281 else
282 {
283 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
284 return false;
285 }
286}
287
289{
290 if ( pointno >= 0 )
291 {
292 return mPointState->at( pointno );
293 }
294 else
295 {
296 QgsDebugError( QStringLiteral( "warning, number below 0" ) );
297 return mPointState->at( 0 ); //just to avoid a compiler warning
298 }
299}
300
301
302bool NormVecDecorator::getTriangle( double x, double y, QgsPoint &p1, int &ptn1, Vector3D *v1, PointState *state1, QgsPoint &p2, int &ptn2, Vector3D *v2, PointState *state2, QgsPoint &p3, int &ptn3, Vector3D *v3, PointState *state3 )
303{
304 if ( v1 && v2 && v3 && state1 && state2 && state3 )
305 {
306 if ( TriDecorator::triangleVertices( x, y, p1, ptn1, p2, ptn2, p3, ptn3 ) ) //everything alright
307 {
308 v1->setX( ( *mNormVec )[( ptn1 )]->getX() );
309 v1->setY( ( *mNormVec )[( ptn1 )]->getY() );
310 v1->setZ( ( *mNormVec )[( ptn1 )]->getZ() );
311
312 ( *state1 ) = ( *mPointState )[( ptn1 )];
313
314 v2->setX( ( *mNormVec )[( ptn2 )]->getX() );
315 v2->setY( ( *mNormVec )[( ptn2 )]->getY() );
316 v2->setZ( ( *mNormVec )[( ptn2 )]->getZ() );
317
318 ( *state2 ) = ( *mPointState )[( ptn2 )];
319
320 v3->setX( ( *mNormVec )[( ptn3 )]->getX() );
321 v3->setY( ( *mNormVec )[( ptn3 )]->getY() );
322 v3->setZ( ( *mNormVec )[( ptn3 )]->getZ() );
323
324 ( *state3 ) = ( *mPointState )[( ptn3 )];
325
326 return true;
327 }
328 else
329 {
330 return false;
331 }
332 }
333 else
334 {
335 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
336 return false;
337 }
338}
339
341{
342 if ( pointno == -1 )
343 {
344 return false;
345 }
346
347 Vector3D part;
348 Vector3D total;
349 total.setX( 0 );
350 total.setY( 0 );
351 total.setZ( 0 );
352 int numberofbreaks = 0; //number of counted breaklines
353 double weights = 0; //sum of the weights
354 double currentweight = 0; //current weight
355 PointState status;
356
357 const QList<int> vlist = surroundingTriangles( pointno ); //get the value list
358
359 if ( vlist.empty() )
360 {
361 //something went wrong in getSurroundingTriangles, set the normal to (0,0,0)
362 if ( mNormVec->size() <= mNormVec->count() ) //allocate more memory if necessary
363 {
364 QgsDebugMsgLevel( QStringLiteral( "resizing mNormVec from %1 to %2" ).arg( mNormVec->size() ).arg( mNormVec->size() + 1 ), 2 );
365 mNormVec->resize( mNormVec->size() + 1 );
366 }
367
368 //todo:resize mNormVec if necessary
369
370 if ( !( ( *mNormVec )[pointno] ) ) //insert a pointer to a Vector3D, if there is none at this position
371 {
372 Vector3D *vec = new Vector3D( total.getX(), total.getY(), total.getZ() );
373 mNormVec->insert( pointno, vec );
374 }
375 else
376 {
377 ( *mNormVec )[pointno]->setX( 0 );
378 ( *mNormVec )[pointno]->setY( 0 );
379 ( *mNormVec )[pointno]->setZ( 0 );
380 }
381 return false;
382 }
383
384 if ( ( vlist.count() % 4 ) != 0 ) //number of items in vlist has to be a multiple of 4
385 {
386 QgsDebugError( QStringLiteral( "warning, wrong number of items in vlist" ) );
387 return false;
388 }
389
390 auto it = vlist.constBegin(); //iterate through the list and analyze it
391 while ( it != vlist.constEnd() )
392 {
393 int p1, p2, p3, flag;
394 part.setX( 0 );
395 part.setY( 0 );
396 part.setZ( 0 );
397
398 currentweight = 0;
399
400 p1 = ( *it );
401 ++it;
402 p2 = ( *it );
403 ++it;
404 p3 = ( *it );
405 ++it;
406 flag = ( *it );
407
408 if ( flag == -10 ) //we found a breakline.
409 {
410 numberofbreaks++;
411 }
412
413 if ( p1 != -1 && p2 != -1 && p3 != -1 ) //don't calculate normal, if a point is a virtual point
414 {
415 MathUtils::normalFromPoints( point( p1 ), point( p2 ), point( p3 ), &part );
416 const double dist1 = point( p3 )->distance3D( *point( p1 ) );
417 const double dist2 = point( p3 )->distance3D( *point( p2 ) );
418 //don't add the normal if the triangle is horizontal
419 if ( ( point( p1 )->z() != point( p2 )->z() ) || ( point( p1 )->z() != point( p3 )->z() ) )
420 {
421 currentweight = 1 / ( dist1 * dist1 * dist2 * dist2 );
422 total.setX( total.getX() + part.getX() * currentweight );
423 total.setY( total.getY() + part.getY() * currentweight );
424 total.setZ( total.getZ() + part.getZ() * currentweight );
425 weights += currentweight;
426 }
427 }
428 ++it;
429 }
430
431 if ( total.getX() == 0 && total.getY() == 0 && total.getZ() == 0 ) //we have a point surrounded by horizontal triangles
432 {
433 total.setZ( 1 );
434 }
435 else
436 {
437 total.setX( total.getX() / weights );
438 total.setY( total.getY() / weights );
439 total.setZ( total.getZ() / weights );
440 total.standardise();
441 }
442
443
444 if ( numberofbreaks == 0 )
445 {
446 status = Normal;
447 }
448 else if ( numberofbreaks == 1 )
449 {
450 status = EndPoint;
451 }
452 else
453 {
454 status = BreakLine;
455 }
456
457 //insert the new calculated vector
458 if ( mNormVec->size() <= mNormVec->count() ) //allocate more memory if necessary
459 {
460 mNormVec->resize( mNormVec->size() + 1 );
461 }
462
463 if ( !( ( *mNormVec )[pointno] ) ) //insert a pointer to a Vector3D, if there is none at this position
464 {
465 Vector3D *vec = new Vector3D( total.getX(), total.getY(), total.getZ() );
466 mNormVec->insert( pointno, vec );
467 }
468 else
469 {
470 ( *mNormVec )[pointno]->setX( total.getX() );
471 ( *mNormVec )[pointno]->setY( total.getY() );
472 ( *mNormVec )[pointno]->setZ( total.getZ() );
473 }
474
475 //insert the new status
476
477 if ( pointno >= mPointState->size() )
478 {
479 mPointState->resize( mPointState->size() + 1 );
480 }
481
482 ( *mPointState )[pointno] = status;
483
484 return true;
485}
486
487//weighted method of little
489{
490 const int numberPoints = pointsCount();
491 for ( int i = 0; i < numberPoints; i++ )
492 {
493 if ( feedback )
494 {
495 feedback->setProgress( 100.0 * static_cast<double>( i ) / numberPoints );
496 }
498 }
499
500 return true;
501}
502
504{
505 if ( mTIN )
506 {
507 if ( alreadyestimated )
508 {
509 mTIN->eliminateHorizontalTriangles();
511 }
512 else
513 {
514 mTIN->eliminateHorizontalTriangles();
515 }
516 }
517 else
518 {
519 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
520 }
521}
522
524{
525 if ( pointno >= 0 )
526 {
527 ( *mPointState )[pointno] = s;
528 }
529 else
530 {
531 QgsDebugError( QStringLiteral( "warning, pointno>0" ) );
532 }
533}
534
535bool NormVecDecorator::swapEdge( double x, double y )
536{
537 if ( mTIN )
538 {
539 bool b = false;
540 if ( alreadyestimated )
541 {
542 const QList<int> list = pointsAroundEdge( x, y );
543 if ( !list.empty() )
544 {
545 b = mTIN->swapEdge( x, y );
546 for ( const int i : list )
547 {
549 }
550 }
551 }
552 else
553 {
554 b = mTIN->swapEdge( x, y );
555 }
556 return b;
557 }
558 else
559 {
560 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
561 return false;
562 }
563}
564
566{
567 if ( !mTIN )
568 {
569 return false;
570 }
571 return mTIN->saveTriangulation( sink, feedback );
572}
573
575{
576 if ( !mTIN )
577 {
578 return QgsMesh();
579 }
580 return mTIN->triangulationToMesh( feedback );
581}
bool getTriangle(double x, double y, QgsPoint &p1, Vector3D *v1, QgsPoint &p2, Vector3D *v2, QgsPoint &p3, Vector3D *v3)
Finds out, in which triangle a point with coordinates x and y is and assigns the triangle points to p...
QVector< PointState > * mPointState
Vector who stores, it a point is not on a breakline, if it is a normal point of the breakline or if i...
bool alreadyestimated
Is true, if the normals already have been estimated.
bool calcNormal(double x, double y, QgsPoint &result) override
Calculates the normal at a point on the surface and assigns it to 'result'. Returns true in case of s...
bool saveTriangulation(QgsFeatureSink *sink, QgsFeedback *feedback=nullptr) const override
Saves the triangulation features to a feature sink.
~NormVecDecorator() override
QgsMesh triangulationToMesh(QgsFeedback *feedback=nullptr) const override
Returns a QgsMesh corresponding to the triangulation.
void eliminateHorizontalTriangles() override
Eliminates the horizontal triangles by swapping or by insertion of new points. If alreadyestimated is...
bool calcPoint(double x, double y, QgsPoint &result) override
Calculates x-, y and z-value of the point on the surface and assigns it to 'result'.
TriangleInterpolator * mInterpolator
Association with an interpolator object.
void setState(int pointno, PointState s)
Sets the state (BreakLine, Normal, EndPoint) of a point.
QVector< Vector3D * > * mNormVec
Vector that stores the normals for the points. If 'estimateFirstDerivatives()' was called and there i...
bool swapEdge(double x, double y) override
Swaps the edge which is closest to the point with x and y coordinates (if this is possible) and force...
PointState getState(int pointno) const
Returns the state of the point with the number 'pointno'.
bool calcNormalForPoint(double x, double y, int pointIndex, Vector3D *result)
Calculates the normal of a triangle-point for the point with coordinates x and y. This is needed,...
bool estimateFirstDerivatives(QgsFeedback *feedback=nullptr)
This method adds the functionality of estimating normals at the data points. Return true in the case ...
bool estimateFirstDerivative(int pointno)
Estimates the first derivative a point. Return true in case of success and false otherwise.
PointState
Enumeration for the state of a point. Normal means, that the point is not on a BreakLine,...
int addPoint(const QgsPoint &p) override
Adds a point to the triangulation.
An interface for objects which accept features via addFeature(s) methods.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:61
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
double distance3D(double x, double y, double z) const
Returns the Cartesian 3D distance between this point and a specified x, y, z coordinate.
Definition qgspoint.h:431
QgsPoint * point(int i) const override
Returns a pointer to the point with number i.
QgsTriangulation * mTIN
Association with a Triangulation object.
QList< int > pointsAroundEdge(double x, double y) override
Returns a value list with the numbers of the four points, which would be affected by an edge swap.
QList< int > surroundingTriangles(int pointno) override
Returns a value list with the information of the triangles surrounding (counterclockwise) a point.
int pointsCount() const override
Returns the number of points.
bool triangleVertices(double x, double y, QgsPoint &p1, int &n1, QgsPoint &p2, int &n2, QgsPoint &p3, int &n3) override
Finds out in which triangle the point with coordinates x and y is and assigns the numbers of the vert...
Represents a 3D-Vector, capable of storing x, y and z-coordinates in double values.
Definition Vector3D.h:37
void standardise()
Standardises the vector.
Definition Vector3D.cpp:24
void setX(double x)
Sets the x-component of the vector.
Definition Vector3D.h:106
double getY() const
Returns the y-component of the vector.
Definition Vector3D.h:96
double getX() const
Returns the x-component of the vector.
Definition Vector3D.h:91
void setY(double y)
Sets the y-component of the vector.
Definition Vector3D.h:111
double getZ() const
Returns the z-component of the vector.
Definition Vector3D.h:101
void setZ(double z)
Sets the z-component of the vector.
Definition Vector3D.h:116
bool ANALYSIS_EXPORT pointInsideTriangle(double x, double y, QgsPoint *p1, QgsPoint *p2, QgsPoint *p3)
Returns true, if the point with coordinates x and y is inside (or at the edge) of the triangle p1,...
void ANALYSIS_EXPORT normalFromPoints(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, Vector3D *vec)
Calculates the normal vector of the plane through the points p1, p2 and p3 and assigns the result to ...
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61
#define QgsDebugError(str)
Definition qgslogger.h:57
Mesh - vertices, edges and faces.