采用的驻点插入算法,距离是按平面来算的。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));
}
}
}