00001
00015 #ifndef DLR_NUMERIC_BSPLINE2D_H
00016 #define DLR_NUMERIC_BSPLINE2D_H
00017
00018 #include <vector>
00019 #include <dlrNumeric/array1D.h>
00020 #include <dlrNumeric/array2D.h>
00021 #include <dlrNumeric/index2D.h>
00022 #include <dlrNumeric/vector2D.h>
00023 #include <dlrNumeric/polynomial.h>
00024
00025 namespace dlr {
00026
00027 namespace numeric {
00028
00047 template <class Type>
00048 class BSpline2D {
00049 public:
00050
00057 BSpline2D();
00058
00059
00065 BSpline2D(const BSpline2D& other);
00066
00067
00109 template <class CoordIter, class ObsIter>
00110 void
00111 approximateScatteredData(CoordIter sBegin,
00112 CoordIter sEnd,
00113 CoordIter tBegin,
00114 ObsIter observationsBegin,
00115 double buffer = 1.0E-10);
00116
00117
00130 void
00131 getMaximumSAndTValues(double& maximumS, double& maximumT);
00132
00133
00146 void
00147 getMinimumSAndTValues(double& minimumS, double& minimumT);
00148
00149
00163 void
00164 setControlPoints(const Array2D<Type>& controlPoints);
00165
00166
00183 void
00184 setNumberOfNodes(size_t numberOfNodesS,
00185 size_t numberOfNodesT);
00186
00187
00193 BSpline2D<Type>&
00194 operator=(const BSpline2D<Type>& other);
00195
00196
00203 Type
00204 operator()(double sValue, double tValue);
00205
00206
00207 protected:
00208
00234 void
00235 decomposeSamplePoint(double sValue, double tValue,
00236 size_t& iIndex, size_t& jIndex);
00237
00238
00239 Array1D< Array1D<double> > m_basisArray;
00240 Array2D<Type> m_controlGrid;
00241 Vector2D m_minimumXY;
00242 Vector2D m_maximumXY;
00243 size_t m_numberOfNodesS;
00244 size_t m_numberOfNodesT;
00245 Array1D<double> m_powersOfS;
00246 Array1D<double> m_powersOfT;
00247 Vector2D m_xyCellOrigin;
00248 Vector2D m_xyCellSize;
00249 };
00250
00251 }
00252
00253 }
00254
00255
00256
00257
00258
00259
00260
00261 #include <cmath>
00262 #include <algorithm>
00263 #include <dlrNumeric/functional.h>
00264 #include <dlrNumeric/utilities.h>
00265
00266 namespace dlr {
00267
00268 namespace numeric {
00269
00270
00271 template <class Type>
00272 BSpline2D<Type>::
00273 BSpline2D()
00274 : m_basisArray(4),
00275 m_controlGrid(),
00276 m_minimumXY(0.0, 0.0),
00277 m_maximumXY(1.0, 1.0),
00278 m_numberOfNodesS(0),
00279 m_numberOfNodesT(0),
00280 m_powersOfS(4),
00281 m_powersOfT(4),
00282 m_xyCellOrigin(),
00283 m_xyCellSize()
00284 {
00285
00286 Array1D<double> basisCoefficients(4);
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 basisCoefficients(0) = 1.0 / 6.0;
00299 basisCoefficients(1) = -0.5;
00300 basisCoefficients(2) = 0.5;
00301 basisCoefficients(3) = -1.0 / 6.0;
00302 m_basisArray(0) = basisCoefficients.copy();
00303
00304
00305
00306 basisCoefficients(0) = 2.0 / 3.0;
00307 basisCoefficients(1) = 0.0;
00308 basisCoefficients(2) = -1.0;
00309 basisCoefficients(3) = 0.5;
00310 m_basisArray(1) = basisCoefficients.copy();
00311
00312
00313
00314 basisCoefficients(0) = 1.0 / 6.0;
00315 basisCoefficients(1) = 0.5;
00316 basisCoefficients(2) = 0.5;
00317 basisCoefficients(3) = -0.5;
00318 m_basisArray(2) = basisCoefficients.copy();
00319
00320
00321
00322 basisCoefficients(0) = 0.0;
00323 basisCoefficients(1) = 0.0;
00324 basisCoefficients(2) = 0.0;
00325 basisCoefficients(3) = 1.0 / 6.0;
00326 m_basisArray(3) = basisCoefficients.copy();
00327
00328 m_xyCellSize.setValue((m_maximumXY.x() - m_minimumXY.x())
00329 / m_numberOfNodesS,
00330 (m_maximumXY.y() - m_minimumXY.y())
00331 / m_numberOfNodesT);
00332 m_xyCellOrigin = m_minimumXY - m_xyCellSize;
00333 m_controlGrid.reinit(
00334 std::ceil((m_maximumXY.x() - m_minimumXY.x()) / m_xyCellSize.x()) + 3,
00335 std::ceil((m_maximumXY.y() - m_minimumXY.y()) / m_xyCellSize.y()) + 3);
00336 m_controlGrid = 0.0;
00337
00338 m_powersOfS = 0.0;
00339 m_powersOfT = 0.0;
00340 }
00341
00342
00343
00344 template <class Type>
00345 BSpline2D<Type>::
00346 BSpline2D(const BSpline2D& other)
00347 : m_basisArray(4),
00348 m_controlGrid(other.m_controlGrid.copy()),
00349 m_minimumXY(other.m_minimumXY),
00350 m_maximumXY(other.m_maximumXY),
00351 m_numberOfNodesS(other.m_numberOfNodesS),
00352 m_numberOfNodesT(other.m_numberOfNodesT),
00353 m_xyCellOrigin(other.m_xyCellOrigin),
00354 m_xyCellSize(other.m_xyCellSize)
00355 {
00356
00357 for(size_t index0 = 0; index0 < m_basisArray.size(); ++index0) {
00358 m_basisArray[index0] = (other.m_basisArray[index0]).copy();
00359 }
00360 }
00361
00362
00363
00364
00365 template <class Type>
00366 template <class CoordIter, class ObsIter>
00367 void
00368 BSpline2D<Type>::
00369 approximateScatteredData(CoordIter sBegin,
00370 CoordIter sEnd,
00371 CoordIter tBegin,
00372 ObsIter observationsBegin,
00373 double buffer)
00374 {
00375 CoordIter tEnd = tBegin + (sEnd - sBegin);
00376
00377
00378 m_minimumXY.setValue(*std::min_element(sBegin, sEnd) - buffer,
00379 *std::min_element(tBegin, tEnd) - buffer);
00380 m_maximumXY.setValue(*std::max_element(sBegin, sEnd) + buffer,
00381 *std::max_element(tBegin, tEnd) + buffer);
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 double cellSize = std::min(
00393 (m_maximumXY.x() - m_minimumXY.x()) / (m_numberOfNodesS - 3),
00394 (m_maximumXY.y() - m_minimumXY.y()) / (m_numberOfNodesT - 3));
00395 m_xyCellSize.setValue(cellSize, cellSize);
00396 m_xyCellOrigin = m_minimumXY - m_xyCellSize;
00397
00398
00399
00400 Array2D<Type> deltaGrid(m_controlGrid.rows(), m_controlGrid.columns());
00401 Array2D<double> omegaGrid(m_controlGrid.rows(), m_controlGrid.columns());
00402 deltaGrid = static_cast<Type>(0.0);
00403 omegaGrid = 0.0;
00404
00405
00406 size_t iIndex;
00407 size_t jIndex;
00408 Array2D<double> wArray(4, 4);
00409 while(sBegin != sEnd) {
00410 double w2Sum = 0.0;
00411
00412
00413
00414 this->decomposeSamplePoint(*sBegin, *tBegin, iIndex, jIndex);
00415
00416
00417 for(size_t kIndex = 0; kIndex < 4; ++kIndex) {
00418 double B_k = dot((this->m_basisArray)[kIndex], m_powersOfS);
00419 for(size_t lIndex = 0; lIndex < 4; ++lIndex) {
00420 double B_l = dot((this->m_basisArray)[lIndex], m_powersOfT);
00421
00422 double wValue = B_k * B_l;
00423 wArray(kIndex, lIndex) = wValue;
00424 w2Sum += wValue * wValue;
00425 }
00426 }
00427 for(size_t kIndex = 0; kIndex < 4; ++kIndex) {
00428 for(size_t lIndex = 0; lIndex < 4; ++lIndex) {
00429 size_t index0 = iIndex + kIndex - 1;
00430 size_t index1 = jIndex + lIndex - 1;
00431 Type phi = (wArray(kIndex, lIndex) / w2Sum) * (*observationsBegin);
00432 double wValue = wArray(kIndex, lIndex);
00433 deltaGrid(index0, index1) += phi * wValue * wValue;
00434 omegaGrid(index0, index1) += wValue * wValue;
00435 }
00436 }
00437 ++sBegin;
00438 ++tBegin;
00439 ++observationsBegin;
00440 }
00441
00442
00443
00444 for(size_t index0 = 0; index0 < m_controlGrid.size(); ++index0) {
00445 if(omegaGrid[index0] == 0.0) {
00446 m_controlGrid[index0] = static_cast<Type>(0.0);
00447 } else {
00448 m_controlGrid[index0] = deltaGrid[index0] / omegaGrid[index0];
00449 }
00450 }
00451 }
00452
00453
00454
00455
00456 template <class Type>
00457 void
00458 BSpline2D<Type>::
00459 getMaximumSAndTValues(double& maximumS, double& maximumT)
00460 {
00461 maximumS = m_maximumXY.x();
00462 maximumT = m_maximumXY.y();
00463 }
00464
00465
00466
00467
00468 template <class Type>
00469 void
00470 BSpline2D<Type>::
00471 getMinimumSAndTValues(double& minimumS, double& minimumT)
00472 {
00473 minimumS = m_minimumXY.x();
00474 minimumT = m_minimumXY.y();
00475 }
00476
00477
00478
00479
00480 template <class Type>
00481 void
00482 BSpline2D<Type>::
00483 setControlPoints(const Array2D<Type>& controlPoints)
00484 {
00485 DLR_THROW(NotImplementedException, "BSpline2D::setControlPoints()",
00486 "Not yet written...");
00487 if(controlPoints.rows() <= 3 || controlPoints.columns() <= 3) {
00488 DLR_THROW(ValueException, "BSpline2D::setControlPoints()",
00489 "For a bicubic spline, control points array must be at "
00490 "least 4x4.");
00491 }
00492 m_controlGrid = controlPoints.copy();
00493
00494 m_minimumXY.setValue(0.0, 0.0);
00495 m_maximumXY.setValue(static_cast<double>(controlPoints.columns() - 3),
00496 static_cast<double>(controlPoints.rows() - 3));
00497 }
00498
00499
00500
00501
00502
00503 template <class Type>
00504 void
00505 BSpline2D<Type>::
00506 setNumberOfNodes(size_t numberOfNodesS,
00507 size_t numberOfNodesT)
00508 {
00509 if(numberOfNodesS <= 3 || numberOfNodesT <= 3) {
00510 DLR_THROW(ValueException, "BSpline2D::setNumberOfNodes()",
00511 "Both arguments must be greater than 3.");
00512 }
00513 m_numberOfNodesS = numberOfNodesS;
00514 m_numberOfNodesT = numberOfNodesT;
00515
00516 m_controlGrid.reinit(m_numberOfNodesT, m_numberOfNodesS);
00517 }
00518
00519
00520
00521 template <class Type>
00522 BSpline2D<Type>&
00523 BSpline2D<Type>::
00524 operator=(const BSpline2D<Type>& other)
00525 {
00526 if(&other != this) {
00527 m_controlGrid = other.m_controlGrid.copy();
00528 m_minimumXY = other.m_minimumXY;
00529 m_maximumXY = other.m_maximumXY;
00530 m_xyCellOrigin = other.m_xyCellOrigin;
00531 m_xyCellSize = other.m_xyCellSize;
00532 }
00533 }
00534
00535
00536
00537
00538 template <class Type>
00539 Type
00540 BSpline2D<Type>::
00541 operator()(double sValue, double tValue)
00542 {
00543
00544
00545
00546 size_t iIndex;
00547 size_t jIndex;
00548 this->decomposeSamplePoint(sValue, tValue, iIndex, jIndex);
00549
00550
00551
00552 int index0 = iIndex - 1;
00553 int index1 = jIndex - 1;
00554 double functionValue = 0.0;
00555 for(size_t kIndex = 0; kIndex < 4; ++kIndex) {
00556 size_t i0PlusK = index0 + kIndex;
00557 double B_k = dot((this->m_basisArray)[kIndex], m_powersOfS);
00558 for(size_t lIndex = 0; lIndex < 4; ++lIndex) {
00559 size_t i1PlusL = index1 + lIndex;
00560 double B_l = dot((this->m_basisArray)[lIndex], m_powersOfT);
00561 functionValue += (B_k * B_l * m_controlGrid(i0PlusK, i1PlusL));
00562 }
00563 }
00564 return functionValue;
00565 }
00566
00567
00568 template <class Type>
00569 void
00570 BSpline2D<Type>::
00571 decomposeSamplePoint(double sValue, double tValue,
00572 size_t& iIndex, size_t& jIndex)
00573 {
00574
00575
00576
00577
00578 double iTmp = (sValue - m_xyCellOrigin.x()) / m_xyCellSize.x();
00579 double jTmp = (tValue - m_xyCellOrigin.y()) / m_xyCellSize.y();
00580 int iCoord = static_cast<int>(std::floor(iTmp));
00581 int jCoord = static_cast<int>(std::floor(jTmp));
00582
00583
00584
00585
00586 m_powersOfS[0] = 1.0;
00587 m_powersOfS[1] = iTmp - iCoord;
00588 m_powersOfS[2] = m_powersOfS[1] * m_powersOfS[1];
00589 m_powersOfS[3] = m_powersOfS[2] * m_powersOfS[1];
00590 m_powersOfT[0] = 1.0;
00591 m_powersOfT[1] = jTmp - jCoord;
00592 m_powersOfT[2] = m_powersOfT[1] * m_powersOfT[1];
00593 m_powersOfT[3] = m_powersOfT[2] * m_powersOfT[1];
00594
00595 iIndex = static_cast<size_t>(iCoord);
00596 jIndex = static_cast<size_t>(jCoord);
00597 }
00598
00599
00600 }
00601
00602 }
00603
00604 #endif