QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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
306 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
307)
308{
309 if ( v1 && v2 && v3 && state1 && state2 && state3 )
310 {
311 if ( TriDecorator::triangleVertices( x, y, p1, ptn1, p2, ptn2, p3, ptn3 ) ) //everything alright
312 {
313 v1->setX( ( *mNormVec )[( ptn1 )]->getX() );
314 v1->setY( ( *mNormVec )[( ptn1 )]->getY() );
315 v1->setZ( ( *mNormVec )[( ptn1 )]->getZ() );
316
317 ( *state1 ) = ( *mPointState )[( ptn1 )];
318
319 v2->setX( ( *mNormVec )[( ptn2 )]->getX() );
320 v2->setY( ( *mNormVec )[( ptn2 )]->getY() );
321 v2->setZ( ( *mNormVec )[( ptn2 )]->getZ() );
322
323 ( *state2 ) = ( *mPointState )[( ptn2 )];
324
325 v3->setX( ( *mNormVec )[( ptn3 )]->getX() );
326 v3->setY( ( *mNormVec )[( ptn3 )]->getY() );
327 v3->setZ( ( *mNormVec )[( ptn3 )]->getZ() );
328
329 ( *state3 ) = ( *mPointState )[( ptn3 )];
330
331 return true;
332 }
333 else
334 {
335 return false;
336 }
337 }
338 else
339 {
340 QgsDebugError( u"warning, null pointer"_s );
341 return false;
342 }
343}
344
346{
347 if ( pointno == -1 )
348 {
349 return false;
350 }
351
352 Vector3D part;
353 Vector3D total;
354 total.setX( 0 );
355 total.setY( 0 );
356 total.setZ( 0 );
357 int numberofbreaks = 0; //number of counted breaklines
358 double weights = 0; //sum of the weights
359 double currentweight = 0; //current weight
360 PointState status;
361
362 const QList<int> vlist = surroundingTriangles( pointno ); //get the value list
363
364 if ( vlist.empty() )
365 {
366 //something went wrong in getSurroundingTriangles, set the normal to (0,0,0)
367 if ( mNormVec->size() <= mNormVec->count() ) //allocate more memory if necessary
368 {
369 QgsDebugMsgLevel( u"resizing mNormVec from %1 to %2"_s.arg( mNormVec->size() ).arg( mNormVec->size() + 1 ), 2 );
370 mNormVec->resize( mNormVec->size() + 1 );
371 }
372
373 //todo:resize mNormVec if necessary
374
375 if ( !( ( *mNormVec )[pointno] ) ) //insert a pointer to a Vector3D, if there is none at this position
376 {
377 Vector3D *vec = new Vector3D( total.getX(), total.getY(), total.getZ() );
378 mNormVec->insert( pointno, vec );
379 }
380 else
381 {
382 ( *mNormVec )[pointno]->setX( 0 );
383 ( *mNormVec )[pointno]->setY( 0 );
384 ( *mNormVec )[pointno]->setZ( 0 );
385 }
386 return false;
387 }
388
389 if ( ( vlist.count() % 4 ) != 0 ) //number of items in vlist has to be a multiple of 4
390 {
391 QgsDebugError( u"warning, wrong number of items in vlist"_s );
392 return false;
393 }
394
395 auto it = vlist.constBegin(); //iterate through the list and analyze it
396 while ( it != vlist.constEnd() )
397 {
398 int p1, p2, p3, flag;
399 part.setX( 0 );
400 part.setY( 0 );
401 part.setZ( 0 );
402
403 currentweight = 0;
404
405 p1 = ( *it );
406 ++it;
407 p2 = ( *it );
408 ++it;
409 p3 = ( *it );
410 ++it;
411 flag = ( *it );
412
413 if ( flag == -10 ) //we found a breakline.
414 {
415 numberofbreaks++;
416 }
417
418 if ( p1 != -1 && p2 != -1 && p3 != -1 ) //don't calculate normal, if a point is a virtual point
419 {
420 MathUtils::normalFromPoints( point( p1 ), point( p2 ), point( p3 ), &part );
421 const double dist1 = point( p3 )->distance3D( *point( p1 ) );
422 const double dist2 = point( p3 )->distance3D( *point( p2 ) );
423 //don't add the normal if the triangle is horizontal
424 if ( ( point( p1 )->z() != point( p2 )->z() ) || ( point( p1 )->z() != point( p3 )->z() ) )
425 {
426 currentweight = 1 / ( dist1 * dist1 * dist2 * dist2 );
427 total.setX( total.getX() + part.getX() * currentweight );
428 total.setY( total.getY() + part.getY() * currentweight );
429 total.setZ( total.getZ() + part.getZ() * currentweight );
430 weights += currentweight;
431 }
432 }
433 ++it;
434 }
435
436 if ( total.getX() == 0 && total.getY() == 0 && total.getZ() == 0 ) //we have a point surrounded by horizontal triangles
437 {
438 total.setZ( 1 );
439 }
440 else
441 {
442 total.setX( total.getX() / weights );
443 total.setY( total.getY() / weights );
444 total.setZ( total.getZ() / weights );
445 total.standardise();
446 }
447
448
449 if ( numberofbreaks == 0 )
450 {
451 status = Normal;
452 }
453 else if ( numberofbreaks == 1 )
454 {
455 status = EndPoint;
456 }
457 else
458 {
459 status = BreakLine;
460 }
461
462 //insert the new calculated vector
463 if ( mNormVec->size() <= mNormVec->count() ) //allocate more memory if necessary
464 {
465 mNormVec->resize( mNormVec->size() + 1 );
466 }
467
468 if ( !( ( *mNormVec )[pointno] ) ) //insert a pointer to a Vector3D, if there is none at this position
469 {
470 Vector3D *vec = new Vector3D( total.getX(), total.getY(), total.getZ() );
471 mNormVec->insert( pointno, vec );
472 }
473 else
474 {
475 ( *mNormVec )[pointno]->setX( total.getX() );
476 ( *mNormVec )[pointno]->setY( total.getY() );
477 ( *mNormVec )[pointno]->setZ( total.getZ() );
478 }
479
480 //insert the new status
481
482 if ( pointno >= mPointState->size() )
483 {
484 mPointState->resize( mPointState->size() + 1 );
485 }
486
487 ( *mPointState )[pointno] = status;
488
489 return true;
490}
491
492//weighted method of little
494{
495 const int numberPoints = pointsCount();
496 for ( int i = 0; i < numberPoints; i++ )
497 {
498 if ( feedback )
499 {
500 feedback->setProgress( 100.0 * static_cast<double>( i ) / numberPoints );
501 }
503 }
504
505 return true;
506}
507
509{
510 if ( mTIN )
511 {
512 if ( alreadyestimated )
513 {
514 mTIN->eliminateHorizontalTriangles();
516 }
517 else
518 {
519 mTIN->eliminateHorizontalTriangles();
520 }
521 }
522 else
523 {
524 QgsDebugError( u"warning, null pointer"_s );
525 }
526}
527
529{
530 if ( pointno >= 0 )
531 {
532 ( *mPointState )[pointno] = s;
533 }
534 else
535 {
536 QgsDebugError( u"warning, pointno>0"_s );
537 }
538}
539
540bool NormVecDecorator::swapEdge( double x, double y )
541{
542 if ( mTIN )
543 {
544 bool b = false;
545 if ( alreadyestimated )
546 {
547 const QList<int> list = pointsAroundEdge( x, y );
548 if ( !list.empty() )
549 {
550 b = mTIN->swapEdge( x, y );
551 for ( const int i : list )
552 {
554 }
555 }
556 }
557 else
558 {
559 b = mTIN->swapEdge( x, y );
560 }
561 return b;
562 }
563 else
564 {
565 QgsDebugError( u"warning, null pointer"_s );
566 return false;
567 }
568}
569
571{
572 if ( !mTIN )
573 {
574 return false;
575 }
576 return mTIN->saveTriangulation( sink, feedback );
577}
578
580{
581 if ( !mTIN )
582 {
583 return QgsMesh();
584 }
585 return mTIN->triangulationToMesh( feedback );
586}
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:65
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:510
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: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:63
#define QgsDebugError(str)
Definition qgslogger.h:59
Mesh - vertices, edges and faces.