File indexing completed on 2024-05-05 03:41:16

0001 /*************************************************************************************
0002  *  Copyright (C) 2007-2009 by Aleix Pol <aleixpol@kde.org>                          *
0003  *  Copyright (C) 2010-2012 by Percy Camilo T. Aucahuasi <percy.camilo.ta@gmail.com> *
0004  *                                                                                   *
0005  *  This program is free software; you can redistribute it and/or                    *
0006  *  modify it under the terms of the GNU General Public License                      *
0007  *  as published by the Free Software Foundation; either version 2                   *
0008  *  of the License, or (at your option) any later version.                           *
0009  *                                                                                   *
0010  *  This program is distributed in the hope that it will be useful,                  *
0011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0013  *  GNU General Public License for more details.                                     *
0014  *                                                                                   *
0015  *  You should have received a copy of the GNU General Public License                *
0016  *  along with this program; if not, write to the Free Software                      *
0017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0018  *************************************************************************************/
0019 
0020 #include "private/abstractplanecurve.h"
0021 #include "private/functiongraphfactory.h"
0022 #include <private/utils/mathutils.h>
0023 
0024 #include <QRectF>
0025 #include <analitza/value.h>
0026 
0027 #ifndef M_PI
0028 #define M_PI           3.14159265358979323846
0029 #endif
0030 
0031 using namespace Analitza;
0032 
0033 class FunctionPolar : public AbstractPlaneCurve
0034 {
0035 public:
0036     FunctionPolar(const Analitza::Expression& e, const QSharedPointer<Analitza::Variables>& v = {});
0037     TYPE_NAME(QT_TRANSLATE_NOOP("Function type", "Polar Curve r=F(p: Polar)"))
0038     EXPRESSION_TYPE(Analitza::ExpressionType(Analitza::ExpressionType::Lambda).addParameter(
0039                     Analitza::ExpressionType(Analitza::ExpressionType::Value)).addParameter(
0040                     Analitza::ExpressionType(Analitza::ExpressionType::Value)))
0041     COORDDINATE_SYSTEM(Polar)
0042     PARAMETERS(QStringList(QStringLiteral("q"))) //q:theta
0043     ICON_NAME(QStringLiteral("newpolar"))
0044     EXAMPLES(QStringList(QStringLiteral("q->3*sin(q/0.142)")) << QStringLiteral("q->q+3"))
0045     
0046     void update(const QRectF& viewport) override;
0047     
0048     QPair<QPointF, QString> image(const QPointF &mousepos) override;
0049     QLineF tangent(const QPointF &mousepos) override ;
0050     
0051     Analitza::Cn *p;
0052 };
0053 
0054 FunctionPolar::FunctionPolar(const Analitza::Expression& e, const QSharedPointer<Analitza::Variables>& v): AbstractPlaneCurve(e, v)
0055 {
0056     p = arg(QStringLiteral("q"));
0057 }
0058 
0059 void FunctionPolar::update(const QRectF& viewport)
0060 {
0061     points.clear();
0062     jumps.clear();
0063     
0064     double dlimit = 0;
0065     double ulimit = 0;
0066     double inv_res = 0;
0067 
0068     if (!hasIntervals()) {
0069         double pi_factor = qMax(qMax(qAbs(viewport.left()), qAbs(viewport.right())), 
0070                                 qMax(qAbs(viewport.bottom()), qAbs(viewport.top())));
0071 
0072         pi_factor = qMax(pi_factor, 16.); // 16 steps at minimum
0073 
0074         dlimit = -M_PI*pi_factor;
0075         ulimit =  M_PI*pi_factor;
0076 
0077         inv_res = qMin(viewport.size().width(), viewport.size().height())/(M_PI*M_PI*pi_factor);
0078 
0079         points.reserve(10*static_cast<int>(pi_factor));
0080     } else {
0081         QPair< double, double> limits = interval(QStringLiteral("q"));
0082         dlimit = limits.first;
0083         ulimit = limits.second;
0084         inv_res = (ulimit-dlimit)/(M_PI*M_PI*16);
0085     }
0086     Q_ASSERT(inv_res!=0);
0087 
0088     double final=ulimit-inv_res;
0089     if((final<0) != (inv_res<0)) {
0090         inv_res *= -1;
0091     }
0092 
0093     for(double th=dlimit; th<final; th+=inv_res) {
0094         p->setValue(th);
0095         double r = analyzer->calculateLambda().toReal().value();
0096         
0097         addPoint(polarToCartesian(r,th));
0098     }
0099 }
0100 
0101 
0102 //Own
0103 QPair<QPointF, QString> FunctionPolar::image(const QPointF &p)
0104 {
0105     QPointF dp=p;
0106     QString pos;
0107 //     if(p==QPointF(0., 0.))
0108 //         return QPair<QPointF, QString>(dp, QCoreApplication::translate("", "center"));
0109 //     double th=atan(p.y()/ p.x()), r=1., d, d2;
0110 //     if(p.x()<0.)    th += pi;
0111 //     else if(th<0.)  th += 2.*pi;
0112 //     
0113 //     
0114 //         //TODO CACHE en intervalvalues!!!
0115 //     static QPair<double, double> c_limits = interval("p");
0116 //     
0117 // //     if ()
0118 // //     
0119 // //     static QPair<double, double> o_limits = c_limits;
0120 //     
0121 //     
0122 //     double ulimit=c_limits.second;
0123 //     double dlimit=c_limits.first;
0124 //     
0125 //     th=qMax(th, dlimit);
0126 //     th=qMin(th, ulimit);
0127 //     
0128 // //     analyzer.setStack(m_runStack);
0129 //     QPointF dist;
0130 //     arg("p")->setValue(th);
0131 //     do {
0132 //         arg("p")->setValue(th);
0133 //         r = analyzer->calculateLambda().toReal().value();
0134 //         
0135 //         dp = polarToCartesian(r,th);
0136 //         dist = (dp-p);
0137 //         d = sqrt(dist.x()*dist.x() + dist.y()*dist.y());
0138 //         
0139 //         arg("p")->setValue(th+2.*pi);
0140 //         r = analyzer->calculateLambda().toReal().value();
0141 // 
0142 //         dp = polarToCartesian(r,th);
0143 //         dist = (dp-p);
0144 //         d2 = sqrt(dist.x()*dist.x() + dist.y()*dist.y());
0145 //         
0146 //         th += 2.*pi;
0147 //     } while(d>d2);
0148 //     th -= 2.*pi;
0149 //     
0150 //     arg("p")->setValue(th);
0151 //     Analitza::Expression res=analyzer->calculateLambda();
0152 //     
0153 //     if(!res.isReal())
0154 //        appendError(QCoreApplication::translate("", "We can only draw Real results."));
0155 //     r = res.toReal().value();
0156 //     
0157 //     
0158 //         
0159 //     dp = polarToCartesian(r,th);
0160 //     
0161 //     pos = QStringLiteral("r=%1 th=%2").arg(r,3,'f',2).arg(th,3,'f',2);
0162     return QPair<QPointF, QString>(dp, pos);
0163 }
0164 
0165 QLineF FunctionPolar::tangent(const QPointF &/*mousepos*/)
0166 {
0167 //     //TODO review calc and this method
0168 // 
0169 //     QString rt = analyzer.expression().lambdaBody().toString();
0170 //     rt.replace("q", "t");
0171 // 
0172 //     QString comp1str = rt + "*cos(t)";
0173 //     QString comp2str = rt + "*sin(t)";
0174 // 
0175 //     QString polart;
0176 //     polart = "t->vector{" + comp1str + ", " + comp2str + "}";
0177 // 
0178 //     Analitza::Analyzer newfunc(analyzer.variables());
0179 //     newanalyzer.setExpression(Analitza::Expression(polart, false));
0180 // 
0181 //     Q_ASSERT(newanalyzer.isCorrect() && newanalyzer.expression().lambdaBody().isVector());
0182 //     
0183 //     Analitza::Analyzer f(newanalyzer.variables());
0184 //     f.setStack(m_runStack);
0185 //     f.setExpression(Analitza::Expression("t->" + newanalyzer.expression().lambdaBody().elementAt(0).toString() + "+" + QString::number(-1.0*point.x()), false));
0186 // 
0187 //     Analitza::Analyzer df(newanalyzer.variables());
0188 //     df.setStack(m_runStack);
0189 //     df.setExpression(f.derivative("t"));
0190 // 
0191 //     if (!df.isCorrect()) return QLineF();
0192 // 
0193 // //TODO
0194 // //    Analitza::Analyzer g(analyzer.variables());
0195 // //    g.setExpression(Analitza::Expression("t->" + analyzer.expression().lambdaBody().elementAt(1).toString() + "+" + QString::number(-1.0*point.y()), false));
0196 // //    g.refExpression()->parameters()[0]->value() = vx;
0197 // //
0198 // //    Analitza::Analyzer dg(analyzer.variables());
0199 // //    dg.setExpression(g.derivative("t"));
0200 // //    dg.refExpression()->parameters()[0]->value() = vx;
0201 // 
0202 //     const int MAX_I = 256;
0203 //     const double E = 0.0001;
0204 //     double t0 = atan(point.y()/ point.x());
0205 // 
0206 //     if(point.x()<0.)    t0 += pi;
0207 //     else if(t0<0.)  t0 += 2.*pi;
0208 // 
0209 //     t0=qBound(downlimit(), t0, uplimit());
0210 // 
0211 //     double t = t0;
0212 //     double error = 1000.0;
0213 //     int i = 0;
0214 // 
0215 //     while (true)
0216 //     {
0217 //         m_th->setValue(t0);
0218 // 
0219 //         double r = f.calculateLambda().toReal().value();
0220 //         double d = df.calculateLambda().toReal().value();
0221 // 
0222 //         i++;
0223 //         t = t0 - r/d;
0224 // 
0225 //         if ((error < E) || (i > MAX_I))
0226 //             break;
0227 // 
0228 //         error = fabs(t - t0);
0229 //         t0 = t;
0230 //     }
0231 // 
0232 // //TODO
0233 // //    t0 = 1.0;
0234 // //    t = t0;
0235 // //    error = 1000.0;
0236 // //    i = 0;
0237 // //
0238 // //    while (true)
0239 // //    {
0240 // //        m_th->setValue(t0);
0241 // //
0242 // //        double r = g.calculateLambda().toReal().value();
0243 // //        double d = dg.calculateLambda().toReal().value();
0244 // //
0245 // //        i++;
0246 // //        t = t0 - r/d;
0247 // //
0248 // //        if ((error < E) || (i > MAX_I))
0249 // //            break;
0250 // //
0251 // //        error = fabs(t - t0);
0252 // //        t0 = t;
0253 // //    }
0254 // 
0255 //     Analitza::Analyzer dfunc(newanalyzer.variables());
0256 //     danalyzer.setExpression(newanalyzer.derivative("t"));
0257 //     danalyzer.setStack(m_runStack);
0258 // 
0259 //     m_th->setValue(t);
0260 // 
0261 //     Expression res = danalyzer.calculateLambda();
0262 //     Cn comp1 = res.elementAt(0).toReal();
0263 //     Cn comp2 = res.elementAt(1).toReal();
0264 // 
0265 //     double m = comp2.value()/comp1.value();
0266 // 
0267 //     return FunctionUtils::slopeToLine(m);
0268     return QLineF();
0269 }
0270 
0271 REGISTER_PLANECURVE(FunctionPolar)
0272