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 }