// Copyright (c) 2015 GeometryFactory (France), All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 3 of the License, // or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // // Author(s) : Simon Giraudot #ifndef CGAL_DIAGONALIZE_TRAITS_H #define CGAL_DIAGONALIZE_TRAITS_H #include #include #include #include #include namespace CGAL { /// A model of the concept `DiagonalizeTraits` /// \cgalModels `DiagonalizeTraits` template class Diagonalize_traits{ public: typedef cpp11::array Vector; typedef cpp11::array Matrix; typedef cpp11::array Covariance_matrix; static bool diagonalize_selfadjoint_covariance_matrix (const Covariance_matrix& cov, Vector& eigenvalues) { Matrix eigenvectors; return diagonalize_selfadjoint_covariance_matrix (cov, eigenvalues, eigenvectors); } // Extract the eigenvector associated to the largest eigenvalue static bool extract_largest_eigenvector_of_covariance_matrix (const Covariance_matrix& cov, Vector& normal) { Vector eigenvalues; Matrix eigenvectors; diagonalize_selfadjoint_covariance_matrix (cov, eigenvalues, eigenvectors); for (std::size_t i = 0; i < dim; ++ i) normal[i] = static_cast (eigenvectors[(dim*(dim-1))+i]); return true; } static bool diagonalize_selfadjoint_covariance_matrix (const Covariance_matrix& mat, Vector& eigen_values, Matrix& eigen_vectors) { const int n = dim; const int MAX_ITER = 100; static const FT EPSILON = (FT)0.00001; // number of entries in mat int nn = (n*(n+1))/2; // copy matrix FT *a = new FT[nn]; int ij; // This function requires lower triangular, so we switch for (int i = 0; i < n; ++ i) for (int j = i; j < n; ++ j) a[(n * i) + j - ((i * (i+1)) / 2)] = mat[i + (j * (j+1) / 2)]; // Fortran-porting a--; // init diagonalization matrix as the unit matrix FT *v = new FT[n*n]; ij = 0; int i; for(i=0; i a_normEPS && nb_iter < MAX_ITER) { nb_iter++; FT thr_nn = thr / nn; for(int l=1; l< n; l++) { for(int m=l+1; m<=n; m++) { // compute sinx and cosx int lq = (l*l-l)/2; int mq = (m*m-m)/2; int lm = l + mq; FT a_lm = a[lm]; FT a_lm_2 = a_lm * a_lm; if(a_lm_2 < thr_nn) continue; int ll = l + lq; int mm = m + mq; FT a_ll = a[ll]; FT a_mm = a[mm]; FT delta = a_ll - a_mm; FT x; if(delta == 0.0) x = (FT) - CGAL_PI / 4; else x = (FT)(- std::atan( (a_lm+a_lm) / delta ) / 2.0); FT sinx = std::sin(x); FT cosx = std::cos(x); FT sinx_2 = sinx * sinx; FT cosx_2 = cosx * cosx; FT sincos = sinx * cosx; // rotate L and M columns int ilv = n*(l-1); int imv = n*(m-1); int i; for( i=1; i<=n;i++ ) { if( (i!=l) && (i!=m) ) { int iq = (i*i-i)/2; int im; if( i eigen_values[j]) { k = j; x = eigen_values[j]; } eigen_values[k] = eigen_values[i]; eigen_values[i] = x; int jj = index[k]; index[k] = index[i]; index[i] = jj; } // save eigen vectors v++; // back to C++ ij = 0; for(int k=0; k