3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 06/01/2010 Added this text. :-)
17 #include "mathextra.h"
19 #include <assert.h> // For test()
26 * Rounds the given double to the next int.
28 int Math::round(double v)
30 return (v - floor(v) < 0.5 ? (int)floor(v) : (int)ceil(v));
36 double Math::pow(double x, double y)
39 double ret = ::pow(x, y);
43 DEBUG->print(Debug::D_ERROR, "Math::pow: EDOM in pow");
46 else if (errno == ERANGE)
48 DEBUG->print(Debug::D_WARNING, "Math::pow: ERANGE in pow");
56 * Converts radians to degrees.
58 double Math::rad2deg(double a)
60 return (a / (2.0 * M_PI) * 360.0);
64 * Converts degrees to radians.
66 double Math::deg2rad(double a)
68 return ((a / 360.0) * (2.0 * M_PI));
72 * Converts radians to gradians.
74 double Math::rad2gra(double a)
76 return (a / (2.0 * M_PI) * 400.0);
80 * Finds greatest common divider using Euclid's algorithm.
82 int Math::findGCD(int a, int b)
95 * Tests if angle a is between a1 and a2. a, a1 and a2 must be in the
96 * range between 0 and 2*PI.
99 * @param reversed true for clockwise testing. false for ccw testing.
100 * @return true if the angle a is between a1 and a2.
102 bool Math::isAngleBetween(double a, double a1, double a2, bool reversed)
113 if (a1 >= a2 - 1.0e-12)
115 if (a >= a1 - 1.0e-12 || a <= a2 + 1.0e-12)
120 if (a >= a1 - 1.0e-12 && a <= a2 + 1.0e-12)
124 //DEBUG->print("angle %f is %sbetween %f and %f",
125 // a, ret ? "" : "not ", a1, a2);
130 * Corrects the given angle to the range of 0-2*Pi.
132 double Math::correctAngle(double a)
144 * @return The angle that needs to be added to a1 to reach a2.
145 * Always positive and less than 2*pi.
147 double Math::getAngleDifference(double a1, double a2)
163 * Makes a text constructed with the given angle readable. Used
164 * for dimension texts and for mirroring texts.
166 * @param readable true: make angle readable, false: unreadable
167 * @param corrected Will point to true if the given angle was
168 * corrected, false otherwise.
170 * @return The given angle or the given angle+PI, depending which on
171 * is readable from the bottom or right.
173 double Math::makeAngleReadable(double angle, bool readable, bool * corrected)
176 bool cor = isAngleReadable(angle) ^ readable;
192 * @return true: if the given angle is in a range that is readable
193 * for texts created with that angle.
195 bool Math::isAngleReadable(double angle)
197 if (angle > M_PI /2.0 * 3.0 + 0.001 || angle < M_PI / 2.0 + 0.001)
204 * @param tol Tolerance in rad.
205 * @retval true The two angles point in the same direction.
207 bool Math::isSameDirection(double dir1, double dir2, double tol)
209 double diff = fabs(dir1 - dir2);
211 if (diff < tol || diff > 2 * M_PI - tol)
218 * Compares two double values with a tolerance.
220 bool Math::cmpDouble(double v1, double v2, double tol)
222 return (fabs(v2 - v1) < tol);
226 * Evaluates a mathematical expression and returns the result.
227 * If an error occured, the given default value 'def' will be returned.
229 double Math::eval(const QString & expr, double def)
232 double res = Math::eval(expr, &ok);
241 * Evaluates a mathematical expression and returns the result.
242 * If an error occured, ok will be set to false (if ok isn't NULL).
244 double Math::eval(const QString & expr, bool * ok)
255 fp.AddConstant("pi", M_PI);
257 // replace '14 3/4' with '14+3/4'
264 int i = s.indexOf(QRegExp("[0-9]* [0-9]*/[0-9]*"));
268 int i2 = s.indexOf(' ', i);
272 s.replace(i2, 1, "+");
279 int ret = fp.Parse(s.toAscii().data(), "", true);
292 return fp.Eval(NULL);
296 * Converts a double into a string which is as short as possible
298 * @param value The double value
299 * @param prec Precision e.g. a precision of 1 would mean that a
300 * value of 2.12030 will be converted to "2.1". 2.000 is always just "2").
302 QString Math::doubleToString(double value, double prec)
306 std::cerr << "Math::doubleToString: invalid precision\n";
311 int num = Math::round(value / prec);
313 QString exaStr = Math::doubleToString(prec, 10);
314 int dotPos = exaStr.indexOf('.');
317 ret.sprintf("%d", Math::round(num * prec));
320 int digits = exaStr.length() - dotPos - 1;
321 ret = Math::doubleToString(num * prec, digits);
328 * Converts a double into a string which is as short as possible.
330 * @param value The double value
331 * @param prec Precision
333 QString Math::doubleToString(double value, int prec)
337 valStr.setNum(value, 'f', prec);
339 if (valStr.contains('.'))
341 // Remove zeros at the end:
342 while (valStr.at(valStr.length() - 1) == '0')
343 valStr.truncate(valStr.length() - 1);
345 if (valStr.at(valStr.length() - 1) == '.')
346 valStr.truncate(valStr.length() - 1);
353 * Performs some testing for the math class.
357 std::cout << "Math::test: doubleToString:\n";
360 QString s = Math::doubleToString(v, 0.1);
362 s = Math::doubleToString(v, 0.01);
364 s = Math::doubleToString(v, 0.0);
368 s = Math::doubleToString(v, 0.1);
370 s = Math::doubleToString(v, 0.01);
372 s = Math::doubleToString(v, 0.0);
376 s = Math::doubleToString(v, 0.1);
378 s = Math::doubleToString(v, 0.01);
380 s = Math::doubleToString(v, 0.001);
381 assert(s == "0.001");
382 s = Math::doubleToString(v, 0.0);
385 std::cout << "Math::test: complete\n";