int tessComputeInterior( TESStesselator *tess ) /* * tessComputeInterior( tess ) computes the planar arrangement specified * by the given contours, and further subdivides this arrangement * into regions. Each region is marked "inside" if it belongs * to the polygon, according to the rule given by tess->windingRule. * Each interior region is guaranteed be monotone. */ { TESSvertex *v, *vNext; /* Each vertex defines an event for our sweep line. Start by inserting * all the vertices in a priority queue. Events are processed in * lexicographic order, ie. * * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y) */ RemoveDegenerateEdges( tess ); if ( !InitPriorityQ( tess ) ) return 0; /* if error */ InitEdgeDict( tess ); while( (v = (TESSvertex *)pqExtractMin( tess->pq )) != NULL ) { for( ;; ) { vNext = (TESSvertex *)pqMinimum( tess->pq ); if( vNext == NULL || ! VertEq( vNext, v )) break; /* Merge together all vertices at exactly the same location. * This is more efficient than processing them one at a time, * simplifies the code (see ConnectLeftDegenerate), and is also * important for correct handling of certain degenerate cases. * For example, suppose there are two identical edges A and B * that belong to different contours (so without this code they would * be processed by separate sweep events). Suppose another edge C * crosses A and B from above. When A is processed, we split it * at its intersection point with C. However this also splits C, * so when we insert B we may compute a slightly different * intersection point. This might leave two edges with a small * gap between them. This kind of error is especially obvious * when using boundary extraction (TESS_BOUNDARY_ONLY). */ vNext = (TESSvertex *)pqExtractMin( tess->pq ); SpliceMergeVertices( tess, v->anEdge, vNext->anEdge ); } SweepEvent( tess, v ); } /* Set tess->event for debugging purposes */ tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org; DebugEvent( tess ); DoneEdgeDict( tess ); DonePriorityQ( tess ); if ( !RemoveDegenerateFaces( tess, tess->mesh ) ) return 0; tessMeshCheckMesh( tess->mesh ); return 1; }
static void DoneEdgeDict( TESStesselator *tess ) { ActiveRegion *reg; while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) { /* * At the end of all processing, the dictionary should contain * only the two sentinel edges, plus at most one "fixable" edge * created by ConnectRightVertex(). */ if( ! reg->sentinel ) { assert( reg->fixUpperEdge ); //assert( ++fixedEdges == 1 ); } assert( reg->windingNumber == 0 ); DeleteRegion( tess, reg ); /* tessMeshDelete( reg->eUp );*/ } dictDeleteDict( &tess->alloc, tess->dict ); }
static void DoneEdgeDict( GLUtesselator *tess ) { ActiveRegion *reg; int fixedEdges = 0; /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */ while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) { /* * At the end of all processing, the dictionary should contain * only the two sentinel edges, plus at most one "fixable" edge * created by ConnectRightVertex(). */ if( ! reg->sentinel ) { assert( reg->fixUpperEdge ); assert( ++fixedEdges == 1 ); } assert( reg->windingNumber == 0 ); DeleteRegion( tess, reg ); /* __gl_meshDelete( reg->eUp );*/ } dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */ }
// Parameter phase only for tracing SimplexResult Tableau::primalSimplex(int phase) { const int width = getWidth(); const int constraintCount = getConstraintCount(); for(int r = 1; r <= constraintCount; r++) { const TableauRow &row = m_table[r]; const int bv = row.m_basisVariable; const Real &a = row.m_a[bv]; if(a == 0) { continue; } Real factor = getObjectFactor(bv) / a; if(factor == 0) { trace(TRACE_WARNINGS,_T("Warning:Cost factor[%s] = 0."), getVariableName(bv).cstr()); continue; } for(int col = 0; col <= width; col++) { objectFactor(col) -= row.m_a[col] * factor; } objectFactor(bv) = 0; } bool looping = false; for(int iteration = 1;; iteration++) { if(isTracing(TRACE_ITERATIONS)) { trace(_T("Phase %d. Iteration %d"), phase, iteration); traceTableau(); // traceBasis(_T("Current basis:")); } int pivotColumn; Real minCost = 1; if(looping) { for(int col = 1; col <= width; col++) { // Apply Bland's anti-cycling rule step 1. const Real &cc = objectFactor(col); if(cc < -EPS) { minCost = cc; pivotColumn = col; break; } } } else { // else find pivot column the old way for(int col = 1; col <= width; col++) { const Real &cc = objectFactor(col); if(cc < minCost) { minCost = cc; pivotColumn = col; } } } if(minCost >= -EPS) { return SIMPLEX_SOLUTION_OK; // Optimal value found } int pivotRow = -1; Real minRatio = 0; if(looping) { // apply Bland's anti-cycling rule step 2. for(int r = 1; r <= constraintCount; r++) { const Real &ar = m_table[r].m_a[pivotColumn]; if(ar > 10*EPS) { const Real &br = getRightSide(r); const Real ratio = br / ar; if((pivotRow == -1) || (ratio < minRatio)) { minRatio = ratio; pivotRow = r; } } } if(pivotRow >= 0) { int minIndex = -1; for(int r = 1; r <= constraintCount; r++) { const Real &ar = m_table[r].m_a[pivotColumn]; if(ar > 10*EPS) { const Real &br = getRightSide(r); const Real ratio = br / ar; if(ratio == minRatio) { const int index = m_table[r].m_basisVariable; if(minIndex == -1 || index < minIndex) { minIndex = index; pivotRow = r; } } } } } } else { // else find pivot row the old way for(int r = 1; r <= constraintCount; r++) { const Real &ar = m_table[r].m_a[pivotColumn]; if(ar > EPS) { const Real &br = getRightSide(r); const Real ratio = br / ar; if(pivotRow == -1 || ratio < minRatio) { minRatio = ratio; pivotRow = r; } } } } if(pivotRow == -1) { return SIMPLEX_SOLUTION_UNLIMITED; } // Check for degeneracy traceDegeneracy(pivotRow, pivotColumn, minRatio); DictionaryKey dictKey(this); if(m_dictionarySet.contains(dictKey)) { looping = true; trace(TRACE_WARNINGS, _T("Looping. Applying Blands anti cycling rule.")); } else { m_dictionarySet.add(dictKey); } pivot(pivotRow,pivotColumn,true); } }
static void ConnectLeftVertex( TESStesselator *tess, TESSvertex *vEvent ) /* * Purpose: connect a "left" vertex (one where both edges go right) * to the processed portion of the mesh. Let R be the active region * containing vEvent, and let U and L be the upper and lower edge * chains of R. There are two possibilities: * * - the normal case: split R into two regions, by connecting vEvent to * the rightmost vertex of U or L lying to the left of the sweep line * * - the degenerate case: if vEvent is close enough to U or L, we * merge vEvent into that edge chain. The subcases are: * - merging with the rightmost vertex of U or L * - merging with the active edge of U or L * - merging with an already-processed portion of U or L */ { ActiveRegion *regUp, *regLo, *reg; TESShalfEdge *eUp, *eLo, *eNew; ActiveRegion tmp; /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */ /* Get a pointer to the active region containing vEvent */ tmp.eUp = vEvent->anEdge->Sym; /* __GL_DICTLISTKEY */ /* tessDictListSearch */ regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp )); regLo = RegionBelow( regUp ); if( !regLo ) { // This may happen if the input polygon is coplanar. return; } eUp = regUp->eUp; eLo = regLo->eUp; /* Try merging with U or L first */ if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) { ConnectLeftDegenerate( tess, regUp, vEvent ); return; } /* Connect vEvent to rightmost processed vertex of either chain. * e->Dst is the vertex that we will connect to vEvent. */ reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo; if( regUp->inside || reg->fixUpperEdge) { if( reg == regUp ) { eNew = tessMeshConnect( tess->mesh, vEvent->anEdge->Sym, eUp->Lnext ); if (eNew == NULL) longjmp(tess->env,1); } else { TESShalfEdge *tempHalfEdge= tessMeshConnect( tess->mesh, eLo->Dnext, vEvent->anEdge); if (tempHalfEdge == NULL) longjmp(tess->env,1); eNew = tempHalfEdge->Sym; } if( reg->fixUpperEdge ) { if ( !FixUpperEdge( tess, reg, eNew ) ) longjmp(tess->env,1); } else { ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew )); } SweepEvent( tess, vEvent ); } else { /* The new vertex is in a region which does not belong to the polygon. * We don''t need to connect this vertex to the rest of the mesh. */ AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE ); } }