From 04826e29aa3641a89f74e2484a4988105e8f2a01 Mon Sep 17 00:00:00 2001 From: Pierre Alliez Date: Thu, 16 Mar 2006 22:52:57 +0000 Subject: [PATCH] tests performed for points on a line in 2D Doc: added definitions, did many fixes. IMPORTANT: sylvain: double-check the definitions, and precise the dimension and types available for each of your function. important change: I suggest to rename the function bounding_box to axis_aligned_bounding_box (min case later you will hack on the general one). --- .../windows/2d/pca.rc | 7 +++++- .../windows/2d/pcaDlg.cpp | 25 ++++++++++++++++++- .../windows/2d/pcaDlg.h | 1 + .../windows/2d/resource.h | 4 ++- .../Principal_component_analysis/intro.tex | 19 ++------------ .../Principal_component_analysis/main.tex | 2 +- .../intro.tex | 22 +++++++++++----- .../bounding_box.C | 12 ++++----- .../include/CGAL/eigen_2.h | 7 ++++-- .../CGAL/linear_least_squares_fitting_3.h | 6 ----- 10 files changed, 64 insertions(+), 41 deletions(-) diff --git a/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pca.rc b/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pca.rc index 7624ea450f6..3fc9df3685e 100644 --- a/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pca.rc +++ b/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pca.rc @@ -210,7 +210,12 @@ BEGIN POPUP "&Fit" BEGIN MENUITEM "&Line", ID_FIT_LINE - MENUITEM "Debug", ID_FIT_DEBUG + POPUP "Debug" + BEGIN + MENUITEM "Many tests for 2 points", ID_FIT_DEBUG + MENUITEM "Many points on a line", ID_DEBUG_MANYTESTSFORNUMEROUSPOINTSONALINE + + END END END diff --git a/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pcaDlg.cpp b/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pcaDlg.cpp index c9169515732..9e15c4f4988 100644 --- a/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pcaDlg.cpp +++ b/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pcaDlg.cpp @@ -90,6 +90,7 @@ BEGIN_MESSAGE_MAP(CpcaDlg, CDialog) ON_COMMAND(ID_RANDOM_HORIZONTALLINE, OnRandomHorizontalline) ON_COMMAND(ID_RANDOM_VERTICALLINE, OnRandomVerticalline) ON_COMMAND(ID_FIT_DEBUG, OnFitDebug) + ON_COMMAND(ID_DEBUG_MANYTESTSFORNUMEROUSPOINTSONALINE, OnDebugManytestsfornumerouspointsonaline) END_MESSAGE_MAP() @@ -469,13 +470,35 @@ void CpcaDlg::OnRandomVerticalline() } void CpcaDlg::OnFitDebug() +{ + BeginWaitCursor(); + for(int i=0;i<10000;i++) + { + m_points.clear(); + double x1 = (double)rand() / (double)RAND_MAX; + double y1 = (double)rand() / (double)RAND_MAX; + double x2 = (double)rand() / (double)RAND_MAX; + double y2 = (double)rand() / (double)RAND_MAX; + m_points.push_back(Point_2(x1,y1)); + m_points.push_back(Point_2(x2,y2)); + OnFitLine(); + } + EndWaitCursor(); + InvalidateRect(NULL,FALSE); +} + +void CpcaDlg::OnDebugManytestsfornumerouspointsonaline() { BeginWaitCursor(); m_points.clear(); + + // random line (y = ax + b) + double a = (double)rand() / (double)RAND_MAX; + double b = (double)rand() / (double)RAND_MAX; for(int i=0;i<10000;i++) { double x = (double)rand() / (double)RAND_MAX; - double y = (double)rand() / (double)RAND_MAX; + double y = a * x + b; m_points.push_back(Point_2(x,y)); } OnFitLine(); diff --git a/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pcaDlg.h b/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pcaDlg.h index 126db1ca909..436f493046f 100644 --- a/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pcaDlg.h +++ b/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/pcaDlg.h @@ -80,4 +80,5 @@ public: afx_msg void OnRandomHorizontalline(); afx_msg void OnRandomVerticalline(); afx_msg void OnFitDebug(); + afx_msg void OnDebugManytestsfornumerouspointsonaline(); }; diff --git a/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/resource.h b/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/resource.h index 4f8a0db2e2c..6bfbe04a84c 100644 --- a/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/resource.h +++ b/Principal_component_analysis/demo/Principal_component_analysis/windows/2d/resource.h @@ -20,13 +20,15 @@ #define ID_RANDOM_HORIZONTALLINE 32781 #define ID_RANDOM_VERTICALLINE 32782 #define ID_FIT_DEBUG 32783 +#define ID_FIT_DEBUG32784 32784 +#define ID_DEBUG_MANYTESTSFORNUMEROUSPOINTSONALINE 32785 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 132 -#define _APS_NEXT_COMMAND_VALUE 32784 +#define _APS_NEXT_COMMAND_VALUE 32786 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/Principal_component_analysis/doc_tex/Principal_component_analysis/intro.tex b/Principal_component_analysis/doc_tex/Principal_component_analysis/intro.tex index a106f274570..f02fa861cd0 100644 --- a/Principal_component_analysis/doc_tex/Principal_component_analysis/intro.tex +++ b/Principal_component_analysis/doc_tex/Principal_component_analysis/intro.tex @@ -1,20 +1,5 @@ This \cgal\ package provides functions to compute global informations -on the shape of a set of 2D or 3D objects such as points. It provides the computation of bounding boxes, centroids of point sets, barycenters of weighted point sets, as well as linear least squares fitting. - -Linear least squares fitting approximates a set of objects by a linear -sub-space such as a line or a plane. Formally, given a set of points in $R^d$, linear least squares fitting amounts -to find the linear sub-space of $R^d$ which minimizes the sum of squared -distances from the points to their projection onto this linear sub-space. This -problem is equivalent to search for the linear sub-space which maximizes the -variance of projected points, the latter being obtained by eigen decomposition -of the covariance matrix. Eigenvectors corresponding to large eigenvalues are -the directions in which the data has strong component, or equivalently large -variance. If eigenvalues are the same there is no preferable sub-space. -This package implements the linear least squares fitting for -several objects of a \cgal\ 2D or 3D kernel: the best fit 2D line for 2D -point sets, and the best fit 3D line or plane for point and -triangle sets. The object sets are specified by iterator ranges of -containers. +on the shape of a set of 2D or 3D objects such as points. It provides the computation of axis-aligned bounding boxes, centroids of point sets, barycenters of weighted point sets, as well as linear least squares fitting for point sets in 2D, and point sets as well as triangle sets in 3D. The sets are specified by iterator ranges of containers.\\ \begin{center} \label{fit} @@ -23,7 +8,7 @@ containers. \includegraphics[width=1.0\textwidth]{Principal_component_analysis/fit} \end{ccTexOnly} \begin{ccHtmlOnly} -

+

\end{ccHtmlOnly} % Title \begin{figure}[h] diff --git a/Principal_component_analysis/doc_tex/Principal_component_analysis/main.tex b/Principal_component_analysis/doc_tex/Principal_component_analysis/main.tex index 72d20e71f62..e2547e3b23c 100644 --- a/Principal_component_analysis/doc_tex/Principal_component_analysis/main.tex +++ b/Principal_component_analysis/doc_tex/Principal_component_analysis/main.tex @@ -13,7 +13,7 @@ \subsection{Bounding Box of a Point Set} In the following example we use \stl\ containers of 2D and 3D points, and -compute their bounding box. The kernel from which the input points +compute their axis-aligned bounding box. The kernel from which the input points come is automatically deduced by the function. \ccIncludeExampleCode{Principal_component_analysis/bounding_box.C} diff --git a/Principal_component_analysis/doc_tex/Principal_component_analysis_ref/intro.tex b/Principal_component_analysis/doc_tex/Principal_component_analysis_ref/intro.tex index 6339621d76a..c7123936481 100644 --- a/Principal_component_analysis/doc_tex/Principal_component_analysis_ref/intro.tex +++ b/Principal_component_analysis/doc_tex/Principal_component_analysis_ref/intro.tex @@ -15,20 +15,30 @@ \subsection*{Summary} This \cgal\ package provides functions to compute global informations -on the shape of a set of 2D or 3D objects such as points. It provides the computation of bounding boxes, centroids of point sets, barycenters of weighted point sets, as well as linear least squares fitting. It assumes the set of kernel primitive elements to be stored into an iterator range of a container. +on the shape of a set of 2D or 3D objects such as points. It provides the computation of axis-aligned bounding boxes for point sets, centroids of point sets and triangle sets in 2D and 3D, barycenters of weighted point sets, as well as linear least squares fitting for point sets in 2D, and point sets and triangle sets in 3D. It assumes the set of kernel primitive elements to be stored into an iterator range of a container. +\subsection*{Definitions} -\subsection*{Definition} -Given a point set in $R^d$, linear least squares fitting amounts to -find the linear sub-space of $R^d$ which minimizes the sum of squared +A \emph{bounding box} for a set of objects is a cuboid that completely +contains the set. An \emph{axis-aligned bounding box} is a bounding box +aligned with the axes of the coordinate system.\\ + +A \emph{centroid} is defined as average of position. A \emph{barycenter} of weighted point sets is defined as weighted average of position. When all weights are equal the barycenter coincides with the centroid.\\ + +Given a point set, \emph{linear least squares fitting} amounts to +find the linear sub-space which minimizes the sum of squared distances from the points to their projection onto this linear sub-space. This problem is equivalent to search for the linear sub-space which maximizes the variance of projected points, the latter being obtained by eigen decomposition of the covariance -matrix. Eigenvectors corresponding to large eigenvalues are the +matrix of the point set. Eigenvectors corresponding to large eigenvalues are the directions in which the data has strong component, or equivalently large variance. If eigenvalues are the same there is no preferable -sub-space. +sub-space.\\ + +Given a triangle set, \emph{linear least squares fitting} amounts to find the linear sub-space which minimizes the sum of squared +distances from all points in the set to their projection onto this linear +sub-space. This problem is equivalent to the one of fitting a linear sub-space to a point set, except that the covariance matrix is now derived from a continuous integral over the triangles instead of a discrete sum over the points. \ccHeading{Functions} diff --git a/Principal_component_analysis/examples/Principal_component_analysis/bounding_box.C b/Principal_component_analysis/examples/Principal_component_analysis/bounding_box.C index 437519a0ed9..1eae2119395 100644 --- a/Principal_component_analysis/examples/Principal_component_analysis/bounding_box.C +++ b/Principal_component_analysis/examples/Principal_component_analysis/bounding_box.C @@ -6,14 +6,14 @@ #include #include -typedef double FT; -typedef CGAL::Cartesian K; -typedef K::Point_2 Point_2; -typedef K::Point_3 Point_3; +typedef double FT; +typedef CGAL::Cartesian K; +typedef K::Point_2 Point_2; +typedef K::Point_3 Point_3; int main() { - // bounding_box of 2D points + // axis-aligned bounding box of 2D points std::list points_2; points_2.push_back(Point_2(1.0, 0.0)); points_2.push_back(Point_2(2.0, 2.0)); @@ -22,7 +22,7 @@ int main() K::Iso_rectangle_2 c2 = CGAL::bounding_box(points_2.begin(), points_2.end()); std::cout << c2 << std::endl; - // bounding_box of 3D points + // axis-aligned bounding box of 3D points std::list points_3; points_3.push_back(Point_3(1.0, 0.0, 0.5)); points_3.push_back(Point_3(2.0, 2.0, 1.2)); diff --git a/Principal_component_analysis/include/CGAL/eigen_2.h b/Principal_component_analysis/include/CGAL/eigen_2.h index a1d70a59730..86c27d61802 100644 --- a/Principal_component_analysis/include/CGAL/eigen_2.h +++ b/Principal_component_analysis/include/CGAL/eigen_2.h @@ -25,8 +25,9 @@ CGAL_BEGIN_NAMESPACE namespace CGALi { - // extract eigenvalues and eigenvectors from a 2x2 symmetric matrix. - // Note: involves a square root. + // extract eigenvalues and eigenvectors from a 2x2 symmetric + // positive definite matrix. + // Note: computations involve a square root. // Matrix numbering: // a b // b c @@ -48,6 +49,8 @@ namespace CGALi { FT c = matrix[2]; FT p = c*c - 2*a*c + 4*b*b + a*a; + CGAL_assertion(a >= 0.0 && c >= 0.0); + // degenerate or isotropic case if(p == 0.0) { diff --git a/Principal_component_analysis/include/CGAL/linear_least_squares_fitting_3.h b/Principal_component_analysis/include/CGAL/linear_least_squares_fitting_3.h index bcaf418c59a..9b9f423cdf9 100644 --- a/Principal_component_analysis/include/CGAL/linear_least_squares_fitting_3.h +++ b/Principal_component_analysis/include/CGAL/linear_least_squares_fitting_3.h @@ -152,9 +152,6 @@ fitting_plane_3(const typename K::FT covariance[6], // covariance matrix FT eigen_values[3]; FT eigen_vectors[9]; eigen_symmetric(covariance,3,eigen_vectors,eigen_values); - CGAL_assertion(eigen_values[0] >= 0.0 && - eigen_values[1] >= 0.0 && - eigen_values[2] >= 0.0); // check unicity and build fitting line accordingly if(eigen_values[0] != eigen_values[1] && @@ -199,9 +196,6 @@ fitting_line_3(const typename K::FT covariance[6], // covariance matrix FT eigen_values[3]; FT eigen_vectors[9]; eigen_symmetric(covariance,3,eigen_vectors,eigen_values); - CGAL_assertion(eigen_values[0] >= 0.0 && - eigen_values[1] >= 0.0 && - eigen_values[2] >= 0.0); // check unicity and build fitting line accordingly if(eigen_values[0] != eigen_values[1])