QGIS API Documentation 3.99.0-Master (09f76ad7019)
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#include <QString>
26
27using namespace Qt::StringLiterals;
28
30{
31 //remove all the normals
32 if ( !mNormVec->isEmpty() )
33 {
34 for ( int i = 0; i < mNormVec->count(); i++ )
35 {
36 delete ( *mNormVec )[i];
37 }
38 }
39
40 delete mNormVec;
41 delete mPointState;
42 delete mTIN;
43}
44
46{
47 if ( mTIN )
48 {
49 int pointno;
50 pointno = mTIN->addPoint( p );
51
52 if ( pointno == -100 ) //a numerical error occurred
53 {
54 // QgsDebugError("warning, numerical error");
55 return -100;
56 }
57
58 //recalculate the necessary normals
59 if ( alreadyestimated )
60 {
61 estimateFirstDerivative( pointno );
62 //update also the neighbours of the new point
63 const QList<int> list = mTIN->surroundingTriangles( pointno );
64 auto it = list.constBegin(); //iterate through the list and analyze it
65 while ( it != list.constEnd() )
66 {
67 int point;
68 point = *it;
69 if ( point != -1 )
70 {
72 }
73 ++it;
74 ++it;
75 ++it;
76 ++it;
77 }
78 }
79 return pointno;
80 }
81
82 return -1;
83}
84
85bool NormVecDecorator::calcNormal( double x, double y, QgsPoint &result )
86{
87 if ( !alreadyestimated )
88 {
90 alreadyestimated = true;
91 }
92
93 if ( mInterpolator )
94 {
95 const bool b = mInterpolator->calcNormVec( x, y, result );
96 return b;
97 }
98 else
99 {
100 QgsDebugError( u"warning, null pointer"_s );
101 return false;
102 }
103}
104
105bool NormVecDecorator::calcNormalForPoint( double x, double y, int pointIndex, Vector3D *result )
106{
107 if ( !alreadyestimated )
108 {
110 alreadyestimated = true;
111 }
112
113 if ( result )
114 {
115 int numberofbreaks = 0; //number of breaklines around the point
116 int ffirstbp = -1000; //numbers of the points related to the first breakline
117 int lfirstbp = -1000;
118 bool pointfound = false; //is set to true, if the triangle with the point in is found
119 int numberofruns = 0; //number of runs of the loop. This integer can be used to prevent endless loops
120 const int limit = 100000; //ater this number of iterations, the method is terminated
121
122 result->setX( 0 );
123 result->setY( 0 );
124 result->setZ( 0 );
125
126 const QList<int> vlist = surroundingTriangles( pointIndex ); //get the value list
127 if ( vlist.empty() ) //an error occurred in 'getSurroundingTriangles'
128 {
129 return false;
130 }
131
132 if ( ( ( vlist.count() ) % 4 ) != 0 ) //number of items in vlist has to be a multiple of 4
133 {
134 QgsDebugError( u"warning, wrong number of items in vlist"_s );
135 return false;
136 }
137
138 auto it = vlist.constBegin();
139
140 bool firstrun;
141
142 while ( true ) //endless loop to analyze vlist
143 {
144 numberofruns++;
145 if ( numberofruns > limit )
146 {
147 QgsDebugError( u"warning, a probable endless loop is detected"_s );
148 return false;
149 }
150
151 int p1, p2, p3, line;
152 firstrun = false; //flag which tells, if it is the first run with a breakline
153 p1 = ( *it );
154 ++it;
155 p2 = ( *it );
156 ++it;
157 p3 = ( *it );
158 ++it;
159 line = ( *it );
160
161
162 if ( numberofbreaks > 0 )
163 {
164 if ( p1 != -1 && p2 != -1 && p3 != -1 )
165 {
166 if ( MathUtils::pointInsideTriangle( x, y, point( p1 ), point( p2 ), point( p3 ) ) )
167 {
168 pointfound = true;
169 }
170
171 Vector3D addvec( 0, 0, 0 );
172 MathUtils::normalFromPoints( point( p1 ), point( p2 ), point( p3 ), &addvec );
173 result->setX( result->getX() + addvec.getX() );
174 result->setY( result->getY() + addvec.getY() );
175 result->setZ( result->getZ() + addvec.getZ() );
176 }
177 }
178
179 if ( line == -10 ) //we found a breakline
180 {
181 if ( numberofbreaks == 0 ) //it is the first breakline
182 {
183 firstrun = true;
184 ffirstbp = p2; //set the marks to recognize the breakline later
185 lfirstbp = p3;
186 }
187
188 if ( p2 == ffirstbp && p3 == lfirstbp && !firstrun ) //we are back at the first breakline
189 {
190 if ( !pointfound ) //the point with coordinates x, y was in no triangle
191 {
192 QgsDebugError( u"warning: point (x,y) was in no triangle"_s );
193 return false;
194 }
195 result->standardise();
196 break;
197 }
198
199 if ( numberofbreaks > 0 && pointfound ) //we found the second break line and the point is between the first and the second
200 {
201 result->standardise();
202 numberofbreaks++; //to make the distinction between endpoints and points on a breakline easier
203 break;
204 }
205
206 result->setX( 0 );
207 result->setY( 0 );
208 result->setZ( 0 );
209 numberofbreaks++;
210 }
211
212 ++it;
213 if ( it == vlist.constEnd() ) //restart at the beginning of the loop
214 {
215 it = vlist.constBegin();
216 }
217 }
218 return true;
219 }
220 else
221 {
222 QgsDebugError( u"warning, null pointer"_s );
223 return false;
224 }
225}
226
227bool NormVecDecorator::calcPoint( double x, double y, QgsPoint &result )
228{
229 if ( !alreadyestimated )
230 {
232 alreadyestimated = true;
233 }
234
235 if ( mInterpolator )
236 {
237 const bool b = mInterpolator->calcPoint( x, y, result );
238 return b;
239 }
240 else
241 {
242 QgsDebugError( u"warning, null pointer"_s );
243 return false;
244 }
245}
246
247bool NormVecDecorator::getTriangle( double x, double y, QgsPoint &p1, Vector3D *v1, QgsPoint &p2, Vector3D *v2, QgsPoint &p3, Vector3D *v3 )
248{
249 if ( v1 && v2 && v3 )
250 {
251 int nr1 = 0;
252 int nr2 = 0;
253 int nr3 = 0;
254
255 if ( TriDecorator::triangleVertices( x, y, p1, nr1, p2, nr2, p3, nr3 ) ) //everything alright
256 {
257 if ( ( *mNormVec )[nr1] && ( *mNormVec )[nr2] && ( *mNormVec )[nr3] )
258 {
259 v1->setX( ( *mNormVec )[nr1]->getX() );
260 v1->setY( ( *mNormVec )[nr1]->getY() );
261 v1->setZ( ( *mNormVec )[nr1]->getZ() );
262
263 v2->setX( ( *mNormVec )[nr2]->getX() );
264 v2->setY( ( *mNormVec )[nr2]->getY() );
265 v2->setZ( ( *mNormVec )[nr2]->getZ() );
266
267 v3->setX( ( *mNormVec )[nr3]->getX() );
268 v3->setY( ( *mNormVec )[nr3]->getY() );
269 v3->setZ( ( *mNormVec )[nr3]->getZ() );
270 }
271 else
272 {
273 QgsDebugError( u"warning, null pointer"_s );
274 return false;
275 }
276 return true;
277 }
278 else
279 {
280 return false;
281 }
282 }
283
284 else
285 {
286 QgsDebugError( u"warning, null pointer"_s );
287 return false;
288 }
289}
290
292{
293 if ( pointno >= 0 )
294 {
295 return mPointState->at( pointno );
296 }
297 else
298 {
299 QgsDebugError( u"warning, number below 0"_s );
300 return mPointState->at( 0 ); //just to avoid a compiler warning
301 }
302}
303
304
305bool 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 )
306{
307 if ( v1 && v2 && v3 && state1 && state2 && state3 )
308 {
309 if ( TriDecorator::triangleVertices( x, y, p1, ptn1, p2, ptn2, p3, ptn3 ) ) //everything alright
310 {
311 v1->setX( ( *mNormVec )[( ptn1 )]->getX() );
312 v1->setY( ( *mNormVec )[( ptn1 )]->getY() );
313 v1->setZ( ( *mNormVec )[( ptn1 )]->getZ() );
314
315 ( *state1 ) = ( *mPointState )[( ptn1 )];
316
317 v2->setX( ( *mNormVec )[( ptn2 )]->getX() );
318 v2->setY( ( *mNormVec )[( ptn2 )]->getY() );
319 v2->setZ( ( *mNormVec )[( ptn2 )]->getZ() );
320
321 ( *state2 ) = ( *mPointState )[( ptn2 )];
322
323 v3->setX( ( *mNormVec )[( ptn3 )]->getX() );
324 v3->setY( ( *mNormVec )[( ptn3 )]->getY() );
325 v3->setZ( ( *mNormVec )[( ptn3 )]->getZ() );
326
327 ( *state3 ) = ( *mPointState )[( ptn3 )];
328
329 return true;
330 }
331 else
332 {
333 return false;
334 }
335 }
336 else
337 {
338 QgsDebugError( u"warning, null pointer"_s );
339 return false;
340 }
341}
342
344{
345 if ( pointno == -1 )
346 {
347 return false;
348 }
349
350 Vector3D part;
351 Vector3D total;
352 total.setX( 0 );
353 total.setY( 0 );
354 total.setZ( 0 );
355 int numberofbreaks = 0; //number of counted breaklines
356 double weights = 0; //sum of the weights
357 double currentweight = 0; //current weight
358 PointState status;
359
360 const QList<int> vlist = surroundingTriangles( pointno ); //get the value list
361
362 if ( vlist.empty() )
363 {
364 //something went wrong in getSurroundingTriangles, set the normal to (0,0,0)
365 if ( mNormVec->size() <= mNormVec->count() ) //allocate more memory if necessary
366 {
367 QgsDebugMsgLevel( u"resizing mNormVec from %1 to %2"_s.arg( mNormVec->size() ).arg( mNormVec->size() + 1 ), 2 );
368 mNormVec->resize( mNormVec->size() + 1 );
369 }
370
371 //todo:resize mNormVec if necessary
372
373 if ( !( ( *mNormVec )[pointno] ) ) //insert a pointer to a Vector3D, if there is none at this position
374 {
375 Vector3D *vec = new Vector3D( total.getX(), total.getY(), total.getZ() );
376 mNormVec->insert( pointno, vec );
377 }
378 else
379 {
380 ( *mNormVec )[pointno]->setX( 0 );
381 ( *mNormVec )[pointno]->setY( 0 );
382 ( *mNormVec )[pointno]->setZ( 0 );
383 }
384 return false;
385 }
386
387 if ( ( vlist.count() % 4 ) != 0 ) //number of items in vlist has to be a multiple of 4
388 {
389 QgsDebugError( u"warning, wrong number of items in vlist"_s );
390 return false;
391 }
392
393 auto it = vlist.constBegin(); //iterate through the list and analyze it
394 while ( it != vlist.constEnd() )
395 {
396 int p1, p2, p3, flag;
397 part.setX( 0 );
398 part.setY( 0 );
399 part.setZ( 0 );
400
401 currentweight = 0;
402
403 p1 = ( *it );
404 ++it;
405 p2 = ( *it );
406 ++it;
407 p3 = ( *it );
408 ++it;
409 flag = ( *it );
410
411 if ( flag == -10 ) //we found a breakline.
412 {
413 numberofbreaks++;
414 }
415
416 if ( p1 != -1 && p2 != -1 && p3 != -1 ) //don't calculate normal, if a point is a virtual point
417 {
418 MathUtils::normalFromPoints( point( p1 ), point( p2 ), point( p3 ), &part );
419 const double dist1 = point( p3 )->distance3D( *point( p1 ) );
420 const double dist2 = point( p3 )->distance3D( *point( p2 ) );
421 //don't add the normal if the triangle is horizontal
422 if ( ( point( p1 )->z() != point( p2 )->z() ) || ( point( p1 )->z() != point( p3 )->z() ) )
423 {
424 currentweight = 1 / ( dist1 * dist1 * dist2 * dist2 );
425 total.setX( total.getX() + part.getX() * currentweight );
426 total.setY( total.getY() + part.getY() * currentweight );
427 total.setZ( total.getZ() + part.getZ() * currentweight );
428 weights += currentweight;
429 }
430 }
431 ++it;
432 }
433
434 if ( total.getX() == 0 && total.getY() == 0 && total.getZ() == 0 ) //we have a point surrounded by horizontal triangles
435 {
436 total.setZ( 1 );
437 }
438 else
439 {
440 total.setX( total.getX() / weights );
441 total.setY( total.getY() / weights );
442 total.setZ( total.getZ() / weights );
443 total.standardise();
444 }
445
446
447 if ( numberofbreaks == 0 )
448 {
449 status = Normal;
450 }
451 else if ( numberofbreaks == 1 )
452 {
453 status = EndPoint;
454 }
455 else
456 {
457 status = BreakLine;
458 }
459
460 //insert the new calculated vector
461 if ( mNormVec->size() <= mNormVec->count() ) //allocate more memory if necessary
462 {
463 mNormVec->resize( mNormVec->size() + 1 );
464 }
465
466 if ( !( ( *mNormVec )[pointno] ) ) //insert a pointer to a Vector3D, if there is none at this position
467 {
468 Vector3D *vec = new Vector3D( total.getX(), total.getY(), total.getZ() );
469 mNormVec->insert( pointno, vec );
470 }
471 else
472 {
473 ( *mNormVec )[pointno]->setX( total.getX() );
474 ( *mNormVec )[pointno]->setY( total.getY() );
475 ( *mNormVec )[pointno]->setZ( total.getZ() );
476 }
477
478 //insert the new status
479
480 if ( pointno >= mPointState->size() )
481 {
482 mPointState->resize( mPointState->size() + 1 );
483 }
484
485 ( *mPointState )[pointno] = status;
486
487 return true;
488}
489
490//weighted method of little
492{
493 const int numberPoints = pointsCount();
494 for ( int i = 0; i < numberPoints; i++ )
495 {
496 if ( feedback )
497 {
498 feedback->setProgress( 100.0 * static_cast<double>( i ) / numberPoints );
499 }
501 }
502
503 return true;
504}
505
507{
508 if ( mTIN )
509 {
510 if ( alreadyestimated )
511 {
512 mTIN->eliminateHorizontalTriangles();
514 }
515 else
516 {
517 mTIN->eliminateHorizontalTriangles();
518 }
519 }
520 else
521 {
522 QgsDebugError( u"warning, null pointer"_s );
523 }
524}
525
527{
528 if ( pointno >= 0 )
529 {
530 ( *mPointState )[pointno] = s;
531 }
532 else
533 {
534 QgsDebugError( u"warning, pointno>0"_s );
535 }
536}
537
538bool NormVecDecorator::swapEdge( double x, double y )
539{
540 if ( mTIN )
541 {
542 bool b = false;
543 if ( alreadyestimated )
544 {
545 const QList<int> list = pointsAroundEdge( x, y );
546 if ( !list.empty() )
547 {
548 b = mTIN->swapEdge( x, y );
549 for ( const int i : list )
550 {
552 }
553 }
554 }
555 else
556 {
557 b = mTIN->swapEdge( x, y );
558 }
559 return b;
560 }
561 else
562 {
563 QgsDebugError( u"warning, null pointer"_s );
564 return false;
565 }
566}
567
569{
570 if ( !mTIN )
571 {
572 return false;
573 }
574 return mTIN->saveTriangulation( sink, feedback );
575}
576
578{
579 if ( !mTIN )
580 {
581 return QgsMesh();
582 }
583 return mTIN->triangulationToMesh( feedback );
584}
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:63
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
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:493
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:63
#define QgsDebugError(str)
Definition qgslogger.h:59
Mesh - vertices, edges and faces.