/********************************************************************/ /* STRIPE: converting a polygonal model to triangle strips Francine Evans, 1996. SUNY @ Stony Brook Advisors: Steven Skiena and Amitabh Varshney */ /********************************************************************/ /*---------------------------------------------------------------------*/ /* STRIPE: partial.c This file contains routines that are used partial triangulation of polygons */ /*---------------------------------------------------------------------*/ #include #include #include #include "global.h" #include "outputex.h" #include "polvertsex.h" #include "triangulatex.h" #include "sturctsex.h" #include "polverts.h" #include "common.h" #include "util.h" void P_Triangulate_Quad(int out_edge1,int out_edge2,int in_edge1, int in_edge2,int size,int *index, FILE *output,FILE *fp,int reversed,int face_id, int *next_id,ListHead *pListHead, P_ADJACENCIES temp, int where) { int vertex4,vertex5,dummy=60; /* This routine will nonblindly triangulate a quad, meaning that there is a definite input and a definite output edge that we must adhere to. Reversed will tell the orientation of the input edge. (Reversed is -1 is we do not have an input edge, in other words we are at the beginning of a strip.) Out_edge* is the output edge, and in_edge* is the input edge. Index are the edges of the polygon and size is the size of the polygon. Begin is whether we are at the start of a new strip. Note that we will not necessarily triangulate the whole quad; maybe we will do half and leave the other half (a triangle) for later. */ /* If we do not have an input edge, then we can make our input edge whatever we like, therefore it will be easier to come out on the output edge. In this case the whole quad is done. */ if (reversed == -1) { vertex4 = AdjacentEx(out_edge1,out_edge2,index,size); vertex5 = Get_Other_Vertex(vertex4,out_edge1,out_edge2,index); Output_TriEx(vertex5,vertex4,out_edge1,output,-1,-1,where); Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where); dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy); RemoveList(pListHead,(PLISTINFO) temp); return; } /* These are the 5 cases that we can have for the output edge */ /* Are they consecutive so that we form a triangle to peel off, but cannot use the whole quad? */ if (in_edge2 == out_edge1) { /* Output the triangle that comes out the correct edge. Save the other half for later. */ vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index); Output_TriEx(in_edge1,in_edge2,out_edge2,output,-1,-1,where); /* Now we have a triangle used, and a triangle that is left for later. */ /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); Delete_AdjEx(out_edge2,in_edge2,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies There are 2 edges that need to be checked for the triangle that was just outputted. For the output edge we definitely will be decreasing the adjacency, but we must check for the input edge. */ dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE); dummy = Change_FaceEx(face_id,in_edge2,out_edge2,pListHead,temp,TRUE); /* Update the face data structure, by deleting the old face and putting in the triangle as the new face */ New_Face(face_id,in_edge1,out_edge2,vertex4); return; } else if (in_edge1 == out_edge1) { /* We want to output the first triangle (whose output edge is not the one that we want. We have to find the vertex that we need, which is the other vertex which we do not have. */ vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index); Output_TriEx(in_edge2,in_edge1,out_edge2,output,-1,-1,where); /* Now we have a triangle used, and a triangle that is left for later. */ /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE); dummy = Change_FaceEx(face_id,in_edge1,out_edge2,pListHead,temp,TRUE); /* Update the face data structure, by deleting the old face and putting in the triangle as the new face */ New_Face(face_id,in_edge2,out_edge2,vertex4); return; } /* Consecutive cases again, but with the output edge reversed */ else if (in_edge1 == out_edge2) { vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index); Output_TriEx(in_edge2,in_edge1,out_edge1,output,-1,-1,where); /* Now we have a triangle used, and a triangle that is left for later. */ /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE); dummy = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp,TRUE); /* Update the face data structure, by deleting the old face and putting in the triangle as the new face */ New_Face(face_id,in_edge2,out_edge1,vertex4); return; } else if (in_edge2 == out_edge2) { vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index); Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where); /* Now we have a triangle used, and a triangle that is left for later. */ /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE); dummy = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp,TRUE); /* Update the face data structure, by deleting the old face and putting in the triangle as the new face */ New_Face(face_id,in_edge1,out_edge1,vertex4); return; } /* The final case is where we want to come out the opposite edge. */ else { if( ((!reversed) && (out_edge1 == (AdjacentEx(in_edge1,in_edge2,index,size)))) || ((reversed) && (out_edge2 == (AdjacentEx(in_edge2,in_edge1,index,size))))) { /* We need to know the orientation of the input edge, so we know which way to put the diagonal. And also the output edge, so that we triangulate correctly. Does not need partial. */ Output_TriEx(in_edge1,in_edge2,out_edge2,output,-1,-1,where); Output_TriEx(in_edge2,out_edge2,out_edge1,output,-1,-1,where); dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy); RemoveList(pListHead,(PLISTINFO) temp); } else { /* Input and output orientation was reversed, so diagonal will be reversed from above. */ Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where); Output_TriEx(in_edge2,out_edge1,out_edge2,output,-1,-1,where); dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy); RemoveList(pListHead,(PLISTINFO) temp); } return; } } void P_Triangulate_Polygon(int out_edge1,int out_edge2,int in_edge1, int in_edge2,int size, int *index,FILE *output,FILE *fp, int reversed,int face_id,int *next_id, ListHead *pListHead, P_ADJACENCIES temp2, int where) { /* We have a polygon greater than 4 sides, which we wish to partially triangulate */ int next_bucket,vertex4,dummy = 60; int *temp; P_ADJACENCIES pfNode; /* Since we are calling this recursively, we have to check whether we are down to the case of the quad. */ if (size == 4) { P_Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size, index,output,fp,reversed,face_id,next_id, pListHead,temp2,where); return; } /* We do not have a specified input edge, and therefore we can make it anything we like, as long as we still come out the output edge that we want. */ if (reversed == -1) { /* Get the vertex for the last triangle, which is the one coming out the output edge, before we do any deletions to the list. We will be doing this bottom up. */ vertex4 = AdjacentEx(out_edge1,out_edge2,index,size); temp = (int *) malloc(sizeof(int) * size); memcpy(temp,index,sizeof(int)*size); Delete_From_ListEx(out_edge2,index,size); /* We do not have to partially triangulate, since we will do the whole thing, so use the whole routine */ Triangulate_PolygonEx(vertex4,out_edge1,in_edge2, vertex4,size-1,index,output,fp,reversed,face_id, next_id,pListHead,temp2,where); memcpy(index,temp,sizeof(int)*size); /* Lastly do the triangle that comes out the output edge. */ Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where); /* We were able to do the whole polygon, now we can delete the whole thing from our data structure. */ dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy); RemoveList(pListHead,(PLISTINFO) temp2); return; } /* These are the 5 cases that we can have for the output edge */ /* Are they consecutive so that we form a triangle to peel off that comes out the correct output edge, but we cannot use the whole polygon? */ if (in_edge2 == out_edge1) { Output_TriEx(in_edge1,out_edge1,out_edge2,output,-1,-1,where); /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE); next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE); /* Create a new edgelist without the triangle that was just outputted. */ Delete_From_ListEx(in_edge2,index,size); /* Update the face data structure, by deleting the old face and putting in the polygon minus the triangle as the new face, here we will be decrementing the size by one. */ New_Size_Face(face_id); return; } /* Next case is where it is again consecutive, but the triangle formed by the consecutive edges do not come out of the correct output edge. (the input edge will be reversed in the next triangle) */ else if (in_edge1 == out_edge1) { /* Get vertex adjacent to in_edge2, but is not in_edge1 */ Output_TriEx(in_edge2,in_edge1,out_edge2,output,-1,-1,where); /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE); next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE); /* Create a new edgelist without the triangle that was just outputted. */ Delete_From_ListEx(in_edge1,index,size); /* Update the face data structure, by deleting the old face and putting in the polygon minus the triangle as the new face, here we will be decrementing the size by one. */ New_Size_Face(face_id); return; } /* Consecutive cases again, but with the output edge reversed */ else if (in_edge1 == out_edge2) { Output_TriEx(in_edge2,in_edge1,out_edge1,output,-1,-1,where); /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(out_edge1,out_edge2,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE); next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE); /* Create a new edgelist without the triangle that was just outputted. */ Delete_From_ListEx(in_edge1,index,size); /* Update the face data structure, by deleting the old face and putting in the polygon minus the triangle as the new face, here we will be decrementing the size by one. */ New_Size_Face(face_id); return; } else if (in_edge2 == out_edge2) { Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where); /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE); next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE); /* Create a new edgelist without the triangle that was just outputted. */ Delete_From_ListEx(in_edge2,index,size); /* Update the face data structure, by deleting the old face and putting in the polygon minus the triangle as the new face, here we will be decrementing the size by one. */ New_Size_Face(face_id); return; } /* Else the edge is not consecutive, and it is sufficiently far away, for us not to make a conclusion at this time. So we can take off a triangle and recursively call this function. */ else { if (!reversed) { vertex4 = AdjacentEx(in_edge2,in_edge1,index,size); Output_TriEx(in_edge1,in_edge2,vertex4,output,-1,-1,where); /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(in_edge1,vertex4,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE); next_bucket = Change_FaceEx(face_id,in_edge1,vertex4,pListHead,temp2,FALSE); /* Create a new edgelist without the triangle that was just outputted. */ Delete_From_ListEx(in_edge1,index,size); /* Update the face data structure, by deleting the old face and putting in the polygon minus the triangle as the new face, here we will be decrementing the size by one. */ New_Size_Face(face_id); /* Save the info for the new bucket, we will need it on the next pass for the variables, pListHead and temp */ pListHead = array[next_bucket]; pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) ); if ( pfNode ) pfNode->face_id = face_id; temp2 = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode, (int (*)(void *,void *)) (Compare))); if (temp2 == NULL) { printf("There is an error finding the next polygon10\n",next_bucket,face_id); exit(0); } P_Triangulate_Polygon(out_edge1,out_edge2,in_edge2, vertex4,size-1,index,output,fp,!reversed, face_id,next_id,pListHead,temp2,where); } else { vertex4 = AdjacentEx(in_edge1,in_edge2,index,size); Output_TriEx(in_edge2,in_edge1,vertex4,output,-1,-1,where); /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(in_edge2,vertex4,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE); next_bucket = Change_FaceEx(face_id,in_edge2,vertex4,pListHead,temp2,FALSE); /* Create a new edgelist without the triangle that was just outputted. */ Delete_From_ListEx(in_edge2,index,size); /* Update the face data structure, by deleting the old face and putting in the polygon minus the triangle as the new face, here we will be decrementing the size by one. */ New_Size_Face(face_id); /* Save the info for the new bucket, we will need it on the next pass for the variables, pListHead and temp */ pListHead = array[next_bucket]; pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) ); if ( pfNode ) pfNode->face_id = face_id; temp2 = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode, (int (*)(void *,void *)) (Compare))); if (temp2 == NULL) { printf("There is an error finding the next polygon11 %d %d\n",face_id,next_bucket); exit(0); } P_Triangulate_Polygon(out_edge1,out_edge2,vertex4, in_edge1,size-1,index,output,fp,!reversed, face_id,next_id,pListHead,temp2,where); } return; } } void P_Triangulate(int out_edge1,int out_edge2,int in_edge1, int in_edge2,int size,int *index, FILE *fp,FILE *output,int reversed,int face_id, int *next_id,ListHead *pListHead, P_ADJACENCIES temp,int where) { if (size == 4) P_Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size, index,fp,output,reversed,face_id,next_id,pListHead, temp,where); else P_Triangulate_Polygon(out_edge1,out_edge2,in_edge1,in_edge2,size, index,fp,output,reversed,face_id,next_id,pListHead,temp,where); } void Partial_Triangulate(int size,int *index, FILE *fp, FILE *output,int next_face_id,int face_id, int *next_id,ListHead *pListHead, P_ADJACENCIES temp, int where) { int id1,id2,id3; int nedge1,nedge2; int reversed; /* We have a polygon that has to be triangulated and we cannot do it blindly, ie we will try to come out on the edge that has the least number of adjacencies, But also we do not want to triangulate the whole polygon now, so that means we will output the least number of triangles that we can and then update the data structures, with the polygon that is left after we are done. */ Last_Edge(&id1,&id2,&id3,0); /* Find the edge that is adjacent to the new face , also return whether the orientation is reversed in the face of the input edge, which is id2 and id3. */ reversed = Get_EdgeEx(&nedge1,&nedge2,index,next_face_id,size,id2,id3); /* Input edge and output edge can be the same if there are more than one polygon on an edge */ if ( ((nedge1 == id2) && (nedge2 == id3)) || ((nedge1 == id3) && (nedge2 == id2)) ) /* Set output edge arbitrarily but when come out of here the next face will be on the old output edge (identical one) */ nedge2 = Return_Other(index,id2,id3); /* Do the triangulation */ P_Triangulate(nedge1,nedge2,id2,id3,size,index,fp,output,reversed, face_id,next_id,pListHead,temp,where); } void Input_Edge(int face_id, int *index, int size, int in_edge1, int in_edge2, FILE *fp, FILE *output,ListHead *pListHead, P_ADJACENCIES temp2, int where) { /* The polygon had an input edge, specified by input1 and input2 */ int output1,next_bucket; int vertex4, vertex5,dummy=60; output1 = Get_Output_Edge(face_id,size,index,in_edge1,in_edge2); vertex5 = AdjacentEx(in_edge2,in_edge1,index,size); vertex4 = AdjacentEx(in_edge1,in_edge2,index,size); if (vertex4 == output1) { Output_TriEx(in_edge2,in_edge1,output1,output,-1,-1,where); /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(in_edge2,output1,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE); next_bucket = Change_FaceEx(face_id,in_edge2,output1,pListHead,temp2,FALSE); /* Create a new edgelist without the triangle that was just outputted. */ Delete_From_ListEx(in_edge2,index,size); } else if (vertex5 == output1) { Output_TriEx(in_edge1,in_edge2,vertex5,output,-1,-1,where); /* Now delete the adjacencies by one for all the faces that are adjacent to the triangle that we just outputted. */ Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id, &dummy,&dummy,&dummy); Delete_AdjEx(in_edge1,vertex5,&dummy,&dummy, face_id,&dummy,&dummy,&dummy); /* Put the new face in the proper bucket of adjacencies */ next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE); next_bucket = Change_FaceEx(face_id,in_edge1,vertex5,pListHead,temp2,FALSE); /* Create a new edgelist without the triangle that was just outputted. */ Delete_From_ListEx(in_edge1,index,size); } /* Update the face data structure, by deleting the old face and putting in the polygon minus the triangle as the new face, here we will be decrementing the size by one. */ New_Size_Face(face_id); return; } void Inside_Polygon(int size,int *index,FILE *fp,FILE *output, int next_face_id,int face_id,int *next_id, ListHead *pListHead,P_ADJACENCIES temp, int where) { /* We know that we have a polygon that is greater than 4 sides, and that it is better for us to go inside the polygon for the next one, since inside will have less adjacencies than going outside. So, we are not doing partial for a part of the polygon. */ int id1,id2,id3; int new1,new2; Last_Edge(&id1,&id2,&id3,0); /* See if the input edge existed in the polygon, that will help us */ if (Exist(face_id,id2,id3)) Input_Edge(face_id,index,size,id2,id3,output,fp,pListHead,temp,where); else { /* Make one of the input edges We will choose it by trying to get an edge that has something in common with the last triangle, or by getting the edge that is adjacent to the least number of thigs, with preference given to the first option */ Get_Input_Edge(index,id1,id2,id3,&new1,&new2,size,face_id); Input_Edge(face_id,index,size,new1,new2,output,fp,pListHead,temp,where); } }