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)