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 The 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, see <https://www.gnu.org/licenses/>.
27 */
28
29#ifndef UTIL_H
30#define UTIL_H
31
32#include <config.h>
33#include <cassert>
34#include <cmath>
35#include <cstdint>
36#include <limits>
37#include <typeinfo>
38#include <type_traits>
39#include <algorithm>
40
44void kimathLogDebug( const char* aFormatString, ... );
45
49void kimathLogOverflow( double v, const char* aTypeName );
50
51
52// Suppress an annoying warning that the explicit rounding we do is not precise
53#ifdef HAVE_WIMPLICIT_FLOAT_CONVERSION
54 _Pragma( "GCC diagnostic push" ) \
55 _Pragma( "GCC diagnostic ignored \"-Wimplicit-int-float-conversion\"" )
56#endif
57
58
64template <typename in_type = long long int, typename ret_type = int>
65inline constexpr ret_type KiCheckedCast( in_type v )
66{
67 if constexpr( std::is_same_v<in_type, long long int> && std::is_same_v<ret_type, int> )
68 {
69 if( v > std::numeric_limits<int>::max() )
70 {
71 kimathLogOverflow( double( v ), typeid( int ).name() );
72
73 return std::numeric_limits<int>::max();
74 }
75 else if( v < std::numeric_limits<int>::lowest() )
76 {
77 kimathLogOverflow( double( v ), typeid( int ).name() );
78
79 return std::numeric_limits<int>::lowest();
80 }
81
82 return int( v );
83 }
84 else
85 {
86 return v;
87 }
88}
89
90
97template <typename fp_type, typename ret_type = int>
98constexpr ret_type KiROUND( fp_type v, bool aQuiet = false )
99{
100 using limits = std::numeric_limits<ret_type>;
101
102#if __cplusplus >= 202302L // isnan is not constexpr until C++23
103 if constexpr( std::is_floating_point_v<fp_type> )
104 {
105 if( std::isnan( v ) )
106 {
107 if( !aQuiet )
108 kimathLogOverflow( double( v ), typeid( ret_type ).name() );
109
110 return 0;
111 }
112 }
113#endif
114
115 long long rounded = std::llround( v );
116 long long clamped = std::clamp<long long>( rounded,
117 static_cast<long long>( limits::lowest() ),
118 static_cast<long long>( limits::max() ) );
119
120 if( !aQuiet && clamped != rounded )
121 kimathLogOverflow( double( v ), typeid( ret_type ).name() );
122
123 return static_cast<ret_type>( clamped );
124}
125
126#ifdef HAVE_WIMPLICIT_FLOAT_CONVERSION
127 _Pragma( "GCC diagnostic pop" )
128#endif
129
133
134template <typename T>
135T rescale( T aNumerator, T aValue, T aDenominator )
136{
137 return aNumerator * aValue / aDenominator;
138}
139
140template <typename T>
141constexpr int sign( T val )
142{
143 return ( T( 0 ) < val) - ( val < T( 0 ) );
144}
145
146// explicit specializations for integer types, taking care of overflow.
147template <>
148int rescale( int aNumerator, int aValue, int aDenominator );
149
150template <>
151int64_t rescale( int64_t aNumerator, int64_t aValue, int64_t aDenominator );
152
153
162template <class T>
163typename std::enable_if<std::is_floating_point<T>::value, bool>::type
164equals( T aFirst, T aSecond, T aEpsilon = std::numeric_limits<T>::epsilon() )
165{
166 const T diff = std::abs( aFirst - aSecond );
167
168 if( diff < aEpsilon )
169 {
170 return true;
171 }
172
173 aFirst = std::abs( aFirst );
174 aSecond = std::abs( aSecond );
175 T largest = aFirst > aSecond ? aFirst : aSecond;
176
177 if( diff <= largest * aEpsilon )
178 {
179 return true;
180 }
181
182 return false;
183}
184
185
186#endif // UTIL_H
const char * name
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
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:164
constexpr int sign(T val)
Definition util.h:141
void kimathLogOverflow(double v, const char *aTypeName)
Workaround to avoid the empty-string conversion issue in wxWidgets.
Definition util.cpp:54
constexpr ret_type KiROUND(fp_type v, bool aQuiet=false)
Round a numeric value to an integer using "round halfway cases away from zero" and clamp the result t...
Definition util.h:98
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
Definition util.h:135
void kimathLogDebug(const char *aFormatString,...)
Helper to avoid directly including wx/log.h for the templated functions in kimath.
Definition util.cpp:40
constexpr ret_type KiCheckedCast(in_type v)
Perform a cast between numerical types.
Definition util.h:65