⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sweep.c

📁 Mesa is an open-source implementation of the OpenGL specification - a system for rendering interacti
💻 C
📖 第 1 页 / 共 4 页
字号:
 * winding numbers and mesh connectivity appropriately.  All right-going * edges share a common origin vOrg.  Edges are inserted CCW starting at * eFirst; the last edge inserted is eLast->Oprev.  If vOrg has any * left-going edges already processed, then eTopLeft must be the edge * such that an imaginary upward vertical segment from vOrg would be * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft * should be NULL. */{  ActiveRegion *reg, *regPrev;  GLUhalfEdge *e, *ePrev;  int firstTime = TRUE;  /* Insert the new right-going edges in the dictionary */  e = eFirst;  do {    assert( VertLeq( e->Org, e->Dst ));    AddRegionBelow( tess, regUp, e->Sym );    e = e->Onext;  } while ( e != eLast );  /* Walk *all* right-going edges from e->Org, in the dictionary order,   * updating the winding numbers of each region, and re-linking the mesh   * edges to match the dictionary ordering (if necessary).   */  if( eTopLeft == NULL ) {    eTopLeft = RegionBelow( regUp )->eUp->Rprev;  }  regPrev = regUp;  ePrev = eTopLeft;  for( ;; ) {    reg = RegionBelow( regPrev );    e = reg->eUp->Sym;    if( e->Org != ePrev->Org ) break;    if( e->Onext != ePrev ) {      /* Unlink e from its current position, and relink below ePrev */      if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);      if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1);    }    /* Compute the winding number and "inside" flag for the new regions */    reg->windingNumber = regPrev->windingNumber - e->winding;    reg->inside = IsWindingInside( tess, reg->windingNumber );    /* Check for two outgoing edges with same slope -- process these     * before any intersection tests (see example in __gl_computeInterior).     */    regPrev->dirty = TRUE;    if( ! firstTime && CheckForRightSplice( tess, regPrev )) {      AddWinding( e, ePrev );      DeleteRegion( tess, regPrev );      if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1);    }    firstTime = FALSE;    regPrev = reg;    ePrev = e;  }  regPrev->dirty = TRUE;  assert( regPrev->windingNumber - e->winding == reg->windingNumber );  if( cleanUp ) {    /* Check for intersections between newly adjacent edges. */    WalkDirtyRegions( tess, regPrev );  }}static void CallCombine( GLUtesselator *tess, GLUvertex *isect,			 void *data[4], GLfloat weights[4], int needed ){  GLdouble coords[3];  /* Copy coord data in case the callback changes it. */  coords[0] = isect->coords[0];  coords[1] = isect->coords[1];  coords[2] = isect->coords[2];  isect->data = NULL;  CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data );  if( isect->data == NULL ) {    if( ! needed ) {      isect->data = data[0];    } else if( ! tess->fatalError ) {      /* The only way fatal error is when two edges are found to intersect,       * but the user has not provided the callback necessary to handle       * generated intersection points.       */      CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK );      tess->fatalError = TRUE;    }  }}static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1,				 GLUhalfEdge *e2 )/* * Two vertices with idential coordinates are combined into one. * e1->Org is kept, while e2->Org is discarded. */{  void *data[4] = { NULL, NULL, NULL, NULL };  GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 };  data[0] = e1->Org->data;  data[1] = e2->Org->data;  CallCombine( tess, e1->Org, data, weights, FALSE );  if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1);}static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst,			   GLfloat *weights )/* * Find some weights which describe how the intersection vertex is * a linear combination of "org" and "dest".  Each of the two edges * which generated "isect" is allocated 50% of the weight; each edge * splits the weight between its org and dst according to the * relative distance to "isect". */{  GLdouble t1 = VertL1dist( org, isect );  GLdouble t2 = VertL1dist( dst, isect );  weights[0] = 0.5 * t2 / (t1 + t2);  weights[1] = 0.5 * t1 / (t1 + t2);  isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0];  isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1];  isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2];}static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect,       GLUvertex *orgUp, GLUvertex *dstUp,       GLUvertex *orgLo, GLUvertex *dstLo )/* * We've computed a new intersection point, now we need a "data" pointer * from the user so that we can refer to this new vertex in the * rendering callbacks. */{  void *data[4];  GLfloat weights[4];  data[0] = orgUp->data;  data[1] = dstUp->data;  data[2] = orgLo->data;  data[3] = dstLo->data;  isect->coords[0] = isect->coords[1] = isect->coords[2] = 0;  VertexWeights( isect, orgUp, dstUp, &weights[0] );  VertexWeights( isect, orgLo, dstLo, &weights[2] );  CallCombine( tess, isect, data, weights, TRUE );}static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp )/* * Check the upper and lower edge of "regUp", to make sure that the * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which * origin is leftmost). * * The main purpose is to splice right-going edges with the same * dest vertex and nearly identical slopes (ie. we can't distinguish * the slopes numerically).  However the splicing can also help us * to recover from numerical errors.  For example, suppose at one * point we checked eUp and eLo, and decided that eUp->Org is barely * above eLo.  Then later, we split eLo into two edges (eg. from * a splice operation like this one).  This can change the result of * our test so that now eUp->Org is incident to eLo, or barely below it. * We must correct this condition to maintain the dictionary invariants. * * One possibility is to check these edges for intersection again * (ie. CheckForIntersect).  This is what we do if possible.  However * CheckForIntersect requires that tess->event lies between eUp and eLo, * so that it has something to fall back on when the intersection * calculation gives us an unusable answer.  So, for those cases where * we can't check for intersection, this routine fixes the problem * by just splicing the offending vertex into the other edge. * This is a guaranteed solution, no matter how degenerate things get. * Basically this is a combinatorial solution to a numerical problem. */{  ActiveRegion *regLo = RegionBelow(regUp);  GLUhalfEdge *eUp = regUp->eUp;  GLUhalfEdge *eLo = regLo->eUp;  if( VertLeq( eUp->Org, eLo->Org )) {    if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE;    /* eUp->Org appears to be below eLo */    if( ! VertEq( eUp->Org, eLo->Org )) {      /* Splice eUp->Org into eLo */      if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);      if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1);      regUp->dirty = regLo->dirty = TRUE;    } else if( eUp->Org != eLo->Org ) {      /* merge the two vertices, discarding eUp->Org */      pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */      SpliceMergeVertices( tess, eLo->Oprev, eUp );    }  } else {    if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE;    /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */    RegionAbove(regUp)->dirty = regUp->dirty = TRUE;    if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);    if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);  }  return TRUE;}static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp )/* * Check the upper and lower edge of "regUp", to make sure that the * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which * destination is rightmost). * * Theoretically, this should always be true.  However, splitting an edge * into two pieces can change the results of previous tests.  For example, * suppose at one point we checked eUp and eLo, and decided that eUp->Dst * is barely above eLo.  Then later, we split eLo into two edges (eg. from * a splice operation like this one).  This can change the result of * the test so that now eUp->Dst is incident to eLo, or barely below it. * We must correct this condition to maintain the dictionary invariants * (otherwise new edges might get inserted in the wrong place in the * dictionary, and bad stuff will happen). * * We fix the problem by just splicing the offending vertex into the * other edge. */{  ActiveRegion *regLo = RegionBelow(regUp);  GLUhalfEdge *eUp = regUp->eUp;  GLUhalfEdge *eLo = regLo->eUp;  GLUhalfEdge *e;  assert( ! VertEq( eUp->Dst, eLo->Dst ));  if( VertLeq( eUp->Dst, eLo->Dst )) {    if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE;    /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */    RegionAbove(regUp)->dirty = regUp->dirty = TRUE;    e = __gl_meshSplitEdge( eUp );    if (e == NULL) longjmp(tess->env,1);    if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1);    e->Lface->inside = regUp->inside;  } else {    if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE;    /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */    regUp->dirty = regLo->dirty = TRUE;    e = __gl_meshSplitEdge( eLo );    if (e == NULL) longjmp(tess->env,1);    if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1);    e->Rface->inside = regUp->inside;  }  return TRUE;}static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp )/* * Check the upper and lower edges of the given region to see if * they intersect.  If so, create the intersection and add it * to the data structures. * * Returns TRUE if adding the new intersection resulted in a recursive * call to AddRightEdges(); in this case all "dirty" regions have been * checked for intersections, and possibly regUp has been deleted. */{  ActiveRegion *regLo = RegionBelow(regUp);  GLUhalfEdge *eUp = regUp->eUp;  GLUhalfEdge *eLo = regLo->eUp;  GLUvertex *orgUp = eUp->Org;  GLUvertex *orgLo = eLo->Org;  GLUvertex *dstUp = eUp->Dst;  GLUvertex *dstLo = eLo->Dst;  GLdouble tMinUp, tMaxLo;  GLUvertex isect, *orgMin;  GLUhalfEdge *e;  assert( ! VertEq( dstLo, dstUp ));  assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 );  assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 );  assert( orgUp != tess->event && orgLo != tess->event );  assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge );  if( orgUp == orgLo ) return FALSE;	/* right endpoints are the same */  tMinUp = MIN( orgUp->t, dstUp->t );  tMaxLo = MAX( orgLo->t, dstLo->t );  if( tMinUp > tMaxLo ) return FALSE;	/* t ranges do not overlap */  if( VertLeq( orgUp, orgLo )) {    if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE;  } else {    if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE;  }  /* At this point the edges intersect, at least marginally */  DebugEvent( tess );  __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect );  /* The following properties are guaranteed: */  assert( MIN( orgUp->t, dstUp->t ) <= isect.t );  assert( isect.t <= MAX( orgLo->t, dstLo->t ));  assert( MIN( dstLo->s, dstUp->s ) <= isect.s );  assert( isect.s <= MAX( orgLo->s, orgUp->s ));  if( VertLeq( &isect, tess->event )) {    /* The intersection point lies slightly to the left of the sweep line,     * so move it until it''s slightly to the right of the sweep line.     * (If we had perfect numerical precision, this would never happen     * in the first place).  The easiest and safest thing to do is     * replace the intersection by tess->event.     */    isect.s = tess->event->s;    isect.t = tess->event->t;  }  /* Similarly, if the computed intersection lies to the right of the   * rightmost origin (which should rarely happen), it can cause   * unbelievable inefficiency on sufficiently degenerate inputs.   * (If you have the test program, try running test54.d with the   * "X zoom" option turned on).   */  orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo;  if( VertLeq( orgMin, &isect )) {    isect.s = orgMin->s;    isect.t = orgMin->t;  }  if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) {    /* Easy case -- intersection at one of the right endpoints */    (void) CheckForRightSplice( tess, regUp );    return FALSE;  }  if(	 (! VertEq( dstUp, tess->event )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -