【问题标题】:Is there a way to generate 2D stretched mesh using CGAL?有没有办法使用 CGAL 生成 2D 拉伸网格?
【发布时间】:2017-06-05 11:06:58
【问题描述】:

我目前使用 CGAL 生成 2D Delaunay 三角剖分。其中一个网格控制参数是三角形边的最大长度。这些例子表明这个参数是一个常数。我想知道如何使这个参数成为其他事物的函数,例如空间位置。

【问题讨论】:

    标签: mesh cgal delaunay stretched


    【解决方案1】:

    我认为 CGAL 不直接支持具有可变密度的 Delaunay 网格划分,尽管您可以独立地划分区域。或者,您可以查看:http://www.geom.at/advanced-mesh-generation/ 我已将其实现为回调函数。

    【讨论】:

      【解决方案2】:

      我也对 CGAL 域上的可变网格标准感兴趣。多年前我找到了替代方案:https://www.cs.cmu.edu/~quake/triangle.html

      但我仍然有兴趣用 CGAL 做同样的事情......我不知道这是否可能......

      【讨论】:

      • 这不是答案:应该将其移至对原始问题的评论。
      • 很抱歉,我无法在原始问题下发表评论,因为我“没有 50 名声望”。此外,也许该链接可以被视为 user6386155 想要做什么的答案。
      【解决方案3】:

      CGAL 似乎没有提供这方面的示例,但他们的机器都在那里。细节变得有点复杂,因为控制三角形是否需要细化的对象还必须了解三角形被细化的优先级。

      为此,我复制了 Delaunay_mesh_size_criteria_2 以创建一个新类 (Delaunay_mesh_user_criteria_2),该类具有空间变化的大小字段。埋在类中的是一个函数(user_sizing_field),可以根据位置使用不同大小的字段来实现。下面的代码将三角形最长边的大小与三个顶点处的最小尺寸字段的尺寸进行比较,但您可以使用重心或外心的尺寸,甚至将整个三角形发送到尺寸功能完全计算三角形上允许的最小尺寸的好方法。

      这是一个起点,虽然更好的解决方案会,

      • 重构一些东西以避免与现有的 Delaunay_mesh_size_criteria 重复,
      • 允许用户将大小调整函数作为参数传递给条件对象,并且
      • 与 CGAL 一起发货。
      template <class CDT>
      class Delaunay_mesh_user_criteria_2 : 
          public virtual Delaunay_mesh_criteria_2<CDT>
      {
      protected:
        typedef typename CDT::Geom_traits Geom_traits;
        double sizebound;
      
      public:
        typedef Delaunay_mesh_criteria_2<CDT> Base;
      
        Delaunay_mesh_user_criteria_2(const double aspect_bound = 0.125,
                                      const Geom_traits& traits = Geom_traits())
          : Base(aspect_bound, traits){}
      
        // first: squared_minimum_sine
        // second: size
        struct Quality : public std::pair<double, double>
        {
          typedef std::pair<double, double> Base;
      
          Quality() : Base() {};
          Quality(double _sine, double _size) : Base(_sine, _size) {}
      
          const double& size() const { return second; }
          const double& sine() const { return first; }
      
          // q1<q2 means q1 is prioritised over q2
          // ( q1 == *this, q2 == q )
          bool operator<(const Quality& q) const
          {
            if( size() > 1 )
              if( q.size() > 1 )
                return ( size() > q.size() );
              else
                return true; // *this is big but not q
            else
              if( q.size() >  1 )
                return false; // q is big but not *this
            return( sine() < q.sine() );
          }
      
          std::ostream& operator<<(std::ostream& out) const
          {
            return out << "(size=" << size()
               << ", sine=" << sine() << ")";
          }
        };
      
        class Is_bad: public Base::Is_bad
        {
        public:
          typedef typename Base::Is_bad::Point_2 Point_2;
      
          Is_bad(const double aspect_bound,
                 const Geom_traits& traits)
            : Base::Is_bad(aspect_bound, traits) {}
      
          Mesh_2::Face_badness operator()(const Quality q) const
          {
            if( q.size() > 1 )
              return Mesh_2::IMPERATIVELY_BAD;
            if( q.sine() < this->B )
              return Mesh_2::BAD;
            else
          return Mesh_2::NOT_BAD;
          }
      
          double user_sizing_function(const Point_2 p) const
          {
            // IMPLEMENT YOUR CUSTOM SIZING FUNCTION HERE.
            // BUT MAKE SURE THIS RETURNS SOMETHING LARGER
            // THAN ZERO TO ALLOW THE ALGORITHM TO TERMINATE
            return std::abs(p.x()) + .025;
          }
      
          Mesh_2::Face_badness operator()(const typename CDT::Face_handle& fh,
                          Quality& q) const
          {
            typedef typename CDT::Geom_traits Geom_traits;
            typedef typename Geom_traits::Compute_area_2 Compute_area_2;
            typedef typename Geom_traits::Compute_squared_distance_2 Compute_squared_distance_2;
      
            Geom_traits traits; /** @warning traits with data!! */
      
            Compute_squared_distance_2 squared_distance = 
              traits.compute_squared_distance_2_object();
      
            const Point_2& pa = fh->vertex(0)->point();
            const Point_2& pb = fh->vertex(1)->point();
            const Point_2& pc = fh->vertex(2)->point();
      
            double size_bound = std::min(std::min(user_sizing_function(pa),
                                                  user_sizing_function(pb)),
                                         user_sizing_function(pc));
            double
              a = CGAL::to_double(squared_distance(pb, pc)),
              b = CGAL::to_double(squared_distance(pc, pa)),
              c = CGAL::to_double(squared_distance(pa, pb));
      
            double max_sq_length; // squared max edge length
            double second_max_sq_length;
      
            if(a<b)
            {
              if(b<c) {
                max_sq_length = c;
                second_max_sq_length = b;
              }
              else { // c<=b
                max_sq_length = b;
                second_max_sq_length = ( a < c ? c : a );
              }
            }
            else // b<=a
            {
              if(a<c) {
                max_sq_length = c;
                second_max_sq_length = a;
              }
              else { // c<=a
                max_sq_length = a;
                second_max_sq_length = ( b < c ? c : b );
              }
            }
      
            q.second = 0;
      
            q.second = max_sq_length / (size_bound*size_bound);
            // normalized by size bound to deal
            // with size field
            if( q.size() > 1 )
            {
              q.first = 1; // (do not compute sine)
              return Mesh_2::IMPERATIVELY_BAD;
            }
      
            Compute_area_2 area_2 = traits.compute_area_2_object();
      
            double area = 2*CGAL::to_double(area_2(pa, pb, pc));
      
            q.first = (area * area) / (max_sq_length * second_max_sq_length); // (sine)
      
            if( q.sine() < this->B )
              return Mesh_2::BAD;
            else
              return Mesh_2::NOT_BAD;
          }
        };
      
        Is_bad is_bad_object() const
        { return Is_bad(this->bound(), this->traits /* from the bad class */); }
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-10
        • 1970-01-01
        • 1970-01-01
        • 2017-06-06
        • 1970-01-01
        • 2016-02-14
        相关资源
        最近更新 更多