1 /****************************************************************************
2 ** $Id: rs_math.cpp 1938 2004-12-09 23:09:53Z andrew $
4 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
6 ** This file is part of the qcadlib Library project.
8 ** This file may be distributed and/or modified under the terms of the
9 ** GNU General Public License version 2 as published by the Free Software
10 ** Foundation and appearing in the file LICENSE.GPL included in the
11 ** packaging of this file.
13 ** Licensees holding valid qcadlib Professional Edition licenses may use
14 ** this file in accordance with the qcadlib Commercial License
15 ** Agreement provided with the Software.
17 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 ** See http://www.ribbonsoft.com for further details.
22 ** Contact info@ribbonsoft.com if any conditions of this licensing are
25 **********************************************************************/
32 * Rounds the given double to the next int.
34 int RS_Math::round(double v)
36 return (v - floor(v) < 0.5 ? (int)floor(v) : (int)ceil(v));
42 double RS_Math::pow(double x, double y)
45 double ret = ::pow(x, y);
49 RS_DEBUG->print(RS_Debug::D_ERROR, "RS_Math::pow: EDOM in pow");
52 else if (errno == ERANGE)
54 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Math::pow: ERANGE in pow");
62 * Converts radians to degrees.
64 double RS_Math::rad2deg(double a)
66 return (a / (2.0 * M_PI) * 360.0);
70 * Converts degrees to radians.
72 double RS_Math::deg2rad(double a)
74 return ((a / 360.0) * (2.0 * M_PI));
78 * Converts radians to gradians.
80 double RS_Math::rad2gra(double a)
82 return (a / (2.0 * M_PI) * 400.0);
86 * Finds greatest common divider using Euclid's algorithm.
88 int RS_Math::findGCD(int a, int b)
101 * Tests if angle a is between a1 and a2. a, a1 and a2 must be in the
102 * range between 0 and 2*PI.
105 * @param reversed true for clockwise testing. false for ccw testing.
106 * @return true if the angle a is between a1 and a2.
108 bool RS_Math::isAngleBetween(double a, double a1, double a2, bool reversed)
119 if (a1 >= a2 - 1.0e-12)
121 if (a >= a1 - 1.0e-12 || a <= a2 + 1.0e-12)
128 if (a >= a1 - 1.0e-12 && a <= a2 + 1.0e-12)
134 //RS_DEBUG->print("angle %f is %sbetween %f and %f",
135 // a, ret ? "" : "not ", a1, a2);
140 * Corrects the given angle to the range of 0-2*Pi.
142 double RS_Math::correctAngle(double a)
154 * @return The angle that needs to be added to a1 to reach a2.
155 * Always positive and less than 2*pi.
157 double RS_Math::getAngleDifference(double a1, double a2)
173 * Makes a text constructed with the given angle readable. Used
174 * for dimension texts and for mirroring texts.
176 * @param readable true: make angle readable, false: unreadable
177 * @param corrected Will point to true if the given angle was
178 * corrected, false otherwise.
180 * @return The given angle or the given angle+PI, depending which on
181 * is readable from the bottom or right.
183 double RS_Math::makeAngleReadable(double angle, bool readable, bool * corrected)
186 bool cor = isAngleReadable(angle) ^ readable;
195 if (corrected != NULL)
202 * @return true: if the given angle is in a range that is readable
203 * for texts created with that angle.
205 bool RS_Math::isAngleReadable(double angle)
207 if (angle > M_PI /2.0 * 3.0 + 0.001 || angle < M_PI / 2.0 + 0.001)
214 * @param tol Tolerance in rad.
215 * @retval true The two angles point in the same direction.
217 bool RS_Math::isSameDirection(double dir1, double dir2, double tol)
219 double diff = fabs(dir1 - dir2);
221 if (diff < tol || diff > 2 * M_PI - tol)
223 //std::cout << "RS_Math::isSameDirection: " << dir1 << " and " << dir2
224 // << " point in the same direction" << "\n";
228 //std::cout << "RS_Math::isSameDirection: " << dir1 << " and " << dir2
229 // << " don't point in the same direction" << "\n";
234 * Compares two double values with a tolerance.
236 bool RS_Math::cmpDouble(double v1, double v2, double tol)
238 return (fabs(v2 - v1) < tol);
242 * Evaluates a mathematical expression and returns the result.
243 * If an error occured, the given default value 'def' will be returned.
245 double RS_Math::eval(const QString & expr, double def)
248 double res = RS_Math::eval(expr, &ok);
252 //std::cerr << "RS_Math::evaluate: Parse error at col "
253 //<< ret << ": " << fp.ErrorMsg() << "\n";
261 * Evaluates a mathematical expression and returns the result.
262 * If an error occured, ok will be set to false (if ok isn't NULL).
264 //double RS_Math::eval(const QString& expr, bool* ok);
267 * Evaluates a mathematical expression and returns the result.
268 * If an error occured, ok will be set to false (if ok isn't NULL).
270 double RS_Math::eval(const QString & expr, bool * ok)
272 #ifndef RS_NO_FPARSER
282 fp.AddConstant("pi", M_PI);
284 // replace '14 3/4' with '14+3/4'
291 // int i = s.find(QRegExp("[0-9]* [0-9]*/[0-9]*"));
292 int i = s.indexOf(QRegExp("[0-9]* [0-9]*/[0-9]*"));
296 // int i2 = s.find(' ', i);
297 int i2 = s.indexOf(' ', i);
301 s.replace(i2, 1, "+");
308 int ret = fp.Parse(s.toLatin1().data(), "", true);
321 return fp.Eval(NULL);
323 //std::cerr << "RS_Math::eval: No FParser support compiled in.\n";
324 return expr.toDouble();
329 * Converts a double into a string which is as short as possible
331 * @param value The double value
332 * @param prec Precision e.g. a precision of 1 would mean that a
333 * value of 2.12030 will be converted to "2.1". 2.000 is always just "2").
335 QString RS_Math::doubleToString(double value, double prec)
339 std::cerr << "RS_Math::doubleToString: invalid precision\n";
346 int num = RS_Math::round(value / prec);
348 exaStr = RS_Math::doubleToString(prec, 10);
349 // dotPos = exaStr.find('.');
350 dotPos = exaStr.indexOf('.');
353 ret.sprintf("%d", RS_Math::round(num * prec));
356 int digits = exaStr.length() - dotPos - 1;
357 ret = RS_Math::doubleToString(num * prec, digits);
364 * Converts a double into a string which is as short as possible.
366 * @param value The double value
367 * @param prec Precision
369 QString RS_Math::doubleToString(double value, int prec)
373 valStr.setNum(value, 'f', prec);
375 if (valStr.contains('.'))
377 // Remove zeros at the end:
378 while (valStr.at(valStr.length() - 1) == '0')
380 valStr.truncate(valStr.length() - 1);
383 if (valStr.at(valStr.length() - 1) == '.')
385 valStr.truncate(valStr.length() - 1);
393 * Performs some testing for the math class.
397 std::cout << "RS_Math::test: doubleToString:\n";
400 QString s = RS_Math::doubleToString(v, 0.1);
402 s = RS_Math::doubleToString(v, 0.01);
404 s = RS_Math::doubleToString(v, 0.0);
408 s = RS_Math::doubleToString(v, 0.1);
410 s = RS_Math::doubleToString(v, 0.01);
412 s = RS_Math::doubleToString(v, 0.0);
416 s = RS_Math::doubleToString(v, 0.1);
418 s = RS_Math::doubleToString(v, 0.01);
420 s = RS_Math::doubleToString(v, 0.001);
421 assert(s == "0.001");
422 s = RS_Math::doubleToString(v, 0.0);
425 std::cout << "RS_Math::test: complete\n";