1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #pragma once 21 22 #include <rtl/math.h> 23 #include <cmath> 24 #include <math.h> 25 #include <basegfx/basegfxdllapi.h> 26 #include <limits> 27 #include <algorithm> 28 29 30 // fTools defines 31 32 namespace basegfx 33 { 34 /** Round double to nearest integer 35 36 @return the nearest integer 37 */ 38 template <class Int = sal_Int32> requires std::is_integral_v<Int> fround(double fVal)39 inline Int fround(double fVal) 40 { 41 if (fVal >= 0.0) 42 { 43 if (fVal >= static_cast<double>(std::numeric_limits<Int>::max()) - 0.5) 44 return std::numeric_limits<Int>::max(); 45 return static_cast<Int>(fVal + .5); 46 } 47 if (fVal <= static_cast<double>(std::numeric_limits<Int>::min()) + 0.5) 48 return std::numeric_limits<Int>::min(); 49 return static_cast<Int>(fVal - .5); 50 } 51 52 /** Round double to nearest integer 53 54 @return the nearest 64 bit integer 55 */ fround64(double fVal)56 inline sal_Int64 fround64(double fVal) { return fround<sal_Int64>(fVal); } 57 58 /** Prune a small epsilon range around zero. 59 60 Use this method e.g. for calculating scale values. There, it 61 is usually advisable not to set a scaling to 0.0, because that 62 yields singular transformation matrices. 63 64 @param fVal 65 An arbitrary, but finite and valid number 66 67 @return either fVal, or a small value slightly above (when 68 fVal>0) or below (when fVal<0) zero. 69 */ pruneScaleValue(double fVal)70 inline double pruneScaleValue( double fVal ) 71 { 72 if(fVal < 0.0) 73 return std::min(fVal, -0.00001); 74 else 75 return std::max(fVal, 0.00001); 76 } 77 78 /** Convert value from degrees to radians 79 */ deg2rad(double v)80 template <int DegMultiple = 1> constexpr double deg2rad( double v ) 81 { 82 // divide first, to get exact values for v being a multiple of 83 // 90 degrees 84 return v / (90.0 * DegMultiple) * M_PI_2; 85 } 86 87 /** Convert value radians to degrees 88 */ rad2deg(double v)89 template <int DegMultiple = 1> constexpr double rad2deg( double v ) 90 { 91 // divide first, to get exact values for v being a multiple of 92 // pi/2 93 return v / M_PI_2 * (90.0 * DegMultiple); 94 } 95 96 /** Snap v to nearest multiple of fStep, from negative and 97 positive side. 98 99 Examples: 100 101 snapToNearestMultiple(-0.1, 0.5) = 0.0 102 snapToNearestMultiple(0.1, 0.5) = 0.0 103 snapToNearestMultiple(0.25, 0.5) = 0.0 104 snapToNearestMultiple(0.26, 0.5) = 0.5 105 */ 106 BASEGFX_DLLPUBLIC double snapToNearestMultiple(double v, const double fStep); 107 108 /** Snap v to the range [0.0 .. fWidth] using modulo 109 */ 110 BASEGFX_DLLPUBLIC double snapToZeroRange(double v, double fWidth); 111 112 /** Snap v to the range [fLow .. fHigh] using modulo 113 */ 114 double snapToRange(double v, double fLow, double fHigh); 115 116 /** return fValue with the sign of fSignCarrier, thus evtl. changed 117 */ copySign(double fValue,double fSignCarrier)118 inline double copySign(double fValue, double fSignCarrier) 119 { 120 #ifdef _WIN32 121 return _copysign(fValue, fSignCarrier); 122 #else 123 return copysign(fValue, fSignCarrier); 124 #endif 125 } 126 127 /** RotateFlyFrame3: Normalize to range defined by [0.0 ... fRange[, independent 128 if v is positive or negative. 129 130 Examples: 131 132 normalizeToRange(0.5, -1.0) = 0.0 133 normalizeToRange(0.5, 0.0) = 0.0 134 normalizeToRange(0.5, 1.0) = 0.5 135 normalizeToRange(-0.5, 1.0) = 0.5 136 normalizeToRange(-0.3, 1.0) = 0.7 137 normalizeToRange(-0.7, 1.0) = 0.3 138 normalizeToRange(3.5, 1.0) = 0.5 139 normalizeToRange(3.3, 1.0) = 0.3 140 normalizeToRange(3.7, 1.0) = 0.7 141 normalizeToRange(-3.5, 1.0) = 0.5 142 normalizeToRange(-3.3, 1.0) = 0.7 143 normalizeToRange(-3.7, 1.0) = 0.3 144 */ 145 BASEGFX_DLLPUBLIC double normalizeToRange(double v, const double fRange); 146 147 namespace fTools 148 { 149 /// Get threshold value for equalZero and friends getSmallValue()150 inline double getSmallValue() { return 0.000000001f; } 151 152 /// Compare against small value 153 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> equalZero(const T & rfVal)154 inline bool equalZero(const T& rfVal) 155 { 156 return (fabs(rfVal) <= getSmallValue()); 157 } 158 159 /// Compare against given small value 160 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> equalZero(const T & rfVal,const T & rfSmallValue)161 inline bool equalZero(const T& rfVal, const T& rfSmallValue) 162 { 163 return (fabs(rfVal) <= rfSmallValue); 164 } 165 166 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> equal(T const & rfValA,T const & rfValB)167 inline bool equal(T const& rfValA, T const& rfValB) 168 { 169 // changed to approxEqual usage for better numerical correctness 170 return rtl_math_approxEqual(rfValA, rfValB); 171 } 172 173 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> equal(const T & rfValA,const T & rfValB,const T & rfSmallValue)174 inline bool equal(const T& rfValA, const T& rfValB, const T& rfSmallValue) 175 { 176 return (fabs(rfValA - rfValB) <= rfSmallValue); 177 } 178 179 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> less(const T & rfValA,const T & rfValB)180 inline bool less(const T& rfValA, const T& rfValB) 181 { 182 return (rfValA < rfValB && !equal(rfValA, rfValB)); 183 } 184 185 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> lessOrEqual(const T & rfValA,const T & rfValB)186 inline bool lessOrEqual(const T& rfValA, const T& rfValB) 187 { 188 return (rfValA < rfValB || equal(rfValA, rfValB)); 189 } 190 191 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> more(const T & rfValA,const T & rfValB)192 inline bool more(const T& rfValA, const T& rfValB) 193 { 194 return (rfValA > rfValB && !equal(rfValA, rfValB)); 195 } 196 197 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> moreOrEqual(const T & rfValA,const T & rfValB)198 inline bool moreOrEqual(const T& rfValA, const T& rfValB) 199 { 200 return (rfValA > rfValB || equal(rfValA, rfValB)); 201 } 202 203 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> betweenOrEqualEither(const T & rfValA,const T & rfValB,const T & rfValC)204 inline bool betweenOrEqualEither(const T& rfValA, const T& rfValB, const T& rfValC) 205 { 206 return (rfValA > rfValB && rfValA < rfValC) || equal(rfValA, rfValB) || equal(rfValA, rfValC); 207 } 208 }; 209 } // end of namespace basegfx 210 211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 212