KiCad PCB EDA Suite
Loading...
Searching...
No Matches
util.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KICAD, a free EDA CAD application.
3 *
4 * Copyright (c) 2005 Michael Niedermayer <[email protected]>
5 * Copyright (C) CERN
6 * Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * @author Tomasz Wlostowski <[email protected]>
9 *
10 * The equals() method to compare two floating point values adapted from
11 * AlmostEqualRelativeAndAbs() on
12 * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
13 * (C) Bruce Dawson subject to the Apache 2.0 license.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, you may find one here:
27 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
28 * or you may search the http://www.gnu.org website for the version 2 license,
29 * or you may write to the Free Software Foundation, Inc.,
30 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
31 */
32
33#ifndef UTIL_H
34#define UTIL_H
35
36#include <config.h>
37#include <cassert>
38#include <cmath>
39#include <cstdint>
40#include <limits>
41#include <typeinfo>
42#include <type_traits>
43
47void kimathLogDebug( const char* aFormatString, ... );
48
52void kimathLogOverflow( double v, const char* aTypeName );
53
65template <typename T> inline constexpr T Clamp( const T& lower, const T& value, const T& upper )
66{
67 assert( upper >= lower );
68
69 if( value < lower )
70 return lower;
71 else if( upper < value )
72 return upper;
73 return value;
74}
75
76// Suppress an annoying warning that the explicit rounding we do is not precise
77#ifdef HAVE_WIMPLICIT_FLOAT_CONVERSION
78 _Pragma( "GCC diagnostic push" ) \
79 _Pragma( "GCC diagnostic ignored \"-Wimplicit-int-float-conversion\"" )
80#endif
81
82
88template <typename in_type = long long int, typename ret_type = int>
89inline constexpr ret_type KiCheckedCast( in_type v )
90{
91 if constexpr( std::is_same_v<in_type, long long int> && std::is_same_v<ret_type, int> )
92 {
93 if( v > std::numeric_limits<int>::max() )
94 {
95 kimathLogOverflow( double( v ), typeid( int ).name() );
96
97 return std::numeric_limits<int>::max();
98 }
99 else if( v < std::numeric_limits<int>::lowest() )
100 {
101 kimathLogOverflow( double( v ), typeid( int ).name() );
102
103 return std::numeric_limits<int>::lowest();
104 }
105
106 return int( v );
107 }
108 else
109 {
110 return v;
111 }
112}
113
114
120template <typename fp_type, typename ret_type = int>
121constexpr ret_type KiROUND( fp_type v )
122{
123 using max_ret = long long int;
124 fp_type ret = v < 0 ? v - 0.5 : v + 0.5;
125
126 if( ret > std::numeric_limits<ret_type>::max() )
127 {
128 kimathLogOverflow( double( v ), typeid( ret_type ).name() );
129
130 return std::numeric_limits<ret_type>::max() - 1;
131 }
132 else if( ret < std::numeric_limits<ret_type>::lowest() )
133 {
134 kimathLogOverflow( double( v ), typeid( ret_type ).name() );
135
136 if( std::numeric_limits<ret_type>::is_signed )
137 return std::numeric_limits<ret_type>::lowest() + 1;
138 else
139 return 0;
140 }
141#if __cplusplus >= 202302L // isnan is not constexpr until C++23
142 else if constexpr( std::is_floating_point_v<fp_type> )
143 {
144 if( std::isnan( v ) )
145 {
146 kimathLogOverflow( double( v ), typeid( ret_type ).name() );
147
148 return 0;
149 }
150 }
151#endif
152
153 return ret_type( max_ret( ret ) );
154}
155
156#ifdef HAVE_WIMPLICIT_FLOAT_CONVERSION
157 _Pragma( "GCC diagnostic pop" )
158#endif
159
164template <typename T>
165T rescale( T aNumerator, T aValue, T aDenominator )
166{
167 return aNumerator * aValue / aDenominator;
168}
169
170template <typename T>
171int sign( T val )
172{
173 return ( T( 0 ) < val) - ( val < T( 0 ) );
174}
175
176// explicit specializations for integer types, taking care of overflow.
177template <>
178int rescale( int aNumerator, int aValue, int aDenominator );
179
180template <>
181int64_t rescale( int64_t aNumerator, int64_t aValue, int64_t aDenominator );
182
183
192template <class T>
193typename std::enable_if<std::is_floating_point<T>::value, bool>::type
194equals( T aFirst, T aSecond, T aEpsilon = std::numeric_limits<T>::epsilon() )
195{
196 T diff = std::abs( aFirst - aSecond );
197
198 if( diff < aEpsilon )
199 {
200 return true;
201 }
202
203 aFirst = std::abs( aFirst );
204 aSecond = std::abs( aSecond );
205 T largest = aFirst > aSecond ? aFirst : aSecond;
206
207 if( diff <= largest * aEpsilon )
208 {
209 return true;
210 }
211
212 return false;
213}
214
215
216#endif // UTIL_H
const char * name
Definition: DXF_plotter.cpp:57
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
std::enable_if< std::is_floating_point< T >::value, bool >::type equals(T aFirst, T aSecond, T aEpsilon=std::numeric_limits< T >::epsilon())
Template to compare two floating point values for equality within a required epsilon.
Definition: util.h:194
int sign(T val)
Definition: util.h:171
void kimathLogOverflow(double v, const char *aTypeName)
Workaround to avoid the empty-string conversion issue in wxWidgets.
Definition: util.cpp:58
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:121
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
Definition: util.h:165
void kimathLogDebug(const char *aFormatString,...)
Helper to avoid directly including wx/log.h for the templated functions in kimath.
Definition: util.cpp:44
constexpr T Clamp(const T &lower, const T &value, const T &upper)
Limit value within the range lower <= value <= upper.
Definition: util.h:65
constexpr ret_type KiCheckedCast(in_type v)
Perform a cast between numerical types.
Definition: util.h:89