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

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