/* ** License Applicability. Except to the extent portions of this file are ** made subject to an alternative license as permitted in the SGI Free ** Software License B, Version 1.1 (the "License"), the contents of this ** file are subject only to the provisions of the License. You may not use ** this file except in compliance with the License. You may obtain a copy ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: ** ** http://oss.sgi.com/projects/FreeB ** ** Note that, as provided in the License, the Software is distributed on an ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. ** ** Original Code. The Original Code is: OpenGL Sample Implementation, ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. ** Copyright in any portions created by third parties is as indicated ** elsewhere herein. All Rights Reserved. ** ** Additional Notice Provisions: The application programming interfaces ** established by SGI in conjunction with the Original Code are The ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X ** Window System(R) (Version 1.3), released October 19, 1998. This software ** was created using the OpenGL(R) version 1.2.1 Sample Implementation ** published by SGI, but has not been independently verified as being ** compliant with the OpenGL(R) version 1.2.1 Specification. ** ** $Date: 2006/03/29 18:46:46 $ $Revision: 1.5 $ */ /* ** $Header: /home/krh/git/sync/mesa-cvs-repo/Mesa/src/glu/sgi/libnurbs/nurbtess/monoTriangulation.cc,v 1.5 2006/03/29 18:46:46 brianp Exp $ */ #include #include #include "gluos.h" #include "glimports.h" #include "zlassert.h" #include "monoTriangulation.h" #include "polyUtil.h" /*for area*/ #include "partitionX.h" #include "monoPolyPart.h" extern directedLine* polygonConvert(directedLine* polygon); /*poly is NOT deleted */ void monoTriangulationOpt(directedLine* poly, primStream* pStream) { Int n_cusps; Int n_edges = poly->numEdges(); directedLine** cusps = (directedLine**) malloc(sizeof(directedLine*)*n_edges); assert(cusps); findInteriorCuspsX(poly, n_cusps, cusps); if(n_cusps ==0) //u monotine { monoTriangulationFun(poly, compV2InX, pStream); } else if(n_cusps == 1) // one interior cusp { directedLine* new_polygon = polygonConvert(cusps[0]); directedLine* other = findDiagonal_singleCuspX(new_polygon); // should NOT be null unless there are self-intersecting //trim curves. In that case, we don't want to core dump, instead, //we triangulate anyway, and print out error message. if(other == NULL) { monoTriangulationFun(poly, compV2InX, pStream); } else { directedLine* ret_p1; directedLine* ret_p2; new_polygon->connectDiagonal_2slines(new_polygon, other, &ret_p1, &ret_p2, new_polygon); monoTriangulationFun(ret_p1, compV2InX, pStream); monoTriangulationFun(ret_p2, compV2InX, pStream); ret_p1->deleteSinglePolygonWithSline(); ret_p2->deleteSinglePolygonWithSline(); } } else { //we need a general partitionX funtion (supposed to be in partitionX.C, //not implemented yet. XXX monoTriangulationFun(poly, compV2InY, pStream); } free(cusps); } void monoTriangulationRecOpt(Real* topVertex, Real* botVertex, vertexArray* left_chain, Int left_current, vertexArray* right_chain, Int right_current, primStream* pStream) { Int i,j; Int n_left = left_chain->getNumElements(); Int n_right = right_chain->getNumElements(); if(left_current>= n_left-1 || right_current>= n_right-1) { monoTriangulationRec(topVertex, botVertex, left_chain, left_current, right_chain, right_current, pStream); return; } //now both left and right have at least two vertices each. Real left_v = left_chain->getVertex(left_current)[1]; Real right_v = right_chain->getVertex(right_current)[1]; if(left_v <= right_v) //first left vertex is below right { //find the last vertex of right which is above or equal to left for(j=right_current; j<=n_right-1; j++) { if(right_chain->getVertex(j)[1] < left_v) break; } monoTriangulationRecGen(topVertex, left_chain->getVertex(left_current), left_chain, left_current, left_current, right_chain, right_current, j-1, pStream); monoTriangulationRecOpt(right_chain->getVertex(j-1), botVertex, left_chain, left_current, right_chain, j, pStream); } else //first right vertex is strictly below left { //find the last vertex of left which is strictly above right for(i=left_current; i<=n_left-1; i++) { if(left_chain->getVertex(i)[1] <= right_v) break; } monoTriangulationRecGen(topVertex, right_chain->getVertex(right_current), left_chain, left_current, i-1, right_chain, right_current, right_current, pStream); monoTriangulationRecOpt(left_chain->getVertex(i-1), botVertex, left_chain, i, right_chain, right_current, pStream); } } void monoTriangulationRecGenTBOpt(Real* topVertex, Real* botVertex, vertexArray* inc_chain, Int inc_current, Int inc_end, vertexArray* dec_chain, Int dec_current, Int dec_end, primStream* pStream) { pStream->triangle(topVertex, inc_chain->getVertex(inc_current), dec_chain->getVertex(dec_current)); /*printf("**(%f,%f)\n", inc_chain->getArray()[0][0],inc_chain->getArray()[0][1]);*/ triangulateXYMonoTB(inc_end-inc_current+1, inc_chain->getArray()+inc_current, dec_end-dec_current+1, dec_chain->getArray()+dec_current, pStream); pStream->triangle(botVertex, dec_chain->getVertex(dec_end), inc_chain->getVertex(inc_end)); } /*n_left>=1 *n_right>=1 *the strip is going top to bottom. compared to the funtion * triangulateXYmono() */ void triangulateXYMonoTB(Int n_left, Real** leftVerts, Int n_right, Real** rightVerts, primStream* pStream) { Int i,j,k,l; Real* topMostV; assert(n_left>=1 && n_right>=1); if(leftVerts[0][1] >= rightVerts[0][1]) { i=1; j=0; topMostV = leftVerts[0]; } else { i=0; j=1; topMostV = rightVerts[0]; } while(1) { if(i >= n_left) /*case1: no more in left*/ { if(jbegin(); pStream->insert(topMostV); for(k=n_right-1; k>=j; k--) pStream->insert(rightVerts[j]); pStream->end(PRIMITIVE_STREAM_FAN); } break; } else if(j>= n_right) /*case2: no more in right*/ { if(ibegin(); pStream->insert(topMostV); for(k=i; kinsert(leftVerts[k]); pStream->end(PRIMITIVE_STREAM_FAN); } break; } else /* case3: neither is empty, plus the topMostV, there is at least one triangle to output*/ { if(leftVerts[i][1] >= rightVerts[j][1]) { pStream->begin(); pStream->insert(rightVerts[j]); /*the origin of this fan*/ pStream->insert(topMostV); /*find the last k>=i such that *leftverts[k][1] >= rightverts[j][1] */ k=i; while(kinsert(leftVerts[l]); } pStream->end(PRIMITIVE_STREAM_FAN); //update i for next loop i = k+1; topMostV = leftVerts[k]; } else /*leftVerts[i][1] < rightVerts[j][1]*/ { pStream->begin(); pStream->insert(leftVerts[i]);/*the origion of this fan*/ /*find the last k>=j such that *rightverts[k][1] > leftverts[i][1]*/ k=j; while(k< n_right) { if(rightVerts[k][1] <= leftVerts[i][1]) break; k++; } k--; for(l=k; l>= j; l--) pStream->insert(rightVerts[l]); pStream->insert(topMostV); pStream->end(PRIMITIVE_STREAM_FAN); j=k+1; topMostV = rightVerts[j-1]; } } } } static int chainConvex(vertexArray* inc_chain, Int inc_current, Int inc_end) { Int i; //if there are no more than 2 vertices, return 1 if(inc_current >= inc_end-1) return 1; for(i=inc_current; i<= inc_end-2; i++) { if(area(inc_chain->getVertex(i), inc_chain->getVertex(i+1), inc_chain->getVertex(i+2)) <0) return 0; } return 1; } static int chainConcave(vertexArray* dec_chain, Int dec_current, Int dec_end) { Int i; //if there are no more than 2 vertices, return 1 if(dec_current >= dec_end -1) return 1; for(i=dec_current; i<=dec_end-2; i++) { if(area(dec_chain->getVertex(i), dec_chain->getVertex(i+1), dec_chain->getVertex(i+2)) >0) return 0; } return 1; } void monoTriangulationRecGenInU(Real* topVertex, Real* botVertex, vertexArray* inc_chain, Int inc_current, Int inc_end, vertexArray* dec_chain, Int dec_current, Int dec_end, primStream* pStream) { } void monoTriangulationRecGenOpt(Real* topVertex, Real* botVertex, vertexArray* inc_chain, Int inc_current, Int inc_end, vertexArray* dec_chain, Int dec_current, Int dec_end, primStream* pStream) { Int i; //copy this to a polygon: directedLine Lioop sampledLine* sline; directedLine* dline; directedLine* poly; if(inc_current <= inc_end) //at least one vertex in inc_chain { sline = new sampledLine(topVertex, inc_chain->getVertex(inc_current)); poly = new directedLine(INCREASING, sline); for(i=inc_current; i<=inc_end-1; i++) { sline = new sampledLine(inc_chain->getVertex(i), inc_chain->getVertex(i+1)); dline = new directedLine(INCREASING, sline); poly->insert(dline); } sline = new sampledLine(inc_chain->getVertex(inc_end), botVertex); dline = new directedLine(INCREASING, sline); poly->insert(dline); } else //inc_chian is empty { sline = new sampledLine(topVertex, botVertex); dline = new directedLine(INCREASING, sline); poly = dline; } assert(poly != NULL); if(dec_current <= dec_end) //at least on vertex in dec_Chain { sline = new sampledLine(botVertex, dec_chain->getVertex(dec_end)); dline = new directedLine(INCREASING, sline); poly->insert(dline); for(i=dec_end; i>dec_current; i--) { sline = new sampledLine(dec_chain->getVertex(i), dec_chain->getVertex(i-1)); dline = new directedLine(INCREASING, sline); poly->insert(dline); } sline = new sampledLine(dec_chain->getVertex(dec_current), topVertex); dline = new directedLine(INCREASING, sline); poly->insert(dline); } else //dec_chain is empty { sline = new sampledLine(botVertex, topVertex); dline = new directedLine(INCREASING, sline); poly->insert(dline); } { Int n_cusps; Int n_edges = poly->numEdges(); directedLine** cusps = (directedLine**) malloc(sizeof(directedLine*)*n_edges); assert(cusps); findInteriorCuspsX(poly, n_cusps, cusps); if(n_cusps ==0) //u monotine { monoTriangulationFun(poly, compV2InX, pStream); } else if(n_cusps == 1) // one interior cusp { directedLine* new_polygon = polygonConvert(cusps[0]); directedLine* other = findDiagonal_singleCuspX(new_polygon); // should NOT be null unless there are self-intersecting //trim curves. In that case, we don't want to core dump, instead, //we triangulate anyway, and print out error message. if(other == NULL) { monoTriangulationFun(poly, compV2InX, pStream); } else { directedLine* ret_p1; directedLine* ret_p2; new_polygon->connectDiagonal_2slines(new_polygon, other, &ret_p1, &ret_p2, new_polygon); monoTriangulationFun(ret_p1, compV2InX, pStream); monoTriangulationFun(ret_p2, compV2InX, pStream); ret_p1->deleteSinglePolygonWithSline(); ret_p2->deleteSinglePolygonWithSline(); } } else { //we need a general partitionX funtion (supposed to be in partitionX.C, //not implemented yet. XXX //monoTriangulationFun(poly, compV2InY, pStream); directedLine* new_polygon = polygonConvert(poly); directedLine* list = monoPolyPart(new_polygon); for(directedLine* temp = list; temp != NULL; temp = temp->getNextPolygon()) { monoTriangulationFun(temp, compV2InX, pStream); } //clean up list->deletePolygonListWithSline(); } free(cusps); /* if(numInteriorCuspsX(poly) == 0) //is u monotone monoTriangulationFun(poly, compV2InX, pStream); else //it is not u motone monoTriangulationFun(poly, compV2InY, pStream); */ //clean up space poly->deleteSinglePolygonWithSline(); return; } //apparently the following code is not reachable, //it is for test purpose if(inc_current > inc_end || dec_current>dec_end) { monoTriangulationRecGen(topVertex, botVertex, inc_chain, inc_current, inc_end, dec_chain, dec_current, dec_end, pStream); return; } if( area(dec_chain->getVertex(dec_current), topVertex, inc_chain->getVertex(inc_current)) >=0 && chainConvex(inc_chain, inc_current, inc_end) && chainConcave(dec_chain, dec_current, dec_end) && area(inc_chain->getVertex(inc_end), botVertex, dec_chain->getVertex(dec_end)) >=0 ) { monoTriangulationRecFunGen(topVertex, botVertex, inc_chain, inc_current, inc_end, dec_chain, dec_current, dec_end, compV2InX, pStream); } else { monoTriangulationRecGen(topVertex, botVertex, inc_chain, inc_current, inc_end, dec_chain, dec_current, dec_end, pStream); } } /*if inc_current>inc_end, then inc_chain has no points to be considered *same for dec_chain */ void monoTriangulationRecGen(Real* topVertex, Real* botVertex, vertexArray* inc_chain, Int inc_current, Int inc_end, vertexArray* dec_chain, Int dec_current, Int dec_end, primStream* pStream) { Real** inc_array ; Real** dec_array ; Int i; if(inc_current > inc_end && dec_current>dec_end) return; else if(inc_current>inc_end) /*no more vertices on inc_chain*/ { dec_array = dec_chain->getArray(); reflexChain rChain(100,0); /*put the top vertex into the reflex chain*/ rChain.processNewVertex(topVertex, pStream); /*process all the vertices on the dec_chain*/ for(i=dec_current; i<=dec_end; i++){ rChain.processNewVertex(dec_array[i], pStream); } /*process the bottom vertex*/ rChain.processNewVertex(botVertex, pStream); } else if(dec_current> dec_end) /*no more vertices on dec_chain*/ { inc_array = inc_chain->getArray(); reflexChain rChain(100,1); /*put the top vertex into the reflex chain*/ rChain.processNewVertex(topVertex, pStream); /*process all the vertices on the inc_chain*/ for(i=inc_current; i<=inc_end; i++){ rChain.processNewVertex(inc_array[i], pStream); } /*process the bottom vertex*/ rChain.processNewVertex(botVertex, pStream); } else /*neither chain is empty*/ { inc_array = inc_chain -> getArray(); dec_array = dec_chain -> getArray(); /*if top of inc_chain is 'lower' than top of dec_chain, process all the *vertices on the dec_chain which are higher than top of inc_chain */ if(compV2InY(inc_array[inc_current], dec_array[dec_current]) <= 0) { reflexChain rChain(100, 0); rChain.processNewVertex(topVertex, pStream); for(i=dec_current; i<=dec_end; i++) { if(compV2InY(inc_array[inc_current], dec_array[i]) <= 0) rChain.processNewVertex(dec_array[i], pStream); else break; } rChain.outputFan(inc_array[inc_current], pStream); monoTriangulationRecGen(dec_array[i-1], botVertex, inc_chain, inc_current, inc_end, dec_chain, i, dec_end, pStream); } else /*compV2InY(inc_array[inc_current], dec_array[dec_current]) > 0*/ { reflexChain rChain(100, 1); rChain.processNewVertex(topVertex, pStream); for(i=inc_current; i<=inc_end; i++) { if(compV2InY(inc_array[i], dec_array[dec_current]) >0) rChain.processNewVertex(inc_array[i], pStream); else break; } rChain.outputFan(dec_array[dec_current], pStream); monoTriangulationRecGen(inc_array[i-1], botVertex, inc_chain, i, inc_end, dec_chain, dec_current,dec_end, pStream); } }/*end case neither is empty*/ } void monoTriangulationFun(directedLine* monoPolygon, Int (*compFun)(Real*, Real*), primStream* pStream) { Int i; /*find the top vertex, bottom vertex, inccreasing chain, and decreasing chain, *then call monoTriangulationRec */ directedLine* tempV; directedLine* topV; directedLine* botV; topV = botV = monoPolygon; for(tempV = monoPolygon->getNext(); tempV != monoPolygon; tempV = tempV->getNext()) { if(compFun(topV->head(), tempV->head())<0) { topV = tempV; } if(compFun(botV->head(), tempV->head())>0) { botV = tempV; } } /*creat increase and decrease chains*/ vertexArray inc_chain(20); /*this is a dynamic array*/ for(i=1; i<=topV->get_npoints()-2; i++) { /*the first vertex is the top vertex which doesn't belong to inc_chain*/ inc_chain.appendVertex(topV->getVertex(i)); } for(tempV = topV->getNext(); tempV != botV; tempV = tempV->getNext()) { for(i=0; i<=tempV->get_npoints()-2; i++){ inc_chain.appendVertex(tempV->getVertex(i)); } } vertexArray dec_chain(20); for(tempV = topV->getPrev(); tempV != botV; tempV = tempV->getPrev()) { for(i=tempV->get_npoints()-2; i>=0; i--){ dec_chain.appendVertex(tempV->getVertex(i)); } } for(i=botV->get_npoints()-2; i>=1; i--){ dec_chain.appendVertex(tempV->getVertex(i)); } if (!(0 == inc_chain.getNumElements() && 0 == dec_chain.getNumElements())) { monoTriangulationRecFun(topV->head(), botV->head(), &inc_chain, 0, &dec_chain, 0, compFun, pStream); } } void monoTriangulation(directedLine* monoPolygon, primStream* pStream) { Int i; /*find the top vertex, bottom vertex, inccreasing chain, and decreasing chain, *then call monoTriangulationRec */ directedLine* tempV; directedLine* topV; directedLine* botV; topV = botV = monoPolygon; for(tempV = monoPolygon->getNext(); tempV != monoPolygon; tempV = tempV->getNext()) { if(compV2InY(topV->head(), tempV->head())<0) { topV = tempV; } if(compV2InY(botV->head(), tempV->head())>0) { botV = tempV; } } /*creat increase and decrease chains*/ vertexArray inc_chain(20); /*this is a dynamic array*/ for(i=1; i<=topV->get_npoints()-2; i++) { /*the first vertex is the top vertex which doesn't belong to inc_chain*/ inc_chain.appendVertex(topV->getVertex(i)); } for(tempV = topV->getNext(); tempV != botV; tempV = tempV->getNext()) { for(i=0; i<=tempV->get_npoints()-2; i++){ inc_chain.appendVertex(tempV->getVertex(i)); } } vertexArray dec_chain(20); for(tempV = topV->getPrev(); tempV != botV; tempV = tempV->getPrev()) { for(i=tempV->get_npoints()-2; i>=0; i--){ dec_chain.appendVertex(tempV->getVertex(i)); } } for(i=botV->get_npoints()-2; i>=1; i--){ dec_chain.appendVertex(tempV->getVertex(i)); } monoTriangulationRec(topV->head(), botV->head(), &inc_chain, 0, &dec_chain, 0, pStream); } /*the chain could be increasing or decreasing, although we use the * name inc_chain. *the argument is_increase_chain indicates whether this chain *is increasing (left chain in V-monotone case) or decreaing (right chain *in V-monotone case). */ void monoTriangulation2(Real* topVertex, Real* botVertex, vertexArray* inc_chain, Int inc_smallIndex, Int inc_largeIndex, Int is_increase_chain, primStream* pStream) { assert( inc_chain != NULL); Real** inc_array ; if(inc_smallIndex > inc_largeIndex) return; //no triangles if(inc_smallIndex == inc_largeIndex) { if(is_increase_chain) pStream->triangle(inc_chain->getVertex(inc_smallIndex), botVertex, topVertex); else pStream->triangle(inc_chain->getVertex(inc_smallIndex), topVertex, botVertex); return; } Int i; if(is_increase_chain && botVertex[1] == inc_chain->getVertex(inc_largeIndex)[1]) { pStream->triangle(botVertex, inc_chain->getVertex(inc_largeIndex-1), inc_chain->getVertex(inc_largeIndex)); monoTriangulation2(topVertex, botVertex, inc_chain, inc_smallIndex, inc_largeIndex-1, is_increase_chain, pStream); return; } else if( (!is_increase_chain) && topVertex[1] == inc_chain->getVertex(inc_smallIndex)[1]) { pStream->triangle(topVertex, inc_chain->getVertex(inc_smallIndex+1), inc_chain->getVertex(inc_smallIndex)); monoTriangulation2(topVertex, botVertex, inc_chain, inc_smallIndex+1, inc_largeIndex, is_increase_chain, pStream); return ; } inc_array = inc_chain->getArray(); reflexChain rChain(20,is_increase_chain); /*1 means the chain is increasing*/ rChain.processNewVertex(topVertex, pStream); for(i=inc_smallIndex; i<=inc_largeIndex; i++){ rChain.processNewVertex(inc_array[i], pStream); } rChain.processNewVertex(botVertex, pStream); } /*if compFun == compV2InY, top to bottom: V-monotone *if compFun == compV2InX, right to left: U-monotone */ void monoTriangulationRecFunGen(Real* topVertex, Real* botVertex, vertexArray* inc_chain, Int inc_current, Int inc_end, vertexArray* dec_chain, Int dec_current, Int dec_end, Int (*compFun)(Real*, Real*), primStream* pStream) { assert( inc_chain != NULL && dec_chain != NULL); assert( ! (inc_current> inc_end && dec_current> dec_end)); /* Int inc_nVertices; Int dec_nVertices; */ Real** inc_array ; Real** dec_array ; Int i; assert( ! ( (inc_chain==NULL) && (dec_chain==NULL))); if(inc_current> inc_end) /*no more vertices on inc_chain*/ { dec_array = dec_chain->getArray(); reflexChain rChain(20,0); /*put the top vertex into the reflex chain*/ rChain.processNewVertex(topVertex, pStream); /*process all the vertices on the dec_chain*/ for(i=dec_current; i<=dec_end; i++){ rChain.processNewVertex(dec_array[i], pStream); } /*process the bottom vertex*/ rChain.processNewVertex(botVertex, pStream); } else if(dec_current> dec_end) /*no more vertices on dec_chain*/ { inc_array = inc_chain->getArray(); reflexChain rChain(20,1); /*put the top vertex into the reflex chain*/ rChain.processNewVertex(topVertex, pStream); /*process all the vertices on the inc_chain*/ for(i=inc_current; i<=inc_end; i++){ rChain.processNewVertex(inc_array[i], pStream); } /*process the bottom vertex*/ rChain.processNewVertex(botVertex, pStream); } else /*neither chain is empty*/ { inc_array = inc_chain -> getArray(); dec_array = dec_chain -> getArray(); /*if top of inc_chain is 'lower' than top of dec_chain, process all the *vertices on the dec_chain which are higher than top of inc_chain */ if(compFun(inc_array[inc_current], dec_array[dec_current]) <= 0) { reflexChain rChain(20, 0); rChain.processNewVertex(topVertex, pStream); for(i=dec_current; i<=dec_end; i++) { if(compFun(inc_array[inc_current], dec_array[i]) <= 0) rChain.processNewVertex(dec_array[i], pStream); else break; } rChain.outputFan(inc_array[inc_current], pStream); monoTriangulationRecFunGen(dec_array[i-1], botVertex, inc_chain, inc_current, inc_end, dec_chain, i, dec_end, compFun, pStream); } else /*compFun(inc_array[inc_current], dec_array[dec_current]) > 0*/ { reflexChain rChain(20, 1); rChain.processNewVertex(topVertex, pStream); for(i=inc_current; i<=inc_end; i++) { if(compFun(inc_array[i], dec_array[dec_current]) >0) rChain.processNewVertex(inc_array[i], pStream); else break; } rChain.outputFan(dec_array[dec_current], pStream); monoTriangulationRecFunGen(inc_array[i-1], botVertex, inc_chain, i,inc_end, dec_chain, dec_current,dec_end, compFun, pStream); } }/*end case neither is empty*/ } /*if compFun == compV2InY, top to bottom: V-monotone *if compFun == compV2InX, right to left: U-monotone */ void monoTriangulationRecFun(Real* topVertex, Real* botVertex, vertexArray* inc_chain, Int inc_current, vertexArray* dec_chain, Int dec_current, Int (*compFun)(Real*, Real*), primStream* pStream) { assert( inc_chain != NULL && dec_chain != NULL); assert( ! (inc_current>=inc_chain->getNumElements() && dec_current>=dec_chain->getNumElements())); Int inc_nVertices; Int dec_nVertices; Real** inc_array ; Real** dec_array ; Int i; assert( ! ( (inc_chain==NULL) && (dec_chain==NULL))); if(inc_current>=inc_chain->getNumElements()) /*no more vertices on inc_chain*/ { dec_array = dec_chain->getArray(); dec_nVertices = dec_chain->getNumElements(); reflexChain rChain(20,0); /*put the top vertex into the reflex chain*/ rChain.processNewVertex(topVertex, pStream); /*process all the vertices on the dec_chain*/ for(i=dec_current; i= dec_chain->getNumElements()) /*no more vertices on dec_chain*/ { inc_array = inc_chain->getArray(); inc_nVertices= inc_chain->getNumElements(); reflexChain rChain(20,1); /*put the top vertex into the reflex chain*/ rChain.processNewVertex(topVertex, pStream); /*process all the vertices on the inc_chain*/ for(i=inc_current; i getArray(); dec_array = dec_chain -> getArray(); inc_nVertices= inc_chain->getNumElements(); dec_nVertices= dec_chain->getNumElements(); /*if top of inc_chain is 'lower' than top of dec_chain, process all the *vertices on the dec_chain which are higher than top of inc_chain */ if(compFun(inc_array[inc_current], dec_array[dec_current]) <= 0) { reflexChain rChain(20, 0); rChain.processNewVertex(topVertex, pStream); for(i=dec_current; i 0*/ { reflexChain rChain(20, 1); rChain.processNewVertex(topVertex, pStream); for(i=inc_current; i0) rChain.processNewVertex(inc_array[i], pStream); else break; } rChain.outputFan(dec_array[dec_current], pStream); monoTriangulationRecFun(inc_array[i-1], botVertex, inc_chain, i, dec_chain, dec_current, compFun, pStream); } }/*end case neither is empty*/ } void monoTriangulationRec(Real* topVertex, Real* botVertex, vertexArray* inc_chain, Int inc_current, vertexArray* dec_chain, Int dec_current, primStream* pStream) { assert( inc_chain != NULL && dec_chain != NULL); assert( ! (inc_current>=inc_chain->getNumElements() && dec_current>=dec_chain->getNumElements())); Int inc_nVertices; Int dec_nVertices; Real** inc_array ; Real** dec_array ; Int i; assert( ! ( (inc_chain==NULL) && (dec_chain==NULL))); if(inc_current>=inc_chain->getNumElements()) /*no more vertices on inc_chain*/ { dec_array = dec_chain->getArray(); dec_nVertices = dec_chain->getNumElements(); reflexChain rChain(20,0); /*put the top vertex into the reflex chain*/ rChain.processNewVertex(topVertex, pStream); /*process all the vertices on the dec_chain*/ for(i=dec_current; i= dec_chain->getNumElements()) /*no more vertices on dec_chain*/ { inc_array = inc_chain->getArray(); inc_nVertices= inc_chain->getNumElements(); reflexChain rChain(20,1); /*put the top vertex into the reflex chain*/ rChain.processNewVertex(topVertex, pStream); /*process all the vertices on the inc_chain*/ for(i=inc_current; i getArray(); dec_array = dec_chain -> getArray(); inc_nVertices= inc_chain->getNumElements(); dec_nVertices= dec_chain->getNumElements(); /*if top of inc_chain is 'lower' than top of dec_chain, process all the *vertices on the dec_chain which are higher than top of inc_chain */ if(compV2InY(inc_array[inc_current], dec_array[dec_current]) <= 0) { reflexChain rChain(20, 0); rChain.processNewVertex(topVertex, pStream); for(i=dec_current; i 0*/ { reflexChain rChain(20, 1); rChain.processNewVertex(topVertex, pStream); for(i=inc_current; i0) rChain.processNewVertex(inc_array[i], pStream); else break; } rChain.outputFan(dec_array[dec_current], pStream); monoTriangulationRec(inc_array[i-1], botVertex, inc_chain, i, dec_chain, dec_current, pStream); } }/*end case neither is empty*/ } /* the name here assumes that the polygon is Y-monotone, but *this function also works for X-monotone polygons. * a monotne polygon consists of two extrem verteices: topVertex and botVertex, and *two monotone chains: inc_chain, and dec_chain. The edges of the increasing chain (inc_chain) *is ordered by following pointer: next, while the edges of the decreasing chain (dec_chain) *is ordered by following pointer: prev * inc_index index the vertex which is the toppest of the inc_chain which we are handling currently. * dec_index index the vertex which is the toppest of the dec_chain which we are handling currently. */ void monoTriangulationRec(directedLine* inc_chain, Int inc_index, directedLine* dec_chain, Int dec_index, directedLine* topVertex, Int top_index, directedLine* botVertex, primStream* pStream) { Int i; directedLine *temp, *oldtemp = NULL; Int tempIndex, oldtempIndex = 0; assert(inc_chain != NULL && dec_chain != NULL); if(inc_chain == botVertex) { reflexChain rChain(20, 0); rChain.processNewVertex(topVertex->getVertex(top_index), pStream); for(i=dec_index; i< dec_chain->get_npoints(); i++){ rChain.processNewVertex(dec_chain->getVertex(i), pStream); } for(temp = dec_chain->getPrev(); temp != botVertex; temp = temp->getPrev()) { for(i=0; iget_npoints(); i++){ rChain.processNewVertex(temp->getVertex(i), pStream); } } } else if(dec_chain==botVertex) { reflexChain rChain(20, 1); rChain.processNewVertex(topVertex->getVertex(top_index), pStream); for(i=inc_index; i< inc_chain->get_npoints(); i++){ rChain.processNewVertex(inc_chain->getVertex(i), pStream); } for(temp = inc_chain->getPrev(); temp != botVertex; temp = temp->getNext()) { for(i=0; iget_npoints(); i++){ rChain.processNewVertex(temp->getVertex(i), pStream); } } } else /*neither reached the bottom*/{ if(compV2InY(inc_chain->getVertex(inc_index), dec_chain->getVertex(dec_index)) <=0) { reflexChain rChain(20, 0); rChain.processNewVertex(topVertex -> getVertex(top_index), pStream); temp = dec_chain; tempIndex = dec_index; while( compV2InY(inc_chain->getVertex(inc_index), temp->getVertex(tempIndex))<=0) { oldtemp = temp; oldtempIndex = tempIndex; rChain.processNewVertex(temp->getVertex(tempIndex), pStream); if(tempIndex == temp->get_npoints()-1){ tempIndex = 0; temp = temp->getPrev(); } else{ tempIndex++; } } rChain.outputFan(inc_chain->getVertex(inc_index), pStream); monoTriangulationRec(inc_chain, inc_index, temp, tempIndex, oldtemp, oldtempIndex, botVertex, pStream); } else /* >0*/ { reflexChain rChain(20, 1); rChain.processNewVertex(topVertex -> getVertex(top_index), pStream); temp = inc_chain; tempIndex = inc_index; while( compV2InY(temp->getVertex(tempIndex), dec_chain->getVertex(dec_index))>0){ oldtemp = temp; oldtempIndex = tempIndex; rChain.processNewVertex(temp->getVertex(tempIndex), pStream); if(tempIndex == temp->get_npoints()-1){ tempIndex = 0; temp = temp->getNext(); } else{ tempIndex++; } } rChain.outputFan(dec_chain->getVertex(dec_index), pStream); monoTriangulationRec(temp, tempIndex, dec_chain, dec_index, oldtemp, oldtempIndex, botVertex, pStream); } } /*end case neither reached the bottom*/ } /***************************vertexArray begin here**********************************/ vertexArray::vertexArray(Real2* vertices, Int nVertices) { Int i; size = index = nVertices; array = (Real**) malloc(sizeof(Real*) * nVertices); assert(array); for(i=0; i= size){ Real** temp = (Real**) malloc(sizeof(Real*) * (2*size +1)); assert(temp); for(i=0; i= v * and array[i+1][1] v *if sartIndex>endIndex, then return endIndex+1. *otherwise, startIndex<=endIndex, it is assumed that * 0<=startIndex<=endIndex endIndex) return endIndex+1; else if(array[endIndex][1] > v) return endIndex+1; else //now array[endIndex][1] <= v { for(i=endIndex-1; i>=startIndex; i--) { if(array[i][1] > v) break; } return i+1; } } /*find the first i<=endIndex such that array[i-1][1] >= v * and array[i][1] < v *if sartIndex>endIndex, then return endIndex+1. *otherwise, startIndex<=endIndex, it is assumed that * 0<=startIndex<=endIndex endIndex) return endIndex+1; else if(array[endIndex][1] >= v) return endIndex+1; else //now array[endIndex][1] < v { for(i=endIndex-1; i>=startIndex; i--) { if(array[i][1] >= v) break; } return i+1; } } /*find the first i>startIndex such that array[i-1][1] > v * and array[i][1] >=v *if sartIndex>endIndex, then return startIndex-1. *otherwise, startIndex<=endIndex, it is assumed that * 0<=startIndex<=endIndex endIndex) return startIndex-1; else if(array[startIndex][1] < v) return startIndex-1; else //now array[startIndex][1] >= v { for(i=startIndex; i<=endIndex; i++) { if(array[i][1] <= v) break; } if(i>endIndex) // v is strictly below all return endIndex; else if(array[i][1] == v) return i; else return i-1; } } /*find the first i>=startIndex such that array[i][1] >= v * and array[i+1][1] endIndex, then return startIndex-1. *otherwise, startIndex<=endIndex, it is assumed that * 0<=startIndex<=endIndex endIndex) return startIndex-1; else if(array[startIndex][1] < v) return startIndex-1; else //now array[startIndex][1] >= v { for(i=startIndex+1; i<=endIndex; i++) { if(array[i][1] < v) break; } return i-1; } } Int vertexArray::findDecreaseChainFromEnd(Int begin, Int end) { Int i = end; Real prevU = array[i][0]; Real thisU; for(i=end-1; i>=begin; i--){ thisU = array[i][0]; if(thisU < prevU) prevU = thisU; else break; } return i; } //if(V(start) == v, return start, other wise return the //last i so that V(i)==v Int vertexArray::skipEqualityFromStart(Real v, Int start, Int end) { Int i; if(array[start][1] != v) return start; //now array[start][1] == v for(i=start+1; i<= end; i++) if(array[i][1] != v) break; return i-1; } /***************************vertexArray end****************************************/ /***************************relfex chain stuff begin here*****************************/ reflexChain::reflexChain(Int size, Int is_increasing) { queue = (Real2*) malloc(sizeof(Real2) * size); assert(queue); index_queue = 0; size_queue = size; isIncreasing = is_increasing; } reflexChain::~reflexChain() { free(queue); } /*put (u,v) at the end of the queue *pay attention to space */ void reflexChain::insert(Real u, Real v) { Int i; if(index_queue >= size_queue) { Real2 *temp = (Real2*) malloc(sizeof(Real2) * (2*size_queue+1)); assert(temp); /*copy*/ for(i=0; ibegin(); pStream->insert(v); if(isIncreasing) { for(i=0; iinsert(queue[i]); } else { for(i=index_queue-1; i>=0; i--) pStream->insert(queue[i]); } pStream->end(PRIMITIVE_STREAM_FAN); } void reflexChain::processNewVertex(Real v[2], primStream* pStream) { Int i,j,k; Int isReflex; /*if there are at most one vertex in the queue, then simply insert */ if(index_queue <=1){ insert(v); return; } /*there are at least two vertices in the queue*/ j=index_queue-1; for(i=j; i>=1; i--) { if(isIncreasing) { isReflex = (area(queue[i-1], queue[i], v) <= 0.0); } else /*decreasing*/{ isReflex = (area(v, queue[i], queue[i-1]) <= 0.0); } if(isReflex) { break; } } /* *if ibegin(); pStream->insert(v); if(isIncreasing) { for(k=i; k<=j; k++) pStream->insert(queue[k]); } else { for(k=j; k>=i; k--) pStream->insert(queue[k]); } pStream->end(PRIMITIVE_STREAM_FAN); } /*delete vertices i+1--j from the queue*/ index_queue = i+1; /*finally insert v at the end of the queue*/ insert(v); } void reflexChain::print() { Int i; printf("reflex chain: isIncreasing=%i\n", isIncreasing); for(i=0; i