00001
00002 #include "Interpol.h"
00003 #include "Tools/Math/LA_Matrix.h"
00004 #include <algorithm>
00005
00006 using namespace std;
00007
00008 namespace interpol {
00009
00010 Point::Point()
00011 : x(0.0),
00012 y(0.0)
00013 {
00014 }
00015
00016 Point::Point(double x, double y)
00017 : x(x),
00018 y(y)
00019 {
00020 }
00021
00022 bool operator<(const Point& p1, const Point& p2)
00023 {
00024 return p1.x < p2.x;
00025 }
00026
00027
00028
00029 Interpolation* InterpolationFactory::Create(Type type)
00030 {
00031 switch (type)
00032 {
00033 case Linear:
00034 return new LinearInterpolation();
00035 case Spline:
00036 return new SplineInterpolation();
00037 default:
00038 return NULL;
00039 }
00040 }
00041
00042 Interpolation* InterpolationFactory::Create(Type type,
00043 const Interpolation* pSource)
00044 {
00045 Interpolation* pInterpolation = Create(type);
00046 pInterpolation->Assign(*pSource);
00047 return pInterpolation;
00048 }
00049
00050 Interpolation* InterpolationFactory::Transform(Type type,
00051 Interpolation* pSource)
00052 {
00053 Interpolation* pNewInterpolation = Create(type, pSource);
00054 Destroy(pSource);
00055 return pNewInterpolation;
00056 }
00057
00058 void InterpolationFactory::Destroy(Interpolation* pInterpolation)
00059 {
00060 delete pInterpolation;
00061 }
00062
00063 void InterpolationFactory::Write(Out& out, const Interpolation* pInterpolation)
00064 {
00065 out << pInterpolation->GetType();
00066 out << pInterpolation->points.size();
00067 std::map<int, interpol::Point>::const_iterator pos;
00068 for (pos = pInterpolation->points.begin();
00069 pos != pInterpolation->points.end();
00070 ++pos)
00071 out << pos->second;
00072 }
00073
00074 Interpolation* InterpolationFactory::Read(In& in)
00075 {
00076 Type type;
00077 in >> (int&)type;
00078 Interpolation* pInterpolation = Create(type);
00079
00080 int count;
00081 in >> count;
00082 for (int i = 1; i <= count; ++i)
00083 {
00084 Point p;
00085 in >> p;
00086 pInterpolation->points.insert(make_pair(i, p));
00087 }
00088 pInterpolation->nextIndex = count + 1;
00089 pInterpolation->BuildSortedPoints();
00090 pInterpolation->OnChange();
00091 return pInterpolation;
00092 }
00093
00094
00095
00096 Interpolation::Interpolation()
00097 : nextIndex(1)
00098 {
00099 }
00100
00101 Interpolation::~Interpolation()
00102 {
00103 }
00104
00105 int Interpolation::AddPoint(const Point& p)
00106 {
00107
00108 if (binary_search(xSortedPoints.begin(), xSortedPoints.end(), p))
00109 return -1;
00110
00111
00112 int id = nextIndex;
00113 points.insert(make_pair(id, p));
00114 ++nextIndex;
00115
00116
00117 BuildSortedPoints();
00118
00119 OnChange();
00120
00121 return id;
00122 }
00123
00124 int Interpolation::AddPoint(double x, double y)
00125 {
00126 return AddPoint(Point(x, y));
00127 }
00128
00129 bool Interpolation::MovePoint(int index, const Point& p)
00130 {
00131
00132 map<int, Point>::iterator ppos = points.find(index);
00133 if (ppos == points.end())
00134 return false;
00135
00136
00137 map<int, Point>::const_iterator pos;
00138 for (pos = points.begin(); pos != points.end(); ++pos)
00139 {
00140 if (pos->first == index)
00141 continue;
00142 if (pos->second.x == p.x)
00143 return false;
00144 }
00145
00146
00147 ppos->second = p;
00148
00149
00150 BuildSortedPoints();
00151
00152 OnChange();
00153
00154 return true;
00155 }
00156
00157 bool Interpolation::RemovePoint(int index)
00158 {
00159
00160 map<int, Point>::iterator ppos = points.find(index);
00161 if (ppos == points.end())
00162 return false;
00163
00164
00165 points.erase(ppos);
00166
00167
00168 BuildSortedPoints();
00169
00170 OnChange();
00171
00172 return true;
00173 }
00174
00175 Interpolation::ConstPointIterator Interpolation::GetPointBegin() const
00176 {
00177 return points.begin();
00178 }
00179
00180 Interpolation::ConstPointIterator Interpolation::GetPointEnd() const
00181 {
00182 return points.end();
00183 }
00184
00185 void Interpolation::Assign(const Interpolation& interpolation)
00186 {
00187 xSortedPoints = interpolation.xSortedPoints;
00188 nextIndex = interpolation.nextIndex;
00189 points = interpolation.points;
00190 OnChange();
00191 }
00192
00193 void Interpolation::BuildSortedPoints()
00194 {
00195 xSortedPoints.clear();
00196 map<int, Point>::const_iterator pos;
00197 for (pos = points.begin(); pos != points.end(); ++pos)
00198 xSortedPoints.push_back(pos->second);
00199 sort(xSortedPoints.begin(), xSortedPoints.end());
00200 }
00201
00202
00203
00204 LinearInterpolation::LinearInterpolation()
00205 : Interpolation()
00206 {
00207 }
00208
00209 LinearInterpolation::~LinearInterpolation()
00210 {
00211 }
00212
00213 double LinearInterpolation::GetInterpolatedY(double x) const
00214 {
00215
00216 int pointCount = (int)xSortedPoints.size();
00217 if (pointCount == 0)
00218 return 0.0;
00219
00220
00221 double leftX = xSortedPoints[0].x;
00222 double rightX = xSortedPoints[pointCount-1].x;
00223 if (x <= leftX)
00224 return xSortedPoints[0].y;
00225 if (x >= rightX)
00226 return xSortedPoints[pointCount-1].y;
00227
00228
00229 vector<Point>::const_iterator right =
00230 lower_bound(xSortedPoints.begin(), xSortedPoints.end(), Point(x, 0.0));
00231 if (right->x == x)
00232 return right->y;
00233 vector<Point>::const_iterator left = right-1;
00234
00235
00236 double x1 = left->x;
00237 double y1 = left->y;
00238 double x2 = right->x;
00239 double y2 = right->y;
00240 return y1 + (x-x1)*(y2-y1)/(x2-x1);
00241 }
00242
00243 InterpolationFactory::Type LinearInterpolation::GetType() const
00244 {
00245 return InterpolationFactory::Linear;
00246 }
00247
00248
00249
00250 SplineInterpolation::SplineInterpolation()
00251 : Interpolation()
00252 {
00253 }
00254
00255 SplineInterpolation::~SplineInterpolation()
00256 {
00257 }
00258
00259 double SplineInterpolation::GetInterpolatedY(double x) const
00260 {
00261 if (this->x.dim() == 0)
00262 return 0.0;
00263 else if (this->x.dim() == 1)
00264 return y(1);
00265
00266 if (x < this->x(1))
00267 return y(1);
00268
00269 int i;
00270 for (i = 0; i < this->x.dim()-1; ++i)
00271 {
00272 if (x < this->x[i+1])
00273 {
00274 double r = x - this->x[i];
00275 double s = a[i] + b[i]*r + (c[i]/2.0)*r*r + (d[i]/6.0)*r*r*r;
00276 return s;
00277 }
00278 }
00279
00280 return y(y.dim());
00281 }
00282
00283 InterpolationFactory::Type SplineInterpolation::GetType() const
00284 {
00285 return InterpolationFactory::Spline;
00286 }
00287
00288 void SplineInterpolation::OnChange()
00289 {
00290 CalcSplines();
00291 }
00292
00293 void SplineInterpolation::CalcSplines()
00294 {
00295 int i;
00296
00297
00298 x.create((int)xSortedPoints.size());
00299 y.create((int)xSortedPoints.size());
00300 for (i = 0; i < x.dim(); ++i)
00301 {
00302 x[i] = xSortedPoints[i].x;
00303 y[i] = xSortedPoints[i].y;
00304 }
00305
00306 if (xSortedPoints.size() < 2)
00307 return;
00308
00309 LA::Vector h(x.dim() - 1);
00310 for (i = 0; i < h.dim(); ++i)
00311 h[i] = x[i+1] - x[i];
00312
00313 LA::Vector lambda(x.dim() - 1);
00314 for (i = 1; i < x.dim()-2; ++i)
00315 lambda[i] = h[i]/(h[i] + h[i-1]);
00316
00317 LA::Vector mue(x.dim() - 1);
00318 for (i = 2; i < x.dim()-1; ++i)
00319 mue[i] = h[i-1]/(h[i] + h[i-1]);
00320
00321 LA::Vector delta(x.dim() - 2);
00322 for (i = 1; i <= x.dim() - 2; ++i)
00323 delta(i) = 6.0/(h[i]+h[i-1]) * ((y[i+1]-y[i])/h[i] - (y[i]-y[i-1])/h[i-1]);
00324
00325 LA::Matrix M(delta.dim(), delta.dim());
00326 for (i = 1; i <= delta.dim(); ++i)
00327 {
00328 M(i, i) = 2.0;
00329 if (i > 1)
00330 M(i, i-1) = mue[i];
00331 if (i < delta.dim())
00332 M(i, i+1) = lambda[i];
00333 }
00334 LA::Vector c_temp = M.solve(delta);
00335
00336 c.create(x.dim());
00337 c.set_sub(2, c_temp);
00338
00339 a.create(x.dim()-1);
00340 for (i = 0; i < a.dim(); ++i)
00341 a[i] = y[i];
00342
00343 d.create(x.dim()-1);
00344 for (i = 0; i < d.dim(); ++i)
00345 d[i] = (c[i+1]-c[i])/h[i];
00346
00347 b.create(x.dim()-1);
00348 for (i = 0; i < b.dim(); ++i)
00349 b[i] = (y[i+1]-y[i])/h[i] - h[i]/6.0*(2.0*c[i] + c[i+1]);
00350
00351 }
00352
00353 Out& operator<<(Out& stream, const interpol::Point& p)
00354 {
00355 stream << p.x;
00356 stream << p.y;
00357 return stream;
00358 }
00359
00360 In& operator>>(In& stream, interpol::Point& p)
00361 {
00362 stream >> p.x;
00363 stream >> p.y;
00364 return stream;
00365 }
00366
00367 }
00368