QGpCoreTools/Curve.h
Go to the documentation of this file.
00001 /***************************************************************************
00002 **
00003 **  This file is part of QGpCoreTools.
00004 **
00005 **  This library is free software; you can redistribute it and/or
00006 **  modify it under the terms of the GNU Lesser General Public
00007 **  License as published by the Free Software Foundation; either
00008 **  version 2.1 of the License, or (at your option) any later version.
00009 **
00010 **  This file is distributed in the hope that it will be useful, but WITHOUT
00011 **  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 **  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00013 **  License for more details.
00014 **
00015 **  You should have received a copy of the GNU Lesser General Public
00016 **  License along with this library; if not, write to the Free Software
00017 **  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018 **
00019 **  See http://www.geopsy.org for more information.
00020 **
00021 **  Created : 2006-09-07
00022 **  Authors :
00023 **    Marc Wathelet
00024 **    Marc Wathelet (LGIT, Grenoble, France)
00025 **
00026 ***************************************************************************/
00027 
00028 #ifndef CURVE_H
00029 #define CURVE_H
00030 
00031 #include <math.h>
00032 
00033 #include "Global.h"
00034 #include "Trace.h"
00035 #include "Point2D.h"
00036 #include "SmoothingParameters.h"
00037 #include "CurvePointOptions.h"
00038 #include "Translations.h"
00039 #include "CoreApplication.h"
00040 
00041 #include "QGpCoreToolsDLLExport.h"
00042 
00043 namespace QGpCoreTools {
00044 
00045 enum SamplingOption {LinearScale=0, LogScale=1, InversedScale=2, Interpole=4, Function=8};
00046 Q_DECLARE_FLAGS(SamplingOptions, SamplingOption)
00047 
00048 template <class pointType>
00049 class QGPCORETOOLS_EXPORT Curve : private QVector<pointType>
00050 {
00051   TRANSLATIONS("Curve");
00052 public:
00053   Curve() {}
00054   Curve(int n) : QVector<pointType>(n) {}
00055   Curve(const Curve<pointType>& o) : QVector<pointType>(o) {}
00056   Curve(const QVector<pointType>& o) : QVector<pointType>(o) {}
00057 
00058   void setFunction();
00059   void unique();
00060 
00061   // Vector functions
00062   bool operator==(const Curve<pointType>& o) const {return QVector<pointType>::operator==(o);}
00063   int count() const {return QVector<pointType>::count();}
00064   bool isEmpty() const {return QVector<pointType>::isEmpty();}
00065   void resize(int n) {QVector<pointType>::resize(n);}
00066   int indexAfter(double valX) const;
00067   int indexOf(const pointType& p) const {return QVector<pointType>::indexOf(p);}
00068   pointType at(double x) const;
00069   const pointType& at(int index) const {return QVector<pointType>::at(index);}
00070   pointType& operator[](int index) {return QVector<pointType>::operator[](index);}
00071   const pointType& operator[](int index) const {return QVector<pointType>::at(index);}
00072   const pointType& first() const {return QVector<pointType>::first();}
00073   const pointType& last() const {return QVector<pointType>::last();}
00074   pointType& first() {return QVector<pointType>::first();}
00075   pointType& last() {return QVector<pointType>::last();}
00076   void remove(int index) {QVector<pointType>::remove(index);}
00077   void insert(int index, const pointType& p) {QVector<pointType>::insert(index, p);}
00078   void insert(const pointType& p);
00079   void clear() {QVector<pointType>::clear();}
00080   void prepend(const pointType& p) {QVector<pointType>::prepend(p);}
00081   void append(const pointType& p) {QVector<pointType>::append(p);}
00082   void append(const Curve<pointType>& c) {QVector<pointType>::operator+=(c);}
00083   typedef pointType * iterator;
00084   typedef const pointType * const_iterator;
00085   const_iterator begin() const {return QVector<pointType>::begin();}
00086   const_iterator end() const {return QVector<pointType>::end();}
00087   iterator begin() {return QVector<pointType>::begin();}
00088   iterator end() {return QVector<pointType>::end();}
00089 
00090   bool sameSampling(const Curve<pointType>& o) const;
00091 
00092   void xLog10();
00093   void xExp10();
00094   void xMultiply(double factor, SamplingOptions options=Function);
00095   void xInverse(SamplingOptions options=Function);
00096 
00097   void ySetValue(double value, const CurvePointOptions * pointOptions=0);
00098   void ySetMinimumValue(double value, const CurvePointOptions * pointOptions=0);
00099   void ySetMaximumValue(double value, const CurvePointOptions * pointOptions=0);
00100   void ySum(double value, const CurvePointOptions * pointOptions=0);
00101   void ySum(const Curve<pointType>& o, const CurvePointOptions * pointOptions=0);
00102   void yMultiply(double factor, const CurvePointOptions * pointOptions=0);
00103   void yMultiply(const Curve<pointType>& o, const CurvePointOptions * pointOptions=0);
00104   void ySquare(const CurvePointOptions * pointOptions=0);
00105   void ySqrt(const CurvePointOptions * pointOptions=0);
00106   void yInverse(const CurvePointOptions * pointOptions=0);
00107   void yLog10(const CurvePointOptions * pointOptions=0);
00108   void yExp10(const CurvePointOptions * pointOptions=0);
00109 
00110   void line(const pointType& p1, const pointType& p2);
00111   void resample(int n, double min, double max, SamplingOptions options,
00112                 double valX, double valY, const CurvePointOptions * pointOptions=0);
00113   void resample(int n, double min, double max, SamplingOptions options);
00114   void resample(const Curve<pointType>& xModel, SamplingOptions options);
00115   void resample(const QVector<double>& xModel, SamplingOptions options);
00116   void cut(double min, double max, SamplingOptions options);
00117   void smooth(double min, double max, const SmoothingParameters& param);
00118   void average(const Curve<pointType>& o);
00119 
00120   bool leastSquare(double& a, double& b, const CurvePointOptions * pointOptions=0) const;
00121   double azimuth(const CurvePointOptions * pointOptions=0) const;
00122   QVector<double> project(const CurvePointOptions * pointOptions=0) const;
00123 
00124   void swapXY(const CurvePointOptions * pointOptions=0);
00125   Curve<pointType> derivative(const CurvePointOptions * pointOptions=0) const;
00126 
00127   void setValid(bool v);
00128   void removeInvalid();
00129   int minimumX(int startIndex=0) const;
00130   int maximumX(int startIndex=0) const;
00131   int minimumY(int startIndex=0, const CurvePointOptions * pointOptions=0) const;
00132   int maximumY(int startIndex=0, const CurvePointOptions * pointOptions=0) const;
00133   int closestMax(int index);
00134 
00135   QVector<double> xVector() const;
00136   QString toString(int precision=6, char format='g') const;
00137 
00138   void operator+=(const Curve<pointType>& o);
00139   void operator*=(const Curve<pointType>& o);
00140 private:
00141   inline static bool lessThan(const pointType& p1, const pointType& p2);
00142   double sumX() const;
00143   double sumY(const CurvePointOptions * pointOptions=0) const;
00144   double sumXY(const CurvePointOptions * pointOptions=0) const;
00145   double sumX2() const;
00146   double sumY2(const CurvePointOptions * pointOptions=0) const;
00147 };
00148 
00149 template <class pointType>
00150 void Curve<pointType>::setFunction()
00151 {
00152   if(!isEmpty()) {
00153     qSort(begin(), end(), lessThan);
00154     // In case of lot of double entries, this is function was quite long with a remove()
00155     Curve<pointType> f;
00156     f.reserve(f.count());
00157     f.append(at(0));
00158     for(int i=1; i<count(); i++) {
00159       if(at(i-1).x()!=at(i).x()) {
00160         f.append(at(i));
00161       }
00162     }
00163     f.squeeze();
00164     // This is quite fast with implicit sharing
00165     *this=f;
00166   }
00167 }
00168 
00169 template <class pointType>
00170 void Curve<pointType>::unique()
00171 {
00172   ::QGpCoreTools::unique(*this);
00173 }
00174 
00175 template <class pointType>
00176 inline bool Curve<pointType>::lessThan(const pointType& p1, const pointType& p2)
00177 {
00178   return p1.x()<p2.x();
00179 }
00180 
00181 template <class pointType>
00182 int Curve<pointType>::indexAfter (double valX) const
00183 {
00184   TRACE;
00185   ASSERT(count()>1);
00186   if(valX <= at(0).x()) return 0;
00187   int lasti=count()-1;
00188   if(valX > at(lasti).x()) return lasti+1;
00189   int i=1;
00190   while(i < count()) i=i << 1;
00191   int step2=i >> 1;
00192   while(step2>0) {
00193     if(i>lasti) i-=step2;
00194     else if(valX <= at(i).x()) {
00195       if(valX > at(i-1).x()) break;
00196       i-=step2;
00197     } else i+=step2;
00198     step2=step2 >> 1;
00199   }
00200   return i;
00201 }
00202 
00203 template <class pointType>
00204 pointType Curve<pointType>::at(double x) const
00205 {
00206   if(count()<2) {
00207     if(count()==1) {
00208       return at(0);
00209     } else {
00210       return pointType();
00211     }
00212   } else {
00213     int i=indexAfter(x);
00214     if(i==0) i++;                // Force interpolation if outside range
00215     else if(i==count()) i--;
00216     pointType p;
00217     p.interpole(x, at(i-1), at(i));
00218     return p;
00219   }
00220 }
00221 
00222 template <class pointType>
00223 void Curve<pointType>::insert(const pointType& p)
00224 {
00225   TRACE;
00226   if(count()<2) {
00227     if(isEmpty()) {
00228       append(p);
00229     } else if(p.x() < at(0).x()) {
00230       prepend(p);
00231     } else if(p.x() > at(0).x()) {
00232       append(p);
00233     } else {
00234       (*this)[0]=p;
00235     }
00236   } else {
00237     int i=indexAfter(p.x());
00238     if(i<count() && at(i).x()==p.x()) {
00239       (*this)[i]=p;
00240     } else {
00241       if(at(p.x()).y()!=p.y()) {
00242         insert(i, p);
00243       }
00244     }
00245   }
00246 }
00247 
00248 template <class pointType>
00249 void Curve<pointType>::resample(int n, double min, double max, SamplingOptions options, double valX, double valY,
00250                                 const CurvePointOptions * pointOptions)
00251 {
00252   TRACE;
00253   // Transforms X scale according to options (log and inv)
00254   if(options & InversedScale) {
00255     xInverse(options);
00256     valX=1.0/valX;
00257   }
00258   if(options & LogScale) {
00259     xLog10();
00260     valX=::log10(valX);
00261     if(options & Function) {
00262       min=::log10(min);
00263       max=::log10(max);
00264     }
00265   }
00266   if(options & Function) {
00267     if(min < first().x())
00268       min=first().x();
00269     if(max > last().x())
00270       max=last().x();
00271   }
00272   int currentN=count();
00273 
00274   // Calculate the total "distance" curve
00275   Curve<Point2D> distances(currentN);
00276   distances[ 0 ].setX(at(0).x());
00277   distances[ 0 ].setY(0.0);
00278   for(int i=1; i < currentN; i++ ) {
00279     const pointType& p1=at(i - 1);
00280     const pointType& p2=at(i);
00281     distances[ i ].setX(p2.x());
00282     double deltaX=(p2.x() - p1.x())/valX;
00283     double deltaY=(p2.y(pointOptions) - p1.y(pointOptions))/valY;
00284     distances[ i ].setY(distances[ i - 1 ].y() + ::sqrt(deltaX * deltaX + deltaY * deltaY));
00285   }
00286   distances.setFunction();
00287 
00288   // Calculate the distance of min and max, and constant step
00289   double distMin, distMax;
00290   if(options & Function) {
00291     Point2D p;
00292     int i;
00293     i=distances.indexAfter(min);
00294     p.interpole(min, distances.at(i-1), distances.at(i));
00295     distMin=p.y();
00296     i=distances.indexAfter(max);
00297     p.interpole(max, distances.at(i-1), distances.at(i));
00298     distMax=p.y();
00299   } else {
00300     distMin=0;
00301     distMax=distances[ currentN - 1 ].y();
00302   }
00303   double cstStep=(distMax - distMin)/(currentN - 1);
00304 
00305   // Map x as a function of distance, function monotoneous, then no need to setFunction()
00306   distances.swapXY();
00307 
00308   // Intepolate x for constant step distance
00309   QVector<double> x(n);
00310   double dist=distMin;
00311   Point2D p;
00312   for(int i=0; i < n; i++, dist += cstStep) {
00313     int iDist=distances.indexAfter(dist  );
00314     p.interpole(dist, distances.at(iDist-1), distances.at(iDist));
00315     x[ i ]=p.y();
00316   }
00317   resample(x, options);
00318 
00319   // Re-Transforms axis according options (log and inv)
00320   if(options & LogScale)
00321     xExp10();
00322   if(options & InversedScale)
00323     xInverse(options);
00324 }
00325 
00326 template <class pointType>
00327 void Curve<pointType>::resample(int n, double min, double max, SamplingOptions options)
00328 {
00329   TRACE;
00330   ASSERT(options & Function);
00331   // Transforms X scale according to options (log and inv)
00332   if(options & InversedScale) {
00333     xInverse(options);
00334   }
00335   if(options & LogScale) {
00336     xLog10();
00337     min=::log10(min);
00338     max=::log10(max);
00339   }
00340   // Calculate the constant step
00341   double cstStep=(max - min)/(n - 1);
00342   QVector<double> x(n);
00343   for(int i=0;i < n;i++ )
00344     x[ i ]=min + (double)i*cstStep;
00345   resample(x, options);
00346 
00347   // Re-Transforms axis according options (log and inv)
00348   if(options & LogScale)
00349     xExp10();
00350   if(options & InversedScale)
00351     xInverse(options);
00352 }
00353 
00354 template <class pointType>
00355 void Curve<pointType>::resample(const Curve<pointType>& xModel, SamplingOptions options)
00356 {
00357   TRACE;
00358   ASSERT(options & Function);
00359   QVector<double> x(xModel.count());
00360   for(int i=0;i < xModel.count();i++ )
00361     x[ i ]=xModel.at(i).x();
00362   resample(x, options);
00363 }
00364 
00365 template <class pointType>
00366 void Curve<pointType>::resample(const QVector<double>& xModel, SamplingOptions options)
00367 {
00368   TRACE;
00369   ASSERT(options & Function);
00370   setFunction(); // Make sure values are sorted
00371   int nCurve=count();
00372   int nModel=xModel.count();
00373   if(nCurve<2 || nModel<2) return;
00374   Curve<pointType> interpolated(nModel);
00375   // Insert values inside xModel
00376   int iCurve=1;
00377   double min=at(0).x()*(1+(at(0).x()<0 ? 1e-15 : -1e-15));
00378   double max=at(nCurve-1).x()*(1+(at(nCurve-1).x()<0 ? -1e-15 : 1e-15));
00379   for(int i =0; i<nModel;i++) {
00380     double x=xModel.at(i);
00381     while(iCurve<nCurve-1 && at(iCurve).x()<x) iCurve++;
00382     interpolated[i].interpole(x, at(iCurve-1), at(iCurve));
00383     if(x<min || x>max || !at(iCurve-1).isValid() || !at(iCurve).isValid()) interpolated[i].setValid(false);
00384   }
00385   // Insert all values outside xModel
00386   if(nModel>1) {
00387     min=xModel.at(0)*(1+(xModel.at(0)<0 ? 1e-15 : -1e-15));
00388     max=xModel.at(nModel-1)*(1+(xModel.at(nModel-1)<0 ? -1e-15 : 1e-15));
00389     for(int i=0;i<nCurve;i++) {
00390       const pointType& p=at(i);
00391       if(p.x()<min || max<p.x()) {
00392         interpolated.append(p);
00393       }
00394     }
00395   }
00396   interpolated.setFunction();
00397   *this=interpolated;
00398 }
00399 
00400 template <class pointType>
00401 void Curve<pointType>::cut(double min, double max, SamplingOptions options)
00402 {
00403   TRACE;
00404   ASSERT(options & Function);
00405   // Assert that count()>1 is made by indexAfter()
00406   // Transforms X scale according to options (log and inv)
00407   if(options & InversedScale) {
00408     xInverse(options);
00409   }
00410   if(min < first().x())
00411     min=first().x();
00412   if(max > last().x())
00413     max=last().x();
00414   // Find the first point
00415   int ix=indexAfter(min);
00416   if(ix>0) {
00417     if(fabs(min - at(ix-1).x()) < 1e-15) {
00418       ix--;
00419     } else if((options & Interpole) && fabs(min - at(ix).x()) > 1e-15) {
00420       ix--;
00421       (*this)[ ix ].interpole(min, at(ix), at(ix+1));
00422     }
00423   }
00424   // Remove everything before
00425   for(int i=0; i<ix; i++) remove(0);
00426   // Find the last point
00427   ix=indexAfter(max);
00428   if(ix < count()) {
00429     if(fabs(max - at(ix).x()) < 1e-15) {
00430       ix++;
00431     } else if((options & Interpole) && fabs(max - at(ix-1).x()) > 1e-15) {
00432       (*this)[ ix ].interpole(max, at(ix-1), at(ix));
00433       ix++;
00434     }
00435   }
00436   // Remove everything after
00437   for(int i=count()-1; i>=ix; i--) remove(i);
00438   // Re-Transforms axis according options (log and inv)
00439   if(options & InversedScale)
00440     xInverse(options);
00441 }
00442 
00443 template <class pointType>
00444 void Curve<pointType>::smooth(double min, double max, const SmoothingParameters& param)
00445 {
00446   TRACE;
00447   
00448 }
00449 
00450 template <class pointType>
00451 void Curve<pointType>::average(const Curve<pointType>& o)
00452 {
00453   TRACE;
00454   if(o.count()<2) return;
00455   if(count()==0) {
00456     *this=o;
00457     return;
00458   }
00459   // Set the same sampling for both curves
00460   QVector<double> x=xVector();
00461   x+=o.xVector();
00462   qSort(x);
00463   ::QGpCoreTools::unique(x);
00464   resample(x, Function);
00465   Curve<pointType> oResamp=o;
00466   oResamp.resample(x, Function);
00467   // Take the average of the two curves
00468   for(int i=x.count()-1; i>=0; i--) {
00469     operator[](i).average(oResamp.at(i));
00470   }
00471   setFunction();
00472 }
00473 
00474 template <class pointType>
00475 void Curve<pointType>::setValid(bool v)
00476 {
00477   TRACE;
00478   iterator it;
00479   for(it=begin(); it!=end(); ++it) {
00480     it->setValid(v);
00481   }
00482 }
00483 
00484 template <class pointType>
00485 void Curve<pointType>::removeInvalid()
00486 {
00487   TRACE;
00488   for(int i=count() - 1; i>=0; i-- ) {
00489     if( !at(i).isValid()) {
00490       remove(i);
00491     }
00492   }
00493 }
00494 
00495 template <class pointType>
00496 void Curve<pointType>::swapXY(const CurvePointOptions * pointOptions)
00497 {
00498   TRACE;
00499   iterator it;
00500   for(it=begin(); it!=end(); ++it) {
00501     double tmp=it->x();
00502     it->setX(it->y(pointOptions));
00503     it->setY(tmp, pointOptions);
00504   }
00505 }
00506 
00507 template <class pointType>
00508 Curve<pointType> Curve<pointType>::derivative(const CurvePointOptions * pointOptions) const
00509 {
00510   TRACE;
00511   int n=count()-1;
00512   ASSERT(n>1);
00513   Curve<pointType> d(n-1);
00514   for(int i=1; i<n; i++ ) {
00515     double v=(at(i).y(pointOptions)-at(i-1).y(pointOptions))
00516                /(at(i).x()-at(i-1).x());
00517     v+=(at(i+1).y(pointOptions)-at(i).y(pointOptions))
00518       /(at(i+1).x()-at(i).x());
00519     v*=2.0;
00520     pointType& p=d[i-1];
00521     p.setX(at(i).x());
00522     p.setY(v, pointOptions);
00523   }
00524   return d;
00525 }
00526 
00527 template <class pointType>
00528 void Curve<pointType>::xMultiply(double factor, SamplingOptions options)
00529 {
00530   TRACE;
00531   iterator it;
00532   for(it=begin(); it!=end(); ++it) {
00533     pointType& p=*it;
00534     p.setX(p.x()*factor);
00535   }
00536   if(factor<0.0 && options & Function) setFunction();
00537 }
00538 
00539 template <class pointType>
00540 void Curve<pointType>::xInverse(SamplingOptions options)
00541 {
00542   TRACE;
00543   iterator it;
00544   for(it=begin(); it!=end(); ++it) {
00545     pointType& p=*it;
00546     p.setX(1.0/p.x());
00547   }
00548   if(options & Function) setFunction();
00549 }
00550 
00551 template <class pointType>
00552 void Curve<pointType>::xExp10()
00553 {
00554   TRACE;
00555   iterator it;
00556   for(it=begin(); it!=end(); ++it) {
00557     pointType& p=*it;
00558     p.setX(pow(10, p.x()));
00559   }
00560 }
00561 
00562 template <class pointType>
00563 void Curve<pointType>::xLog10()
00564 {
00565   TRACE;
00566   iterator it;
00567   for(it=begin(); it!=end(); ++it) {
00568     pointType& p=*it;
00569     if(p.x()>0.0) p.setX(::log10(p.x()));
00570   }
00571 }
00572 
00573 template <class pointType>
00574 void Curve<pointType>::ySetValue(double v, const CurvePointOptions * pointOptions)
00575 {
00576   int n=count();
00577   for(int i=0; i<n; i++) {
00578     (*this)[i].setY(v, pointOptions);
00579   }
00580 }
00581 
00582 template <class pointType>
00583 void Curve<pointType>::ySetMinimumValue(double v, const CurvePointOptions * pointOptions)
00584 {
00585   int n=count();
00586   for(int i=0; i<n; i++) {
00587     pointType& p=(*this)[i];
00588     if(p.y(pointOptions)<v) {
00589       p.setY(v, pointOptions);
00590     }
00591   }
00592 }
00593 
00594 template <class pointType>
00595 void Curve<pointType>::ySetMaximumValue(double v, const CurvePointOptions * pointOptions)
00596 {
00597   int n=count();
00598   for(int i=0; i<n; i++) {
00599     pointType& p=(*this)[i];
00600     if(p.y(pointOptions)>v) {
00601       p.setY(v, pointOptions);
00602     }
00603   }
00604 }
00605 
00606 template <class pointType>
00607 void Curve<pointType>::ySum(double value, const CurvePointOptions * pointOptions)
00608 {
00609   TRACE;
00610   iterator it;
00611   for(it=begin(); it!=end(); ++it) {
00612     pointType& p=*it;
00613     p.setY(p.y(pointOptions)+value, pointOptions);
00614   }
00615 }
00616 
00617 template <class pointType>
00618 void Curve<pointType>::ySum(const Curve<pointType>& o, const CurvePointOptions * pointOptions)
00619 {
00620   if(isEmpty()) {
00621     *this=o;
00622     return;
00623   }
00624   int n=count();
00625   if(n!=o.count()) {
00626     App::stream() << tr("Curve::ySum(): uncompatible sampling.") << endl;
00627     return;
00628   }
00629   for(int i=0; i<n; i++) {
00630     pointType& p=(*this)[i];
00631     p.setY(p.y(pointOptions)+o.at(i).y(pointOptions), pointOptions);
00632   }
00633 }
00634 
00635 template <class pointType>
00636 void Curve<pointType>::yMultiply(double factor, const CurvePointOptions * pointOptions)
00637 {
00638   TRACE;
00639   iterator it;
00640   for(it=begin(); it!=end(); ++it) {
00641     pointType& p=*it;
00642     p.setY(p.y(pointOptions)*factor, pointOptions);
00643   }
00644 }
00645 
00646 template <class pointType>
00647 void Curve<pointType>::yMultiply(const Curve<pointType>& o, const CurvePointOptions * pointOptions)
00648 {
00649   if(isEmpty()) {
00650     *this=o;
00651     return;
00652   }
00653   int n=count();
00654   if(n!=o.count()) {
00655     App::stream() << tr("Curve::yMultiply(): uncompatible sampling.") << endl;
00656     return;
00657   }
00658   for(int i=0; i<n; i++) {
00659     pointType& p=(*this)[i];
00660     p.setY(p.y(pointOptions)*o.at(i).y(pointOptions), pointOptions);
00661   }
00662 }
00663 
00664 template <class pointType>
00665 void Curve<pointType>::ySquare(const CurvePointOptions * pointOptions)
00666 {
00667   int n=count();
00668   for(int i=0; i<n; i++) {
00669     pointType& p=(*this)[i];
00670     double v=p.y(pointOptions);
00671     p.setY(v*v, pointOptions);
00672   }
00673 }
00674 
00675 template <class pointType>
00676 void Curve<pointType>::ySqrt(const CurvePointOptions * pointOptions)
00677 {
00678   int n=count();
00679   for(int i=0; i<n; i++) {
00680     pointType& p=(*this)[i];
00681     double v=p.y(pointOptions);
00682     if(v>=0.0) p.setY(::sqrt(v), pointOptions);
00683   }
00684 }
00685 
00686 template <class pointType>
00687 void Curve<pointType>::yInverse(const CurvePointOptions * pointOptions)
00688 {
00689   TRACE;
00690   iterator it;
00691   for(it=begin(); it!=end(); ++it) {
00692     pointType& p=*it;
00693     double v=p.y(pointOptions);
00694     if(v!=0.0) p.setY(1.0/v, pointOptions);
00695   }
00696 }
00697 
00698 template <class pointType>
00699 void Curve<pointType>::yLog10(const CurvePointOptions * pointOptions)
00700 {
00701   TRACE;
00702   iterator it;
00703   for(it=begin(); it!=end(); ++it) {
00704     pointType& p=*it;
00705     double v=p.y(pointOptions);
00706     if(v>0.0) p.setY(::log10(v), pointOptions);
00707   }
00708 }
00709 
00710 template <class pointType>
00711 void Curve<pointType>::yExp10(const CurvePointOptions * pointOptions)
00712 {
00713   TRACE;
00714   iterator it;
00715   for(it=begin(); it!=end(); ++it) {
00716     pointType& p=*it;
00717     p.setY(pow(10, p.y(pointOptions)), pointOptions);
00718   }
00719 }
00720 
00721 template <class pointType>
00722 void Curve<pointType>::line(const pointType& p1, const pointType& p2)
00723 {
00724   TRACE;
00725   resize(2);
00726   (*this)[0]=p1;
00727   (*this)[1]=p2;
00728 }
00729 
00730 template <class pointType>
00731 QVector<double> Curve<pointType>::xVector() const
00732 {
00733   int n=count();
00734   QVector<double> x(n);
00735   for(int i=0; i<n; i++ ) {
00736     x[i]=at(i).x();
00737   }
00738   return x;
00739 }
00740 
00741 template <class pointType>
00742 int Curve<pointType>::minimumX(int startIndex) const
00743 {
00744   int n=count();
00745   ASSERT(n>0 && startIndex<n);
00746   if(startIndex<0) startIndex=0;
00747   const pointType * p=&at(startIndex);
00748   int iMin=startIndex;
00749   for(int i=startIndex+1; i<n; i++ ) {
00750     if(at(i).x() < p->x()) {
00751       p=&at(i);
00752       iMin=i;
00753     }
00754   }
00755   return iMin;
00756 }
00757 
00758 template <class pointType>
00759 int Curve<pointType>::maximumX(int startIndex) const
00760 {
00761   int n=count();
00762   ASSERT(n>0 && startIndex<n);
00763   if(startIndex<0) startIndex=0;
00764   const pointType * p=&at(startIndex);
00765   int iMax=startIndex;
00766   for(int i=startIndex+1; i<n; i++ ) {
00767     if(at(i).x() > p->x()) {
00768       p=&at(i);
00769       iMax=i;
00770     }
00771   }
00772   return iMax;
00773 }
00774 
00775 template <class pointType>
00776 int Curve<pointType>::minimumY(int startIndex, const CurvePointOptions * pointOptions) const
00777 {
00778   int n=count();
00779   ASSERT(n>0 && startIndex<n);
00780   if(startIndex<0) startIndex=0;
00781   const pointType * p=&at(startIndex);
00782   int iMin=startIndex;
00783   for(int i=startIndex+1; i<n; i++ ) {
00784     if(at(i).y(pointOptions) < p->y(pointOptions)) {
00785       p=&at(i);
00786       iMin=i;
00787     }
00788   }
00789   return iMin;
00790 }
00791 
00792 template <class pointType>
00793 int Curve<pointType>::maximumY(int startIndex, const CurvePointOptions * pointOptions) const
00794 {
00795   int n=count();
00796   ASSERT(n>0 && startIndex<n);
00797   if(startIndex<0) startIndex=0;
00798   const pointType * p=&at(startIndex);
00799   int iMax=startIndex;
00800   for(int i=startIndex+1; i<n; i++ ) {
00801     if(at(i).y(pointOptions) > p->y(pointOptions)) {
00802       p=&at(i);
00803       iMax=i;
00804     }
00805   }
00806   return iMax;
00807 }
00808 
00809 template <class pointType>
00810 int Curve<pointType>::closestMax(int index)
00811 {
00812   TRACE;
00813   int n=count();
00814   int di;
00815 
00816   if(index==0) {
00817     di=1;
00818     index=1;
00819   }
00820   else if(index>=n) {
00821     index=n;
00822     di=-1;
00823   } else if(at(index).y()>at(index-1).y()) di=1;
00824   else if(at(index).y()<at(index-1).y()) di=-1;
00825   else return index;
00826 
00827   if(di>0) {
00828     while(index<n) {
00829       if(at(index).y()<at(index-1).y()) {
00830         index--;
00831         break;
00832       }
00833       index+=di;
00834     }
00835     if(index==n) index--;
00836   } else {
00837     while(index>0) {
00838       if(at(index).y()>at(index-1).y()) break;
00839       index+=di;
00840     }
00841   }
00842   return index;
00843 }
00844 
00845 template <class pointType>
00846 QString Curve<pointType>::toString(int precision, char format) const
00847 {
00848   TRACE;
00849   QString s;
00850   for(const_iterator it=begin(); it!=end(); ++it) {
00851     s+=it->toString(precision, format);
00852     s+="\n";
00853   }
00854   return s;
00855 }
00856 
00860 template <class pointType>
00861 double Curve<pointType>::sumX() const
00862 {
00863   TRACE;
00864   double sum=0.0;
00865   const_iterator it;
00866   for(it=begin();it!=end();++it) sum+=it->x();
00867   return sum;
00868 }
00869 
00873 template <class pointType>
00874 double Curve<pointType>::sumY(const CurvePointOptions * pointOptions) const
00875 {
00876   TRACE;
00877   double sum=0.0;
00878   const_iterator it;
00879   for(it=begin();it!=end();++it) sum+=it->y(pointOptions);
00880   return sum;
00881 }
00882 
00886 template <class pointType>
00887 double Curve<pointType>::sumXY(const CurvePointOptions * pointOptions) const
00888 {
00889   TRACE;
00890   double sum=0.0;
00891   const_iterator it;
00892   for(it=begin();it!=end();++it) sum+=it->x()*it->y(pointOptions);
00893   return sum;
00894 }
00895 
00899 template <class pointType>
00900 double Curve<pointType>::sumX2() const
00901 {
00902   TRACE;
00903   double sum=0.0;
00904   const_iterator it;
00905   for(it=begin();it!=end();++it) sum+=it->x()*it->x();
00906   return sum;
00907 }
00908 
00912 template <class pointType>
00913 double Curve<pointType>::sumY2(const CurvePointOptions * pointOptions) const
00914 {
00915   TRACE;
00916   double sum=0.0;
00917   const_iterator it;
00918   for(it=begin();it!=end();++it) sum+=it->y()*it->y(pointOptions);
00919   return sum;
00920 }
00921 
00929 template <class pointType>
00930 bool Curve<pointType>::leastSquare(double& a, double& b, const CurvePointOptions * pointOptions) const
00931 {
00932   TRACE;
00933   int n=count();
00934   if(n>1) {
00935     double invn=1.0/(double)n;
00936     double sx=sumX();
00937     double sy=sumY(pointOptions);
00938     double sxy=sumXY(pointOptions);
00939     double sx2=sumX2();
00940     printf("sum x=%lg sum x*sum x=%lg nsum2 x=%lg\n", sx, sx*sx, n*sx2);
00941     double denom=sx2-invn*sx*sx;
00942     if(denom!=0.0) {
00943       a=(sxy-invn*sy*sx)/denom;
00944       b=(invn*sy*sx2-invn*sxy*sx)/denom;
00945       return true;
00946     } else {
00947       a=0.0;
00948       b=sx*invn;
00949     }
00950   }
00951   return false;
00952 }
00953 
00959 template <class pointType>
00960 double Curve<pointType>::azimuth(const CurvePointOptions * pointOptions) const
00961 {
00962   TRACE;
00963   int n=count();
00964   if(n>1) {
00965     double a, b;
00966     if(leastSquare(a, b, pointOptions)) {
00967       return atan(a);
00968     } else {
00969       return 0.5*M_PI;
00970     }
00971   }
00972   return 0.0;
00973 }
00974 
00980 template <class pointType>
00981 QVector<double> Curve<pointType>::project(const CurvePointOptions * pointOptions) const
00982 {
00983   TRACE;
00984   int n=count();
00985   if(!n) return QVector<double>();
00986   QVector<double> projections(n);
00987   if(n>1) {
00988     double a, b;
00989     double min=1e99;
00990     if(leastSquare(a, b, pointOptions)) {
00991       for(int i=0; i<n; i++) {
00992         const pointType& p=at(i);
00993         double denom=a*a+1.0;
00994         double cp=-p.x()-a*p.y(pointOptions);
00995         double xp=(-cp-a*b)/denom;
00996         double yp=(-a*cp+b)/denom-b;
00997         double d=::sqrt(xp*xp+yp*yp);
00998         projections[i]=(xp>=0)? d : -d;
00999         if(projections[i]<min) min=projections[i];
01000       }
01001     } else {
01002       for(int i=0; i<n; i++) {
01003         const pointType& p=at(i);
01004         projections[i]=p.y(pointOptions);
01005         if(projections[i]<min) min=projections[i];
01006       }
01007     }
01008     // set min to abcsisse=0
01009     for(int i=0; i<n;i++) projections[i]-=min;
01010   } else {
01011     projections[0]=0;
01012   }
01013   return projections;
01014 }
01015 
01016 template <class pointType>
01017 bool Curve<pointType>::sameSampling(const Curve<pointType>& o) const
01018 {
01019   TRACE;
01020   int n=count();
01021   if(n!=o.count()) {
01022     return false;
01023   }
01024   for(int i=0; i<n; i++) {
01025     if(at(i).x()!=o.at(i).x()) {
01026       return false;
01027     }
01028   }
01029   return true;
01030 }
01031 
01032 } // namespace QGpCoreTools
01033 
01034 Q_DECLARE_OPERATORS_FOR_FLAGS(QGpCoreTools::SamplingOptions)
01035 
01036 #endif // CURVE_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines