Add a pass in triangulation to create convex triangle fans. These triangles will have smaller bounding boxes and look better.
parent
b3eb589240
commit
575ddb5aaa
|
@ -131,6 +131,7 @@ public:
|
|||
void FindPointWithMinX();
|
||||
Vector AnyEdgeMidpoint() const;
|
||||
|
||||
bool IsEmptyTriangle(int ap, int bp, int cp, double scaledEPS) const;
|
||||
bool IsEar(int bp, double scaledEps) const;
|
||||
bool BridgeToContour(SContour *sc, SEdgeList *el, List<Vector> *vl);
|
||||
void ClipEarInto(SMesh *m, int bp, double scaledEps);
|
||||
|
|
|
@ -213,6 +213,41 @@ haveEdge:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SContour::IsEmptyTriangle(int ap, int bp, int cp, double scaledEPS) const {
|
||||
|
||||
STriangle tr = {};
|
||||
tr.a = l[ap].p;
|
||||
tr.b = l[bp].p;
|
||||
tr.c = l[cp].p;
|
||||
|
||||
// Accelerate with an axis-aligned bounding box test
|
||||
Vector maxv = tr.a, minv = tr.a;
|
||||
(tr.b).MakeMaxMin(&maxv, &minv);
|
||||
(tr.c).MakeMaxMin(&maxv, &minv);
|
||||
|
||||
Vector n = Vector::From(0, 0, -1);
|
||||
|
||||
int i;
|
||||
for(i = 0; i < l.n; i++) {
|
||||
if(i == ap || i == bp || i == cp) continue;
|
||||
|
||||
Vector p = l[i].p;
|
||||
if(p.OutsideAndNotOn(maxv, minv)) continue;
|
||||
|
||||
// A point on the edge of the triangle is considered to be inside,
|
||||
// and therefore makes it a non-ear; but a point on the vertex is
|
||||
// "outside", since that's necessary to make bridges work.
|
||||
if(p.EqualsExactly(tr.a)) continue;
|
||||
if(p.EqualsExactly(tr.b)) continue;
|
||||
if(p.EqualsExactly(tr.c)) continue;
|
||||
|
||||
if(tr.ContainsPointProjd(n, p)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SContour::IsEar(int bp, double scaledEps) const {
|
||||
int ap = WRAP(bp-1, l.n),
|
||||
cp = WRAP(bp+1, l.n);
|
||||
|
@ -308,6 +343,71 @@ void SContour::UvTriangulateInto(SMesh *m, SSurface *srf) {
|
|||
}
|
||||
l.RemoveTagged();
|
||||
|
||||
// Handle simple triangle fans all at once. This pass is optional.
|
||||
if(srf->degm == 1 && srf->degn == 1) {
|
||||
l.ClearTags();
|
||||
int j=0;
|
||||
int pstart = 0;
|
||||
double elen = -1.0;
|
||||
double oldspan = 0.0;
|
||||
for(i = 1; i < l.n; i++) {
|
||||
Vector ab = l[i].p.Minus(l[i-1].p);
|
||||
// first time just measure the segment
|
||||
if (elen < 0.0) {
|
||||
elen = ab.Dot(ab);
|
||||
oldspan = elen;
|
||||
j = 1;
|
||||
continue;
|
||||
}
|
||||
// check for consecutive segments of similar size which are also
|
||||
// ears and where the group forms a convex ear
|
||||
bool end = false;
|
||||
double ratio = ab.Dot(ab) / elen;
|
||||
if ((ratio < 0.25) || (ratio > 4.0)) end = true;
|
||||
|
||||
double slen = l[pstart].p.Minus(l[i].p).MagSquared();
|
||||
if (slen < oldspan) end = true;
|
||||
|
||||
if (!IsEar(i-1, scaledEps) ) end = true;
|
||||
// if ((j>0) && !IsEar(pstart, i-1, i, scaledEps)) end = true;
|
||||
if ((j>0) && !IsEmptyTriangle(pstart, i-1, i, scaledEps)) end = true;
|
||||
// the new segment is valid so add to the fan
|
||||
if (!end) {
|
||||
j++;
|
||||
oldspan = slen;
|
||||
}
|
||||
// we need to stop at the end of polygon but may still
|
||||
if (i == l.n-1) {
|
||||
end = true;
|
||||
}
|
||||
if (end) { // triangulate the fan and tag the verticies
|
||||
if (j > 3) {
|
||||
Vector center = l[pstart+1].p.Plus(l[pstart+j-1].p).ScaledBy(0.5);
|
||||
for (int x=0; x<j; x++) {
|
||||
STriangle tr = {};
|
||||
tr.a = center;
|
||||
tr.b = l[pstart+x].p;
|
||||
tr.c = l[pstart+x+1].p;
|
||||
m->AddTriangle(&tr);
|
||||
}
|
||||
for (int x=1; x<j; x++) {
|
||||
l[pstart+x].tag = 1;
|
||||
}
|
||||
STriangle tr = {};
|
||||
tr.a = center;
|
||||
tr.b = l[pstart+j].p;
|
||||
tr.c = l[pstart].p;
|
||||
m->AddTriangle(&tr);
|
||||
}
|
||||
pstart = i-1;
|
||||
elen = ab.Dot(ab);
|
||||
oldspan = elen;
|
||||
j = 1;
|
||||
}
|
||||
}
|
||||
l.RemoveTagged();
|
||||
} // end optional fan creation pass
|
||||
|
||||
bool toggle = false;
|
||||
while(l.n > 3) {
|
||||
int bestEar = -1;
|
||||
|
|
Loading…
Reference in New Issue