Fix #693 issues.
This set of changes covers all triangulation errors in issue 693. A point coincident with a triangle vertex is OK and needed for bridges, but sometimes the middle point has edges cutting through the triangle that make it a non-ear. We fix that and a couple of off-by-one error (that fixes one of the test cases).pull/697/head
parent
0413c1b926
commit
705249627a
|
@ -124,7 +124,7 @@ bool SContour::BridgeToContour(SContour *sc,
|
||||||
// to the leftmost point of the new segment.
|
// to the leftmost point of the new segment.
|
||||||
int thiso = 0;
|
int thiso = 0;
|
||||||
double dmin = 1e10;
|
double dmin = 1e10;
|
||||||
for(i = 0; i < l.n; i++) {
|
for(i = 0; i < l.n-1; i++) {
|
||||||
Vector p = l[i].p;
|
Vector p = l[i].p;
|
||||||
double d = (p.Minus(sc->xminPt)).MagSquared();
|
double d = (p.Minus(sc->xminPt)).MagSquared();
|
||||||
if(d < dmin) {
|
if(d < dmin) {
|
||||||
|
@ -140,7 +140,7 @@ bool SContour::BridgeToContour(SContour *sc,
|
||||||
// First check if the contours share a point; in that case we should
|
// First check if the contours share a point; in that case we should
|
||||||
// merge them there, without a bridge.
|
// merge them there, without a bridge.
|
||||||
for(i = 0; i < l.n; i++) {
|
for(i = 0; i < l.n; i++) {
|
||||||
thisp = WRAP(i+thiso, l.n);
|
thisp = WRAP(i+thiso, l.n-1);
|
||||||
a = l[thisp].p;
|
a = l[thisp].p;
|
||||||
|
|
||||||
for(f = avoidPts->First(); f; f = avoidPts->NextAfter(f)) {
|
for(f = avoidPts->First(); f; f = avoidPts->NextAfter(f)) {
|
||||||
|
@ -256,6 +256,28 @@ bool SContour::IsEmptyTriangle(int ap, int bp, int cp, double scaledEPS) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test if ray b->d passes through triangle a,b,c
|
||||||
|
static bool RayIsInside(Vector a, Vector c, Vector b, Vector d) {
|
||||||
|
// coincident edges are not considered to intersect the triangle
|
||||||
|
if (d.Equals(a)) return false;
|
||||||
|
if (d.Equals(c)) return false;
|
||||||
|
// if d and c are on opposite sides of ba, we are ok
|
||||||
|
// likewise if d and a are on opposite sides of bc
|
||||||
|
Vector ba = a.Minus(b);
|
||||||
|
Vector bc = c.Minus(b);
|
||||||
|
Vector bd = d.Minus(b);
|
||||||
|
|
||||||
|
// perpendicular to (x,y) is (x,-y) so dot that with the two points. If they
|
||||||
|
// have opposite signs their product will be negative. If bd and bc are on
|
||||||
|
// opposite sides of ba the ray does not intersect. Likewise for bd,ba and bc.
|
||||||
|
if ( (bd.x*(ba.y) + (bd.y * (-ba.x))) * ( bc.x*(ba.y) + (bc.y * (-ba.x))) < LENGTH_EPS)
|
||||||
|
return false;
|
||||||
|
if ( (bd.x*(bc.y) + (bd.y * (-bc.x))) * ( ba.x*(bc.y) + (ba.y * (-bc.x))) < LENGTH_EPS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool SContour::IsEar(int bp, double scaledEps) const {
|
bool SContour::IsEar(int bp, double scaledEps) const {
|
||||||
int ap = WRAP(bp-1, l.n),
|
int ap = WRAP(bp-1, l.n),
|
||||||
cp = WRAP(bp+1, l.n);
|
cp = WRAP(bp+1, l.n);
|
||||||
|
@ -294,8 +316,19 @@ bool SContour::IsEar(int bp, double scaledEps) const {
|
||||||
// and therefore makes it a non-ear; but a point on the vertex is
|
// and therefore makes it a non-ear; but a point on the vertex is
|
||||||
// "outside", since that's necessary to make bridges work.
|
// "outside", since that's necessary to make bridges work.
|
||||||
if(p.EqualsExactly(tr.a)) continue;
|
if(p.EqualsExactly(tr.a)) continue;
|
||||||
if(p.EqualsExactly(tr.b)) continue;
|
|
||||||
if(p.EqualsExactly(tr.c)) continue;
|
if(p.EqualsExactly(tr.c)) continue;
|
||||||
|
// points coincident with bp have to be allowed for bridges but edges
|
||||||
|
// from that other point must not cross through our triangle.
|
||||||
|
if(p.EqualsExactly(tr.b)) {
|
||||||
|
int j = WRAP(i-1, l.n);
|
||||||
|
int k = WRAP(i+1, l.n);
|
||||||
|
Vector jp = l[j].p;
|
||||||
|
Vector kp = l[k].p;
|
||||||
|
|
||||||
|
// check both edges from the point in question
|
||||||
|
if (!RayIsInside(tr.a, tr.c, p,jp) && !RayIsInside(tr.a, tr.c, p,kp))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(tr.ContainsPointProjd(n, p)) {
|
if(tr.ContainsPointProjd(n, p)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -349,6 +382,9 @@ void SContour::UvTriangulateInto(SMesh *m, SSurface *srf) {
|
||||||
l[i].tag = 1;
|
l[i].tag = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( (l[0].p).Equals(l[l.n-1].p) ) {
|
||||||
|
l[l.n-1].tag = 1;
|
||||||
|
}
|
||||||
l.RemoveTagged();
|
l.RemoveTagged();
|
||||||
|
|
||||||
// Handle simple triangle fans all at once. This pass is optional.
|
// Handle simple triangle fans all at once. This pass is optional.
|
||||||
|
|
Loading…
Reference in New Issue