1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
// SPDX-License-Identifier: GPL-2.0-or-later
/**
* Mathematical/numerical functions.
*
* Authors:
* Johan Engelen <goejendaagh@zonnet.nl>
*
* Copyright (C) 2007 Johan Engelen
*
* Released under GNU GPL v2+, read the file 'COPYING' for more information.
*/
#ifndef INKSCAPE_HELPER_MATHFNS_H
#define INKSCAPE_HELPER_MATHFNS_H
#include <cmath>
#include <2geom/point.h>
namespace Inkscape {
namespace Util {
/**
* \return x rounded to the nearest multiple of c1 plus c0.
*
* \note
* If c1==0 (and c0 is finite), then returns +/-inf. This makes grid spacing of zero
* mean "ignore the grid in this dimension".
*/
inline double round_to_nearest_multiple_plus(double x, double c1, double c0)
{
return std::floor((x - c0) / c1 + 0.5) * c1 + c0;
}
/**
* \return x rounded to the lower multiple of c1 plus c0.
*
* \note
* If c1 == 0 (and c0 is finite), then returns +/-inf. This makes grid spacing of zero
* mean "ignore the grid in this dimension".
*/
inline double round_to_lower_multiple_plus(double x, double c1, double c0 = 0.0)
{
return std::floor((x - c0) / c1) * c1 + c0;
}
/**
* \return x rounded to the upper multiple of c1 plus c0.
*
* \note
* If c1 == 0 (and c0 is finite), then returns +/-inf. This makes grid spacing of zero
* mean "ignore the grid in this dimension".
*/
inline double round_to_upper_multiple_plus(double x, double const c1, double const c0 = 0)
{
return std::ceil((x - c0) / c1) * c1 + c0;
}
/// Returns floor(log_2(x)), assuming x >= 1.
// Note: This is a naive implementation.
// Todo: (C++20) Replace with std::bit_floor.
template <typename T>
int constexpr floorlog2(T x)
{
int n = -1;
while (x > 0) {
x /= 2;
n++;
}
return n;
}
/// Returns \a a mod \a b, always in the range 0..b-1, assuming b >= 1.
template <typename T, typename std::enable_if<std::is_integral<T>::value, bool>::type = true>
T constexpr safemod(T a, T b)
{
a %= b;
return a < 0 ? a + b : a;
}
/// Returns \a a rounded down to the nearest multiple of \a b, assuming b >= 1.
template <typename T, typename std::enable_if<std::is_integral<T>::value, bool>::type = true>
T constexpr rounddown(T a, T b)
{
return a - safemod(a, b);
}
/// Returns \a a rounded up to the nearest multiple of \a b, assuming b >= 1.
template <typename T, typename std::enable_if<std::is_integral<T>::value, bool>::type = true>
T constexpr roundup(T a, T b)
{
return rounddown(a - 1, b) + b;
}
/**
* Just like std::clamp, except it doesn't deliberately crash if lo > hi due to rounding errors,
* so is safe to use with floating-point types. (Note: compiles to branchless.)
*/
template <typename T>
T safeclamp(T val, T lo, T hi)
{
if (val < lo) return lo;
if (val > hi) return hi;
return val;
}
} // namespace Util
} // namespace Inkscape
#endif // INKSCAPE_HELPER_MATHFNS_H
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
|