1 /* This file is part of Step.
2    Copyright (C) 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
3 
4    Step is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    Step is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with Step; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18 
19 #include "unitscalc.h"
20 
21 #ifdef STEP_WITH_QALCULATE
22 #include <libqalculate/qalculate.h>
23 #endif
24 
25 class UnitsCalcHelper
26 {
27 public:
UnitsCalcHelper()28     UnitsCalcHelper(): q(0) {}
~UnitsCalcHelper()29     ~UnitsCalcHelper() { delete q; }
30     UnitsCalc* q;
31 };
32 
Q_GLOBAL_STATIC(UnitsCalcHelper,s_unitsCalcHelper)33 Q_GLOBAL_STATIC(UnitsCalcHelper, s_unitsCalcHelper)
34 
35 UnitsCalc* UnitsCalc::self()
36 {
37     if(!s_unitsCalcHelper->q) {
38         new UnitsCalc();
39     }
40 
41     return s_unitsCalcHelper->q;
42 }
43 
44 class UnitsCalcPrivate
45 {
46 public:
47 #ifdef STEP_WITH_QALCULATE
48     EvaluationOptions eo;
49 #endif
50 };
51 
UnitsCalc()52 UnitsCalc::UnitsCalc()
53 {
54     Q_ASSERT(!s_unitsCalcHelper->q);
55     s_unitsCalcHelper->q = this;
56 
57     d = new UnitsCalcPrivate;
58 
59 #ifdef STEP_WITH_QALCULATE
60     new Calculator();
61     CALCULATOR->loadGlobalPrefixes();
62     CALCULATOR->loadGlobalUnits();
63     CALCULATOR->loadGlobalVariables();
64     CALCULATOR->loadGlobalFunctions();
65 
66     ParseOptions po;
67     po.unknowns_enabled = false;
68     po.limit_implicit_multiplication = true;
69     po.angle_unit = ANGLE_UNIT_RADIANS;
70 
71     d->eo.parse_options = po;
72     d->eo.approximation = APPROXIMATION_APPROXIMATE;
73     d->eo.allow_complex = false;
74     d->eo.auto_post_conversion = POST_CONVERSION_BEST;
75     d->eo.structuring = STRUCTURING_SIMPLIFY;
76 #endif
77 }
78 
~UnitsCalc()79 UnitsCalc::~UnitsCalc()
80 {
81     delete d;
82 
83 #ifdef STEP_WITH_QALCULATE
84     delete CALCULATOR;
85 #endif
86 }
87 
88 #ifdef STEP_WITH_QALCULATE
parseNumber(const QString & expression,const QString & units,double & result)89 bool UnitsCalc::parseNumber(const QString& expression, const QString& units, double& result)
90 {
91     std::string ulexpression = CALCULATOR->unlocalizeExpression(
92                     expression.toUtf8().constData(), d->eo.parse_options);
93 
94     MathStructure expr;
95     CALCULATOR->parse(&expr, ulexpression, d->eo.parse_options);
96     expr.eval(d->eo);
97 
98     if(!units.isEmpty()) {
99         CompositeUnit *cu = NULL;
100         Unit *u = NULL;
101         std::string strUnits(units.toUtf8().constData());
102         u = CALCULATOR->getUnit(strUnits);
103         if(!u) {
104             cu = new CompositeUnit("", "temporary_composite_convert", "", strUnits);
105             if(cu->get(1)) u = cu;
106             else return false;
107         }
108 
109         expr.convert(u, true);
110         expr.divide(u, true);
111         expr.eval(d->eo);
112 
113         delete cu;
114     }
115 
116     if(!expr.isNumber() && expr.countChildren()) return false;
117     result = expr.number().floatValue();
118     return true;
119 
120 }
121 #else
parseNumber(const QString &,const QString &,double &)122 bool UnitsCalc::parseNumber(const QString&, const QString&, double&)
123 {
124     return false;
125 }
126 #endif
127 
128