bSpline2D.h

Go to the documentation of this file.
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   } // namespace numeric
00252   
00253 } // namespace dlr
00254 
00255 
00256 /* =============================================================== */
00257 /* Implementation follows.                                         */
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     // This constructor builds a BSpline2D instance of unspecified length.
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       // Temporary storage for polynomial coefficients.
00286       Array1D<double> basisCoefficients(4);
00287 
00288       // // The following basis functions are copied from Lee,
00289       // // Wolberg, and Shin.  We present them here without further
00290       // // justification, although we suspect you could them recursively
00291       // // using a 2D version of the procedure used in
00292       // // BSpline::computeBasisFunction() from file bSpline.h.
00293       
00294       // First cubic spline basis component is
00295       // B(s) = (1 - s)**3 / 6.
00296       // This expands to
00297       // B(s) = -(1/6)s**3 + (1/2)s**2 - (1/2)s + 1/6.
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       // Second cubic spline basis component is
00305       // B(s) = (1/2)t**3 - t**2 + 2/3.
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       // Third cubic spline basis component is
00313       // B(s) = -(1/2)t**3 + (1/2)t**2 + (1/2)t + 1/6.
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       // Fourth cubic spline basis component is
00321       // B(s) = (1/6)t**3.
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     // The copy constructor does a deep copy.
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       // Deep copy basis coefficients.
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     // This function allows the spline parameters to be automatically
00364     // set in order to approximate an irregularly sampled function.
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       // Set bounds for reconstruction
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       // Chose the origin and spacing of the control grid.
00384       //
00385       // For now, we require square cells.
00386       // m_xyCellSize.setValue(
00387       //   (m_maximumXY.x() - m_minimumXY.x()) / (m_numberOfNodesS - 3),
00388       //   (m_maximumXY.y() - m_minimumXY.y()) / (m_numberOfNodesT - 3));
00389       //
00390       // Note(xxx): Here is where we diverge from the reference
00391       // implementation.
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       // Allocate some space for intermediate grids, as described in
00399       // Lee, Wolberg, and Shin.
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       // This code implements the algorithm on page 231 of the paper.
00406       size_t iIndex;
00407       size_t jIndex;
00408       Array2D<double> wArray(4, 4);
00409       while(sBegin != sEnd) {
00410         double w2Sum = 0.0;
00411         // This call sets the value of m_powersOfS and m_powersOfT,
00412         // and returns by reference the indices of the control grid
00413         // cell into which (s, t) falls.
00414         this->decomposeSamplePoint(*sBegin, *tBegin, iIndex, jIndex);
00415 
00416         // Now on with Lee, Wolberg, and Shin's algorithm.
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       // Final averaging step in case neighboring input points want
00443       // different control grid values.
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     // This member function returns the maximum values for the spline
00455     // parameters S and T.
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     // This member function returns the minimum values for the spline
00467     // parameters S and T.
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     // This member function sets the values of the control points of
00479     // the spline.  If the spline is periodic, then the value of the
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       // xxx m_xyCellOrigin = ??;
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     // This member function both specifies the number of nodes in
00501     // the spline and sets the node positions so that the spline is
00502     // "uniform".
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       // Warning(xxx): need to reverse interpretation of these indices below.
00516       m_controlGrid.reinit(m_numberOfNodesT, m_numberOfNodesS);
00517     }
00518 
00519     
00520     // The assigment operator does a deep copy.
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     // This operator evaluates the spline at the specified value of
00537     // spline parameter s.
00538     template <class Type>
00539     Type
00540     BSpline2D<Type>::
00541     operator()(double sValue, double tValue)
00542     {
00543       // This call sets the value of m_powersOfS and m_powersOfT,
00544       // and returns by reference the indices of the control grid
00545       // cell into which (s, t) falls.
00546       size_t iIndex;
00547       size_t jIndex;
00548       this->decomposeSamplePoint(sValue, tValue, iIndex, jIndex);
00549 
00550       // Interpolate by adding spline basis functions from the
00551       // surrounding control points.
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       // Note(xxx): consider using std::modf() here.
00575       
00576       // Find the integer coords of the control grid cell in which the
00577       // input point lies.
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       // Find real valued coords within the cell, along with all of
00584       // the powers of those coords we'll be wanting to plug into
00585       // spline basis functions.
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   } // namespace numeric
00601 
00602 } // namespace dlr
00603 
00604 #endif /* #ifndef DLR_NUMERIC_BSPLINE2D_H */

Generated on Wed Nov 25 00:42:41 2009 for dlrUtilities Utility Library by  doxygen 1.5.8