/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ /* */ #include #include #include #include #include #define DEBUG 1 typedef struct { float x; float y; } Point2D; typedef struct { int first; int second; int tri1; int tri2; } edge; static int CheckThem(Triangle *, Triangle *, int); static int InTheSet(int, Triangle *, int, int); static float GetAngle(float *, int, int, int); static int Not(Triangle, int, int); static int NeighborEdge(int, int, int, Triangle *, Triangle *); static Error FlipEm(int, edge *, Triangle *, Triangle *, float *); static Error DoTheFlip(int, int, int, int, int, int, Triangle *, Triangle *, edge *); /* returns the handedness of a triangle */ static int Handedness(float *pos_ptr, int i, int index1, int index2) { Vector v1, v2, v3, v4, v5; float c; v1 = DXVec(pos_ptr[2*i], pos_ptr[2*i+1], 0.0); v2 = DXVec(pos_ptr[2*index1], pos_ptr[2*index1+1], 0.0); v3 = DXVec(pos_ptr[2*index2], pos_ptr[2*index2+1], 0.0); v4 = DXSub(v2, v1); v5 = DXSub(v3, v1); /* since I only care about the z component, I won't bother with * the true cross product */ c = v4.x*v5.y - v4.y*v5.x; if (c < 0) return -1; else if (c > 0) return 1; else return 0; } /* find out if the new point is on any of the boundaries of the triangle */ static int AnyDegenerate(Triangle vertices, float *pos_ptr, int new) { int hand1, hand2, hand3; hand1 = Handedness(pos_ptr, vertices.p, vertices.q, new); hand2 = Handedness(pos_ptr, new, vertices.q, vertices.r); hand3 = Handedness(pos_ptr, vertices.r, vertices.p, new); if (hand1==0) return 1; else if (hand2==0) return 2; else if (hand3==0) return 3; else return 0; } static Error GetVertices(Triangle *trianglelist, int j, Triangle *vertices) { *vertices = trianglelist[j]; return OK; } /* determines whether or not a given 2D point is inside a given 2D triangle */ static int Inside(float *pos_ptr, Triangle vertices, int new) { int hand1, hand2, hand3; hand1 = Handedness(pos_ptr, vertices.p, vertices.q, new); hand2 = Handedness(pos_ptr, new, vertices.q, vertices.r); hand3 = Handedness(pos_ptr, vertices.r, vertices.p, new); /* Handedness returns 0 if the 3 points are on a line. The * following checks for hand==0 ensure that if a point is on * the boundary of a triangle, it will be considered in the triangle */ if (hand1==0) { if ((hand2==0)||(hand3==0)) return -1; if (hand2==hand3) return 1; } else if (hand2==0) { if ((hand1==0)||(hand3==0)) return -1; if (hand1==hand3) return 1; } else if (hand3==0) { if ((hand1==0)||(hand2==0)) return -1; if (hand1==hand2) return 1; } else if ((hand1==hand2)&&(hand2==hand3)) { return 1; } return 0; } /* given a position list and an index, along with a list of triangles * covering the plane, determines which of those triangles the new point * lies within */ static Error FindWhichTriangle(float *pos_ptr, Triangle *trianglelist, int howmany, int new, int *which) { int i, in; Triangle vertices; /* for all the triangles there are.... discount the first three, it * won't be there by definition */ for (i=0; imaxx) maxx = old_pos_ptr[2*i]; if (old_pos_ptr[2*i+1]>maxy) maxy = old_pos_ptr[2*i+1]; } deltax = maxx-minx; deltay = maxy-miny; /* make the box much bigger for good measure */ minx = minx-15*(deltax); miny = miny-15*(deltay); maxx = maxx+15*(deltax); maxy = maxy+15*(deltay); /* construct the triangle which bounds the points */ deltax = (maxx-minx); deltay = (maxy-miny); offset = sqrt(deltax*deltay/2.0); pos_ptr[0] = minx-offset; pos_ptr[1] = miny; pos_ptr[2] = maxx+offset; pos_ptr[3] = miny; pos_ptr[4] = minx+(deltax/2.0); pos_ptr[5] = maxy+offset; } else { /* get the bounding box of the points */ if (!DXBoundingBox((Object)ino,box)) { DXSetError(ERROR_INVALID_DATA,"object has no bounding box"); goto error; } minx = DXD_MAX_FLOAT; miny = DXD_MAX_FLOAT; maxx = -DXD_MAX_FLOAT; maxy = -DXD_MAX_FLOAT; for (i=0; i<7; i++) { if (box[i].x < minx) minx = box[i].x; if (box[i].y < miny) miny = box[i].y; if (box[i].x > maxx) maxx = box[i].x; if (box[i].y > maxy) maxy = box[i].y; } deltax = maxx-minx; deltay = maxy-miny; /* make the box bigger for good measure */ minx = minx-15*(deltax); miny = miny-15*(deltay); maxx = maxx+15*(deltax); maxy = maxy+15*(deltay); /* construct the triangle which bounds the points */ deltax = (maxx-minx); deltay = (maxy-miny); offset = sqrt(deltax*deltay/2.0); pos_ptr[0] = minx-offset; pos_ptr[1] = miny; pos_ptr[2] = maxx+offset; pos_ptr[3] = miny; pos_ptr[4] = minx+(deltax/2.0); pos_ptr[5] = maxy+offset; } tmp = &pos_ptr[6]; memcpy(tmp, old_pos_ptr, numpos*2*sizeof(float)); /* initialize the first three triangles. * -1 corresponds to the point at infinity. * XXX what if the first triangle is degenerate? */ /* By convention, * if trianglelist = a, b, c, and neighborlist = d, e, f, then * d is the neighbor lying between a and b, e is the neighbor lying * between b and c, and f is the neighbor lying between c and a. */ /* the triangle in the center */ trianglelist[3] = DXTri(0, 2, 1); neighborlist[3] = DXTri(2, 1, 0); /* the boundary triangles */ trianglelist[0] = DXTri(0, 1, -1); neighborlist[0] = DXTri(3, 1, 2); trianglelist[1] = DXTri(1, 2, -1); neighborlist[1] = DXTri(3, 2, 0); trianglelist[2] = DXTri(2, 0, -1); neighborlist[2] = DXTri(3, 0, 1); numtri = 4; /* for the rest of the valid points */ while ((i=DXGetNextValidElementIndex(handle)) != -1) { i+=3; /* j is the triangle which the new point is found in */ if (!FindWhichTriangle(pos_ptr, trianglelist, numtri, i, &j)) goto error; /* if j == -1, it was a duplicated point */ if (j==-1) continue; /* vertices are the vertices of the triangle which the new point * was found within */ if (!GetVertices(trianglelist, j, &vertices)) goto error; /* neighbors are the three neighbors of the triangle the new point * was found within */ if (!GetNeighbors(neighborlist, j, &neighbors)) goto error; theseneighbors[0] = neighbors.p; theseneighbors[1] = neighbors.q; theseneighbors[2] = neighbors.r; /* add the new triangles; the first one replaces triangle j */ if (whichdegenerate=AnyDegenerate(vertices, pos_ptr, i)) { numsuspect = 4; if (whichdegenerate==1) { /* p q new is degenerate */ trianglelist[j] = DXTri(i, vertices.q, vertices.r); neighborlist[j] = DXTri(neighbors.p, neighbors.q, numtri); /* need to update the old neighbor of j along the pr side */ /* which is theseneighbors[2] */ if (((trianglelist[theseneighbors[2]].p == vertices.p)&& (trianglelist[theseneighbors[2]].q == vertices.r)) || ((trianglelist[theseneighbors[2]].p == vertices.r)&& (trianglelist[theseneighbors[2]].q == vertices.p))) neighborlist[theseneighbors[2]].p = numtri; else if (((trianglelist[theseneighbors[2]].q == vertices.p)&& (trianglelist[theseneighbors[2]].r == vertices.r)) || ((trianglelist[theseneighbors[2]].q == vertices.r)&& (trianglelist[theseneighbors[2]].r == vertices.p))) neighborlist[theseneighbors[2]].q = numtri; else if (((trianglelist[theseneighbors[2]].r == vertices.p)&& (trianglelist[theseneighbors[2]].p == vertices.r)) || ((trianglelist[theseneighbors[2]].r == vertices.r)&& (trianglelist[theseneighbors[2]].p == vertices.p))) neighborlist[theseneighbors[2]].r = numtri; else { DXSetError(ERROR_INTERNAL,"invalid neighbors"); goto error; } suspectedges[0].first = vertices.q; suspectedges[0].second = vertices.r; suspectedges[0].tri1 = j; suspectedges[0].tri2 = neighbors.q; trianglelist[numtri] = DXTri(i, vertices.r, vertices.p); neighborlist[numtri] = DXTri(j, neighbors.r, numtri+1); suspectedges[1].first = vertices.r; suspectedges[1].second = vertices.p; suspectedges[1].tri1 = numtri; suspectedges[1].tri2 = neighbors.r; numtri++; GetVertices(trianglelist, neighbors.p, &n_vertices); GetNeighbors(neighborlist, neighbors.p, &n_neighbors); /* need to update the old neighbor of j along the p q side (we need to split that triangle) Depends on how that neighbor is oriented */ if ((n_vertices.r==vertices.p)&& (n_vertices.q==vertices.q)) { trianglelist[neighbors.p]=DXTri(i, n_vertices.p, n_vertices.q); neighborlist[neighbors.p]=DXTri(numtri,n_neighbors.p, j); suspectedges[2].first = n_vertices.p; suspectedges[2].second = n_vertices.q; suspectedges[2].tri1 = neighbors.p; suspectedges[2].tri2 = n_neighbors.p; trianglelist[numtri]=DXTri(i, n_vertices.r, n_vertices.p); neighborlist[numtri]=DXTri(numtri-1, n_neighbors.r, neighbors.p); suspectedges[3].first = n_vertices.r; suspectedges[3].second = n_vertices.p; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.r; GetNeighbors(neighborlist, n_neighbors.r, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.p) neighborlist[n_neighbors.r].p = numtri; else if (n.q == neighbors.p) neighborlist[n_neighbors.r].q = numtri; else if (n.r == neighbors.p) neighborlist[n_neighbors.r].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.r==vertices.q)&& (n_vertices.q==vertices.p)) { trianglelist[neighbors.p]=DXTri(i, n_vertices.p, n_vertices.r); neighborlist[neighbors.p]=DXTri(numtri,n_neighbors.r, j); /* changed n_neighbors.p to n_neighbors.r above XXX */ suspectedges[2].first = n_vertices.p; suspectedges[2].second = n_vertices.r; suspectedges[2].tri1 = neighbors.p; suspectedges[2].tri2 = n_neighbors.r; /* changed n_neighbors.p to n_neighbors.r above XXX 1/6/95*/ trianglelist[numtri]=DXTri(i, n_vertices.q, n_vertices.p); neighborlist[numtri]=DXTri(numtri-1, n_neighbors.p, neighbors.p); suspectedges[3].first = n_vertices.q; suspectedges[3].second = n_vertices.p; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.p; GetNeighbors(neighborlist, n_neighbors.p, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.p) neighborlist[n_neighbors.p].p = numtri; else if (n.q == neighbors.p) neighborlist[n_neighbors.p].q = numtri; else if (n.r == neighbors.p) neighborlist[n_neighbors.p].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.q==vertices.p)&& (n_vertices.p==vertices.q)) { trianglelist[neighbors.p]=DXTri(i, n_vertices.r, n_vertices.p); /* XXX changed n_vertices.q to n_vertices.p above */ neighborlist[neighbors.p]=DXTri(numtri,n_neighbors.r, j); suspectedges[2].first = n_vertices.r; suspectedges[2].second = n_vertices.p; /* XXX changed n_vertices.q to n_vertices.p above */ suspectedges[2].tri1 = neighbors.p; suspectedges[2].tri2 = n_neighbors.r; trianglelist[numtri]=DXTri(i, n_vertices.q, n_vertices.r); neighborlist[numtri]=DXTri(numtri-1,n_neighbors.q, neighbors.p); suspectedges[3].first = n_vertices.q; suspectedges[3].second = n_vertices.r; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.q; GetNeighbors(neighborlist, n_neighbors.q, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.p) neighborlist[n_neighbors.q].p = numtri; else if (n.q == neighbors.p) neighborlist[n_neighbors.q].q = numtri; else if (n.r == neighbors.p) neighborlist[n_neighbors.q].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.q==vertices.q)&& (n_vertices.p==vertices.p)) { trianglelist[neighbors.p]=DXTri(i, n_vertices.r, n_vertices.q); neighborlist[neighbors.p]=DXTri(numtri,n_neighbors.q, j); suspectedges[2].first = n_vertices.r; suspectedges[2].second = n_vertices.q; suspectedges[2].tri1 = neighbors.p; suspectedges[2].tri2 = n_neighbors.q; trianglelist[numtri]=DXTri(i, n_vertices.p, n_vertices.r); neighborlist[numtri]=DXTri(numtri-1,n_neighbors.r, neighbors.p); suspectedges[3].first = n_vertices.p; suspectedges[3].second = n_vertices.r; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.r; GetNeighbors(neighborlist, n_neighbors.r, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.p) neighborlist[n_neighbors.r].p = numtri; else if (n.q == neighbors.p) neighborlist[n_neighbors.r].q = numtri; else if (n.r == neighbors.p) neighborlist[n_neighbors.r].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.p==vertices.p)&& (n_vertices.r==vertices.q)) { trianglelist[neighbors.p]=DXTri(i, n_vertices.q, n_vertices.r); neighborlist[neighbors.p]=DXTri(numtri,n_neighbors.q, j); suspectedges[2].first = n_vertices.q; suspectedges[2].second = n_vertices.r; suspectedges[2].tri1 = neighbors.p; suspectedges[2].tri2 = n_neighbors.q; trianglelist[numtri]=DXTri(i, n_vertices.p, n_vertices.q); neighborlist[numtri]=DXTri(numtri-1, n_neighbors.p, neighbors.p); suspectedges[3].first = n_vertices.p; suspectedges[3].second = n_vertices.q; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.p; GetNeighbors(neighborlist, n_neighbors.p, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.p) neighborlist[n_neighbors.p].p = numtri; else if (n.q == neighbors.p) neighborlist[n_neighbors.p].q = numtri; else if (n.r == neighbors.p) neighborlist[n_neighbors.p].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.p==vertices.q)&& (n_vertices.r==vertices.p)) { trianglelist[neighbors.p]=DXTri(i, n_vertices.q, n_vertices.p); neighborlist[neighbors.p]=DXTri(numtri,n_neighbors.p, j); suspectedges[2].first = n_vertices.q; suspectedges[2].second = n_vertices.p; suspectedges[2].tri1 = neighbors.p; suspectedges[2].tri2 = n_neighbors.p; trianglelist[numtri]=DXTri(i, n_vertices.r, n_vertices.q); neighborlist[numtri]=DXTri(numtri-1, n_neighbors.q, neighbors.p); suspectedges[3].first = n_vertices.r; suspectedges[3].second = n_vertices.q; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.q; GetNeighbors(neighborlist, n_neighbors.q, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.p) neighborlist[n_neighbors.q].p = numtri; else if (n.q == neighbors.p) neighborlist[n_neighbors.q].q = numtri; else if (n.r == neighbors.p) neighborlist[n_neighbors.q].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else { DXSetError(ERROR_INTERNAL,"neighbors are incorrect"); goto error; } numtri++; } else if (whichdegenerate==2) { /* new q r is degenerate */ trianglelist[j] = DXTri(i, vertices.p, vertices.q); neighborlist[j] = DXTri(numtri, neighbors.p, neighbors.q); suspectedges[0].first = vertices.p; suspectedges[0].second = vertices.q; suspectedges[0].tri1 = j; suspectedges[0].tri2 = neighbors.p; /* need to update the old neighbor of j along the pr side */ /* which is theseneighbors[2] */ if (((trianglelist[theseneighbors[2]].p == vertices.p)&& (trianglelist[theseneighbors[2]].q == vertices.r)) || ((trianglelist[theseneighbors[2]].p == vertices.r)&& (trianglelist[theseneighbors[2]].q == vertices.p))) neighborlist[theseneighbors[2]].p = numtri; else if (((trianglelist[theseneighbors[2]].q == vertices.p)&& (trianglelist[theseneighbors[2]].r == vertices.r)) || ((trianglelist[theseneighbors[2]].q == vertices.r)&& (trianglelist[theseneighbors[2]].r == vertices.p))) neighborlist[theseneighbors[2]].q = numtri; else if (((trianglelist[theseneighbors[2]].r == vertices.p)&& (trianglelist[theseneighbors[2]].p == vertices.r)) || ((trianglelist[theseneighbors[2]].r == vertices.r)&& (trianglelist[theseneighbors[2]].p == vertices.p))) neighborlist[theseneighbors[2]].r = numtri; else { DXSetError(ERROR_INTERNAL,"invalid neighbors"); goto error; } trianglelist[numtri] = DXTri(i, vertices.r, vertices.p); neighborlist[numtri] = DXTri(numtri+1, neighbors.r, j); suspectedges[1].first = vertices.r; suspectedges[1].second = vertices.p; suspectedges[1].tri1 = numtri; suspectedges[1].tri2 = neighbors.r; numtri++; GetVertices(trianglelist, neighbors.q, &n_vertices); GetNeighbors(neighborlist, neighbors.q, &n_neighbors); /* need to update the old neighbor of j along the q r side (we need to split that triangle) Depends on how that neighbor is oriented */ if ((n_vertices.q==vertices.r)&& (n_vertices.r==vertices.q)) { trianglelist[neighbors.q]=DXTri(i, n_vertices.r, n_vertices.p); neighborlist[neighbors.q]=DXTri(j,n_neighbors.r, numtri); suspectedges[2].first = n_vertices.r; suspectedges[2].second = n_vertices.p; suspectedges[2].tri1 = neighbors.q; /* XXX changed n_neighbors.q to neighbors.q above */ suspectedges[2].tri2 = n_neighbors.r; trianglelist[numtri]=DXTri(i, n_vertices.p, n_vertices.q); neighborlist[numtri]=DXTri(neighbors.q, n_neighbors.p, numtri-1); suspectedges[3].first = n_vertices.p; suspectedges[3].second = n_vertices.q; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.p; GetNeighbors(neighborlist, n_neighbors.p, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.q) neighborlist[n_neighbors.p].p = numtri; else if (n.q == neighbors.q) neighborlist[n_neighbors.p].q = numtri; else if (n.r == neighbors.q) neighborlist[n_neighbors.p].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.r==vertices.r)&& (n_vertices.q==vertices.q)) { trianglelist[neighbors.q]=DXTri(i, n_vertices.q, n_vertices.p); neighborlist[neighbors.q]=DXTri(j,n_neighbors.p, numtri); suspectedges[2].first = n_vertices.q; suspectedges[2].second = n_vertices.p; suspectedges[2].tri1 = neighbors.q; suspectedges[2].tri2 = n_neighbors.p; trianglelist[numtri]=DXTri(i, n_vertices.p, n_vertices.r); neighborlist[numtri]=DXTri(neighbors.q, n_neighbors.r, numtri-1); suspectedges[3].first = n_vertices.p; suspectedges[3].second = n_vertices.r; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.r; GetNeighbors(neighborlist, n_neighbors.r, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.q) neighborlist[n_neighbors.r].p = numtri; else if (n.q == neighbors.q) neighborlist[n_neighbors.r].q = numtri; else if (n.r == neighbors.q) neighborlist[n_neighbors.r].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.p==vertices.r)&& (n_vertices.q==vertices.q)) { trianglelist[neighbors.q]=DXTri(i, n_vertices.q, n_vertices.r); neighborlist[neighbors.q]=DXTri(j,n_neighbors.q, numtri); suspectedges[2].first = n_vertices.q; suspectedges[2].second = n_vertices.r; suspectedges[2].tri1 = neighbors.q; suspectedges[2].tri2 = n_neighbors.q; trianglelist[numtri]=DXTri(i, n_vertices.r, n_vertices.p); neighborlist[numtri]=DXTri(neighbors.q, n_neighbors.r, numtri-1); suspectedges[3].first = n_vertices.r; suspectedges[3].second = n_vertices.p; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.r; GetNeighbors(neighborlist, n_neighbors.r, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.q) neighborlist[n_neighbors.r].p = numtri; else if (n.q == neighbors.q) neighborlist[n_neighbors.r].q = numtri; else if (n.r == neighbors.q) neighborlist[n_neighbors.r].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.q==vertices.r)&& (n_vertices.p==vertices.q)) { trianglelist[neighbors.q]=DXTri(i, n_vertices.p, n_vertices.r); neighborlist[neighbors.q]=DXTri(j,n_neighbors.r, numtri); suspectedges[2].first = n_vertices.p; suspectedges[2].second = n_vertices.r; suspectedges[2].tri1 = neighbors.q; suspectedges[2].tri2 = n_neighbors.r; trianglelist[numtri]=DXTri(i, n_vertices.r, n_vertices.q); neighborlist[numtri]=DXTri(neighbors.q, n_neighbors.q, numtri-1); suspectedges[3].first = n_vertices.r; suspectedges[3].second = n_vertices.q; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.q; GetNeighbors(neighborlist, n_neighbors.q, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.q) neighborlist[n_neighbors.q].p = numtri; else if (n.q == neighbors.q) neighborlist[n_neighbors.q].q = numtri; else if (n.r == neighbors.q) neighborlist[n_neighbors.q].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.r==vertices.r)&& (n_vertices.p==vertices.q)) { trianglelist[neighbors.q]=DXTri(i, n_vertices.p, n_vertices.q); neighborlist[neighbors.q]=DXTri(j,n_neighbors.p, numtri); suspectedges[2].first = n_vertices.p; suspectedges[2].second = n_vertices.q; suspectedges[2].tri1 = neighbors.q; suspectedges[2].tri2 = n_neighbors.p; trianglelist[numtri]=DXTri(i, n_vertices.q, n_vertices.r); neighborlist[numtri]=DXTri(neighbors.q, n_neighbors.q, numtri-1); suspectedges[3].first = n_vertices.q; suspectedges[3].second = n_vertices.r; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.q; GetNeighbors(neighborlist, n_neighbors.q, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.q) neighborlist[n_neighbors.q].p = numtri; else if (n.q == neighbors.q) neighborlist[n_neighbors.q].q = numtri; else if (n.r == neighbors.q) neighborlist[n_neighbors.q].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.p==vertices.r)&& (n_vertices.r==vertices.q)) { trianglelist[neighbors.q]=DXTri(i, n_vertices.r, n_vertices.q); neighborlist[neighbors.q]=DXTri(j,n_neighbors.q, numtri); suspectedges[2].first = n_vertices.r; suspectedges[2].second = n_vertices.q; suspectedges[2].tri1 = neighbors.q; suspectedges[2].tri2 = n_neighbors.q; trianglelist[numtri]=DXTri(i, n_vertices.q, n_vertices.p); neighborlist[numtri]=DXTri(neighbors.q, n_neighbors.p, numtri-1); suspectedges[3].first = n_vertices.q; suspectedges[3].second = n_vertices.p; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.p; GetNeighbors(neighborlist, n_neighbors.p, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.q) neighborlist[n_neighbors.p].p = numtri; else if (n.q == neighbors.q) neighborlist[n_neighbors.p].q = numtri; else if (n.r == neighbors.q) neighborlist[n_neighbors.p].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else { DXSetError(ERROR_INTERNAL,"neighbors are incorrect"); goto error; } numtri++; } /* else whichdegenerate==3 */ else { /* r p new is degenerate */ trianglelist[j] = DXTri(i, vertices.q, vertices.r); neighborlist[j] = DXTri(numtri, neighbors.q, neighbors.r); suspectedges[0].first = vertices.q; suspectedges[0].second = vertices.r; suspectedges[0].tri1 = j; suspectedges[0].tri2 = neighbors.q; /* need to update the old neighbor of j along the pq side */ /* which is theseneighbors[0] */ if (((trianglelist[theseneighbors[0]].p == vertices.p)&& (trianglelist[theseneighbors[0]].q == vertices.q)) || ((trianglelist[theseneighbors[0]].p == vertices.q)&& (trianglelist[theseneighbors[0]].q == vertices.p))) neighborlist[theseneighbors[0]].p = numtri; else if (((trianglelist[theseneighbors[0]].q == vertices.p)&& (trianglelist[theseneighbors[0]].r == vertices.q)) || ((trianglelist[theseneighbors[0]].q == vertices.q)&& (trianglelist[theseneighbors[0]].r == vertices.p))) neighborlist[theseneighbors[0]].q = numtri; else if (((trianglelist[theseneighbors[0]].r == vertices.p)&& (trianglelist[theseneighbors[0]].p == vertices.q)) || ((trianglelist[theseneighbors[0]].r == vertices.q)&& (trianglelist[theseneighbors[0]].p == vertices.p))) neighborlist[theseneighbors[0]].r = numtri; else { DXSetError(ERROR_INTERNAL,"invalid neighbors"); goto error; } trianglelist[numtri] = DXTri(i, vertices.p, vertices.q); neighborlist[numtri] = DXTri(numtri+1, neighbors.p, j); suspectedges[1].first = vertices.p; suspectedges[1].second = vertices.q; suspectedges[1].tri1 = numtri; suspectedges[1].tri2 = neighbors.p; numtri++; GetVertices(trianglelist, neighbors.r, &n_vertices); GetNeighbors(neighborlist, neighbors.r, &n_neighbors); /* need to update the old neighbor of j along the r p side (we need to split that triangle) Depends on how that neighbor is oriented */ if ((n_vertices.p==vertices.p)&& (n_vertices.q==vertices.r)) { trianglelist[neighbors.r]=DXTri(i, n_vertices.q, n_vertices.r); neighborlist[neighbors.r]=DXTri(j, n_neighbors.q, numtri); suspectedges[2].first = n_vertices.q; suspectedges[2].second = n_vertices.r; suspectedges[2].tri1 = neighbors.r; suspectedges[2].tri2 = n_neighbors.q; trianglelist[numtri]=DXTri(i, n_vertices.r, n_vertices.p); neighborlist[numtri]=DXTri(neighbors.r, n_neighbors.r, numtri-1); suspectedges[3].first = n_vertices.r; suspectedges[3].second = n_vertices.p; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.r; GetNeighbors(neighborlist, n_neighbors.r, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.r) neighborlist[n_neighbors.r].p = numtri; else if (n.q == neighbors.r) neighborlist[n_neighbors.r].q = numtri; else if (n.r == neighbors.r) neighborlist[n_neighbors.r].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.q==vertices.p)&& (n_vertices.p==vertices.r)) { trianglelist[neighbors.r]=DXTri(i, n_vertices.r, n_vertices.p); neighborlist[neighbors.r]=DXTri(numtri, n_neighbors.r, j); suspectedges[2].first = n_vertices.r; suspectedges[2].second = n_vertices.p; suspectedges[2].tri1 = neighbors.r; suspectedges[2].tri2 = n_neighbors.r; trianglelist[numtri]=DXTri(i, n_vertices.q, n_vertices.r); neighborlist[numtri]=DXTri(numtri-1,n_neighbors.q, neighbors.r); suspectedges[3].first = n_vertices.q; suspectedges[3].second = n_vertices.r; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.q; GetNeighbors(neighborlist, n_neighbors.q, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.r) neighborlist[n_neighbors.q].p = numtri; else if (n.q == neighbors.r) neighborlist[n_neighbors.q].q = numtri; else if (n.r == neighbors.r) neighborlist[n_neighbors.q].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.r==vertices.p)&& (n_vertices.p==vertices.r)) { trianglelist[neighbors.r]=DXTri(i, n_vertices.p, n_vertices.q); neighborlist[neighbors.r]=DXTri(j,n_neighbors.p, numtri); suspectedges[2].first = n_vertices.p; suspectedges[2].second = n_vertices.q; suspectedges[2].tri1 = neighbors.r; suspectedges[2].tri2 = n_neighbors.p; trianglelist[numtri]=DXTri(i, n_vertices.q, n_vertices.r); neighborlist[numtri]=DXTri(neighbors.r, n_neighbors.q, numtri-1); suspectedges[3].first = n_vertices.q; suspectedges[3].second = n_vertices.r; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.q; GetNeighbors(neighborlist, n_neighbors.q, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.r) neighborlist[n_neighbors.q].p = numtri; else if (n.q == neighbors.r) neighborlist[n_neighbors.q].q = numtri; else if (n.r == neighbors.r) neighborlist[n_neighbors.q].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.p==vertices.p)&& (n_vertices.r==vertices.r)) { trianglelist[neighbors.r]=DXTri(i, n_vertices.r, n_vertices.q); neighborlist[neighbors.r]=DXTri(j,n_neighbors.q, numtri); suspectedges[2].first = n_vertices.r; suspectedges[2].second = n_vertices.q; suspectedges[2].tri1 = neighbors.r; suspectedges[2].tri2 = n_neighbors.q; trianglelist[numtri]=DXTri(i, n_vertices.q, n_vertices.p); neighborlist[numtri]=DXTri(neighbors.r, n_neighbors.p, numtri-1); suspectedges[3].first = n_vertices.q; suspectedges[3].second = n_vertices.p; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.p; GetNeighbors(neighborlist, n_neighbors.p, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.r) neighborlist[n_neighbors.p].p = numtri; else if (n.q == neighbors.r) neighborlist[n_neighbors.p].q = numtri; else if (n.r == neighbors.r) neighborlist[n_neighbors.p].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.q==vertices.p)&& (n_vertices.r==vertices.r)) { trianglelist[neighbors.r]=DXTri(i, n_vertices.r, n_vertices.p); neighborlist[neighbors.r]=DXTri(j,n_neighbors.r, numtri); suspectedges[2].first = n_vertices.r; suspectedges[2].second = n_vertices.p; suspectedges[2].tri1 = neighbors.r; suspectedges[2].tri2 = n_neighbors.r; trianglelist[numtri]=DXTri(i, n_vertices.p, n_vertices.q); neighborlist[numtri]=DXTri(neighbors.r, n_neighbors.p, numtri-1); suspectedges[3].first = n_vertices.p; suspectedges[3].second = n_vertices.q; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.p; GetNeighbors(neighborlist, n_neighbors.p, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.r) neighborlist[n_neighbors.p].p = numtri; else if (n.q == neighbors.r) neighborlist[n_neighbors.p].q = numtri; else if (n.r == neighbors.r) neighborlist[n_neighbors.p].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else if ((n_vertices.r==vertices.p)&& (n_vertices.q==vertices.r)) { trianglelist[neighbors.r]=DXTri(i, n_vertices.q, n_vertices.p); neighborlist[neighbors.r]=DXTri(j,n_neighbors.p, numtri); suspectedges[2].first = n_vertices.q; suspectedges[2].second = n_vertices.p; suspectedges[2].tri1 = neighbors.r; suspectedges[2].tri2 = n_neighbors.p; trianglelist[numtri]=DXTri(i, n_vertices.p, n_vertices.r); neighborlist[numtri]=DXTri(neighbors.r, n_neighbors.r, numtri-1); suspectedges[3].first = n_vertices.p; suspectedges[3].second = n_vertices.r; suspectedges[3].tri1 = numtri; suspectedges[3].tri2 = n_neighbors.r; GetNeighbors(neighborlist, n_neighbors.r, &n); /* update the neighbor of the old triangle neighbors.p */ if (n.p == neighbors.r) neighborlist[n_neighbors.r].p = numtri; else if (n.q == neighbors.r) neighborlist[n_neighbors.r].q = numtri; else if (n.r == neighbors.r) neighborlist[n_neighbors.r].r = numtri; else { DXSetError(ERROR_INVALID_DATA,"invalid neighbors"); goto error; } } else { DXSetError(ERROR_INTERNAL,"neighbors are incorrect"); goto error; } numtri++; } } /* else there aren't any degeneracies */ else { numsuspect=3; trianglelist[j] = DXTri(vertices.p, vertices.q, i); neighborlist[j] = DXTri(neighbors.p, numtri, numtri+1); suspectedges[0].first = vertices.p; suspectedges[0].second = vertices.q; suspectedges[0].tri1 = j; suspectedges[0].tri2 = neighbors.p; trianglelist[numtri] = DXTri(i, vertices.q, vertices.r); neighborlist[numtri] = DXTri(j, neighbors.q, numtri+1); suspectedges[1].first = vertices.q; suspectedges[1].second = vertices.r; suspectedges[1].tri1 = numtri; suspectedges[1].tri2 = neighbors.q; /* need to update the old neighbor of j along the q r side, * which is theseneighbors[1] */ if (((trianglelist[theseneighbors[1]].p == vertices.q)&& (trianglelist[theseneighbors[1]].q == vertices.r)) || ((trianglelist[theseneighbors[1]].p == vertices.r)&& (trianglelist[theseneighbors[1]].q == vertices.q))) neighborlist[theseneighbors[1]].p = numtri; else if (((trianglelist[theseneighbors[1]].q == vertices.q)&& (trianglelist[theseneighbors[1]].r == vertices.r)) || ((trianglelist[theseneighbors[1]].q == vertices.r)&& (trianglelist[theseneighbors[1]].r == vertices.q))) neighborlist[theseneighbors[1]].q = numtri; else if (((trianglelist[theseneighbors[1]].r == vertices.q)&& (trianglelist[theseneighbors[1]].p == vertices.r)) || ((trianglelist[theseneighbors[1]].r == vertices.r)&& (trianglelist[theseneighbors[1]].p == vertices.q))) neighborlist[theseneighbors[1]].r = numtri; else { DXSetError(ERROR_INTERNAL,"invalid neighbors"); goto error; } numtri++; trianglelist[numtri] = DXTri(vertices.p, i, vertices.r); neighborlist[numtri] = DXTri(j, numtri-1, neighbors.r); suspectedges[2].first = vertices.p; suspectedges[2].second = vertices.r; suspectedges[2].tri1 = numtri; suspectedges[2].tri2 = neighbors.r; /* need to update the old neighbor of j along the p r side, * which is theseneighbors[2] */ if (((trianglelist[theseneighbors[2]].p == vertices.p)&& (trianglelist[theseneighbors[2]].q == vertices.r)) || ((trianglelist[theseneighbors[2]].p == vertices.r)&& (trianglelist[theseneighbors[2]].q == vertices.p))) neighborlist[theseneighbors[2]].p = numtri; else if (((trianglelist[theseneighbors[2]].q == vertices.p)&& (trianglelist[theseneighbors[2]].r == vertices.r)) || ((trianglelist[theseneighbors[2]].q == vertices.r)&& (trianglelist[theseneighbors[2]].r == vertices.p))) neighborlist[theseneighbors[2]].q = numtri; else if (((trianglelist[theseneighbors[2]].r == vertices.p)&& (trianglelist[theseneighbors[2]].p == vertices.r)) || ((trianglelist[theseneighbors[2]].r == vertices.r)&& (trianglelist[theseneighbors[2]].p == vertices.p))) neighborlist[theseneighbors[2]].r = numtri; else { DXSetError(ERROR_INTERNAL,"invalid neighbors"); goto error; } numtri++; } /* now we're ready to start flipping bonds */ /* need to check all the suspect edges. We start with either three * or four suspect edges (three if the new point was strictly inside * a triangle; four if it was on an edge) */ FlipEm(numsuspect, suspectedges, trianglelist, neighborlist, pos_ptr); #if DEBUG if (!CheckThem(neighborlist, trianglelist, numtri)) { DXSetError(ERROR_INTERNAL, "Check Failed i = %d", i); goto error; } #endif } /* we've munged the connections */ if (!DXChangedComponentStructure((Field)ino,"connections")) goto error; connections = (Array)DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 3); if (!connections) goto error; /* we don't want to add any triangles with -1 to 2 in them */ /* there will be less than numtri triangles */ if (!DXAllocateArray(connections, numtri)) goto error; trianglecount = 0; for (i=0; i= 3) && (triangle.q >= 3) && (triangle.r >= 3)) { if (Handedness(pos_ptr, triangle.p, triangle.q, triangle.r)==-1) { triangle = DXTri(triangle.p, triangle.r, triangle.q); } /* subtract off the three added points at the beginning */ triangle.p = triangle.p-3; triangle.q = triangle.q-3; triangle.r = triangle.r-3; if (!DXAddArrayData(connections, trianglecount, 1, &triangle)) goto error; trianglecount++; } } if (trianglecount == 0) { DXSetError(ERROR_INVALID_DATA, "all triangles were degenerate"); goto error; } if (!DXSetComponentValue((Field)ino,"connections", (Object)connections)) goto error; connections=NULL; if (!DXSetComponentAttribute((Field)ino, "connections", "element type", (Object)DXNewString("triangles"))) goto error; if (!DXSetComponentAttribute((Field)ino, "connections", "ref", (Object)DXNewString("positions"))) goto error; /* get rid of the invalid positions */ if (!DXInvalidateConnections((Object)ino)) goto error; if (!DXInvalidateUnreferencedPositions((Object)ino)) goto error; if (!DXCull((Object)ino)) goto error; /* check how many triangles got made */ if (!DXEndField((Field)ino)) goto error; DXGetArrayInfo(connections, &trianglecount, NULL, NULL, NULL, NULL); if (trianglecount == 0) { DXWarning("no triangles created; all were degenerate"); } DXFree((Pointer)trianglelist); DXFree((Pointer)neighborlist); DXFree((Pointer)pos_ptr); DXFreeInvalidComponentHandle(handle); if (shape[0]==3) DXFree((Pointer)old_pos_ptr); return OK; error: DXFree((Pointer)trianglelist); DXFreeInvalidComponentHandle(handle); DXFree((Pointer)neighborlist); DXFree((Pointer)pos_ptr); DXDelete((Object)connections); if (shape[0]==3) DXFree((Pointer)old_pos_ptr); DXAbortTaskGroup(); return ERROR; } static Error FlipEm(int numsuspect, edge *edges, Triangle *trianglelist, Triangle *neighborlist, float *pos_ptr) { int k, index1, index2, tri1, tri2; int A, B, C, D; edge *suspectedges; Triangle vertices1, vertices2; float angle1, angle2; suspectedges = DXAllocate(2*sizeof(edge)); if (!suspectedges) return ERROR; for (k = 0; k angle(ABC)+angle(CDA) */ /* don't flip if the outer triangle is one of the three boundary tris */ if (tri2 > 2) { /* don't flip if the quad is not convex */ if (Convex(pos_ptr, A, B, C, D)) { angle1 = GetAngle(pos_ptr, D, A, B) + GetAngle(pos_ptr, B, C, D); angle2 = GetAngle(pos_ptr, A, B, C) + GetAngle(pos_ptr, C, D, A); if (angle1 > angle2) { if (!DoTheFlip(A, B, C, D, tri1, tri2, trianglelist, neighborlist, suspectedges)) return ERROR; /* two more suspect edges */ /* A is supposed to be our new point, by the way */ FlipEm(2, suspectedges, trianglelist, neighborlist, pos_ptr); } } } } DXFree((Pointer)suspectedges); return OK; } static Error DoTheFlip(int A, int B, int C, int D, int first, int second, Triangle *trianglelist, Triangle *neighborlist, edge *suspectedges) { /* given an edge which should be flipped (BD), it flips it, * and also returns the two new suspect edges in suspectedges */ /* The suspect edges are BC and CD */ int n11, n21, n31, n12, n22, n32, n1old, n2old, neighborBC, neighborCD; neighborBC = NeighborEdge(second, B, C, trianglelist, neighborlist); neighborCD = NeighborEdge(second, C, D, trianglelist, neighborlist); suspectedges[0].first = B; suspectedges[0].second = C; suspectedges[0].tri1 = first; suspectedges[0].tri2 = neighborBC; suspectedges[1].first = C; suspectedges[1].second = D; suspectedges[1].tri1 = second; suspectedges[1].tri2 = neighborCD; n1old = NeighborEdge(first, A, D, trianglelist, neighborlist); n2old = NeighborEdge(second, B, C, trianglelist, neighborlist); n11 = NeighborEdge(first, A, B, trianglelist, neighborlist); n21 = NeighborEdge(second, B, C, trianglelist, neighborlist); n31 = second; n12 = NeighborEdge(second, C, D, trianglelist, neighborlist); n22 = NeighborEdge(first, D, A, trianglelist, neighborlist); n32 = first; trianglelist[first] = DXTri(A, B, C); neighborlist[first] = DXTri(n11, n21, n31); trianglelist[second] = DXTri(C, D, A); neighborlist[second] = DXTri(n12, n22, n32); /* need to update the old neighbor of first along the AD side */ if (((trianglelist[n1old].p == A)&& (trianglelist[n1old].q == D)) || ((trianglelist[n1old].p == D)&& (trianglelist[n1old].q == A))) neighborlist[n1old].p = second; else if (((trianglelist[n1old].q == A)&& (trianglelist[n1old].r == D)) || ((trianglelist[n1old].q == D)&& (trianglelist[n1old].r == A))) neighborlist[n1old].q = second; else if (((trianglelist[n1old].r == A)&& (trianglelist[n1old].p == D)) || ((trianglelist[n1old].r == D)&& (trianglelist[n1old].p == A))) neighborlist[n1old].r = second; else { DXSetError(ERROR_INTERNAL,"invalid neighbors"); return ERROR; } /* need to update the old neighbor of second along the BC side */ if (((trianglelist[n2old].p == B)&& (trianglelist[n2old].q == C)) || ((trianglelist[n2old].p == C)&& (trianglelist[n2old].q == B))) neighborlist[n2old].p = first; else if (((trianglelist[n2old].q == B)&& (trianglelist[n2old].r == C)) || ((trianglelist[n2old].q == C)&& (trianglelist[n2old].r == B))) neighborlist[n2old].q = first; else if (((trianglelist[n2old].r == B)&& (trianglelist[n2old].p == C)) || ((trianglelist[n2old].r == C)&& (trianglelist[n2old].p == B))) neighborlist[n2old].r = first; else { DXSetError(ERROR_INTERNAL,"invalid neighbors"); return ERROR; } return OK; } static int NeighborEdge(int whichtri, int vert1, int vert2, Triangle *trianglelist, Triangle *neighborlist) { Triangle neighbors, vertices; GetVertices(trianglelist, whichtri, &vertices); GetNeighbors(neighborlist, whichtri, &neighbors); if (((vert1==vertices.p)&&(vert2==vertices.q)) || (vert2==vertices.p)&&(vert1==vertices.q)) return neighbors.p; if (((vert1==vertices.q)&&(vert2==vertices.r)) || (vert2==vertices.q)&&(vert1==vertices.r)) return neighbors.q; if (((vert1==vertices.r)&&(vert2==vertices.p)) || (vert2==vertices.r)&&(vert1==vertices.p)) return neighbors.r; } static float GetAngle(float *pos_ptr, int A, int B, int C) { Point2D a, b, c; float angle, dotprod, mag; double factor; a.x = pos_ptr[2*A]; a.y = pos_ptr[2*A+1]; b.x = pos_ptr[2*B]; b.y = pos_ptr[2*B+1]; c.x = pos_ptr[2*C]; c.y = pos_ptr[2*C+1]; dotprod = (a.x - b.x)*(c.x - b.x) + (a.y - b.y)*(c.y - b.y); mag = sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)) * sqrt((c.x-b.x)*(c.x-b.x) + (c.y-b.y)*(c.y-b.y)); factor = dotprod/mag; if ((factor >= .99999)) { angle = 0.0; } else if ((factor <= -.99999)) { angle = 3.1415926; } else { angle = acos(factor); } return angle; } static int Not(Triangle tri, int i, int j) { if ((tri.p != i)&&(tri.p != j)) return tri.p; else if ((tri.q != i)&&(tri.q != j)) return tri.q; else if ((tri.r != i)&&(tri.r != j)) return tri.r; } static int CheckThem(Triangle *neighborlist, Triangle *trianglelist, int numtri) { int i; Triangle vertices, neighbors; for (i=0; i