SAGA API v2.0.8
H:/saga/saga_svn/saga-gis/src/saga_core/saga_api/mat_spline.cpp
Go to the documentation of this file.
00001 /**********************************************************
00002  * Version $Id: mat_spline.cpp 1173 2011-09-23 14:39:27Z oconrad $
00003  *********************************************************/
00004 
00006 //                                                       //
00007 //                         SAGA                          //
00008 //                                                       //
00009 //      System for Automated Geoscientific Analyses      //
00010 //                                                       //
00011 //           Application Programming Interface           //
00012 //                                                       //
00013 //                  Library: SAGA_API                    //
00014 //                                                       //
00015 //-------------------------------------------------------//
00016 //                                                       //
00017 //                    mat_spline.cpp                     //
00018 //                                                       //
00019 //          Copyright (C) 2005 by Olaf Conrad            //
00020 //                                                       //
00021 //-------------------------------------------------------//
00022 //                                                       //
00023 // This file is part of 'SAGA - System for Automated     //
00024 // Geoscientific Analyses'.                              //
00025 //                                                       //
00026 // This library is free software; you can redistribute   //
00027 // it and/or modify it under the terms of the GNU Lesser //
00028 // General Public License as published by the Free       //
00029 // Software Foundation, version 2.1 of the License.      //
00030 //                                                       //
00031 // This library is distributed in the hope that it will  //
00032 // be useful, but WITHOUT ANY WARRANTY; without even the //
00033 // implied warranty of MERCHANTABILITY or FITNESS FOR A  //
00034 // PARTICULAR PURPOSE. See the GNU Lesser General Public //
00035 // License for more details.                             //
00036 //                                                       //
00037 // You should have received a copy of the GNU Lesser     //
00038 // General Public License along with this program; if    //
00039 // not, write to the Free Software Foundation, Inc.,     //
00040 // 59 Temple Place - Suite 330, Boston, MA 02111-1307,   //
00041 // USA.                                                  //
00042 //                                                       //
00043 //-------------------------------------------------------//
00044 //                                                       //
00045 //    contact:    Olaf Conrad                            //
00046 //                Institute of Geography                 //
00047 //                University of Goettingen               //
00048 //                Goldschmidtstr. 5                      //
00049 //                37077 Goettingen                       //
00050 //                Germany                                //
00051 //                                                       //
00052 //    e-mail:     oconrad@saga-gis.org                   //
00053 //                                                       //
00055 
00056 //---------------------------------------------------------
00057 
00058 
00060 //                                                                                                               //
00061 //                                                                                                               //
00062 //                                                                                                               //
00064 
00065 //---------------------------------------------------------
00066 #include "mat_tools.h"
00067 
00068 
00070 //                                                                                                               //
00071 //                                                                                                               //
00072 //                                                                                                               //
00074 
00075 //---------------------------------------------------------
00076 CSG_Spline::CSG_Spline(void)
00077 {
00078         m_Values        = NULL;
00079         m_nValues       = 0;
00080         m_nBuffer       = 0;
00081         m_bCreated      = false;
00082 }
00083 
00084 //---------------------------------------------------------
00085 CSG_Spline::~CSG_Spline(void)
00086 {
00087         Destroy();
00088 }
00089 
00090 
00092 //                                                                                                               //
00094 
00095 //---------------------------------------------------------
00096 void CSG_Spline::Destroy(void)
00097 {
00098         if( m_Values )
00099         {
00100                 SG_Free(m_Values);
00101 
00102                 m_Values        = NULL;
00103                 m_nValues       = 0;
00104                 m_nBuffer       = 0;
00105                 m_bCreated      = false;
00106         }
00107 }
00108 
00109 //---------------------------------------------------------
00110 bool CSG_Spline::Create(double *xValues, double *yValues, int nValues, double yA, double yB)
00111 {
00112         Destroy();
00113 
00114         for(int i=0; i<nValues; i++)
00115         {
00116                 Add(xValues[i], yValues[i]);
00117         }
00118 
00119         return( _Create(yA, yB) );
00120 }
00121 
00122 //---------------------------------------------------------
00123 bool CSG_Spline::Create(double yA, double yB)
00124 {
00125         return( _Create(yA, yB) );
00126 }
00127 
00128 
00130 //                                                                                                               //
00132 
00133 //---------------------------------------------------------
00134 void CSG_Spline::Add(double x, double y)
00135 {
00136         m_bCreated      = false;
00137 
00138         //-----------------------------------------------------
00139         if( m_nValues >= m_nBuffer )
00140         {
00141                 m_nBuffer       += 64;
00142                 m_Values         = (TSG_Point_Z *)SG_Realloc(m_Values, m_nBuffer * sizeof(TSG_Point_Z));
00143         }
00144 
00145         m_nValues++;
00146 
00147         //-----------------------------------------------------
00148         if( m_nValues == 1 )
00149         {
00150                 m_Values[0].x   = x;
00151                 m_Values[0].y   = y;
00152         }
00153         else
00154         {
00155                 int             i, iAdd;
00156 
00157                 for(iAdd=0; iAdd<m_nValues-1 && m_Values[iAdd].x<x; iAdd++)     {}
00158 
00159                 for(i=m_nValues-1; i>iAdd; i--)
00160                 {
00161                         m_Values[i]     = m_Values[i - 1];
00162                 }
00163 
00164                 m_Values[iAdd].x        = x;
00165                 m_Values[iAdd].y        = y;
00166         }
00167 }
00168 
00169 
00171 //                                                                                                               //
00173 
00174 //---------------------------------------------------------
00175 bool CSG_Spline::_Create(double yA, double yB)
00176 {
00177         int             i, k;
00178         double  p, qn, sig, un, *u;
00179 
00180         if( m_nValues > 2 )
00181         {
00182                 m_bCreated      = true;
00183                 u                       = (double *)SG_Malloc(m_nValues * sizeof(double));
00184 
00185                 if( yA > 0.99e30 )
00186                 {
00187                         m_Values[0].z   = u[0]  = 0.0;
00188                 }
00189                 else
00190                 {
00191                         m_Values[0].z   = -0.5;
00192                         u[0]                    = (3.0 / (m_Values[1].x - m_Values[0].x))
00193                                                         * ((m_Values[1].y - m_Values[0].y) / (m_Values[1].x - m_Values[0].x) - yA);
00194                 }
00195 
00196                 for(i=1; i<m_nValues-1; i++)
00197                 {
00198                         sig                             = (m_Values[i].x - m_Values[i - 1].x) / (m_Values[i + 1].x - m_Values[i - 1].x);
00199                         p                               = sig * m_Values[i - 1].z + 2.0;
00200                         m_Values[i].z   = (sig - 1.0) / p;
00201                         u[i]                    = (m_Values[i + 1].y - m_Values[i    ].y) / (m_Values[i + 1].x - m_Values[i    ].x)
00202                                                         - (m_Values[i    ].y - m_Values[i - 1].y) / (m_Values[i    ].x - m_Values[i - 1].x);
00203                         u[i]                    = (6.0 * u[i] / (m_Values[i + 1].x - m_Values[i - 1].x) - sig * u[i - 1]) / p;
00204                 }
00205 
00206                 if( yB > 0.99e30 )
00207                 {
00208                         qn      = un    = 0.0;
00209                 }
00210                 else
00211                 {
00212                         qn                              = 0.5;
00213                         un                              = (3.0 / (m_Values[m_nValues - 1].x - m_Values[m_nValues - 2].x))
00214                                                         * (yB  - (m_Values[m_nValues - 1].y - m_Values[m_nValues - 2].y)
00215                                                                / (m_Values[m_nValues - 1].x - m_Values[m_nValues - 2].x));
00216                 }
00217 
00218                 m_Values[m_nValues - 1].z       = (un - qn * u[m_nValues - 2]) / (qn * m_Values[m_nValues - 2].z + 1.0);
00219 
00220                 for(k=m_nValues-2; k>=0; k--)
00221                 {
00222                         m_Values[k].z   = m_Values[k].z * m_Values[k + 1].z + u[k];
00223                 }
00224 
00225                 SG_Free(u);
00226 
00227                 return( true );
00228         }
00229 
00230         return( false );
00231 }
00232 
00233 
00235 //                                                                                                               //
00237 
00238 //---------------------------------------------------------
00239 bool CSG_Spline::Get_Value(double x, double &y)
00240 {
00241         if( m_bCreated || Create() )
00242         {
00243                 int             klo, khi, k;
00244                 double  h, b, a;
00245 
00246                 klo     = 0;
00247                 khi     = m_nValues - 1;
00248 
00249                 while( khi - klo > 1 )
00250                 {
00251                         k       = (khi+klo) >> 1;
00252 
00253                         if( m_Values[k].x > x )
00254                         {
00255                                 khi     = k;
00256                         }
00257                         else
00258                         {
00259                                 klo     = k;
00260                         }
00261                 }
00262 
00263                 h       = m_Values[khi].x - m_Values[klo].x;
00264 
00265                 if( h != 0.0 )
00266                 {
00267                         a       = (m_Values[khi].x - x) / h;
00268                         b       = (x - m_Values[klo].x) / h;
00269 
00270                         y       = a * m_Values[klo].y + b * m_Values[khi].y
00271                                 + ((a*a*a - a) * m_Values[klo].z + (b*b*b - b) * m_Values[khi].z) * (h*h) / 6.0;
00272 
00273                         return( true );
00274                 }
00275         }
00276 
00277         return( false );
00278 }
00279 
00280 //---------------------------------------------------------
00281 double CSG_Spline::Get_Value(double x)
00282 {
00283         Get_Value(x, x);
00284 
00285         return( x );
00286 }
00287 
00288 
00290 //                                                                                                               //
00291 //                                                                                                               //
00292 //                                                                                                               //
00294 
00295 //---------------------------------------------------------
00296 //
00297 // Based on:
00298 //
00299 // Thin Plate Spline demo/example in C++
00300 // Copyright (C) 2003, 2005 by Jarno Elonen
00301 //
00302 // Permission to use, copy, modify, distribute and sell this software
00303 // and its documentation for any purpose is hereby granted without fee,
00304 // provided that the above copyright notice appear in all copies and
00305 // that both that copyright notice and this permission notice appear
00306 // in supporting documentation. The authors make no representations
00307 // about the suitability of this software for any purpose.
00308 // It is provided "as is" without express or implied warranty.
00309 //
00310 // Reference:
00311 // - Donato, G., Belongie, S. (2002):
00312 //   'Approximation Methods for Thin Plate Spline Mappings and Principal Warps'
00313 //
00314 //---------------------------------------------------------
00315 
00317 //                                                                                                               //
00318 //                                                                                                               //
00319 //                                                                                                               //
00321 
00322 //---------------------------------------------------------
00323 CSG_Thin_Plate_Spline::CSG_Thin_Plate_Spline(void)
00324 {
00325 }
00326 
00327 //---------------------------------------------------------
00328 CSG_Thin_Plate_Spline::~CSG_Thin_Plate_Spline(void)
00329 {
00330         Destroy();
00331 }
00332 
00333 
00335 //                                                                                                               //
00337 
00338 //---------------------------------------------------------
00339 bool CSG_Thin_Plate_Spline::Destroy(void)
00340 {
00341         m_Points.Clear();
00342         m_V.Destroy();
00343 
00344         return( true );
00345 }
00346 
00347 
00349 //                                                                                                               //
00351 
00352 //---------------------------------------------------------
00353 double CSG_Thin_Plate_Spline::_Get_hDistance(TSG_Point_Z A, TSG_Point_Z B)
00354 {
00355         A.x     -= B.x;
00356         A.y     -= B.y;
00357 
00358         return( sqrt(A.x*A.x + A.y*A.y) );
00359 }
00360 
00361 //---------------------------------------------------------
00362 double CSG_Thin_Plate_Spline::_Get_Base_Funtion(double x)
00363 {
00364         return( x > 0.0 ? x*x * log(x) : 0.0 );
00365 }
00366 
00367 //---------------------------------------------------------
00368 double CSG_Thin_Plate_Spline::_Get_Base_Funtion(TSG_Point_Z A, double x, double y)
00369 {
00370         x       -= A.x;
00371         y       -= A.y;
00372         x       = sqrt(x*x + y*y);
00373 
00374         return( x > 0.0 ? x*x * log(x) : 0.0 );
00375 }
00376 
00377 
00379 //                                                                                                               //
00381 
00382 //---------------------------------------------------------
00383 //      Calculate Thin Plate Spline (TPS) weights from control points.
00384 //
00385 bool CSG_Thin_Plate_Spline::Create(double Regularization, bool bSilent)
00386 {
00387         bool            bResult = false;
00388         int                     n;
00389 
00390         //-----------------------------------------------------
00391         // You We need at least 3 points to define a plane
00392         if( (n = m_Points.Get_Count()) >= 3 )
00393         {
00394                 int                             i, j;
00395                 double                  a, b;
00396                 TSG_Point_Z     Point;
00397                 CSG_Matrix              M;
00398 
00399                 //-------------------------------------------------
00400                 // Allocate the matrix and vector
00401                 M       .Create(n + 3, n + 3);
00402                 m_V     .Create(n + 3);
00403 
00404                 //-------------------------------------------------
00405                 // Fill K (n x n, upper left of L) and calculate
00406                 // mean edge length from control points
00407                 //
00408                 // K is symmetrical so we really have to
00409                 // calculate only about half of the coefficients.
00410                 for(i=0, a=0.0; i<n && (bSilent || SG_UI_Process_Set_Progress(i, n)); ++i )
00411                 {
00412                         Point   = m_Points[i];
00413 
00414                         for(j=i+1; j<n; ++j)
00415                         {
00416                                 b                = _Get_hDistance(Point, m_Points[j]);
00417                                 a               += b * 2.0;     // same for upper & lower tri
00418                                 M[i][j]  = (M[j][i]     = _Get_Base_Funtion(b));
00419                         }
00420                 }
00421 
00422                 a       /= (double)(n*n);
00423 
00424                 //-------------------------------------------------
00425                 // Fill the rest of L
00426                 for(i=0; i<n; ++i)
00427                 {
00428                         // diagonal: reqularization parameters (lambda * a^2)
00429                         M[i][i]         = Regularization * (a*a);
00430 
00431                         // P (n x 3, upper right)
00432                         M[i][n + 0]     = 1.0;
00433                         M[i][n + 1]     = m_Points[i].x;
00434                         M[i][n + 2]     = m_Points[i].y;
00435 
00436                         // P transposed (3 x n, bottom left)
00437                         M[n + 0][i]     = 1.0;
00438                         M[n + 1][i]     = m_Points[i].x;
00439                         M[n + 2][i]     = m_Points[i].y;
00440                 }
00441 
00442                 //-------------------------------------------------
00443                 // O (3 x 3, lower right)
00444                 for(i=n; i<n+3; ++i)
00445                 {
00446                         for(j=n; j<n+3; ++j)
00447                         {
00448                                 M[i][j] = 0.0;
00449                         }
00450                 }
00451 
00452                 //-------------------------------------------------
00453                 // Fill the right hand vector m_V
00454                 for(i=0; i<n; ++i)
00455                 {
00456                         m_V[i]  = m_Points[i].z;
00457                 }
00458 
00459                 m_V[n + 0]      = m_V[n + 1]    = m_V[n + 2]    = 0.0;
00460 
00461                 //-------------------------------------------------
00462                 // Solve the linear system "inplace"
00463                 if( !bSilent )
00464                 {
00465                         SG_UI_Process_Set_Text(LNG("Thin Plate Spline: solving matrix"));
00466                 }
00467 
00468                 bResult         = SG_Matrix_Solve(M, m_V, bSilent);
00469         }
00470 
00471         //-----------------------------------------------------
00472         if( !bResult )
00473         {
00474                 Destroy();
00475         }
00476 
00477         return( bResult );
00478 }
00479 
00480 //---------------------------------------------------------
00481 double CSG_Thin_Plate_Spline::Get_Value(double x, double y)
00482 {
00483         if( m_V.Get_N() > 0 )
00484         {
00485                 int             n       = m_Points.Get_Count();
00486                 double  z       = m_V[n + 0] + m_V[n + 1] * x + m_V[n + 2] * y;
00487 
00488                 for(int i=0; i<n; i++)
00489                 {
00490                         z       += m_V[i] * _Get_Base_Funtion(m_Points[i], x, y);
00491                 }
00492 
00493                 return( z );
00494         }
00495 
00496         return( 0.0 );
00497 }
00498 
00499 
00501 //                                                                                                               //
00502 //                                                                                                               //
00503 //                                                                                                               //
00505 
00506 //---------------------------------------------------------