QGIS API Documentation
4.3.0-Master (16eddb2670e)
Toggle main menu visibility
Loading...
Searching...
No Matches
src
core
qgsmathutils.cpp
Go to the documentation of this file.
1
/***************************************************************************
2
qgsmathutils.cpp
3
----------------------
4
begin : July 2025
5
copyright : (C) 2025 by Nyall Dawson
6
email : nyall dot dawson at gmail dot com
7
***************************************************************************
8
* *
9
* This program is free software; you can redistribute it and/or modify *
10
* it under the terms of the GNU General Public License as published by *
11
* the Free Software Foundation; either version 2 of the License, or *
12
* (at your option) any later version. *
13
* *
14
***************************************************************************/
15
16
17
#include "
qgsmathutils.h
"
18
19
#include <cmath>
20
21
#include "
qgis.h
"
22
23
#include "moc_qgsmathutils.cpp"
24
25
void
QgsMathUtils::doubleToRational
(
double
value, qlonglong &numerator, qlonglong &denominator,
double
tolerance,
int
maxIterations )
26
{
27
// This method uses the "continued fraction" algorithm to calculate approximate rational fractions
28
29
if
(
qgsDoubleNear
( value, 0.0 ) )
30
{
31
numerator = 0;
32
denominator = 1;
33
return
;
34
}
35
36
const
int
sign = ( value > 0 ) ? 1 : -1;
37
const
double
x = std::abs( value );
38
39
// convergents:
40
// numerator continuants
41
long
long
previousAConvergent = 0;
42
long
long
currentAConvergent = 1;
43
// denominator continuants
44
long
long
previousBConvergent = 1;
45
long
long
currentBConvergent = 0;
46
47
double
fractionalPart = x;
48
const
double
relativeTolerance = tolerance * x;
49
50
for
(
int
i = 0; i < maxIterations; ++i )
51
{
52
long
long
a =
static_cast<
long
long
>
( std::floor( fractionalPart ) );
53
54
// guard against overflows before continuing, if so, abort early
55
if
( currentAConvergent != 0 && a > ( std::numeric_limits<long long>::max() - previousAConvergent ) / currentAConvergent )
56
{
57
break
;
58
}
59
if
( currentBConvergent != 0 && a > ( std::numeric_limits<long long>::max() - previousBConvergent ) / currentBConvergent )
60
{
61
break
;
62
}
63
64
long
long
nextHConvergent = a * currentAConvergent + previousAConvergent;
65
long
long
nextKConvergent = a * currentBConvergent + previousBConvergent;
66
previousAConvergent = currentAConvergent;
67
previousBConvergent = currentBConvergent;
68
currentAConvergent = nextHConvergent;
69
currentBConvergent = nextKConvergent;
70
71
// is approximation within the specified tolerance?
72
if
( currentBConvergent != 0 && std::abs( x -
static_cast<
double
>
( currentAConvergent ) /
static_cast<
double
>
( currentBConvergent ) ) <= relativeTolerance )
73
{
74
// if so, we've found our answer...
75
break
;
76
}
77
78
// update the fractional part for the next iteration
79
const
double
remainder = fractionalPart -
static_cast<
double
>
( a );
80
if
(
qgsDoubleNear
( remainder, 0.0 ) )
81
{
82
// found exact representation
83
break
;
84
}
85
fractionalPart = 1.0 / remainder;
86
}
87
88
numerator = sign * currentAConvergent;
89
denominator = currentBConvergent;
90
}
91
92
double
QgsMathUtils::roundingInterval
(
double
span,
int
divisions )
93
{
94
if
( !std::isfinite( span ) || span <= 0 || divisions < 1 )
95
return
0;
96
97
return
std::pow( 10.0, std::floor( std::log10( span / divisions ) ) );
98
}
99
100
QgsDoubleRange
QgsMathUtils::roundedRange
(
const
QgsDoubleRange
&range )
101
{
102
const
double
interval =
roundingInterval
( range.
upper
() - range.
lower
() );
103
if
( interval <= 0 )
104
return
range;
105
106
double
lower = std::floor( range.
lower
() / interval ) * interval;
107
double
upper = std::ceil( range.
upper
() / interval ) * interval;
108
109
const
int
decimals = -
static_cast<
int
>
( std::floor( std::log10( interval ) ) );
110
if
( decimals > 0 )
111
{
112
// strip the noise the multiplication above leaves in fractional values
113
lower =
qgsRound
( lower, decimals );
114
upper =
qgsRound
( upper, decimals );
115
}
116
return
QgsDoubleRange
( lower, upper );
117
}
QgsDoubleRange
QgsRange which stores a range of double values.
Definition
qgsrange.h:217
QgsMathUtils::doubleToRational
static Q_INVOKABLE void doubleToRational(double value, qlonglong &numerator, qlonglong &denominator, double tolerance=1.0e-9, int maxIterations=100)
Converts a double value to a rational fraction.
Definition
qgsmathutils.cpp:25
QgsMathUtils::roundedRange
static QgsDoubleRange roundedRange(const QgsDoubleRange &range)
Expands a range outward to round values, e.g.
Definition
qgsmathutils.cpp:100
QgsMathUtils::roundingInterval
static double roundingInterval(double span, int divisions=10)
Returns a round interval, a power of ten, which splits the given span into at least divisions parts.
Definition
qgsmathutils.cpp:92
QgsRange::lower
T lower() const
Returns the lower bound of the range.
Definition
qgsrange.h:79
QgsRange::upper
T upper() const
Returns the upper bound of the range.
Definition
qgsrange.h:86
qgis.h
qgsRound
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
Definition
qgis.h:7837
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition
qgis.h:7743
qgsmathutils.h
Generated on
for QGIS API Documentation by
1.17.0