QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
MathUtils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 MathUtils.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 "MathUtils.h"
18
19#include "Vector3D.h"
21#include "qgslogger.h"
22#include "qgspoint.h"
23
24bool MathUtils::calcBarycentricCoordinates( double x, double y, QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *result )
25{
26 if ( p1 && p2 && p3 && result )
27 {
28 QgsPoint p( x, y, 0 );
29 const double area = triArea( p1, p2, p3 );
30 if ( area == 0 ) //p1, p2, p3 are in a line
31 {
32 return false;
33 }
34 const double area1 = triArea( &p, p2, p3 );
35 const double area2 = triArea( p1, &p, p3 );
36 const double area3 = triArea( p1, p2, &p );
37 const double u = area1 / area;
38 const double v = area2 / area;
39 const double w = area3 / area;
40 result->setX( u );
41 result->setY( v );
42 result->setZ( w );
43 return true;
44 }
45 else //null pointer
46 {
47 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
48 return false;
49 }
50}
51
52bool MathUtils::BarycentricToXY( double u, double v, double w, QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *result ) //this is wrong at the moment. Furthermore, the case, where the denominators are 0 have to be treated (two ways of calculating px and py)
53{
54 Q_UNUSED( w )
55
56 double px, py;
57 if ( p1 && p2 && p3 && result )
58 {
59 const double area = triArea( p1, p2, p3 );
60
61 if ( area == 0 )
62 {
63 QgsDebugError( QStringLiteral( "warning, p1, p2 and p3 are in a line" ) );
64 return false;
65 }
66
67 const double denominator = ( ( p2->y() - p3->y() ) * ( p1->x() - p3->x() ) - ( p3->y() - p1->y() ) * ( p3->x() - p2->x() ) );
68 if ( denominator != 0 ) //drop out py in the two equations
69 {
70 px = ( 2 * u * area * ( p1->x() - p3->x() ) - 2 * v * area * ( p3->x() - p2->x() ) - p2->x() * p3->y() * ( p1->x() - p3->x() ) + p3->x() * p1->y() * ( p3->x() - p2->x() ) + p3->x() * p2->y() * ( p1->x() - p3->x() ) - p1->x() * p3->y() * ( p3->x() - p2->x() ) ) / denominator;
71 if ( ( p3->x() - p2->x() ) != 0 )
72 {
73 py = ( 2 * u * area - px * ( p2->y() - p3->y() ) - p2->x() * p3->y() + p3->x() * p2->y() ) / ( p3->x() - p2->x() );
74 }
75 else
76 {
77 py = ( 2 * v * area - px * ( p3->y() - p1->y() ) - p3->x() * p1->y() + p1->x() * p3->y() ) / ( p1->x() - p3->x() );
78 }
79 }
80 else //drop out px in the two equations(maybe this possibility occurs only, if p1, p2 and p3 are coplanar
81 {
82 py = ( 2 * u * area * ( p3->y() - p1->y() ) - 2 * v * area * ( p2->y() - p3->y() ) - p2->x() * p3->y() * ( p3->y() - p1->y() ) + p3->x() * p1->y() * ( p2->y() - p3->y() ) + p3->x() * p2->y() * ( p3->y() - p1->y() ) - p1->x() * p3->y() * ( p2->y() - p3->y() ) ) / ( ( p3->x() - p2->x() ) * ( p3->y() - p1->y() ) - ( p1->x() - p3->x() ) * ( p2->y() - p3->y() ) );
83 if ( ( p2->y() - p3->y() ) != 0 )
84 {
85 px = ( 2 * u * area - py * ( p3->x() - p2->x() ) - p2->x() * p3->y() + p3->x() * p2->y() ) / ( p2->y() - p3->y() );
86 }
87 else
88 {
89 px = ( 2 * v * area - py * ( p1->x() - p3->x() ) - p3->x() * p1->y() + p1->x() * p3->y() ) / ( p3->y() - p1->y() );
90 }
91 }
92 result->setX( px );
93 result->setY( py );
94 return true;
95 }
96 else //null pointer
97 {
98 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
99 return false;
100 }
101}
102
103double MathUtils::calcBernsteinPoly( int n, int i, double t )
104{
105 if ( i < 0 )
106 {
107 return 0;
108 }
109
110 return lower( n, i ) * std::pow( t, i ) * std::pow( ( 1 - t ), ( n - i ) );
111}
112
113double MathUtils::cFDerBernsteinPoly( int n, int i, double t )
114{
115 return n * ( calcBernsteinPoly( n - 1, i - 1, t ) - calcBernsteinPoly( n - 1, i, t ) );
116}
117
118bool MathUtils::circumcenter( QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *result ) //version using the property that the distances from p1, p2, p3 to the circumcenter have to be equal. Possibly there is a bug
119{
120 if ( p1 && p2 && p3 && result )
121 {
122 const double distp1p2 = p1->distance( *p2 );
123 const double distp2p3 = p2->distance( *p3 );
124 if ( distp1p2 > distp2p3 )
125 {
126 //swap p1 and p3 to avoid round-off errors
127 QgsPoint *temp = p1;
128 p1 = p3;
129 p3 = temp;
130 }
131 const double denominator = -p3->x() * p2->y() + p3->x() * p1->y() + p1->x() * p2->y() + p2->x() * p3->y() - p2->x() * p1->y() - p1->x() * p3->y();
132 //if one of the denominator is zero we will have problems
133 if ( denominator == 0 )
134 {
135 QgsDebugError( QStringLiteral( "error: the three points are in a line" ) );
136 return false;
137 }
138 else
139 {
140 result->setX( 0.5 * ( p1->x() * p1->x() * p2->y() - p1->x() * p1->x() * p3->y() - p3->x() * p3->x() * p2->y() - p1->y() * p2->x() * p2->x() - p1->y() * p1->y() * p3->y() - p3->y() * p3->y() * p2->y() + p1->y() * p1->y() * p2->y() + p3->y() * p2->x() * p2->x() - p1->y() * p2->y() * p2->y() + p1->y() * p3->y() * p3->y() + p1->y() * p3->x() * p3->x() + p3->y() * p2->y() * p2->y() ) / denominator );
141 result->setY( -0.5 * ( p3->x() * p2->x() * p2->x() + p2->x() * p1->y() * p1->y() + p3->x() * p2->y() * p2->y() - p3->x() * p1->x() * p1->x() + p1->x() * p3->y() * p3->y() - p3->x() * p1->y() * p1->y() - p1->x() * p2->x() * p2->x() - p2->x() * p3->y() * p3->y() - p1->x() * p2->y() * p2->y() - p2->x() * p3->x() * p3->x() + p1->x() * p3->x() * p3->x() + p2->x() * p1->x() * p1->x() ) / denominator );
142
143 return true;
144 }
145 }
146 else
147 {
148 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
149 return false;
150 }
151}
152
154{
155 if ( thepoint && p1 && p2 )
156 {
157 Vector3D normal( 0, 0, 0 );
158 Vector3D line( p2->x() - p1->x(), p2->y() - p1->y(), 0 );
159 MathUtils::normalLeft( &line, &normal, 1 );
160 const double a = normal.getX();
161 const double b = normal.getY();
162 const double c = -( normal.getX() * p2->x() + normal.getY() * p2->y() );
163 const double distance = std::fabs( ( a * thepoint->x() + b * thepoint->y() + c ) / ( std::sqrt( a * a + b * b ) ) );
164 return distance;
165 }
166 else
167 {
168 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
169 return 0;
170 }
171}
172
174{
175 return std::tgamma( n + 1 );
176}
177
179{
180 const double tolerance = 0.0001; //if the amount of aValue is below this, testp is approximately on the circle and we have to define another criterion to tell, if it is inside or outside.
181
182 if ( testp && p1 && p2 && p3 )
183 {
184 double ax = p1->x();
185 double ay = p1->y();
186 double bx = p2->x();
187 double by = p2->y();
188 double cx = p3->x();
189 double cy = p3->y();
190 double px = testp->x();
191 double py = testp->y();
192
193 const double xmin = std::min( std::min( ax, px ), std::min( bx, cx ) );
194 const double ymin = std::min( std::min( ay, py ), std::min( by, cy ) );
195 ax -= xmin;
196 bx -= xmin;
197 cx -= xmin;
198 px -= xmin;
199 ay -= ymin;
200 by -= ymin;
201 cy -= ymin;
202 py -= ymin;
203
204 double aValue = ( ax * ax + ay * ay ) * triArea( p2, p3, testp );
205 aValue = aValue - ( ( bx * bx + by * by ) * triArea( p1, p3, testp ) );
206 aValue = aValue + ( ( cx * cx + cy * cy ) * triArea( p1, p2, testp ) );
207 aValue = aValue - ( ( px * px + py * py ) * triArea( p1, p2, p3 ) );
208
209 return aValue > tolerance;
210 }
211 else
212 {
213 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
214 return false;
215 }
216}
217
219{
220 return angle( p1, point, p2, point ) > 90;
221}
222
223double MathUtils::leftOf( const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2 )
224{
225 if ( p1 && p2 )
226 {
227 //just for debugging
228 const double f1 = thepoint.x() - p1->x();
229 const double f2 = p2->y() - p1->y();
230 const double f3 = thepoint.y() - p1->y();
231 const double f4 = p2->x() - p1->x();
232 return f1 * f2 - f3 * f4;
233 //return thepoint->getX()-p1->getX())*(p2->getY()-p1->getY())-(thepoint->getY()-p1->getY())*(p2->getX()-p1->getX();//calculating the vectorproduct
234 }
235 else
236 {
237 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
238 return 0;
239 }
240}
241
243{
244 if ( p1 && p2 && p3 && p4 )
245 {
246 double t1, t2;
247 const Vector3D p1p2( p2->x() - p1->x(), p2->y() - p1->y(), 0 );
248 const Vector3D p3p4( p4->x() - p3->x(), p4->y() - p3->y(), 0 );
249 if ( ( p3p4.getX() * p1p2.getY() - p3p4.getY() * p1p2.getX() ) != 0 && p1p2.getX() != 0 ) //avoid division through zero
250 {
251 t2 = ( p1->x() * p1p2.getY() - p1->y() * p1p2.getX() + p3->y() * p1p2.getX() - p3->x() * p1p2.getY() ) / ( p3p4.getX() * p1p2.getY() - p3p4.getY() * p1p2.getX() );
252 t1 = ( p3->x() - p1->x() + t2 * p3p4.getX() ) / p1p2.getX();
253 }
254 else if ( ( p1p2.getX() * p3p4.getY() - p1p2.getY() * p3p4.getX() ) != 0 && p3p4.getX() != 0 )
255 {
256 t1 = ( p3->x() * p3p4.getY() - p3->y() * p3p4.getX() - p1->x() * p3p4.getY() + p1->y() * p3p4.getX() ) / ( p1p2.getX() * p3p4.getY() - p1p2.getY() * p3p4.getX() );
257 t2 = ( p1->x() + t1 * p1p2.getX() - p3->x() ) / p3p4.getX();
258 }
259 else //the lines are parallel
260 {
261 return false;
262 }
263
264 if ( t1 > 0 && t1 < 1 && t2 > 0 && t2 < 1 )
265 {
266 if ( ( *p1 ) == ( *p3 ) || ( *p1 ) == ( *p4 ) || ( *p2 ) == ( *p3 ) || ( *p2 ) == ( *p4 ) ) //the lines touch each other, so they do not cross
267 {
268 return false;
269 }
270 return true;
271 }
272 else
273 {
274 return false;
275 }
276 }
277
278 else
279 {
280 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
281 return false;
282 }
283}
284
285bool MathUtils::lineIntersection( QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4, QgsPoint *intersection_point )
286{
287 if ( p1 && p2 && p3 && p4 )
288 {
289 double t1, t2;
290 const Vector3D p1p2( p2->x() - p1->x(), p2->y() - p1->y(), 0 );
291 const Vector3D p3p4( p4->x() - p3->x(), p4->y() - p3->y(), 0 );
292 if ( ( p3p4.getX() * p1p2.getY() - p3p4.getY() * p1p2.getX() ) != 0 && p1p2.getX() != 0 ) //avoid division through zero
293 {
294 t2 = ( p1->x() * p1p2.getY() - p1->y() * p1p2.getX() + p3->y() * p1p2.getX() - p3->x() * p1p2.getY() ) / ( p3p4.getX() * p1p2.getY() - p3p4.getY() * p1p2.getX() );
295 t1 = ( p3->x() - p1->x() + t2 * p3p4.getX() ) / p1p2.getX();
296 }
297 else if ( ( p1p2.getX() * p3p4.getY() - p1p2.getY() * p3p4.getX() ) != 0 && p3p4.getX() != 0 )
298 {
299 t1 = ( p3->x() * p3p4.getY() - p3->y() * p3p4.getX() - p1->x() * p3p4.getY() + p1->y() * p3p4.getX() ) / ( p1p2.getX() * p3p4.getY() - p1p2.getY() * p3p4.getX() );
300 t2 = ( p1->x() + t1 * p1p2.getX() - p3->x() ) / p3p4.getX();
301 }
302 else //the lines are parallel
303 {
304 intersection_point->setX( 0 );
305 intersection_point->setY( 0 );
306 intersection_point->setZ( 0 );
307 return false;
308 }
309
310 if ( t1 > 0 && t1 < 1 && t2 > 0 && t2 < 1 )
311 {
312 if ( ( *p1 ) == ( *p3 ) || ( *p1 ) == ( *p4 ) || ( *p2 ) == ( *p3 ) || ( *p2 ) == ( *p4 ) ) //the lines touch each other, so they do not cross
313 {
314 intersection_point->setX( 0 );
315 intersection_point->setY( 0 );
316 intersection_point->setZ( 0 );
317 return false;
318 }
319 //calculate the intersection point
320 intersection_point->setX( p1->x() * ( 1 - t1 ) + p2->x() * t1 );
321 intersection_point->setY( p1->y() * ( 1 - t1 ) + p2->y() * t1 );
322 intersection_point->setZ( 0 );
323 return true;
324 }
325 else
326 {
327 return false;
328 }
329 }
330
331 else
332 {
333 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
334 return false;
335 }
336}
337
338int MathUtils::lower( int n, int i )
339{
340 if ( i >= 0 && i <= n )
341 {
342 return faculty( n ) / ( faculty( i ) * faculty( n - i ) );
343 }
344 else
345 {
346 return 0;
347 }
348}
349
351{
352 if ( pa && pb && pc )
353 {
354 const double deter = ( pa->x() * pb->y() + pb->x() * pc->y() + pc->x() * pa->y() - pa->x() * pc->y() - pb->x() * pa->y() - pc->x() * pb->y() );
355 return 0.5 * deter;
356 }
357 else //null pointer
358 {
359 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
360 return 0;
361 }
362}
363
364double MathUtils::calcCubicHermitePoly( int n, int i, double t )
365{
366 if ( n != 3 || i > n )
367 {
368 QgsDebugError( QStringLiteral( "error, can't calculate hermite polynom" ) );
369 }
370
371 if ( n == 3 && i == 0 )
372 {
373 return ( calcBernsteinPoly( 3, 0, t ) + calcBernsteinPoly( 3, 1, t ) );
374 }
375
376 if ( n == 3 && i == 1 )
377 {
378 return ( calcBernsteinPoly( 3, 1, t ) * 0.33333333 );
379 }
380
381 if ( n == 3 && i == 2 )
382 {
383 return ( calcBernsteinPoly( 3, 2, t ) * -0.33333333 );
384 }
385
386 if ( n == 3 && i == 3 )
387 {
388 return ( calcBernsteinPoly( 3, 2, t ) + calcBernsteinPoly( 3, 3, t ) );
389 }
390 else //something went wrong
391 {
392 QgsDebugError( QStringLiteral( "unexpected error" ) );
393 return 0;
394 }
395}
396
397double MathUtils::cFDerCubicHermitePoly( int n, int i, double t )
398{
399 if ( n != 3 || i > n )
400 {
401 QgsDebugError( QStringLiteral( "error, can't calculate hermite polynom" ) );
402 }
403
404 if ( n == 3 && i == 0 )
405 {
406 //cout << "cFDerBernsteinPoly(3,0,t): " << cFDerBernsteinPoly(3,0,t) << endl << flush;
407 //cout << "cFDerBernsteinPoly(3,1,t): " << cFDerBernsteinPoly(3,1,t) << endl << flush;
408 return ( cFDerBernsteinPoly( 3, 0, t ) + cFDerBernsteinPoly( 3, 1, t ) );
409 }
410
411 if ( n == 3 && i == 1 )
412 {
413 //cout << "cFDerBernsteinPoly(3,1,t)/3: " << cFDerBernsteinPoly(3,1,t)/3 << endl << flush;
414 return ( cFDerBernsteinPoly( 3, 1, t ) / 3 );
415 }
416
417 if ( n == 3 && i == 2 )
418 {
419 //cout << "cFDerBernsteinPoly(3,2,t)/3: " << cFDerBernsteinPoly(3,2,t)/3 << endl << flush;
420 return ( -cFDerBernsteinPoly( 3, 2, t ) / 3 );
421 }
422
423 if ( n == 3 && i == 3 )
424 {
425 //cout << "cFDerBernsteinPoly(3,2,t): " << cFDerBernsteinPoly(3,2,t) << endl << flush;
426 //cout << "cFDerBernsteinPoly(3,3,t): " << cFDerBernsteinPoly(3,3,t) << endl << flush;
427 return ( cFDerBernsteinPoly( 3, 2, t ) + cFDerBernsteinPoly( 3, 3, t ) );
428 }
429 else
430 {
431 QgsDebugError( QStringLiteral( "unexpected error" ) );
432 return 0;
433 }
434}
435
436bool MathUtils::derVec( const Vector3D *v1, const Vector3D *v2, Vector3D *result, double x, double y )
437{
438 if ( v1 && v2 && result ) //no null pointers
439 {
440 const double u = ( x * v2->getY() - y * v2->getX() ) / ( v1->getX() * v2->getY() - v1->getY() * v2->getX() );
441 const double v = ( x * v1->getY() - y * v1->getX() ) / ( v2->getX() * v1->getY() - v2->getY() * v1->getX() );
442 result->setX( x );
443 result->setY( y );
444 result->setZ( u * v1->getZ() + v * v2->getZ() );
445 return true;
446 }
447 return false;
448}
449
450
451bool MathUtils::normalLeft( Vector3D *v1, Vector3D *result, double length )
452{
453 if ( v1 && result ) //we don't like null pointers
454 {
455 if ( v1->getY() == 0 ) //this would cause a division with zero
456 {
457 result->setX( 0 );
458
459 if ( v1->getX() < 0 )
460 {
461 result->setY( -length );
462 }
463
464 else
465 {
466 result->setY( length );
467 }
468 return true;
469 }
470
471 //coefficients for the quadratic equation
472 const double a = 1 + ( v1->getX() * v1->getX() ) / ( v1->getY() * v1->getY() );
473 const double b = 0;
474 const double c = -( length * length );
475 const double d = b * b - 4 * a * c;
476
477 if ( d < 0 ) //no solution in R
478 {
479 QgsDebugError( QStringLiteral( "Determinant Error" ) );
480 return false;
481 }
482
483 result->setX( ( -b + std::sqrt( d ) ) / ( 2 * a ) ); //take one of the two solutions of the quadratic equation
484 result->setY( ( -result->getX() * v1->getX() ) / v1->getY() );
485
486 const QgsPoint point1( 0, 0, 0 );
487 const QgsPoint point2( v1->getX(), v1->getY(), 0 );
488 const QgsPoint point3( result->getX(), result->getY(), 0 );
489
490 if ( !( leftOf( point1, &point2, &point3 ) < 0 ) ) //if we took the solution on the right side, change the sign of the components of the result
491 {
492 result->setX( -result->getX() );
493 result->setY( -result->getY() );
494 }
495
496 return true;
497 }
498
499 else
500 {
501 return false;
502 }
503}
504
505
506bool MathUtils::normalRight( Vector3D *v1, Vector3D *result, double length )
507{
508 if ( v1 && result ) //we don't like null pointers
509 {
510 if ( v1->getY() == 0 ) //this would cause a division with zero
511 {
512 result->setX( 0 );
513
514 if ( v1->getX() < 0 )
515 {
516 result->setY( length );
517 }
518
519 else
520 {
521 result->setY( -length );
522 }
523 return true;
524 }
525
526 //coefficients for the quadratic equation
527 const double a = 1 + ( v1->getX() * v1->getX() ) / ( v1->getY() * v1->getY() );
528 const double b = 0;
529 const double c = -( length * length );
530 const double d = b * b - 4 * a * c;
531
532 if ( d < 0 ) //no solution in R
533 {
534 QgsDebugError( QStringLiteral( "Determinant Error" ) );
535 return false;
536 }
537
538 result->setX( ( -b + std::sqrt( d ) ) / ( 2 * a ) ); //take one of the two solutions of the quadratic equation
539 result->setY( ( -result->getX() * v1->getX() ) / v1->getY() );
540
541 const QgsPoint point1( 0, 0, 0 );
542 const QgsPoint point2( v1->getX(), v1->getY(), 0 );
543 const QgsPoint point3( result->getX(), result->getY(), 0 );
544
545 if ( ( leftOf( point1, &point2, &point3 ) < 0 ) ) //if we took the solution on the right side, change the sign of the components of the result
546 {
547 result->setX( -result->getX() );
548 result->setY( -result->getY() );
549 }
550
551 return true;
552 }
553
554 else
555 {
556 return false;
557 }
558}
559
560
562{
563 if ( p1 && p2 && p3 && vec ) //no null pointers
564 {
565 const double ax = p2->x() - p1->x();
566 const double ay = p2->y() - p1->y();
567 const double az = p2->z() - p1->z();
568 const double bx = p3->x() - p1->x();
569 const double by = p3->y() - p1->y();
570 const double bz = p3->z() - p1->z();
571
572 vec->setX( ay * bz - az * by );
573 vec->setY( az * bx - ax * bz );
574 vec->setZ( ax * by - ay * bx );
575 }
576}
577
578double MathUtils::crossVec( QgsPoint *first, Vector3D *vec1, QgsPoint *second, Vector3D *vec2 )
579{
580 if ( first && vec1 && second && vec2 )
581 {
582 if ( ( vec2->getX() * vec1->getY() - vec2->getY() * vec1->getX() ) != 0 )
583 {
584 /*cout << "first: " << first->getX() << "//" << first->getY() << "//" << first->getZ() << endl << flush;
585 cout << "vec1: " << vec1->getX() << "//" << vec1->getY() << "//" << vec1->getZ() << endl << flush;
586 cout << "second: " << second->getX() << "//" << second->getY() << "//" << second->getZ() << endl << flush;
587 cout << "vec2: " << vec2->getX() << "//" << vec2->getY() << "//" << vec2->getZ() << endl << flush;
588 cout << "t2: " << ((first->getX()*vec1->getY()-first->getY()*vec1->getX()-second->getX()*vec1->getY()+second->getY()*vec1->getX())/(vec2->getX()*vec1->getY()-vec2->getY()*vec1->getX())) << endl << flush;*/
589
590 return ( ( first->x() * vec1->getY() - first->y() * vec1->getX() - second->x() * vec1->getY() + second->y() * vec1->getX() ) / ( vec2->getX() * vec1->getY() - vec2->getY() * vec1->getX() ) );
591 }
592 else //if a division by zero would occur
593 {
594 QgsDebugError( QStringLiteral( "warning: vectors are parallel" ) );
595 return 0;
596 }
597 }
598
599
600 else //null pointer
601 {
602 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
603 return 0;
604 }
605}
606
607bool MathUtils::pointInsideTriangle( double x, double y, QgsPoint *p1, QgsPoint *p2, QgsPoint *p3 )
608{
609 const QgsPoint thepoint( x, y, 0 );
610 if ( MathUtils::leftOf( thepoint, p1, p2 ) > 0 )
611 {
612 return false;
613 }
614 if ( MathUtils::leftOf( thepoint, p2, p3 ) > 0 )
615 {
616 return false;
617 }
618 if ( MathUtils::leftOf( thepoint, p3, p1 ) > 0 )
619 {
620 return false;
621 }
622 return true;
623}
624
625bool MathUtils::normalMinDistance( Vector3D *tangent, Vector3D *target, Vector3D *result )
626{
627 if ( tangent && target && result )
628 {
629 const double xt = tangent->getX();
630 const double yt = tangent->getY();
631 const double zt = tangent->getZ();
632
633 const double xw = target->getX();
634 const double yw = target->getY();
635 const double zw = target->getZ();
636
637 double xg1, yg1, zg1; //the coordinates of the first result
638 double xg2, yg2, zg2; //the coordinates of the second result
639
640 //calculate xg
641 const double xgalpha1 = 1 / ( 2 * xt * xt * yw * yw * zt * zt - 2 * zt * zt * zt * xt * zw * xw + yt * yt * yt * yt * zw * zw + yt * yt * zw * zw * zt * zt + xt * xt * yt * yt * xw * xw + xt * xt * yw * yw * yt * yt - 2 * xt * xt * xt * zt * zw * xw + yt * yt * yt * yt * xw * xw + yt * yt * yw * yw * zt * zt + 2 * xt * xt * yt * yt * zw * zw - 2 * yt * yt * yt * yw * zt * zw + zt * zt * xt * xt * zw * zw + zt * zt * zt * zt * xw * xw + xt * xt * zt * zt * xw * xw + 2 * zt * zt * xw * xw * yt * yt - 2 * xt * xt * yw * zt * yt * zw - 2 * xt * yt * yt * yt * xw * yw - 2 * xt * xt * xt * yw * yt * xw - 2 * xt * zt * zt * xw * yt * yw - 2 * xt * zt * xw * yt * yt * zw - 2 * yw * zt * zt * zt * yt * zw + xt * xt * xt * xt * yw * yw + yw * yw * zt * zt * zt * zt + xt * xt * xt * xt * zw * zw );
642 if ( xgalpha1 < 0 )
643 {
644 QgsDebugError( QStringLiteral( "warning, only complex solution of xg" ) );
645 return false;
646 }
647 xg1 = std::sqrt( xgalpha1 ) * ( -yt * yw * xt + yt * yt * xw + xw * zt * zt - zt * xt * zw );
648 xg2 = -sqrt( xgalpha1 ) * ( -yt * yw * xt + yt * yt * xw + xw * zt * zt - zt * xt * zw );
649
650 //calculate yg
651 const double ygalpha1 = 1 / ( 2 * xt * xt * yw * yw * zt * zt - 2 * zt * zt * zt * xt * zw * xw + yt * yt * yt * yt * zw * zw + yt * yt * zw * zw * zt * zt + xt * xt * yt * yt * xw * xw + xt * xt * yw * yw * yt * yt - 2 * xt * xt * xt * zt * zw * xw + yt * yt * yt * yt * xw * xw + yt * yt * yw * yw * zt * zt + 2 * xt * xt * yt * yt * zw * zw - 2 * yt * yt * yt * yw * zt * zw + zt * zt * xt * xt * zw * zw + zt * zt * zt * zt * xw * xw + xt * xt * zt * zt * xw * xw + 2 * zt * zt * xw * xw * yt * yt - 2 * xt * xt * yw * zt * yt * zw - 2 * xt * yt * yt * yt * xw * yw - 2 * xt * xt * xt * yw * yt * xw - 2 * xt * zt * zt * xw * yt * yw - 2 * xt * zt * xw * yt * yt * zw - 2 * yw * zt * zt * zt * yt * zw + xt * xt * xt * xt * yw * yw + yw * yw * zt * zt * zt * zt + xt * xt * xt * xt * zw * zw );
652 if ( ygalpha1 < 0 )
653 {
654 QgsDebugError( QStringLiteral( "warning, only complex solution of yg" ) );
655 return false;
656 }
657 yg1 = -sqrt( ygalpha1 ) * ( -yw * xt * xt - zt * zt * yw + zt * yt * zw + yt * xw * xt );
658 yg2 = std::sqrt( ygalpha1 ) * ( -yw * xt * xt - zt * zt * yw + zt * yt * zw + yt * xw * xt );
659
660 //calculate zg
661 const double zgalpha1 = 1 / ( 2 * xt * xt * yw * yw * zt * zt - 2 * zt * zt * zt * xt * zw * xw + yt * yt * yt * yt * zw * zw + yt * yt * zw * zw * zt * zt + xt * xt * yt * yt * xw * xw + xt * xt * yw * yw * yt * yt - 2 * xt * xt * xt * zt * zw * xw + yt * yt * yt * yt * xw * xw + yt * yt * yw * yw * zt * zt + 2 * xt * xt * yt * yt * zw * zw - 2 * yt * yt * yt * yw * zt * zw + zt * zt * xt * xt * zw * zw + zt * zt * zt * zt * xw * xw + xt * xt * zt * zt * xw * xw + 2 * zt * zt * xw * xw * yt * yt - 2 * xt * xt * yw * zt * yt * zw - 2 * xt * yt * yt * yt * xw * yw - 2 * xt * xt * xt * yw * yt * xw - 2 * xt * zt * zt * xw * yt * yw - 2 * xt * zt * xw * yt * yt * zw - 2 * yw * zt * zt * zt * yt * zw + xt * xt * xt * xt * yw * yw + yw * yw * zt * zt * zt * zt + xt * xt * xt * xt * zw * zw );
662 if ( zgalpha1 < 0 )
663 {
664 QgsDebugError( QStringLiteral( "warning, only complex solution of zg" ) );
665 return false;
666 }
667 zg1 = -sqrt( zgalpha1 ) * ( yt * yw * zt - yt * yt * zw + xw * zt * xt - xt * xt * zw );
668 zg2 = std::sqrt( zgalpha1 ) * ( yt * yw * zt - yt * yt * zw + xw * zt * xt - xt * xt * zw );
669
670 const double distance1 = QgsGeometryUtilsBase::distance2D( xw, yw, xg1, yg1 );
671 const double distance2 = QgsGeometryUtilsBase::distance2D( xw, yw, xg2, yg2 );
672
673 if ( distance1 <= distance2 ) //find out, which solution is the maximum and which the minimum
674 {
675 result->setX( xg1 );
676 result->setY( yg1 );
677 result->setZ( zg1 );
678 }
679 else
680 {
681 result->setX( xg2 );
682 result->setY( yg2 );
683 result->setZ( zg2 );
684 }
685 return true;
686 }
687
688 else
689 {
690 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
691 return false;
692 }
693}
694
695
696double MathUtils::planeTest( QgsPoint *test, QgsPoint *pt1, QgsPoint *pt2, QgsPoint *pt3 )
697{
698 if ( test && pt1 && pt2 && pt3 )
699 {
700 const double a = ( pt1->z() * ( pt2->y() - pt3->y() ) + pt2->z() * ( pt3->y() - pt1->y() ) + pt3->z() * ( pt1->y() - pt2->y() ) ) / ( ( pt1->x() - pt2->x() ) * ( pt2->y() - pt3->y() ) - ( pt2->x() - pt3->x() ) * ( pt1->y() - pt2->y() ) );
701 const double b = ( pt1->z() * ( pt2->x() - pt3->x() ) + pt2->z() * ( pt3->x() - pt1->x() ) + pt3->z() * ( pt1->x() - pt2->x() ) ) / ( ( pt1->y() - pt2->y() ) * ( pt2->x() - pt3->x() ) - ( pt2->y() - pt3->y() ) * ( pt1->x() - pt2->x() ) );
702 const double c = pt1->z() - a * pt1->x() - b * pt1->y();
703 const double zpredicted = test->x() * a + test->y() * b + c;
704 return ( test->z() - zpredicted );
705 }
706 else
707 {
708 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
709 return 0;
710 }
711}
712
714{
715 if ( p1 && p2 && p3 && p4 )
716 {
717 const Vector3D v1( p2->x() - p1->x(), p2->y() - p1->y(), 0 );
718 const Vector3D v2( p4->x() - p3->x(), p4->y() - p3->y(), 0 );
719 const double value = acos( ( v1.getX() * v2.getX() + v1.getY() * v2.getY() ) / ( v1.getLength() * v2.getLength() ) ) * 180 / M_PI;
720 return value;
721 }
722 else
723 {
724 QgsDebugError( QStringLiteral( "warning, null pointer" ) );
725 return 0;
726 }
727}
static double distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
void setY(double y)
Sets the point's y-coordinate.
Definition qgspoint.h:337
void setX(double x)
Sets the point's x-coordinate.
Definition qgspoint.h:326
double z
Definition qgspoint.h:54
double x
Definition qgspoint.h:52
double distance(double x, double y) const
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition qgspoint.h:387
void setZ(double z)
Sets the point's z-coordinate.
Definition qgspoint.h:350
double y
Definition qgspoint.h:53
Represents a 3D-Vector, capable of storing x, y and z-coordinates in double values.
Definition Vector3D.h:37
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
double getLength() const
Returns the length of the vector.
Definition Vector3D.cpp:19
void setZ(double z)
Sets the z-component of the vector.
Definition Vector3D.h:116
bool ANALYSIS_EXPORT normalLeft(Vector3D *v1, Vector3D *result, double length)
Assigns the vector 'result', which is normal to the vector 'v1', on the left side of v1 and has lengt...
bool ANALYSIS_EXPORT inDiametral(QgsPoint *p1, QgsPoint *p2, QgsPoint *point)
Tests, whether 'point' is inside the diametral circle through 'p1' and 'p2'.
bool ANALYSIS_EXPORT derVec(const Vector3D *v1, const Vector3D *v2, Vector3D *result, double x, double y)
Calculates the z-component of a vector with coordinates 'x' and 'y'which is in the same tangent plane...
double ANALYSIS_EXPORT calcBernsteinPoly(int n, int i, double t)
Calculates the value of a Bernstein polynomial.
int ANALYSIS_EXPORT faculty(int n)
Faculty function.
bool ANALYSIS_EXPORT BarycentricToXY(double u, double v, double w, QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *result)
Definition MathUtils.cpp:52
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored).
double ANALYSIS_EXPORT triArea(QgsPoint *pa, QgsPoint *pb, QgsPoint *pc)
Returns the area of a triangle. If the points are ordered counterclockwise, the value will be positiv...
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,...
bool ANALYSIS_EXPORT normalRight(Vector3D *v1, Vector3D *result, double length)
Assigns the vector 'result', which is normal to the vector 'v1', on the right side of v1 and has leng...
double ANALYSIS_EXPORT crossVec(QgsPoint *first, Vector3D *vec1, QgsPoint *second, Vector3D *vec2)
Calculates the intersection of the two vectors vec1 and vec2, which start at first(vec1) and second(v...
bool ANALYSIS_EXPORT lineIntersection(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Returns true, if line1 (p1 to p2) and line2 (p3 to p4) intersect. If the lines have an endpoint in co...
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
double ANALYSIS_EXPORT planeTest(QgsPoint *test, QgsPoint *pt1, QgsPoint *pt2, QgsPoint *pt3)
Tests, if 'test' is in the same plane as 'p1', 'p2' and 'p3' and returns the z-difference from the pl...
bool ANALYSIS_EXPORT circumcenter(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *result)
Calculates the center of the circle passing through p1, p2 and p3. Returns true in case of success an...
double ANALYSIS_EXPORT cFDerBernsteinPoly(int n, int i, double t)
Calculates the first derivative of a Bernstein polynomial with respect to the parameter t.
double ANALYSIS_EXPORT cFDerCubicHermitePoly(int n, int i, double t)
Calculates the first derivative of a cubic Hermite polynomial with respect to the parameter t.
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negative values mean left ...
double ANALYSIS_EXPORT distPointFromLine(QgsPoint *thepoint, QgsPoint *p1, QgsPoint *p2)
Calculates the (2 dimensional) distance from 'thepoint' to the line defined by p1 and p2.
bool ANALYSIS_EXPORT calcBarycentricCoordinates(double x, double y, QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *result)
Calculates the barycentric coordinates of a point (x,y) with respect to p1, p2, p3 and stores the thr...
Definition MathUtils.cpp:24
double ANALYSIS_EXPORT calcCubicHermitePoly(int n, int i, double t)
Calculates the value of a cubic Hermite polynomial.
bool ANALYSIS_EXPORT inCircle(QgsPoint *testp, QgsPoint *p1, QgsPoint *p2, QgsPoint *p3)
Tests, whether 'testp' is inside the circle through 'p1', 'p2' and 'p3'.
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 ...
bool ANALYSIS_EXPORT normalMinDistance(Vector3D *tangent, Vector3D *target, Vector3D *result)
Calculates a Vector orthogonal to 'tangent' with length 1 and closest possible to result....
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define QgsDebugError(str)
Definition qgslogger.h:57