00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
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
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++;
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
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
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
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
00306 distances.swapXY();
00307
00308
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
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
00332 if(options & InversedScale) {
00333 xInverse(options);
00334 }
00335 if(options & LogScale) {
00336 xLog10();
00337 min=::log10(min);
00338 max=::log10(max);
00339 }
00340
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
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();
00371 int nCurve=count();
00372 int nModel=xModel.count();
00373 if(nCurve<2 || nModel<2) return;
00374 Curve<pointType> interpolated(nModel);
00375
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
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
00406
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
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
00425 for(int i=0; i<ix; i++) remove(0);
00426
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
00437 for(int i=count()-1; i>=ix; i--) remove(i);
00438
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
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
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
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 }
01033
01034 Q_DECLARE_OPERATORS_FOR_FLAGS(QGpCoreTools::SamplingOptions)
01035
01036 #endif // CURVE_H