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