QWT 7.0.1
Loading...
Searching...
No Matches
qwt_math.h
1/******************************************************************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *
9 * Modified by ChenZongYan in 2024 <czy.t@163.com>
10 * Summary of major modifications (see ChangeLog.md for full history):
11 * 1. CMake build system & C++11 throughout.
12 * 2. Core panner/ zoomer refactored:
13 * - QwtPanner → QwtCachePanner (pixmap-cache version)
14 * - New real-time QwtPlotPanner derived from QwtPicker.
15 * 3. Zoomer supports multi-axis.
16 * 4. Parasite-plot framework:
17 * - QwtFigure, QwtPlotParasiteLayout, QwtPlotTransparentCanvas,
18 * - QwtPlotScaleEventDispatcher, built-in pan/zoom on axis.
19 * 5. New picker: QwtPlotSeriesDataPicker (works with date axis).
20 * 6. Raster & color-map extensions:
21 * - QwtGridRasterData (2-D table + interpolation)
22 * - QwtLinearColorMap::stopColors(), stopPos() API rename.
23 * 7. Bar-chart: expose pen/brush control.
24 * 8. Amalgamated build: single QwtPlot.h / QwtPlot.cpp pair in src-amalgamate.
25 *****************************************************************************/
26
27#ifndef QWT_MATH_H
28#define QWT_MATH_H
29// stl
30#include <iterator>
31#include <type_traits>
32#include <algorithm>
33// qt
34#include <QPointF>
35#include <QtMath>
36// qwt
37#include "qwt_global.h"
38/*
39 Microsoft says:
40
41 Define _USE_MATH_DEFINES before including math.h to expose these macro
42 definitions for common math constants. These are placed under an #ifdef
43 since these commonly-defined names are not part of the C/C++ standards.
44 */
45
46#ifndef _USE_MATH_DEFINES
47#define _USE_MATH_DEFINES
48#define undef_USE_MATH_DEFINES
49#endif
50
51#include <cmath>
52
53#ifdef undef_USE_MATH_DEFINES
54#undef _USE_MATH_DEFINES
55#undef undef_USE_MATH_DEFINES
56#endif
57
58#ifndef M_E
59#define M_E (2.7182818284590452354)
60#endif
61
62#ifndef M_LOG2E
63#define M_LOG2E (1.4426950408889634074)
64#endif
65
66#ifndef M_LOG10E
67#define M_LOG10E (0.43429448190325182765)
68#endif
69
70#ifndef M_LN2
71#define M_LN2 (0.69314718055994530942)
72#endif
73
74#ifndef M_LN10
75#define M_LN10 (2.30258509299404568402)
76#endif
77
78#ifndef M_PI
79#define M_PI (3.14159265358979323846)
80#endif
81
82#ifndef M_PI_2
83#define M_PI_2 (1.57079632679489661923)
84#endif
85
86#ifndef M_PI_4
87#define M_PI_4 (0.78539816339744830962)
88#endif
89
90#ifndef M_1_PI
91#define M_1_PI (0.31830988618379067154)
92#endif
93
94#ifndef M_2_PI
95#define M_2_PI (0.63661977236758134308)
96#endif
97
98#ifndef M_2_SQRTPI
99#define M_2_SQRTPI (1.12837916709551257390)
100#endif
101
102#ifndef M_SQRT2
103#define M_SQRT2 (1.41421356237309504880)
104#endif
105
106#ifndef M_SQRT1_2
107#define M_SQRT1_2 (0.70710678118654752440)
108#endif
109
110#if defined(QT_WARNING_PUSH)
111/*
112 early Qt versions not having QT_WARNING_PUSH is full of warnings
113 so that we do not care of suppressing those from below
114 */
115QT_WARNING_PUSH
116QT_WARNING_DISABLE_CLANG("-Wdouble-promotion")
117QT_WARNING_DISABLE_GCC("-Wdouble-promotion")
118#endif
119
120/*
121 On systems, where qreal is a float you often run into
122 compiler issues with qMin/qMax.
123 */
124
126QWT_CONSTEXPR inline float qwtMinF(float a, float b)
127{
128 return (a < b) ? a : b;
129}
130
132QWT_CONSTEXPR inline double qwtMinF(double a, double b)
133{
134 return (a < b) ? a : b;
135}
136
138QWT_CONSTEXPR inline qreal qwtMinF(float a, double b)
139{
140 return (a < b) ? a : b;
141}
142
144QWT_CONSTEXPR inline qreal qwtMinF(double a, float b)
145{
146 return (a < b) ? a : b;
147}
148
150QWT_CONSTEXPR inline float qwtMaxF(float a, float b)
151{
152 return (a < b) ? b : a;
153}
154
156QWT_CONSTEXPR inline double qwtMaxF(double a, double b)
157{
158 return (a < b) ? b : a;
159}
160
162QWT_CONSTEXPR inline qreal qwtMaxF(float a, double b)
163{
164 return (a < b) ? b : a;
165}
166
168QWT_CONSTEXPR inline qreal qwtMaxF(double a, float b)
169{
170 return (a < b) ? b : a;
171}
172
173#if defined(QT_WARNING_POP)
174QT_WARNING_POP
175#endif
176
177QWT_EXPORT double qwtNormalizeRadians(double radians);
178QWT_EXPORT double qwtNormalizeDegrees(double degrees);
179QWT_EXPORT quint32 qwtRand();
180
193inline int qwtFuzzyCompare(double value1, double value2, double intervalSize)
194{
195 const double eps = qAbs(1.0e-6 * intervalSize);
196
197 if (value2 - value1 > eps)
198 return -1;
199
200 if (value1 - value2 > eps)
201 return 1;
202
203 return 0;
204}
205
207inline int qwtSign(double x)
208{
209 if (x > 0.0)
210 return 1;
211 else if (x < 0.0)
212 return (-1);
213 else
214 return 0;
215}
216
218inline double qwtSqr(double x)
219{
220 return x * x;
221}
222
224inline double qwtFastAtan(double x)
225{
226 if (x < -1.0)
227 return -M_PI_2 - x / (x * x + 0.28);
228
229 if (x > 1.0)
230 return M_PI_2 - x / (x * x + 0.28);
231
232 return x / (1.0 + x * x * 0.28);
233}
234
236inline double qwtFastAtan2(double y, double x)
237{
238 if (x > 0)
239 return qwtFastAtan(y / x);
240
241 if (x < 0) {
242 const double d = qwtFastAtan(y / x);
243 return (y >= 0) ? d + M_PI : d - M_PI;
244 }
245
246 if (y < 0.0)
247 return -M_PI_2;
248
249 if (y > 0.0)
250 return M_PI_2;
251
252 return 0.0;
253}
254
255/* !
256 \brief Calculate a value of a cubic polynomial
257
258 \param x Value
259 \param a Cubic coefficient
260 \param b Quadratic coefficient
261 \param c Linear coefficient
262 \param d Constant offset
263
264 \return Value of the polyonom for x
265 */
266inline double qwtCubicPolynomial(double x, double a, double b, double c, double d)
267{
268 return (((a * x) + b) * x + c) * x + d;
269}
270
272inline double qwtRadians(double degrees)
273{
274 return degrees * M_PI / 180.0;
275}
276
278inline double qwtDegrees(double degrees)
279{
280 return degrees * 180.0 / M_PI;
281}
282
287inline int qwtCeil(qreal value)
288{
289 using std::ceil;
290 return int(ceil(value));
291}
296inline int qwtFloor(qreal value)
297{
298 using std::floor;
299 return int(floor(value));
300}
301
322inline int qwtVerifyRange(int size, int& i1, int& i2)
323{
324 if (size < 1)
325 return 0;
326
327 i1 = qBound(0, i1, size - 1);
328 i2 = qBound(0, i2, size - 1);
329
330 if (i1 > i2)
331 qSwap(i1, i2);
332
333 return (i2 - i1 + 1);
334}
335
342inline double qwtDistance(const QPointF& p1, const QPointF& p2)
343{
344 double dx = p2.x() - p1.x();
345 double dy = p2.y() - p1.y();
346 return qSqrt(dx * dx + dy * dy);
347}
348
377template< typename T >
378inline typename std::enable_if< std::is_floating_point< T >::value, bool >::type qwt_is_nan_or_inf(const T& value)
379{
380 return !std::isfinite(value);
381}
382
406inline bool qwt_is_nan_or_inf(const QPointF& point)
407{
408 return !std::isfinite(point.x()) || !std::isfinite(point.y());
409}
410
411// 默认检查函数 - 用于其他类型
412template< typename T >
413typename std::enable_if< !std::is_floating_point< T >::value && !std::is_same< T, QPointF >::value,
414 bool >::type inline qwt_is_nan_or_inf(const T& /*value*/)
415{
416 return false;
417}
418
442template< typename InputIt >
443inline bool qwtContainsNanOrInf(InputIt first, InputIt last)
444{
445 // 使用迭代器遍历,对每个元素调用适当的 qwt_is_nan_or_inf 函数
446 for (InputIt it = first; it != last; ++it) {
447 if (qwt_is_nan_or_inf(*it)) {
448 return true;
449 }
450 }
451 return false;
452}
453
470template< typename Container >
471inline std::size_t qwtRemoveNanOrInf(Container& container)
472{
473 // 使用 std::remove_if 算法将需要保留的元素移动到容器前部
474 auto new_end = std::remove_if(container.begin(), container.end(), [](const typename Container::value_type& value) {
475 return qwt_is_nan_or_inf(value);
476 });
477
478 // 计算被删除的元素数量
479 std::size_t removed_count = std::distance(new_end, container.end());
480
481 // 实际删除不需要的元素
482 if (removed_count > 0) {
483 container.erase(new_end, container.end());
484 }
485
486 return removed_count;
487}
488
495template< typename Container >
496inline Container qwtRemoveNanOrInfCopy(const Container& container)
497{
498 Container result;
499 result.reserve(container.size()); // 预分配空间以提高效率
500
501 // 只复制不是 NaN 或 Inf 的元素
502 std::copy_if(container.begin(),
503 container.end(),
504 std::back_inserter(result),
505 [](const typename Container::value_type& value) { return !qwt_is_nan_or_inf(value); });
506
507 return result;
508}
509
569template< typename It1, typename It2 >
570bool fuzzyRangeEqual(It1 first1, It1 last1, It2 first2, It2 last2)
571{
572 // 1. 长度不同 => 不相等
573 if (std::distance(first1, last1) != std::distance(first2, last2))
574 return false;
575
576 // 2. 逐元素 qFuzzyCompare
577 for (; first1 != last1; ++first1, ++first2) {
578 if (!qFuzzyCompare(*first1, *first2))
579 return false;
580 }
581 return true;
582}
583
584#endif