PCL
SurfacePolynomial.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.7.0
6 // ----------------------------------------------------------------------------
7 // pcl/SurfacePolynomial.h - Released 2024-06-18T15:48:54Z
8 // ----------------------------------------------------------------------------
9 // This file is part of the PixInsight Class Library (PCL).
10 // PCL is a multiplatform C++ framework for development of PixInsight modules.
11 //
12 // Copyright (c) 2003-2024 Pleiades Astrophoto S.L. All Rights Reserved.
13 //
14 // Redistribution and use in both source and binary forms, with or without
15 // modification, is permitted provided that the following conditions are met:
16 //
17 // 1. All redistributions of source code must retain the above copyright
18 // notice, this list of conditions and the following disclaimer.
19 //
20 // 2. All redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
25 // of their contributors, may be used to endorse or promote products derived
26 // from this software without specific prior written permission. For written
27 // permission, please contact info@pixinsight.com.
28 //
29 // 4. All products derived from this software, in any form whatsoever, must
30 // reproduce the following acknowledgment in the end-user documentation
31 // and/or other materials provided with the product:
32 //
33 // "This product is based on software from the PixInsight project, developed
34 // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
35 //
36 // Alternatively, if that is where third-party acknowledgments normally
37 // appear, this acknowledgment must be reproduced in the product itself.
38 //
39 // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
40 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
43 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
45 // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
46 // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 // POSSIBILITY OF SUCH DAMAGE.
50 // ----------------------------------------------------------------------------
51 
52 #ifndef __PCL_SurfacePolynomial_h
53 #define __PCL_SurfacePolynomial_h
54 
56 
57 #include <pcl/Defs.h>
58 #include <pcl/Diagnostics.h>
59 
60 #include <pcl/Matrix.h>
61 #include <pcl/Point.h>
62 #include <pcl/Vector.h>
63 
64 namespace pcl
65 {
66 
67 // ----------------------------------------------------------------------------
68 
85 template <typename T>
86 class PCL_CLASS SurfacePolynomial
87 {
88 public:
89 
95 
100  using scalar = typename vector_type::scalar;
101 
106  SurfacePolynomial() = default;
107 
112 
117 
122  {
123  }
124 
128  SurfacePolynomial& operator =( const SurfacePolynomial& ) = default;
129 
133  SurfacePolynomial& operator =( SurfacePolynomial&& ) = default;
134 
139  bool IsValid() const
140  {
141  return !m_polynomial.IsEmpty();
142  }
143 
147  int Degree() const
148  {
149  return m_degree;
150  }
151 
165  void SetDegree( int degree )
166  {
167  PCL_PRECONDITION( degree >= 1 )
168  Clear();
169  m_degree = pcl::Max( 1, degree );
170  }
171 
188  void Initialize( const T* x, const T* y, const T* z, int n )
189  {
190  PCL_PRECONDITION( x != nullptr && y != nullptr && z != nullptr )
191  PCL_PRECONDITION( n > 2 )
192 
193  if ( n < 3 )
194  throw Error( "At least three input nodes are required in SurfacePolynomial::Initialize()" );
195 
196  Clear();
197 
198  // Find mean coordinate values
199  m_x0 = m_y0 = 0;
200  for ( int i = 0; i < n; ++i )
201  {
202  m_x0 += x[i];
203  m_y0 += y[i];
204  }
205  m_x0 /= n;
206  m_y0 /= n;
207 
208  // Find radius of unit circle
209  m_r0 = 0;
210  for ( int i = 0; i < n; ++i )
211  {
212  double dx = m_x0 - x[i];
213  double dy = m_y0 - y[i];
214  double r = Sqrt( dx*dx + dy*dy );
215  if ( r > m_r0 )
216  m_r0 = r;
217  }
218  if ( 1 + m_r0 == 1 )
219  throw Error( "SurfacePolynomial::Initialize(): Empty or insignificant interpolation space" );
220 
221  m_r0 = 1/m_r0;
222 
223  const int size = (m_degree + 1)*(m_degree + 2) >> 1;
224 
225  DMatrix M( 0.0, size, size );
226  DVector R( 0.0, size );
227  {
228  // Transform coordinates to unit circle
229  DVector X( n ), Y( n );
230  for ( int i = 0; i < n; ++i )
231  {
232  X[i] = m_r0*(x[i] - m_x0);
233  Y[i] = m_r0*(y[i] - m_y0);
234  }
235 
236  GenericVector<DVector> Z( n );
237  for ( int k = 0; k < n; ++k )
238  {
239  Z[k] = DVector( size );
240  for ( int i = 0, l = 0; i <= m_degree; ++i )
241  for ( int j = 0; j <= m_degree-i; ++j, ++l )
242  Z[k][l] = PowI( X[k], i ) * PowI( Y[k], j );
243  }
244 
245  int n2 = n*n;
246  for ( int i = 0; i < size; ++i )
247  {
248  for ( int j = 0; j < size; ++j )
249  {
250  for ( int k = 0; k < n; ++k )
251  M[i][j] += Z[k][i] * Z[k][j];
252  M[i][j] /= n2;
253  }
254 
255  for ( int k = 0; k < n; ++k )
256  R[i] += z[k] * Z[k][i];
257  R[i] /= n2;
258  }
259  }
260 
261  for ( int i = 0; i < size; ++i )
262  {
263  double pMi = M[i][i];
264  if ( M[i][i] != 0 )
265  {
266  for ( int j = i; j < size; ++j )
267  M[i][j] /= pMi;
268  R[i] /= pMi;
269  }
270 
271  for ( int k = 1; i+k < size; ++k )
272  {
273  double pMk = M[i+k][i];
274  if ( M[i+k][i] != 0 )
275  {
276  for ( int j = i; j < size; ++j )
277  {
278  M[i+k][j] /= pMk;
279  M[i+k][j] -= M[i][j];
280  }
281  R[i+k] /= pMk;
282  R[i+k] -= R[i];
283  }
284  }
285  }
286 
287  m_polynomial = vector_type( size );
288  for ( int i = size; --i >= 0; )
289  {
290  m_polynomial[i] = scalar( R[i] );
291  for ( int j = i; --j >= 0; )
292  R[j] -= M[j][i]*R[i];
293  }
294  }
295 
300  T operator ()( double x, double y ) const
301  {
302  PCL_PRECONDITION( !m_polynomial.IsEmpty() )
303 
304  double dx = m_r0*(x - m_x0);
305  double dy = m_r0*(y - m_y0);
306  double z = 0;
307  double px = 1;
308  for ( int i = 0, l = 0; ; px *= dx )
309  {
310  double py = 1;
311  for ( int j = 0; j <= m_degree-i; py *= dy, ++j, ++l )
312  z += m_polynomial[l]*px*py;
313  if ( ++i > m_degree )
314  break;
315  }
316  return T( z );
317  }
318 
323  void Clear()
324  {
325  m_polynomial.Clear();
326  }
327 
328 protected:
329 
330  double m_r0 = 1; // scaling factor for normalization of node coordinates
331  double m_x0 = 0; // zero offset for normalization of X node coordinates
332  double m_y0 = 0; // zero offset for normalization of Y node coordinates
333  int m_degree = 3; // polynomial degree > 0
334  vector_type m_polynomial; // coefficients of the 2-D surface polynomial
335 };
336 
337 // ----------------------------------------------------------------------------
338 
350 template <class P = DPoint>
351 class PCL_CLASS PointSurfacePolynomial
352 {
353 public:
354 
358  using point = P;
359 
364 
369 
375 
380 
385 
393  PointSurfacePolynomial( const point_list& P1, const point_list& P2, int degree = 3 )
394  {
395  Initialize( P1, P2, degree );
396  }
397 
405  PointSurfacePolynomial( const surface& Sx, const surface& Sy )
406  {
407  Initialize( Sx, Sy );
408  }
409 
413  PointSurfacePolynomial& operator =( const PointSurfacePolynomial& ) = default;
414 
418  PointSurfacePolynomial& operator =( PointSurfacePolynomial&& ) = default;
419 
443  void Initialize( const point_list& P1, const point_list& P2, int degree = 3 )
444  {
445  PCL_PRECONDITION( P1.Length() >= 3 )
446  PCL_PRECONDITION( P1.Length() <= P2.Length() )
447  PCL_PRECONDITION( degree > 0 )
448 
449  m_Sx.Clear();
450  m_Sy.Clear();
451 
452  m_Sx.SetDegree( degree );
453  m_Sy.SetDegree( degree );
454 
455  if ( P1.Length() < 3 || P2.Length() < 3 )
456  throw Error( "PointSurfacePolynomial::Initialize(): At least three input nodes must be specified." );
457 
458  if ( P2.Length() < P1.Length() )
459  throw Error( "PointSurfacePolynomial::Initialize(): Incompatible point array lengths." );
460 
461  DVector X( int( P1.Length() ) ),
462  Y( int( P1.Length() ) ),
463  Zx( int( P1.Length() ) ),
464  Zy( int( P1.Length() ) );
465  for ( int i = 0; i < X.Length(); ++i )
466  {
467  X[i] = P1[i].x;
468  Y[i] = P1[i].y;
469  Zx[i] = P2[i].x;
470  Zy[i] = P2[i].y;
471  }
472  m_Sx.Initialize( X.Begin(), Y.Begin(), Zx.Begin(), X.Length() );
473  m_Sy.Initialize( X.Begin(), Y.Begin(), Zy.Begin(), X.Length() );
474  }
475 
480  void Clear()
481  {
482  m_Sx.Clear();
483  m_Sy.Clear();
484  }
485 
490  bool IsValid() const
491  {
492  return m_Sx.IsValid() && m_Sy.IsValid();
493  }
494 
499  const surface& SurfaceX() const
500  {
501  return m_Sx;
502  }
503 
508  const surface& SurfaceY() const
509  {
510  return m_Sy;
511  }
512 
516  template <typename T>
517  DPoint operator ()( T x, T y ) const
518  {
519  return DPoint( m_Sx( x, y ), m_Sy( x, y ) );
520  }
521 
525  template <typename T>
526  DPoint operator ()( const GenericPoint<T>& p ) const
527  {
528  return operator ()( p.x, p.y );
529  }
530 
531 private:
532 
533  /*
534  * The surface interpolations in the X and Y plane directions.
535  */
536  surface m_Sx, m_Sy;
537 };
538 
539 // ----------------------------------------------------------------------------
540 
541 } // pcl
542 
543 #endif // __PCL_SurfacePolynomial_h
544 
545 // ----------------------------------------------------------------------------
546 // EOF pcl/SurfacePolynomial.h - Released 2024-06-18T15:48:54Z
size_type Length() const noexcept
Definition: Array.h:266
A simple exception with an associated error message.
Definition: Exception.h:239
Generic dynamic matrix of arbitrary dimensions.
Definition: Matrix.h:123
A generic point in the two-dimensional space.
Definition: Point.h:100
component x
Abscissa (horizontal, or X-axis coordinate).
Definition: Point.h:111
component y
Ordinate (vertical, or Y-axis coordinate).
Definition: Point.h:112
Generic vector of arbitrary length.
Definition: Vector.h:107
iterator Begin()
Definition: Vector.h:1900
Vector polynomial interpolation/approximation in two dimensions.
const surface & SurfaceX() const
PointSurfacePolynomial(PointSurfacePolynomial &&)=default
PointSurfacePolynomial(const PointSurfacePolynomial &)=default
void Initialize(const point_list &P1, const point_list &P2, int degree=3)
PointSurfacePolynomial(const surface &Sx, const surface &Sy)
const surface & SurfaceY() const
PointSurfacePolynomial(const point_list &P1, const point_list &P2, int degree=3)
Two-dimensional interpolating/approximating surface polynomial.
void Initialize(const T *x, const T *y, const T *z, int n)
typename vector_type::scalar scalar
void SetDegree(int degree)
SurfacePolynomial(const SurfacePolynomial &)=default
SurfacePolynomial(SurfacePolynomial &&)=default
Complex< T > Sqrt(const Complex< T > &c) noexcept
Definition: Complex.h:674
T PowI(T x, int n) noexcept
Definition: Math.h:1755
constexpr const T & Max(const T &a, const T &b) noexcept
Definition: Utility.h:119
PCL root namespace.
Definition: AbstractImage.h:77