Path: blob/master/sage/graphs/planarity/graphNonplanar.c
4079 views
/*1Planarity-Related Graph Algorithms Project2Copyright (c) 1997-2010, John M. Boyer3All rights reserved. Includes a reference implementation of the following:45* John M. Boyer. "Simplified O(n) Algorithms for Planar Graph Embedding,6Kuratowski Subgraph Isolation, and Related Problems". Ph.D. Dissertation,7University of Victoria, 2001.89* John M. Boyer and Wendy J. Myrvold. "On the Cutting Edge: Simplified O(n)10Planarity by Edge Addition". Journal of Graph Algorithms and Applications,11Vol. 8, No. 3, pp. 241-273, 2004.1213* John M. Boyer. "A New Method for Efficiently Generating Planar Graph14Visibility Representations". In P. Eades and P. Healy, editors,15Proceedings of the 13th International Conference on Graph Drawing 2005,16Lecture Notes Comput. Sci., Volume 3843, pp. 508-511, Springer-Verlag, 2006.1718Redistribution and use in source and binary forms, with or without modification,19are permitted provided that the following conditions are met:2021* Redistributions of source code must retain the above copyright notice, this22list of conditions and the following disclaimer.2324* Redistributions in binary form must reproduce the above copyright notice, this25list of conditions and the following disclaimer in the documentation and/or26other materials provided with the distribution.2728* Neither the name of the Planarity-Related Graph Algorithms Project nor the names29of its contributors may be used to endorse or promote products derived from this30software without specific prior written permission.3132THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"33AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE34IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE35DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR36ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES37(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;38LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON39ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT40(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS41SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.42*/4344#define GRAPHNONPLANAR_C4546#include "graph.h"4748/* Imported functions */4950extern void _ClearIsolatorContext(graphP theGraph);51extern void _FillVisitedFlags(graphP, int);52extern int _FillVisitedFlagsInBicomp(graphP theGraph, int BicompRoot, int FillValue);53extern int _SetVertexTypeInBicomp(graphP theGraph, int BicompRoot, int theType);54extern int _HideInternalEdges(graphP theGraph, int vertex);55extern int _RestoreInternalEdges(graphP theGraph, int stackBottom);5657extern int _GetNextVertexOnExternalFace(graphP theGraph, int curVertex, int *pPrevLink);58extern int _OrientVerticesInEmbedding(graphP theGraph);59extern int _OrientVerticesInBicomp(graphP theGraph, int BicompRoot, int PreserveSigns);6061/* Private functions (exported to system) */6263int _ChooseTypeOfNonplanarityMinor(graphP theGraph, int I, int R);64int _InitializeNonplanarityContext(graphP theGraph, int I, int R);6566int _FindNonplanarityBicompRoot(graphP theGraph);67void _FindActiveVertices(graphP theGraph, int R, int *pX, int *pY);68int _FindPertinentVertex(graphP theGraph);69int _SetVertexTypesForMarkingXYPath(graphP theGraph);7071int _PopAndUnmarkVerticesAndEdges(graphP theGraph, int Z, int stackBottom);7273int _MarkHighestXYPath(graphP theGraph);74int _MarkZtoRPath(graphP theGraph);75int _FindExtActivityBelowXYPath(graphP theGraph);7677/****************************************************************************78_ChooseTypeOfNonplanarityMinor()79****************************************************************************/8081int _ChooseTypeOfNonplanarityMinor(graphP theGraph, int I, int R)82{83int N, X, Y, W, Px, Py, Z, DFSChild, RootId;8485/* Create the initial non-planarity minor state in the isolator context */8687if (_InitializeNonplanarityContext(theGraph, I, R) != OK)88return NOTOK;8990N = theGraph->N;91R = theGraph->IC.r;92X = theGraph->IC.x;93Y = theGraph->IC.y;94W = theGraph->IC.w;9596/* If the root copy is not a root copy of the current vertex I,97then the Walkdown terminated because it couldn't find98a viable path along a child bicomp, which is Minor A. */99100if (theGraph->V[R - N].DFSParent != I)101{102theGraph->IC.minorType |= MINORTYPE_A;103return OK;104}105106/* If W has an externally active pertinent child bicomp, then107we've found Minor B */108109if (theGraph->V[W].pertinentBicompList != NIL)110{111RootId = LCGetPrev(theGraph->BicompLists,112theGraph->V[W].pertinentBicompList, NIL);113DFSChild = RootId;114if (theGraph->V[DFSChild].Lowpoint < I)115{116theGraph->IC.minorType |= MINORTYPE_B;117return OK;118}119}120121/* Find the highest obstructing X-Y path */122123if (_MarkHighestXYPath(theGraph) != TRUE)124return NOTOK;125126Px = theGraph->IC.px;127Py = theGraph->IC.py;128129/* If either point of attachment is 'high' (P_x closer to R than X130or P_y closer to R than Y along external face), then we've131matched Minor C. */132133if (theGraph->G[Px].type == VERTEX_HIGH_RXW ||134theGraph->G[Py].type == VERTEX_HIGH_RYW)135{136theGraph->IC.minorType |= MINORTYPE_C;137return OK;138}139140/* For Minor D, we search for a path from an internal141vertex Z along the X-Y path up to the root R of the bicomp. */142143if (_MarkZtoRPath(theGraph) != OK)144return NOTOK;145146if (theGraph->IC.z != NIL)147{148theGraph->IC.minorType |= MINORTYPE_D;149return OK;150}151152/* For Minor E, we search for an externally active vertex Z153below the points of attachment of the X-Y path */154155Z = _FindExtActivityBelowXYPath(theGraph);156if (Z != NIL)157{158theGraph->IC.z = Z;159theGraph->IC.minorType |= MINORTYPE_E;160return OK;161}162163return NOTOK;164}165166/****************************************************************************167_InitializeNonplanarityContext()168169This method finds the stopping vertices X and Y, and the pertinent vertex W170of a bicomp rooted by vertex R.171172If R is NIL, the routine first determines which bicomp produced non-planarity173condition. If the stack is non-empty, then R is on the top of the stack.174Otherwise, an unembedded fwdArc from the fwdArcList of vertex I is used in175combination with the separatedDFSChildList of I to determine R.176177If the parameter R was not NIL, then this method assumes it must operate178only on the bicomp rooted by R, and it also assumes that the caller has179not cleared the visited flags in the bicomp, so they are cleared.180181This routine imparts consistent orientation to all vertices in bicomp R182since several subroutines count on this. The edge signs are preserved so that183the original orientations of all vertices can be restored. If the vertices184of the embedding are already consistently oriented, then this operation185simply has no effect.186187Finally, in the bicomp R, the vertex types of all non-root vertices on the188external face are classified according to whether or not they are closer to189the root R than X and Y along the external face paths (R X W) and (R Y W).190****************************************************************************/191192int _InitializeNonplanarityContext(graphP theGraph, int I, int R)193{194int singleBicompMode = (R == NIL) ? FALSE : TRUE;195196// Blank out the isolator context, then assign the input graph reference197// and the current vertext I into the context.198_ClearIsolatorContext(theGraph);199theGraph->IC.v = I;200201// The Walkdown halted on one or more bicomps without embedding all back202// edges to descendants of the root(s) of said bicomp(s).203// If the bicomp root has not been provided, we now find the root of one such bicomp.204if (!singleBicompMode)205R = _FindNonplanarityBicompRoot(theGraph);206207// When in singleBicompMode, the bicomp root provided was the one on which208// the WalkDown was performed, but in the case of Minor A, the central bicomp209// of the minor is at the top of the stack, so R must be changed to that value.210else if (sp_NonEmpty(theGraph->theStack))211R = _FindNonplanarityBicompRoot(theGraph);212213if (R == NIL)214return NOTOK;215216theGraph->IC.r = R;217218// A number of subroutines require the main bicomp of the minor to be219// consistently oriented and its visited flags clear.220if (_OrientVerticesInBicomp(theGraph, R, 1) != OK)221return NOTOK;222223// In singleBicompMode, clear the visited members of all vertex and edge records.224if (singleBicompMode)225{226if (_FillVisitedFlagsInBicomp(theGraph, R, 0) != OK)227return NOTOK;228}229230// Now we find the active vertices along both external face paths231// extending from R.232_FindActiveVertices(theGraph, R, &theGraph->IC.x, &theGraph->IC.y);233234// Now, we obtain the pertinent vertex W on the lower external face235// path between X and Y (that path that does not include R).236theGraph->IC.w = _FindPertinentVertex(theGraph);237238// Now we can classify the vertices along the external face of the bicomp239// rooted at R as 'high RXW', 'low RXW', 'high RXY', 'low RXY'240if (_SetVertexTypesForMarkingXYPath(theGraph) != OK)241return NOTOK;242243// All work is done, so return success244return OK;245}246247/****************************************************************************248_SetVertexTypesForMarkingXYPath()249250Label the vertices along the external face of the bicomp rooted at R as251'high RXW', 'low RXW', 'high RXY', 'low RXY'252****************************************************************************/253254int _SetVertexTypesForMarkingXYPath(graphP theGraph)255{256int I, R, X, Y, W, Z, ZPrevLink, ZType;257258// Unpack the context for efficiency of loops259I = theGraph->IC.v;260R = theGraph->IC.r;261X = theGraph->IC.x;262Y = theGraph->IC.y;263W = theGraph->IC.w;264265// Ensure basic preconditions of this routine are met266if (R==NIL || X==NIL || Y==NIL || W==NIL)267return NOTOK;268269// Clear the type member of each vertex in the bicomp270if (_SetVertexTypeInBicomp(theGraph, R, TYPE_UNKNOWN) != OK)271return NOTOK;272273// Traverse from R to W in the X direction274ZPrevLink = 1;275Z = _GetNextVertexOnExternalFace(theGraph, R, &ZPrevLink);276ZType = VERTEX_HIGH_RXW;277while (Z != W)278{279if (Z == X) ZType = VERTEX_LOW_RXW;280theGraph->G[Z].type = ZType;281Z = _GetNextVertexOnExternalFace(theGraph, Z, &ZPrevLink);282}283284// Traverse from R to W in the Y direction285ZPrevLink = 0;286Z = _GetNextVertexOnExternalFace(theGraph, R, &ZPrevLink);287ZType = VERTEX_HIGH_RYW;288while (Z != W)289{290if (Z == Y) ZType = VERTEX_LOW_RYW;291theGraph->G[Z].type = ZType;292Z = _GetNextVertexOnExternalFace(theGraph, Z, &ZPrevLink);293}294295return OK;296}297298/****************************************************************************299_FindNonplanarityBicompRoot()300301This procedure finds the root copy R of the current vertex on which the302Walkdown failed (whether it failed while traversing the bicomp rooted by303R or some descendant bicomp is determined later).304305We iterate the forward cycle edges of the vertex I looking for a forward306edge (I, W) that was not embedded. Once it is found, we figure out which307bicomp rooted by a root copy of I contains W or contains a DFS ancestor of W.308309This turns out to be an easy test. The desired bicomp is rooted by the DFS310tree edge (I, C) with the largest value of C that does not exceed W. C is311a DFS ancestor of Z.312313Return: The desired root copy, or NIL on error.314****************************************************************************/315316int _FindNonplanarityBicompRoot(graphP theGraph)317{318int R, tempChild, fwdArc, W=NIL, C=NIL, I=theGraph->IC.v;319320/* If the stack is non-empty, then the Walkdown stopped on a descendant321bicomp, not one rooted by I. We need to get that root before the322stack is destroyed by other routines. */323324if (sp_NonEmpty(theGraph->theStack))325{326int e;327328sp_Pop2(theGraph->theStack, R, e);329return R;330}331332/* Obtain the forward arc of an unembedded back edge from I to one of its333descendants (edges are removed from the forward arc list as they are334embedded, so the list will be empty if all edges were embedded). */335336if ((fwdArc = theGraph->V[I].fwdArcList) == NIL)337return NIL;338339W = theGraph->G[fwdArc].v;340341/* Find the greatest DFS child C of I that is less than W. This will342give us the ancestor of W that is a child of I. Since the343ancestors of I have not been processed by the planarity algorithm,344the separatedDFSChildList of I contains all the children of I. */345346tempChild = theGraph->V[I].separatedDFSChildList;347348while (tempChild != NIL)349{350if (tempChild > C && tempChild < W)351C = tempChild;352353tempChild = LCGetNext(theGraph->DFSChildLists,354theGraph->V[I].separatedDFSChildList, tempChild);355}356357if (C == NIL) return NIL;358359/* The root vertex of a bicomp rooted by edge (I, C) is located at360position C+N in our data structures */361362R = C + theGraph->N;363return R;364}365366/****************************************************************************367_FindActiveVertices()368369Descends from the root of a bicomp R along both external face paths (which370are indicated by the first and last arcs in R's adjacency list), returning371the first active vertex appearing in each direction.372****************************************************************************/373374void _FindActiveVertices(graphP theGraph, int R, int *pX, int *pY)375{376int XPrevLink=1, YPrevLink=0, I=theGraph->IC.v;377378*pX = _GetNextVertexOnExternalFace(theGraph, R, &XPrevLink);379*pY = _GetNextVertexOnExternalFace(theGraph, R, &YPrevLink);380381while (_VertexActiveStatus(theGraph, *pX, I) == VAS_INACTIVE)382*pX = _GetNextVertexOnExternalFace(theGraph, *pX, &XPrevLink);383384while (_VertexActiveStatus(theGraph, *pY, I) == VAS_INACTIVE)385*pY = _GetNextVertexOnExternalFace(theGraph, *pY, &YPrevLink);386}387388/****************************************************************************389_FindPertinentVertex()390391Get the first vertex after x. Since x was obtained using a prevlink of 1 on r,392we use the same prevlink so we don't go back to R.393Then, we proceed around the lower path until we find a vertex W that either394has pertinent child bicomps or is directly adjacent to the current vertex I.395****************************************************************************/396397int _FindPertinentVertex(graphP theGraph)398{399int W=theGraph->IC.x, WPrevLink=1;400401W = _GetNextVertexOnExternalFace(theGraph, W, &WPrevLink);402403while (W != theGraph->IC.y)404{405if (PERTINENT(theGraph, W))406return W;407408W = _GetNextVertexOnExternalFace(theGraph, W, &WPrevLink);409}410411return NIL;412}413414/****************************************************************************415_PopAndUnmarkVerticesAndEdges()416417Pop all vertex/edge pairs from the top of the stack up to a terminating418vertex Z and mark as unvisited. If Z is NIL, then all vertex/edge pairs419are popped and marked as unvisited.420The stackBottom indicates where other material besides the vertex/edge421pairs may appear.422****************************************************************************/423424int _PopAndUnmarkVerticesAndEdges(graphP theGraph, int Z, int stackBottom)425{426int V, e;427428// Pop vertex/edge pairs until all have been popped from the stack,429// and all that's left is what was under the pairs, or until...430while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)431{432sp_Pop(theGraph->theStack, V);433434// If we pop the terminating vertex Z, then put it back and break435if (V == Z)436{437sp_Push(theGraph->theStack, V);438break;439}440441// Otherwise, pop the edge part of the vertex/edge pair442sp_Pop(theGraph->theStack, e);443444// Now unmark the vertex and edge (i.e. revert to "unvisited")445theGraph->G[V].visited = 0;446theGraph->G[e].visited = 0;447theGraph->G[gp_GetTwinArc(theGraph, e)].visited = 0;448}449450return OK;451}452453/****************************************************************************454_MarkHighestXYPath()455456An X-Y path in the bicomp rooted by R is a path attached to the external457face at points Px and Py that separates W from R such that a back edge (R, W)458cannot be embedded within the bicomp. Recall that R is a root copy of I, so459(R, W) is the representative of (I, W). Also, note that W is pertinent if460either W *or* one of its descendants in a separate bicomp has, in the input461graph, a back edge to I.462463If no X-Y path separating W from R is found, then NOTOK is returned because464the proof of correctness guarantees that one exists (although this routine465can also be used to help test for the existence of an X-Y path, and NOTOK466means 'no' in that case).467468The desired output is to set the 'visited' flags of the X-Y path with469highest points of attachment to the external face (i.e. the points of470attachment that are closest to R along the external face). This includes471marking both the vertices and edges along the X-Y path.472473Previously, during non-planarity context initialization, the vertices along474the external face (other than R and W) have been classified as 'high RXW',475'low RXW', 'high RXY', or 'low RXY'. Once the vertices have been categorized,476we proceed with trying to set the visitation flags in the way described above.477First, we remove all edges incident to R except the two edges that join R to478the external face. The result is that R and its two remaining edges are a479'corner' in the external face but also in a single proper face whose boundary480includes the X-Y path with the highest attachment points. Thus, we simply need481to walk this proper face to find the desired X-Y path. Note, however, that the482resulting face boundary may have attached cut vertices. Any such separable483component contains a vertex neighbor of R, but the edge to R has been484temporarily removed. The algorithm removes loop of vertices and edges along485the proper face so that only a path is identified.486487To walk the proper face containing R, we begin with its first arc successor,488then take the *predecessor* arc at every subsequent corner. For each vertex,489we mark as visited the vertex as well as the edge used to enter the vertex490(except for the edge used to enter the RXW vertex). We also push the visited491vertices and edges onto a stack.492493As we walk the proper face, we keep track of the last vertex P_x we visited of494type RXW (high or low). Each time we encounter a vertex of type RXW (high or495low), we pop the stack and unmark all of the edges and vertices visited because496they were part of a path parallel to the external face that does not obstruct497W from reaching R within the bicomp. If we encounter vertex W, then there is498no obstructing X-Y path since we removed only edges incident to R, so we pop499the stack unmarking everything then return NOTOK as stated above. If we500encounter a vertex Z previously visited, then we pop the stack, unmarking the501vertices and edges popped, until we find the prior occurence of Z on the stack.502503Otherwise, the first time we encounter a vertex P_y of type 'RYW', we stop504because the obstructing X-Y path has been marked visited and its points of505connection P_x and P_y have been found.506507Once the X-Y path is identified, we restore the edges incident to R.508509This method uses the stack, but it preserves any prior content.510The stack space used is no greater than 3N. The first N accounts for removing511the edges incident to R. The other 2N accounts for the fact that each512iteration of the main loop visits a vertex, pushing its index and the513location of an edge record. If a vertex is encountered that is already514on the stack, then it is not pushed again (and in fact part of the stack515is removed).516517Returns TRUE if the X-Y path is found, FALSE otherwise.518In debug mode it can also return NOTOK. This is equivalent to FALSE, but519NOTOK is better for documenting the error condition in the code, and520it produces a debug message. Also, in many cases the equivalent-to-FALSE521result is an error condition for the caller, so NOTOK usually percolates up.522****************************************************************************/523524int _MarkHighestXYPath(graphP theGraph)525{526int J, Z;527int R, X, Y, W;528int stackBottom1, stackBottom2;529530/* Initialization */531532R = theGraph->IC.r;533X = theGraph->IC.x;534Y = theGraph->IC.y;535W = theGraph->IC.w;536theGraph->IC.px = theGraph->IC.py = NIL;537538/* Save the stack bottom before we start hiding internal edges, so539we will know how many edges to restore */540541stackBottom1 = sp_GetCurrentSize(theGraph->theStack);542543/* Remove the internal edges incident to vertex R */544545if (_HideInternalEdges(theGraph, R) != OK)546return NOTOK;547548/* Now we're going to use the stack to collect the vertices of potential549* X-Y paths, so we need to store where the hidden internal edges are550* located because we must, at times, pop the collected vertices if551* the path being collected doesn't work out. */552553stackBottom2 = sp_GetCurrentSize(theGraph->theStack);554555/* Walk the proper face containing R to find and mark the highest556X-Y path. Note that if W is encountered, then there is no557intervening X-Y path, so we would return FALSE in that case. */558559Z = R;560// This setting of J is the arc equivalent of prevLink=1561// As loop progresses, J indicates the arc used to enter Z, not the exit arc562J = gp_GetLastArc(theGraph, R);563564while (theGraph->G[Z].type != VERTEX_HIGH_RYW &&565theGraph->G[Z].type != VERTEX_LOW_RYW)566{567/* Advance J and Z along the proper face containing R */568569J = gp_GetPrevArcCircular(theGraph, J);570Z = theGraph->G[J].v;571J = gp_GetTwinArc(theGraph, J);572573/* If Z is already visited, then pop everything since the last time574we visited Z because its all part of a separable component. */575576if (theGraph->G[Z].visited)577{578if (_PopAndUnmarkVerticesAndEdges(theGraph, Z, stackBottom2) != OK)579return NOTOK;580}581582/* If we have not visited this vertex before... */583584else585{586/* If we find W, then there is no X-Y path. Never happens587for Kuratowski subgraph isolator, but this routine is588also used to test for certain X-Y paths.589So, we clean up and bail out in that case. */590591if (Z == W)592{593if (_PopAndUnmarkVerticesAndEdges(theGraph, NIL, stackBottom2) != OK)594return NOTOK;595break;596}597598/* If we found another vertex along the RXW path, then blow off599all the vertices we visited so far because they're not part of600the obstructing path */601602if (theGraph->G[Z].type == VERTEX_HIGH_RXW ||603theGraph->G[Z].type == VERTEX_LOW_RXW)604{605theGraph->IC.px = Z;606if (_PopAndUnmarkVerticesAndEdges(theGraph, NIL, stackBottom2) != OK)607return NOTOK;608}609610/* Push the current vertex onto the stack of vertices visited611since the last RXW vertex was encountered */612613sp_Push(theGraph->theStack, J);614sp_Push(theGraph->theStack, Z);615616/* Mark the vertex Z as visited as well as its edge of entry617(except the entry edge for P_x).*/618619theGraph->G[Z].visited = 1;620if (Z != theGraph->IC.px)621{622theGraph->G[J].visited = 1;623theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1;624}625626/* If we found an RYW vertex, then we have successfully finished627identifying the highest X-Y path, so we record the point of628attachment and break the loop. */629630if (theGraph->G[Z].type == VERTEX_HIGH_RYW ||631theGraph->G[Z].type == VERTEX_LOW_RYW)632{633theGraph->IC.py = Z;634break;635}636}637}638639/* Remove any remaining vertex-edge pairs on the top of the stack, then640Restore the internal edges incident to R that were previously removed. */641642sp_SetCurrentSize(theGraph->theStack, stackBottom2);643644if (_RestoreInternalEdges(theGraph, stackBottom1) != OK)645return NOTOK;646647/* Return the result */648649return theGraph->IC.py==NIL ? FALSE : TRUE;650}651652/****************************************************************************653_MarkZtoRPath()654655This function assumes that _MarkHighestXYPath() has already been called,656which marked as visited the vertices and edges along the X-Y path.657658We begin at the point of attachment P_x, take the last arc and traverse659the predecessor arcs until we find one marked visited, which leads to the660first internal vertex along the X-Y path. We begin with this vertex661(and its edge of entry), and we run until we find P_y. For each internal662vertex Z and its edge of entry ZPrevArc, we take the predecessor edge record663of ZPrevArc. This is called ZNextArc. If ZNextArc is marked visited664then it is along the X-Y path, so we use it to exit Z and go to the next665vertex on the X-Y path.666667If ZNextArc is not visited, then when _MarkHighestXYPath() ran, it exited668Z from ZNextArc, then eventually reentered Z. In other words, Z became a669cut vertex when we removed the internal edges incident to R. Thus, ZNextArc670indicates the first edge in an internal path to R.671672When we find an unvisited ZNextArc, we stop running the X-Y path and instead673begin marking the Z to R path. We move to successive vertices using a674twin arc then its predecessor arc in the adjacency list, only this time675we have not removed the internal edges incident to R, so this technique does676eventually lead us all the way to R.677678If we do not find an unvisited ZNextArc for any vertex Z on the X-Y path and679inside the bicomp, then there is no Z to R path, so we return.680****************************************************************************/681682int _MarkZtoRPath(graphP theGraph)683{684int ZPrevArc, ZNextArc, Z, R, Px, Py;685686/* Initialize */687688R = theGraph->IC.r;689Px = theGraph->IC.px;690Py = theGraph->IC.py;691theGraph->IC.z = NIL;692693/* Begin at Px and search its adjacency list for the edge leading to694the first internal vertex of the X-Y path. */695696Z = Px;697ZNextArc = gp_GetLastArc(theGraph, Z);698while (ZNextArc != gp_GetFirstArc(theGraph, Z))699{700if (theGraph->G[ZNextArc].visited) break;701702ZNextArc = gp_GetPrevArc(theGraph, ZNextArc);703}704705if (!theGraph->G[ZNextArc].visited)706return NOTOK;707708/* For each internal vertex Z, determine whether it has a path to root. */709710while (theGraph->G[ZNextArc].visited)711{712ZPrevArc = gp_GetTwinArc(theGraph, ZNextArc);713ZNextArc = gp_GetPrevArcCircular(theGraph, ZPrevArc);714}715716ZPrevArc = gp_GetTwinArc(theGraph, ZNextArc);717Z = theGraph->G[ZPrevArc].v;718719/* If there is no Z to R path, return */720721if (Z == Py) return OK;722723/* Otherwise, store Z in the isolation context */724725theGraph->IC.z = Z;726727/* Walk the proper face starting with (Z, ZNextArc) until we reach R, marking728the vertices and edges encountered along the way, then Return OK. */729730while (Z != R)731{732/* If we ever encounter a non-internal vertex (other than the root R),733then corruption has occured, so we return NOTOK */734735if (theGraph->G[Z].type != TYPE_UNKNOWN)736return NOTOK;737738/* Go to the next vertex indicated by ZNextArc */739740Z = theGraph->G[ZNextArc].v;741742/* Mark the next vertex and the edge leading to it as visited. */743744theGraph->G[ZNextArc].visited = 1;745theGraph->G[ZPrevArc].visited = 1;746theGraph->G[Z].visited = 1;747748/* Go to the next edge in the proper face */749750ZNextArc = gp_GetPrevArcCircular(theGraph, ZPrevArc);751ZPrevArc = gp_GetTwinArc(theGraph, ZNextArc);752}753754/* Found Z to R path, so indicate as much to caller */755756return OK;757}758759/****************************************************************************760_FindExtActivityBelowXYPath()761762Get an externally active vertex along the lower external face path between763the points of attachment P_x and P_y of a 'low' X-Y Path.764NOTE: By the time this function is called, Px and Py have already been found765to be at or below X and Y.766****************************************************************************/767768int _FindExtActivityBelowXYPath(graphP theGraph)769{770int Z=theGraph->IC.px, ZPrevLink=1,771Py=theGraph->IC.py, I=theGraph->IC.v;772773Z = _GetNextVertexOnExternalFace(theGraph, Z, &ZPrevLink);774775while (Z != Py)776{777if (_VertexActiveStatus(theGraph, Z, I) == VAS_EXTERNAL)778return Z;779780Z = _GetNextVertexOnExternalFace(theGraph, Z, &ZPrevLink);781}782783return NIL;784}785786787