approximate_min_ellipsoid_d_impl.h

来自「很多二维 三维几何计算算法 C++ 类库」· C头文件 代码 · 共 282 行

H
282
字号
// Copyright (c) 1997-2001  ETH Zurich (Switzerland).// All rights reserved.//// This file is part of CGAL (www.cgal.org); you may redistribute it under// the terms of the Q Public License version 1.0.// See the file LICENSE.QPL distributed with CGAL.//// 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: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.3-branch/Approximate_min_ellipsoid_d/include/CGAL/Approximate_min_ellipsoid_d/Approximate_min_ellipsoid_d_impl.h $// $Id: Approximate_min_ellipsoid_d_impl.h 37145 2007-03-16 08:27:32Z afabri $// //// Author(s)     : Kaspar Fischer <fischerk@inf.ethz.ch>#include <CGAL/eigen_2.h>#include <CGAL/eigen.h>#include <CGAL/Approximate_min_ellipsoid_d.h>namespace CGAL {  template<class Traits>  void Approximate_min_ellipsoid_d<Traits>::  find_lower_dimensional_approximation()  {    // (No implementation yet, in accordance with the current    // specification in doc_tex ...)  }  template<class Traits>  void Approximate_min_ellipsoid_d<Traits>::  compute_center()  {    // According to (****), the computed ellipsoid E* has the representation    //    //   E* = { y in R^d | y^T M'/alpha y + 2/alpha y^Tm + (nu/alpha-1) <= 0 }    //     // for    //    //       [ M'  m  ]    //   M = [ m^T nu ]    //    // where M is the matrix defined via E->matrix(i,j).  We need    // something in the form    //    //    E* = { y | (y - c)^T M'/alpha (y - c) + mu <= 0 }.    //    // Expanding the later and comparing with the original form we    // obtain    //    //    c = - M'^{-1} m    //    // as the formula for the ellipsoid's center.  Comparing    // coefficients we also get    //    //    mu = nu/alpha-1 - c^T M'/alpha c     //       = nu/alpha-1 + c^T m / alpha    //       = (nu + c^Tm)/alpha - 1                               (********)    //    // In order to compute c, we will compute the inverse of M' and    // multiply with m.    // precondition checking:    CGAL_APPEL_ASSERT(!has_center);    // compute M'^{-1}:    mi.resize(d * d);    E->compute_inverse_of_submatrix(mi.begin());    // compute center:    center_.resize(d);    for (int i=0; i<d; ++i) {      FT ci(0);      for (int j=0; j<d; ++j)	ci += mi[i+d*j] * E->matrix(d,j);      center_[i] = -ci;    }    // remember that we have computed the center:    has_center = true;  }  template<class Traits>  void Approximate_min_ellipsoid_d<Traits>::  compute_axes_2_3()  {    // According to (****), the computed ellipsoid E* has the representation    //    //   E* = { y in R^d | y^T M'/alpha y + 2/alpha y^Tm + (nu/alpha-1) <= 0 }    //     // for    //    //       [ M'  m  ]    //   M = [ m^T nu ]    //    // where M is the matrix defined via E->matrix(i,j).  After caling    // compute_center() (see above), we have in center_ a point c such    // that    //     //   E* = { y | (y - c)^T M'/alpha (y - c) + mu <= 0 }.    //    // where mu = nu/alpha-1 - c^T M'/alpha c.    //    // Now if we can write M' = U D U^T holds for some diagonal matrix    // D and an orthogonal matrix U then the length l_i of the ith axes    // (corresponding to the ith "direcion" stored in the ith row of    // U) can be obtained by plugging (0,...,0,l_i,0,...,0)U^T=y-c into    // the above equation for E*:    //    //   l_i^2 d[i]/alpha = -mu,     //    // which gives l_i = sqrt(-mu*alpha/d[i]).    // precondition checking:    CGAL_APPEL_ASSERT(!has_axes && lengths_.size() == 0 &&		      directions_.size() == 0);    // compute M'^{-1}, if need be:    if (!has_center)      compute_center();    const double alpha = (1+achieved_epsilon()) * (d+1);    // compute mu according to (********):    double mu = E->matrix(d,d);    for (int i=0; i<d; ++i)      mu += center_[i] * E->matrix(d,i);    mu = mu/alpha - 1.0;    const double factor = -mu*alpha;        // compute Eigendecomposition:    if (d == 2)      compute_axes_2(alpha, factor);    else      compute_axes_3(alpha, factor);    // remember that we have computed the axes:    has_axes = true;  }  template<class Traits>  void Approximate_min_ellipsoid_d<Traits>::  compute_axes_2(const double /* alpha */, const double factor)  {    CGAL_APPEL_ASSERT(d==2);    typedef Cartesian<double> K;    typedef Vector_2<K> Vector_2;    // write matrix M' as [ a, b; b, c ]:    const double matrix[3] = { E->matrix(0, 0),   // a			       E->matrix(0, 1),   // b			       E->matrix(1, 1) }; // c        std::pair<Vector_2, Vector_2> eigenvectors; // Note: not neces. normalized.    std::pair<double, double>     eigenvalues;  // Note: sorted descendent.    CGALi::eigen_symmetric_2<K>(matrix, eigenvectors, eigenvalues);        // normalize eigenvectors:    double l1=1.0/std::sqrt(eigenvectors.first.x()*eigenvectors.first.x()+			    eigenvectors.first.y()*eigenvectors.first.y());    double l2=1.0/std::sqrt(eigenvectors.second.x()*eigenvectors.second.x()+			    eigenvectors.second.y()*eigenvectors.second.y());        // store axes lengths:    lengths_.push_back(std::sqrt(factor/eigenvalues.first));    lengths_.push_back(std::sqrt(factor/eigenvalues.second));        // store directions:    directions_.resize(2);    directions_[0].push_back(eigenvectors.first.x()*l1);    directions_[0].push_back(eigenvectors.first.y()*l1);    directions_[1].push_back(eigenvectors.second.x()*l2);    directions_[1].push_back(eigenvectors.second.y()*l2);  }    template<class Traits>  void Approximate_min_ellipsoid_d<Traits>::  compute_axes_3(const double /* alpha */, const double factor)  {    CGAL_APPEL_ASSERT(d==3);    // write matrix M' as    //    //        [ a b c ]    //   M' = [ b d e ]    //        [ c e f ]    //    const double matrix[6] = { E->matrix(0, 0),   // a			       E->matrix(0, 1),   // b			       E->matrix(1, 1),   // d			       E->matrix(0, 2),   // c			       E->matrix(1, 2),   // e			       E->matrix(2, 2) }; // f        double eigenvectors[3 * 3]; // Note: not necessarily normalized.    double eigenvalues[3];      // Note: sorted descendent.    CGALi::eigen_symmetric<double>(matrix, 3, eigenvectors, eigenvalues);        // normalize eigenvectors:    double l1 = 1.0/std::sqrt(eigenvectors[0] * eigenvectors[0]+  // x^2			      eigenvectors[1] * eigenvectors[1]+  // y^2			      eigenvectors[2] * eigenvectors[2]); // z^2    double l2 = 1.0/std::sqrt(eigenvectors[3] * eigenvectors[3]+  // x^2			      eigenvectors[4] * eigenvectors[4]+  // y^2			      eigenvectors[5] * eigenvectors[5]); // z^2    double l3 = 1.0/std::sqrt(eigenvectors[6] * eigenvectors[6]+  // x^2			      eigenvectors[7] * eigenvectors[7]+  // y^2			      eigenvectors[8] * eigenvectors[8]); // z^2        // store axes lengths:    for (int i=0; i<3; ++i)      lengths_.push_back(std::sqrt(factor/eigenvalues[i]));        // store directions:    directions_.resize(3);    directions_[0].push_back(eigenvectors[0]*l1);    directions_[0].push_back(eigenvectors[1]*l1);    directions_[0].push_back(eigenvectors[2]*l1);    directions_[1].push_back(eigenvectors[3]*l2);    directions_[1].push_back(eigenvectors[4]*l2);    directions_[1].push_back(eigenvectors[5]*l2);    directions_[2].push_back(eigenvectors[6]*l3);    directions_[2].push_back(eigenvectors[7]*l3);    directions_[2].push_back(eigenvectors[8]*l3);  }  template<class Traits>  void Approximate_min_ellipsoid_d<Traits>::  write_eps(const std::string& name)  {    CGAL_APPEL_ASSERT(d==2 && !is_degenerate());    namespace Impl = Approximate_min_ellipsoid_d_impl;    Impl::Eps_export_2 epsf(name,2.0);    epsf.set_label_mode(Impl::Eps_export_2::None);    // output the input points:    for (unsigned int k=0; k<P.size(); ++k) {      C_it pk = tco.cartesian_begin(P[k]);      const double u = to_double(*pk++);      const double v = to_double(*pk);      epsf.write_circle(u,v,0.0);    }    // output center:    Center_coordinate_iterator c = center_cartesian_begin();    const double cx = *c;    const double cy = *++c;    epsf.write_circle(cx, cy, 0.0, true); // (Note: last arg says to color.)    // output axes:    Axes_lengths_iterator axes = axes_lengths_begin();    const double a1 = *axes;    const double a2 = *++axes;    Axes_direction_coordinate_iterator d1 = axis_direction_cartesian_begin(0);    const double d1_x = *d1;    const double d1_y = *++d1;    Axes_direction_coordinate_iterator d2 = axis_direction_cartesian_begin(1);    const double d2_x = *d2;    const double d2_y = *++d2;    epsf.write_line(cx, cy, cx+a1*d1_x, cy+a1*d1_y, true);    epsf.write_line(cx, cy, cx+a2*d2_x, cy+a2*d2_y, true);    // output the inscribed ellipse:    const double alpha_inv = 1.0/((1+achieved_epsilon())*(d+1));    epsf.set_stroke_mode(Impl::Eps_export_2::Dashed);    epsf.write_ellipse(to_double(defining_matrix(0,0)*alpha_inv),		       to_double(defining_matrix(1,1)*alpha_inv),		       to_double(defining_matrix(0,1)*alpha_inv),		       to_double(defining_vector(0)*alpha_inv),		       to_double(defining_vector(1)*alpha_inv),		       to_double(defining_scalar()*alpha_inv-1.0));  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?