Skip to content

Commit

Permalink
Add a pass in triangulation to create convex triangle fans. These tri…
Browse files Browse the repository at this point in the history
…angles will have smaller bounding boxes and look better.
  • Loading branch information
phkahler committed Jul 22, 2020
1 parent e0fa99b commit 3de9f3b
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/polygon.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class SContour {
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);
Expand Down
100 changes: 100 additions & 0 deletions src/srf/triangulate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,41 @@ bool SContour::BridgeToContour(SContour *sc,
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);
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 3de9f3b

Please sign in to comment.