PCL
SurfacePolynomial.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.8.5
6 // ----------------------------------------------------------------------------
7 // pcl/SurfacePolynomial.h - Released 2024-12-28T16:53:48Z
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 
338  template <typename T1>
339  void Evaluate( T1* Z, const T1* X, const T1* Y, size_type n ) const
340  {
341  PCL_PRECONDITION( !m_polynomial.IsEmpty() )
342  PCL_PRECONDITION( X != nullptr && Y != nullptr && Z != nullptr )
343  PCL_PRECONDITION( n > 0 )
344  for ( size_type i = 0; i < n; ++i )
345  Z[i] = T1( operator()( double( X[i] ), double( Y[i] ) ) );
346  }
347 
358  {
359  return false;
360  }
361 
362 protected:
363 
364  double m_r0 = 1; // scaling factor for normalization of node coordinates
365  double m_x0 = 0; // zero offset for normalization of X node coordinates
366  double m_y0 = 0; // zero offset for normalization of Y node coordinates
367  int m_degree = 3; // polynomial degree > 0
368  vector_type m_polynomial; // coefficients of the 2-D surface polynomial
369 };
370 
371 // ----------------------------------------------------------------------------
372 
384 template <class P = DPoint>
385 class PCL_CLASS PointSurfacePolynomial
386 {
387 public:
388 
392  using point = P;
393 
398 
403 
409 
414 
419 
427  PointSurfacePolynomial( const point_list& P1, const point_list& P2, int degree = 3 )
428  {
429  Initialize( P1, P2, degree );
430  }
431 
439  PointSurfacePolynomial( const surface& Sx, const surface& Sy )
440  {
441  Initialize( Sx, Sy );
442  }
443 
447  PointSurfacePolynomial& operator =( const PointSurfacePolynomial& ) = default;
448 
452  PointSurfacePolynomial& operator =( PointSurfacePolynomial&& ) = default;
453 
477  void Initialize( const point_list& P1, const point_list& P2, int degree = 3 )
478  {
479  PCL_PRECONDITION( P1.Length() >= 3 )
480  PCL_PRECONDITION( P1.Length() <= P2.Length() )
481  PCL_PRECONDITION( degree > 0 )
482 
483  m_Sx.Clear();
484  m_Sy.Clear();
485 
486  m_Sx.SetDegree( degree );
487  m_Sy.SetDegree( degree );
488 
489  if ( P1.Length() < 3 || P2.Length() < 3 )
490  throw Error( "PointSurfacePolynomial::Initialize(): At least three input nodes must be specified." );
491 
492  if ( P2.Length() < P1.Length() )
493  throw Error( "PointSurfacePolynomial::Initialize(): Incompatible point array lengths." );
494 
495  DVector X( int( P1.Length() ) ),
496  Y( int( P1.Length() ) ),
497  Zx( int( P1.Length() ) ),
498  Zy( int( P1.Length() ) );
499  for ( int i = 0; i < X.Length(); ++i )
500  {
501  X[i] = P1[i].x;
502  Y[i] = P1[i].y;
503  Zx[i] = P2[i].x;
504  Zy[i] = P2[i].y;
505  }
506  m_Sx.Initialize( X.Begin(), Y.Begin(), Zx.Begin(), X.Length() );
507  m_Sy.Initialize( X.Begin(), Y.Begin(), Zy.Begin(), X.Length() );
508  }
509 
514  void Clear()
515  {
516  m_Sx.Clear();
517  m_Sy.Clear();
518  }
519 
524  bool IsValid() const
525  {
526  return m_Sx.IsValid() && m_Sy.IsValid();
527  }
528 
533  const surface& SurfaceX() const
534  {
535  return m_Sx;
536  }
537 
542  const surface& SurfaceY() const
543  {
544  return m_Sy;
545  }
546 
550  template <typename T>
551  DPoint operator ()( T x, T y ) const
552  {
553  return DPoint( m_Sx( x, y ), m_Sy( x, y ) );
554  }
555 
559  template <typename T>
560  DPoint operator ()( const GenericPoint<T>& p ) const
561  {
562  return operator ()( p.x, p.y );
563  }
564 
576  template <typename T>
577  void Evaluate( T* ZX, T* ZY, const T* X, const T* Y, size_type n ) const
578  {
579  PCL_PRECONDITION( ISValid() )
580  m_Sx.Evaluate( ZX, X, Y, n );
581  m_Sy.Evaluate( ZY, X, Y, n );
582  }
583 
594  {
595  return false;
596  }
597 
598 private:
599 
600  /*
601  * The surface interpolations in the X and Y plane directions.
602  */
603  surface m_Sx, m_Sy;
604 };
605 
606 // ----------------------------------------------------------------------------
607 
608 } // pcl
609 
610 #endif // __PCL_SurfacePolynomial_h
611 
612 // ----------------------------------------------------------------------------
613 // EOF pcl/SurfacePolynomial.h - Released 2024-12-28T16:53:48Z
size_type Length() const noexcept
Definition: Array.h:278
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:1918
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
void Evaluate(T *ZX, T *ZY, const T *X, const T *Y, size_type n) 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)
bool HasFastVectorEvaluation() const
SurfacePolynomial(const SurfacePolynomial &)=default
void Evaluate(T1 *Z, const T1 *X, const T1 *Y, size_type n) const
SurfacePolynomial(SurfacePolynomial &&)=default
Complex< T > Sqrt(const Complex< T > &c) noexcept
Definition: Complex.h:688
T PowI(T x, int n) noexcept
Definition: Math.h:1786
size_t size_type
Definition: Defs.h:609
constexpr const T & Max(const T &a, const T &b) noexcept
Definition: Utility.h:119
PCL root namespace.
Definition: AbstractImage.h:77