graphNonplanar.c

Go to the documentation of this file.
00001 /* Copyright (c) 2005 by John M. Boyer, All Rights Reserved.  Please see
00002  * License.txt for use and redistribution license. */
00003 /* Copyright (c) 1997-2003 by John M. Boyer, All Rights Reserved.
00004         This code may not be reproduced or disseminated in whole or in part 
00005         without the written permission of the author. */
00006 
00007 #define GRAPHNONPLANAR_C
00008 
00009 #include "graph_boyer.h"
00010 
00011 /* Imported functions */
00012 extern void _ClearIsolatorContext (graphP theGraph);
00013 extern void _FillVisitedFlags (graphP,
00014                                int);
00015 extern void _FillVisitedFlagsInBicomp (graphP theGraph,
00016                                        int BicompRoot,
00017                                        int FillValue);
00018 extern void _SetVertexTypeInBicomp (graphP theGraph,
00019                                     int BicompRoot,
00020                                     int theType);
00021 extern int _GetNextVertexOnExternalFace (graphP theGraph,
00022                                          int curVertex,
00023                                          int *pPrevLink);
00024 extern int _GetPertinentChildBicomp (graphP theGraph,
00025                                      int W);
00026 extern void _WalkDown (graphP theGraph,
00027                        int I,
00028                        int RootVertex);
00029 extern void _OrientVerticesInEmbedding (graphP theGraph);
00030 extern void _OrientVerticesInBicomp (graphP theGraph,
00031                                      int BicompRoot,
00032                                      int PreserveSigns);
00033 
00034 /* Private functions (exported to system) */
00035 int _ChooseTypeOfNonplanarityMinor (graphP theGraph,
00036                                     int I,
00037                                     int R);
00038 int _InitializeNonplanarityContext (graphP theGraph,
00039                                     int I,
00040                                     int R);
00041 int _FindNonplanarityBicompRoot (graphP theGraph);
00042 void _FindActiveVertices (graphP theGraph,
00043                           int R,
00044                           int *pX,
00045                           int *pY);
00046 int _FindPertinentVertex (graphP theGraph);
00047 void _PopAndUnmarkVerticesAndEdges (graphP theGraph,
00048                                     int Z);
00049 int _MarkHighestXYPath (graphP theGraph);
00050 int _MarkZtoRPath (graphP theGraph);
00051 int _FindExtActivityBelowXYPath (graphP theGraph);
00052 
00053 /****************************************************************************
00054  _ChooseTypeOfNonplanarityMinor()
00055  ****************************************************************************/
00056 int _ChooseTypeOfNonplanarityMinor (graphP theGraph,
00057                                     int I,
00058                                     int R)
00059 {
00060   int N,
00061     X,
00062     Y,
00063     W,
00064     Px,
00065     Py,
00066     Z,
00067     DFSChild,
00068     RootId;
00069 
00070 /* Create the initial non-planarity minor state in the isolator context */
00071   if (_InitializeNonplanarityContext (theGraph, I, R) != OK)
00072     return NOTOK;
00073   N = theGraph->N;
00074   R = theGraph->IC.r;
00075   X = theGraph->IC.x;
00076   Y = theGraph->IC.y;
00077   W = theGraph->IC.w;
00078 
00079 /* If the root copy is not a root copy of the current vertex I,
00080         then the Walkdown terminated because it couldn't find 
00081         a viable path along a child bicomp, which is Minor A. */
00082   if (theGraph->V[R - N].DFSParent != I)
00083 
00084   {
00085     theGraph->IC.minorType |= FLAGS_MINOR_A;
00086     return OK;
00087   }
00088 
00089 /* If W has an externally active pertinent child bicomp, then
00090      we've found Minor B */
00091   if (theGraph->V[W].pertinentBicompList != NIL)
00092 
00093   {
00094     RootId =
00095       LCGetPrev (theGraph->BicompLists, theGraph->V[W].pertinentBicompList,
00096                  NIL);
00097     DFSChild = RootId;
00098     if (theGraph->V[DFSChild].Lowpoint < I)
00099 
00100     {
00101       theGraph->IC.minorType |= FLAGS_MINOR_B;
00102       return OK;
00103     }
00104   }
00105 
00106 /* Find the highest obstructing X-Y path */
00107   if (_MarkHighestXYPath (theGraph) != OK)
00108     return NOTOK;
00109   Px = theGraph->IC.px;
00110   Py = theGraph->IC.py;
00111 
00112 /* If either point of attachment is 'high' (P_x closer to R than X
00113      or P_y closer to R than Y along external face), then we've
00114      matched Minor C. */
00115   if (theGraph->G[Px].type == VERTEX_HIGH_RXW
00116       || theGraph->G[Py].type == VERTEX_HIGH_RYW)
00117 
00118   {
00119     theGraph->IC.minorType |= FLAGS_MINOR_C;
00120     return OK;
00121   }
00122 
00123 /* For Minor D, we search for a path from an internal
00124      vertex Z along the X-Y path up to the root R of the bicomp. */
00125   if (_MarkZtoRPath (theGraph) == NOTOK)
00126     return NOTOK;
00127   if (theGraph->IC.z != NIL)
00128 
00129   {
00130     theGraph->IC.minorType |= FLAGS_MINOR_D;
00131     return OK;
00132   }
00133 
00134 /* For Minor E, we search for an externally active vertex Z
00135      below the points of attachment of the X-Y path */
00136   Z = _FindExtActivityBelowXYPath (theGraph);
00137   if (Z != NIL)
00138 
00139   {
00140     theGraph->IC.z = Z;
00141     theGraph->IC.minorType |= FLAGS_MINOR_E;
00142     return OK;
00143   }
00144   return NOTOK;
00145 }
00146 
00147 
00148 /****************************************************************************
00149  _InitializeNonplanarityContext()
00150  ****************************************************************************/
00151 int _InitializeNonplanarityContext (graphP theGraph,
00152                                     int I,
00153                                     int R)
00154 {
00155   int e,
00156     X,
00157     Y,
00158     W,
00159     Z,
00160     ZPrevLink,
00161     ZType;
00162   int singleBicompMode = (R == NIL) ? 0 : 1;
00163 
00164 /* For the embedding or in a given bicomp, orient the vertices, 
00165     and clear the visited members of all vertex and edge records. */
00166   if (!singleBicompMode)
00167 
00168   {
00169     _OrientVerticesInEmbedding (theGraph);
00170     _FillVisitedFlags (theGraph, 0);
00171   }
00172 
00173   else
00174 
00175   {
00176     _OrientVerticesInBicomp (theGraph, R, 1);
00177     _FillVisitedFlagsInBicomp (theGraph, R, 0);
00178   }
00179 
00180 /* Blank out the isolator context, then assign the input graph reference
00181      and the current vertext I into the context. */
00182   _ClearIsolatorContext (theGraph);
00183   theGraph->IC.v = I;
00184 
00185 /* Now we find a root copy R of the current vertex on which the Walkdown failed
00186    (i.e. there is an unembedded back edge between an ancestor of the current
00187    vertex and descendant of the current vertex in the subtree rooted by
00188    the DFS child C=R-N. */
00189   R = _FindNonplanarityBicompRoot (theGraph);
00190   if (R == NIL)
00191     return NOTOK;
00192 
00193 /* Now we find the active vertices along both external face paths extending 
00194      from R. If either is not a stopping vertex, then we call Walkdown to
00195      reconstruct the stack to the root of the descendant bicomp that blocked 
00196      the Walkdown. Otherwise, R is the desired root. Either way, the stopping
00197      vertices x and y are calculated. */
00198   _FindActiveVertices (theGraph, R, &X, &Y);
00199   if (theGraph->V[X].pertinentBicompList != NIL
00200       || theGraph->V[Y].pertinentBicompList != NIL)
00201 
00202   {
00203 
00204     /* We are dealing with minor A, which has a main bicomp rooted by
00205      * a descendant of R.  So we put the bicomp rooted by R back
00206      * the way we found it. */
00207     if (singleBicompMode)
00208       _OrientVerticesInBicomp (theGraph, R, 1);
00209 
00210     /* Now we do the Walkdown to find the descendant bicomp. */
00211     _WalkDown (theGraph, I, R);
00212     if (sp_IsEmpty (theGraph->theStack))
00213       return NOTOK;
00214     sp_Pop2 (theGraph->theStack, R, e);
00215 
00216     /* Now we give the proper orientation to the descendant bicomp, 
00217      * but we make it reversible (last param=1) to make processing
00218      * easier for the K3,3 search, which simply reinitializes
00219      * everything when it finds minor A. */
00220     if (singleBicompMode)
00221       _OrientVerticesInBicomp (theGraph, R, 1);
00222 
00223     /* Now we find the stopping vertices along the external face
00224      * paths of the descendant bicomp. */
00225     _FindActiveVertices (theGraph, R, &X, &Y);
00226   }
00227 
00228 /* We store the info we have gathered so far in the isolator context */
00229   theGraph->IC.r = R;
00230   theGraph->IC.x = X;
00231   theGraph->IC.y = Y;
00232 
00233 /* Now, we obtain the pertinent vertex W on the lower external face
00234     path between X and Y (that path that does not include R). */
00235   theGraph->IC.w = W = _FindPertinentVertex (theGraph);
00236 
00237 /* In the current bicomp, we clear the type flags */
00238 
00239 /* Now we can classify the vertices along the external face of the bicomp
00240     rooted at R as 'high RXW', 'low RXW', 'high RXY', 'low RXY' */
00241   _SetVertexTypeInBicomp (theGraph, R, TYPE_UNKNOWN);
00242   ZPrevLink = 1;
00243   Z = _GetNextVertexOnExternalFace (theGraph, R, &ZPrevLink);
00244   ZType = VERTEX_HIGH_RXW;
00245   while (Z != W)
00246 
00247   {
00248     if (Z == X)
00249       ZType = VERTEX_LOW_RXW;
00250     theGraph->G[Z].type = ZType;
00251     Z = _GetNextVertexOnExternalFace (theGraph, Z, &ZPrevLink);
00252   }
00253   ZPrevLink = 0;
00254   Z = _GetNextVertexOnExternalFace (theGraph, R, &ZPrevLink);
00255   ZType = VERTEX_HIGH_RYW;
00256   while (Z != W)
00257 
00258   {
00259     if (Z == Y)
00260       ZType = VERTEX_LOW_RYW;
00261     theGraph->G[Z].type = ZType;
00262     Z = _GetNextVertexOnExternalFace (theGraph, Z, &ZPrevLink);
00263   }
00264 
00265 /* All work is done, so return success */
00266   return OK;
00267 }
00268 
00269 
00270 /****************************************************************************
00271  _FindNonplanarityBicompRoot()
00272 
00273  This procedure finds the root copy R of the current vertex on which the
00274  Walkdown failed (whether it failed while traversing the bicomp rooted by
00275  R or some descendant bicomp is determined later).
00276 
00277  We iterate the forward cycle edges of the vertex I looking for a forward 
00278  edge (I, W) that was not embedded.  Once it is found, we figure out which 
00279  bicomp rooted by a root copy of I contains W or contains a DFS ancestor of W.
00280 
00281  This turns out to be an easy test.  The desired bicomp is rooted by the DFS
00282  tree edge (I, C) with the largest value of C that does not exceed W.  C is
00283  a DFS ancestor of Z.
00284 
00285  Return: The desired root copy, or NIL on error.
00286  ****************************************************************************/
00287 int _FindNonplanarityBicompRoot (graphP theGraph)
00288 {
00289   int R,
00290     tempChild,
00291     fwdArc,
00292     W = NIL,
00293     C = NIL,
00294     I = theGraph->IC.v;
00295 
00296 /* Obtain the forward arc of an unembedded back edge from I to one of its
00297     descendants (edges are removed from the forward arc list as they are
00298     embedded, so the list will be empty if all edges were embedded). */
00299   if ((fwdArc = theGraph->V[I].fwdArcList) == NIL)
00300     return NIL;
00301   W = theGraph->G[fwdArc].v;
00302 
00303 /* Find the greatest DFS child C of I that is less than W.  This will
00304     give us the ancestor of W that is a child of I.  Since the
00305     ancestors of I have not been processed by the planarity algorithm,
00306     the separatedDFSChildList of I contains all the children of I. */
00307   tempChild = theGraph->V[I].separatedDFSChildList;
00308   while (tempChild != NIL)
00309 
00310   {
00311     if (tempChild > C && tempChild < W)
00312       C = tempChild;
00313     tempChild =
00314       LCGetNext (theGraph->DFSChildLists, theGraph->V[I].separatedDFSChildList,
00315                  tempChild);
00316   }
00317   if (C == NIL)
00318     return NIL;
00319 
00320 /* The root vertex of a bicomp rooted by edge (I, C) is located at
00321         position C+N in our data structures */
00322   R = C + theGraph->N;
00323   return R;
00324 }
00325 
00326 
00327 /****************************************************************************
00328  _FindStoppingVertices()
00329 
00330  Descends from the root of a bicomp R in both the link[0] and link[1] 
00331  directions, returning the first active vertex appearing in either direction.
00332  ****************************************************************************/
00333 void _FindActiveVertices (graphP theGraph,
00334                           int R,
00335                           int *pX,
00336                           int *pY)
00337 {
00338   int XPrevLink = 1,
00339     YPrevLink = 0,
00340     I = theGraph->IC.v;
00341   *pX = _GetNextVertexOnExternalFace (theGraph, R, &XPrevLink);
00342   *pY = _GetNextVertexOnExternalFace (theGraph, R, &YPrevLink);
00343   while (_VertexActiveStatus (theGraph, *pX, I) == VAS_INACTIVE)
00344     *pX = _GetNextVertexOnExternalFace (theGraph, *pX, &XPrevLink);
00345   while (_VertexActiveStatus (theGraph, *pY, I) == VAS_INACTIVE)
00346     *pY = _GetNextVertexOnExternalFace (theGraph, *pY, &YPrevLink);
00347 }
00348 
00349 
00350 /****************************************************************************
00351  _FindPertinentVertex()
00352 
00353  Get the first vertex after x. Since x was obtained using a prevlink of 1 on r,
00354  we use the same prevlink so we don't go back to r (works because all vertices
00355  have the same orientation).
00356  Then, we proceed around the lower path until we find a vertex W that either
00357  has pertinent child bicomps or is directly adjacent to the current vertex I.
00358  ****************************************************************************/
00359 int _FindPertinentVertex (graphP theGraph)
00360 {
00361   int W = theGraph->IC.x,
00362     WPrevLink = 1,
00363     I = theGraph->IC.v;
00364   W = _GetNextVertexOnExternalFace (theGraph, W, &WPrevLink);
00365   while (W != theGraph->IC.y)
00366 
00367   {
00368     if (PERTINENT (theGraph, W, I))
00369       return W;
00370     W = _GetNextVertexOnExternalFace (theGraph, W, &WPrevLink);
00371   }
00372   return NIL;
00373 }
00374 
00375 
00376 /****************************************************************************
00377  _PopAndUnmarkVerticesAndEdges()
00378 
00379  Pop all vertex/edge pairs from the top of the stack up to a terminating
00380  vertex Z and mark as unvisited.  If Z is NIL, then all vertex/edge pairs
00381  are popped and marked as unvisited.
00382  ****************************************************************************/
00383 void _PopAndUnmarkVerticesAndEdges (graphP theGraph,
00384                                     int Z)
00385 {
00386   int V,
00387     e;
00388   while (sp_NonEmpty (theGraph->theStack))
00389 
00390   {
00391     sp_Pop (theGraph->theStack, e);
00392 
00393     /* If we popped a vertex other than the termination vertex Z, then
00394      * we also pop the edge we pushed, and we clear the visited flags
00395      * for the vertex and the edge's two edge records. */
00396     if (e < 2 * theGraph->N && e != Z)
00397 
00398     {
00399       V = e;
00400       sp_Pop (theGraph->theStack, e);
00401       theGraph->G[V].visited = 0;
00402       theGraph->G[e].visited = 0;
00403       theGraph->G[gp_GetTwinArc (theGraph, e)].visited = 0;
00404     }
00405 
00406     /* If we popped an edge or the terminating vertex Z, then put it
00407      * back and break */
00408 
00409     else
00410 
00411     {
00412       sp_Push (theGraph->theStack, e);
00413       break;
00414     }
00415   }
00416 }
00417 
00418 
00419 /****************************************************************************
00420  _MarkHighestXYPath()
00421 
00422  An X-Y path in the bicomp rooted by R is a path attached to the external
00423  face at points Px and Py that separates W from R such that a back edge (R, W)
00424  cannot be embedded within the bicomp. Recall that R is a root copy of I, so
00425  (R, W) is the representative of (I, W).  Also, note that W is pertinent if
00426  either W *or* one of its descendants in a separate bicomp has, in the input 
00427  graph, a back edge to I.
00428 
00429  If no X-Y path separating W from R is found, then NOTOK is returned because
00430  this procedure is only called once an X-Y path is guaranteed (by our proof
00431  of correctness) to exist.
00432 
00433  The desired output is to set the 'visited' flags of the X-Y path with
00434  highest points of attachment to the external face (i.e. the points of
00435  attachment that are closest to R along the external face).  This includes
00436  marking both the vertices and edges along the X-Y path.
00437 
00438  As a function of initialization, the vertices along the external face
00439  (other than R and W) have been classified as 'high RXW', 'low RXW', 'high RXY', 
00440  or 'low RXY'. Once the vertices have been categorized, we proceed with trying 
00441  to set the visitation flags in the way described above.  To do this, we first 
00442  remove all edges incident to R except the two edges that join R to the external 
00443  face. The result is that R and its two remaining edges are a 'corner' in the
00444  external face but also in a single proper face whose boundary includes the
00445  X-Y path with the highest attachment points. Thus, we simply need to walk
00446  this proper face to find the desired X-Y path. Note, however, that the
00447  resulting face boundary may have attached cut vertices.  Any such separable
00448  component contains a vertex neighbor of R, but the edge to R has been
00449  temporarily removed.  The algorithm removes loop of vertices and edges along
00450  the proper face so that only a path is identified.
00451 
00452  To walk the proper face containing R, we begin with its link[0] successor,
00453  then take the link[1] corner at every subsequent turn.  For each vertex,
00454  we mark as visited the vertex as well as the edge used to enter the vertex
00455  (except for the edge used to enter the RXW vertex).  We also push the visited
00456  vertices and edges onto a stack.
00457 
00458  As we walk the proper face, we keep track of the last vertex P_x we visited of
00459  type RXW (high or low).  Each time we encounter a vertex of type RXW (high or
00460  low), we pop the stack and unmark all of the edges and vertices visited because
00461  they were part of a path parallel to the external face that does not obstruct
00462  W from reaching R within the bicomp.  If we encounter vertex W, then there is
00463  no obstructing X-Y path since we removed only edges incident to R, so we pop
00464  the stack unmarking everything then return NOTOK as stated above.  If we
00465  encounter a vertex Z previously visited, then we pop the stack, unmarking the
00466  vertices and edges popped, until we find the prior occurence of Z on the stack.
00467 
00468  Otherwise, the first time we encounter a vertex P_y of type 'RYW', we stop
00469  because the obstructing X-Y path has been marked visited and its points of
00470  connection P_x and P_y have been found.
00471 
00472  Once the X-Y path is identified, we restore the edges incident to R.
00473 
00474  The stack space used is no greater than 3N.  The first N accounts for removing
00475  the edges incident to R.  The other 2N accounts for the fact that each
00476  iteration of the main loop visits a vertex, pushing its index and the
00477  location of an edge record.  If a vertex is encountered that is already
00478  on the stack, then it is not pushed again (and in fact part of the stack
00479  is removed). 
00480  ****************************************************************************/
00481 int _MarkHighestXYPath (graphP theGraph)
00482 {
00483   int J,
00484     Z,
00485     e;
00486   int R,
00487     X,
00488     Y,
00489     W;
00490 
00491 /* Initialization */
00492   R = theGraph->IC.r;
00493   X = theGraph->IC.x;
00494   Y = theGraph->IC.y;
00495   W = theGraph->IC.w;
00496   theGraph->IC.px = theGraph->IC.py = NIL;
00497   sp_ClearStack (theGraph->theStack);
00498 
00499 /* Remove the internal edges incident to vertex R */
00500   J = theGraph->G[R].link[0];
00501   J = theGraph->G[J].link[0];
00502   while (J != theGraph->G[R].link[1])
00503 
00504   {
00505     sp_Push (theGraph->theStack, J);
00506     gp_HideEdge (theGraph, J);
00507     J = theGraph->G[J].link[0];
00508   }
00509 
00510 /* Walk the proper face containing R to find and mark the highest
00511         X-Y path. Note that if W is encountered, then there is no
00512         intervening X-Y path, so we would return NOTOK. */
00513   Z = R;
00514   J = theGraph->G[R].link[1];
00515   while (theGraph->G[Z].type != VERTEX_HIGH_RYW
00516          && theGraph->G[Z].type != VERTEX_LOW_RYW)
00517 
00518   {
00519 
00520     /* Advance J and Z along the proper face containing R */
00521     J = theGraph->G[J].link[1];
00522     if (J < 2 * theGraph->N)
00523       J = theGraph->G[J].link[1];
00524     Z = theGraph->G[J].v;
00525     J = gp_GetTwinArc (theGraph, J);
00526 
00527     /* If Z is already visited, then pop everything since the last time
00528      * we visited Z because its all part of a separable component. */
00529     if (theGraph->G[Z].visited)
00530 
00531     {
00532       _PopAndUnmarkVerticesAndEdges (theGraph, Z);
00533     }
00534 
00535     /* If we have not visited this vertex before... */
00536 
00537     else
00538 
00539     {
00540 
00541       /* If we found another vertex along the RXW path, then blow off
00542        * all the vertices we visited so far because they're not part of
00543        * the obstructing path */
00544       if (theGraph->G[Z].type == VERTEX_HIGH_RXW
00545           || theGraph->G[Z].type == VERTEX_LOW_RXW)
00546 
00547       {
00548         theGraph->IC.px = Z;
00549         _PopAndUnmarkVerticesAndEdges (theGraph, NIL);
00550       }
00551 
00552       /* Push the current vertex onto the stack of vertices visited
00553        * since the last RXW vertex was encountered */
00554       sp_Push (theGraph->theStack, J);
00555       sp_Push (theGraph->theStack, Z);
00556 
00557       /* Mark the vertex Z as visited as well as its edge of entry
00558        * (except the entry edge for P_x). */
00559       theGraph->G[Z].visited = 1;
00560       if (Z != theGraph->IC.px)
00561 
00562       {
00563         theGraph->G[J].visited = 1;
00564         theGraph->G[gp_GetTwinArc (theGraph, J)].visited = 1;
00565       }
00566 
00567       /* If we found an RYW vertex, then we have successfully finished
00568        * identifying the highest X-Y path, so we record the point of
00569        * attachment and break the loop. */
00570       if (theGraph->G[Z].type == VERTEX_HIGH_RYW
00571           || theGraph->G[Z].type == VERTEX_LOW_RYW)
00572 
00573       {
00574         theGraph->IC.py = Z;
00575         break;
00576       }
00577     }
00578   }
00579 
00580 /* Restore the internal edges incident to R that were previously removed,
00581         ignoring any leftover vertices that might be on the stack. */
00582   while (sp_NonEmpty (theGraph->theStack))
00583 
00584   {
00585     sp_Pop (theGraph->theStack, e);
00586     if (e < 2 * theGraph->N)
00587       sp_Pop (theGraph->theStack, e);
00588 
00589     else
00590       gp_RestoreEdge (theGraph, e);
00591   }
00592 
00593 /* Return the result */
00594   return theGraph->IC.py == NIL ? NOTOK : OK;
00595 }
00596 
00597 
00598 /****************************************************************************
00599  _MarkZtoRPath()
00600 
00601  This function assumes that _MarkHighestXYPath() has already been called,
00602  which marked as visited the vertices and edges along the X-Y path.
00603 
00604  We begin at the point of attachment P_x and traverse its link[1] edge records
00605  until we find one marked visited, which leads to the first internal vertex
00606  along the X-Y path.  We begin with this vertex (and its edge of entry), and
00607  we run until we find P_y.  For each internal vertex Z and its edge of entry
00608  ZPrevArc, we take the link[1] successor edge record of ZPrevArc (skipping Z
00609  if it intervenes).  This is called ZNextArc.  If ZNextArc is marked visited
00610  then it is along the X-Y path, so we use it to exit Z and go to the next
00611  vertex on the X-Y path.
00612 
00613  If ZNextArc is not visited, then when _MarkHighestXYPath() ran, it exited
00614  Z from ZNextArc, then eventually reentered Z.  In other words, Z became a
00615  cut vertex when we removed the internal edges incident to R. Thus, ZNextArc
00616  indicates the first edge in an internal path to R.
00617 
00618  When we find an unvisited ZNextArc, we stop running the X-Y path and instead
00619  begin marking the Z to R path.  We move to successive vertices using a
00620  twin arc then a link[1] successor edge record, only this time we have not
00621  removed the internal edges incident to R, so this technique does eventually
00622  lead us all the way to R.
00623 
00624  If we do not find an unvisited ZNextArc for any vertex Z on the X-Y path and
00625  inside the bicomp, then there is no Z to R path, so we return.
00626  ****************************************************************************/
00627 int _MarkZtoRPath (graphP theGraph)
00628 {
00629   int ZPrevArc,
00630     ZNextArc,
00631     Z,
00632     R,
00633     Px,
00634     Py;
00635 
00636 /* Initialize */
00637   R = theGraph->IC.r;
00638   Px = theGraph->IC.px;
00639   Py = theGraph->IC.py;
00640   theGraph->IC.z = NIL;
00641 
00642 /* Begin at Px and search its adjacency list for the edge leading to
00643    the first internal vertex of the X-Y path. */
00644   Z = Px;
00645   ZNextArc = theGraph->G[Z].link[1];
00646   while (ZNextArc != theGraph->G[Z].link[0])
00647 
00648   {
00649     if (theGraph->G[ZNextArc].visited)
00650       break;
00651     ZNextArc = theGraph->G[ZNextArc].link[1];
00652   }
00653   if (!theGraph->G[ZNextArc].visited)
00654     return NOTOK;
00655 
00656 /* For each internal vertex Z, determine whether it has a path to root. */
00657   while (theGraph->G[ZNextArc].visited)
00658 
00659   {
00660     ZPrevArc = gp_GetTwinArc (theGraph, ZNextArc);
00661     ZNextArc = theGraph->G[ZPrevArc].link[1];
00662     if (ZNextArc < 2 * theGraph->N)
00663       ZNextArc = theGraph->G[ZNextArc].link[1];
00664   }
00665   ZPrevArc = gp_GetTwinArc (theGraph, ZNextArc);
00666   Z = theGraph->G[ZPrevArc].v;
00667 
00668 /* If there is no Z to R path, return */
00669   if (Z == Py)
00670     return OK;
00671 
00672 /* Otherwise, store Z in the isolation context */
00673   theGraph->IC.z = Z;
00674 
00675 /* Walk the proper face starting with (Z, ZNextArc) until we reach R, marking
00676         the vertices and edges encountered along the way, then Return OK. */
00677   while (Z != R)
00678 
00679   {
00680 
00681     /* If we ever encounter a non-internal vertex (other than the root R),
00682      * then corruption has occured, so we return NOTOK */
00683     if (theGraph->G[Z].type != TYPE_UNKNOWN)
00684       return NOTOK;
00685 
00686     /* Go to the next vertex indicated by ZNextArc */
00687     Z = theGraph->G[ZNextArc].v;
00688 
00689     /* Mark the next vertex and the edge leading to it as visited. */
00690     theGraph->G[ZNextArc].visited = 1;
00691     theGraph->G[ZPrevArc].visited = 1;
00692     theGraph->G[Z].visited = 1;
00693 
00694     /* Go to the next edge in the proper face */
00695     ZNextArc = theGraph->G[ZPrevArc].link[1];
00696     if (ZNextArc < 2 * theGraph->N)
00697       ZNextArc = theGraph->G[ZNextArc].link[1];
00698     ZPrevArc = gp_GetTwinArc (theGraph, ZNextArc);
00699   }
00700 
00701 /* Found Z to R path, so indicate as much to caller */
00702   return OK;
00703 }
00704 
00705 
00706 /****************************************************************************
00707  _FindExtActivityBelowXYPath()
00708 
00709  Get an externally active vertex along the lower external face path between
00710  the points of attachment P_x and P_y of a 'low' X-Y Path.
00711  NOTE: By the time this function is called, Px and Py have already been found
00712         to be at or below X and Y.
00713  ****************************************************************************/
00714 int _FindExtActivityBelowXYPath (graphP theGraph)
00715 {
00716   int Z = theGraph->IC.px,
00717     ZPrevLink = 1,
00718     Py = theGraph->IC.py,
00719     I = theGraph->IC.v;
00720   Z = _GetNextVertexOnExternalFace (theGraph, Z, &ZPrevLink);
00721   while (Z != Py)
00722 
00723   {
00724     if (_VertexActiveStatus (theGraph, Z, I) == VAS_EXTERNAL)
00725       return Z;
00726     Z = _GetNextVertexOnExternalFace (theGraph, Z, &ZPrevLink);
00727   }
00728   return NIL;
00729 }

Generated on Thu Oct 20 14:58:41 2005 for DominoParitySeparator by  doxygen 1.4.5