osg::DelaunayTriangular解析个人理解(一)

采用的驻点插入算法,距离是按平面来算的。z轴不算在内。
//class Triangle//只存储索引

public:

Triangle():
    a_(0),
    b_(0),
    c_(0) {}

//typedef GLuint Vertex_index;,三角形建立时即存储了索引值,points数组是已经排过序的顶点数组,
//排序函数是Sample_point_compare,x越大越靠前,x相同 y越大越在前,排序是为了能计算凸包,而且后插入算法时也有好处
Triangle(Vertex_index a, Vertex_index b, Vertex_index c, osg::Vec3Array *points)
: a_(a),
b_(b),
c_©,
cc_(compute_circumcircle((*points)[a_], (*points)[b_], (*points)[c_]))//函数解释见4
{
edge_[0] = Edge(a_, b_);//边的端点索引,
edge_[1] = Edge(b_, c_);
edge_[2] = Edge(c_, a_);
}//
class Edge {
public:

// Comparison object (for sorting)//比较对象类 方便排序
struct Less
{
//1边排序后的第一个端点,索引号的最小值,小于2边排序后的第一个端点,索引号的最小值返回true若大于返回false
//若相等,检查1边排序后的第二个端点,索引号的最大值,若小于2边排序后的第二个端点,索引号的最大值,返回true
//否则返回false,整个是为了把边按照边的起点按照索引号从大到小进行排序,若是起点索引号相同则按照终点从小到大排序
    inline bool operator()(const Edge &e1, const Edge &e2) const
    {
        if (e1.ibs() < e2.ibs()) return true;
        if (e1.ibs() > e2.ibs()) return false;
        if (e1.ies() < e2.ies()) return true;
        return false;
    }
};

Edge(): ib_(0), ie_(0), ibs_(0), ies_(0), duplicate_(false) {}
Edge(Vertex_index ib, Vertex_index ie) : ib_(ib), ie_(ie), ibs_(osg::minimum(ib, ie)), ies_(osg::maximum(ib, ie)), duplicate_(false) {}

// first endpoint第一个端点
inline Vertex_index ib() const { return ib_; }

// second endpoint第二个端点
inline Vertex_index ie() const { return ie_; }

// first sorted endpoint,排序后的第一个端点,索引号的最小值
inline Vertex_index ibs() const { return ibs_; }

// second sorted endpoint排序后的第儿个端点,索引号的最小值。
inline Vertex_index ies() const { return ies_; }

// get the "duplicate" flag复制;重复?
inline bool get_duplicate() const { return duplicate_; }

// set the "duplicate" flag
inline void set_duplicate(bool v) { duplicate_ = v; }

private:
Vertex_index ib_, ie_;
Vertex_index ibs_, ies_;
bool duplicate_;
};
// Compute the circumcircle of a triangle (only x and y coordinates are used),计算外接圆
// return (Cx, Cy, r^2) 返回的是坐标和半径,不是半径的平方
inline osg::Vec3 compute_circumcircle(
const osg::Vec3 &a,
const osg::Vec3 &b,
const osg::Vec3 &c)
{
float D =//为了计算退化状态的三角形,处于退化状态的三角形,半径会赋值1
(a.x() - c.x()) * (b.y() - c.y()) -
(b.x() - c.x()) * (a.y() - c.y());

float cx, cy, r2;

if(D==0.0)
{
    // (Nearly) degenerate condition - either two of the points are equal (which we discount)
    // or the three points are colinear. In this case we just determine the average of
    // the three points as the centre for correctness, but squirt out a zero radius.
    // This method will produce a triangulation with zero area, so we have to check later
    //(几乎)退化状态 - 两个点中的两个相等(我们打折)或三个点是共线的。 
    //在这种情况下,我们只确定三个点的平均值作为正确的中心,但是喷出零半径。 
    //这种方法会产生零区域的三角测量,所以我们必须稍后检查
    cx = (a.x()+b.x()+c.x())/3.0;
    cy = (a.y()+b.y()+c.y())/3.0;
    r2 = 0.0;
}
else
{
    cx =
    (((a.x() - c.x()) * (a.x() + c.x()) +
    (a.y() - c.y()) * (a.y() + c.y())) / 2 * (b.y() - c.y()) -
    ((b.x() - c.x()) * (b.x() + c.x()) +
    (b.y() - c.y()) * (b.y() + c.y())) / 2 * (a.y() - c.y())) / D;

    cy =
    (((b.x() - c.x()) * (b.x() + c.x()) +
    (b.y() - c.y()) * (b.y() + c.y())) / 2 * (a.x() - c.x()) -
    ((a.x() - c.x()) * (a.x() + c.x()) +
    (a.y() - c.y()) * (a.y() + c.y())) / 2 * (b.x() - c.x())) / D;

  //  r2 = (c.x() - cx) * (c.x() - cx) + (c.y() - cy) * (c.y() - cy);
    // the return r square is compared with r*r many times in an inner loop
    // so for efficiency use the inefficient sqrt once rather than 30* multiplies later.
    r2 = sqrt((c.x() - cx) * (c.x() - cx) + (c.y() - cy) * (c.y() - cy));
}
return osg::Vec3(cx, cy, r2);

}
构建三角网
for (osg::Vec3Array::const_iterator i=points->begin(); i!=points->end(); ++i, ++pidx)
{

    // don't process supertriangle vertices
    if (pidx > last_valid_index) break;

    Edge_set edges;//typedef std::set<Edge, Edge::Less> Edge_set;,以Less()为评判标准进行排序,Less是仿函数,

    // iterate through triangles
    Triangle_list::iterator j, next_j;
    //初始的triangles是两个初始三角形,能包含所有的顶点。
    for (j=triangles.begin(); j!=triangles.end(); j = next_j)
    {
       //j是存储三角形的地方,i是输入的排序好的顶点数组
        next_j = j;
        ++next_j;

        // get the circumcircle (x,y centre & radius)
        osg::Vec3 cc = j->get_circumcircle();

        // OPTIMIZATION: since points are pre-sorted by the X component,
        // check whether we can discard this triangle for future operations
        float xdist = i->x() - cc.x();//?要是小于零了怎么办只是为了消除一些三角形,可以暂且略过
        // this is where the circumcircles radius rather than R^2 is faster.
        // original code used r^2 and needed to test xdist*xdist>cc.z && i->x()>cc.x().
        if ((xdist ) > cc.z() )
        {
            discarded_tris.push_back(*j); // these are not needed for further tests as no more
            // points will ever lie inside this triangle.
            triangles.erase(j);
        }
        else
        {

            // if the point lies in the triangle's circumcircle then add
            // its edges to the edge list and remove the triangle//开始逐点插入,采用空外接圆准则
            if (point_in_circle(*i, cc))
            {
                for (int ei=0; ei<3; ++ei)
                {
                //pair的实现是一个结构体,主要的两个成员变量是first second 因为是使用struct不是class,所以可以直接使用pair的成员变量。
                //pair的一个新用法,参考CSDN:https://blog.csdn.net/hailong0715/article/details/51381680
                //若是有点在三角形内部,执行,边留下,三角形删除。而且存储的是set数据,若是有重复边则执行if语句里的内容,让edge类的_duplicate变量
                //设为true
                    std::pair<Edge_set::iterator, bool> result = edges.insert(j->get_edge(ei));
                    if (!result.second)
                    {
                        // cast away constness of a set element, which is
                        // safe in this case since the set_duplicate is
                        // not used as part of the Less operator.
                        Edge& edge = const_cast<Edge&>(*(result.first));
                        // not clear why this change is needed? But prevents removal of twice referenced edges??
                  //      edge.set_duplicate(true);
                        edge.set_duplicate(!edge.get_duplicate());
                    }
                }
                triangles.erase(j);
            }
        }
    }

    // remove duplicate edges and add new triangles
    Edge_set::iterator ci;
    for (ci=edges.begin(); ci!=edges.end(); ++ci)
    {
        if (!ci->get_duplicate())
        {    //pidx是一个记录索引的值 与osg::Vec3Array::const_iterator i 同步。   
            triangles.push_back(Triangle(pidx, ci->ib(), ci->ie(), points));
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值