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