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