void _K33Search_EmbedBackEdgeToDescendant(graphP theGraph, int RootSide, int RootVertex, int W, int WPrevLink) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { // K33 search may have been attached, but not enabled if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { // Get the fwdArc from the adjacentTo field, and use it to get the backArc int backArc = gp_GetTwinArc(theGraph, gp_GetVertexPertinentEdge(theGraph, W)); // Remove the backArc from the backArcList if (context->VI[W].backArcList == backArc) { if (gp_GetNextArc(theGraph, backArc) == backArc) context->VI[W].backArcList = NIL; else context->VI[W].backArcList = gp_GetNextArc(theGraph, backArc); } gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, backArc), gp_GetNextArc(theGraph, backArc)); gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, backArc), gp_GetPrevArc(theGraph, backArc)); } // Invoke the superclass version of the function context->functions.fpEmbedBackEdgeToDescendant(theGraph, RootSide, RootVertex, W, WPrevLink); } }
/******************************************************************** _ColorVertices_HideEdge() An overload to perform the degree list updates for the edge endpoints. This routine also covers the work done by _HideVertex() and part of the work done by _ContractEdge() and _IdentifyVertices(). ********************************************************************/ void _ColorVertices_HideEdge(graphP theGraph, int e) { ColorVerticesContext *context = (ColorVerticesContext *) gp_GetExtension(theGraph, COLORVERTICES_ID); if (context != NULL) { int u, v, udeg, vdeg; // Get the endpoint vertices of the edge u = theGraph->G[e].v; v = theGraph->G[gp_GetTwinArc(theGraph, e)].v; // Get the degrees of the vertices udeg = _GetVertexDegree(context, u); vdeg = _GetVertexDegree(context, v); // Remove them from the degree lists that contain them _RemoveVertexFromDegList(context, theGraph, u, udeg); _RemoveVertexFromDegList(context, theGraph, v, vdeg); // Hide the edge context->functions.fpHideEdge(theGraph, e); // Decrement the degrees of the endpoint vertices udeg--; vdeg--; // Add them to the new degree lists _AddVertexToDegList(context, theGraph, u, udeg); _AddVertexToDegList(context, theGraph, v, vdeg); } }
int _MarkPathAlongBicompExtFace(graphP theGraph, int startVert, int endVert) { int Z, ZPrevLink, ZPrevArc; /* Mark the start vertex (and if it is a root copy, mark the parent copy too. */ theGraph->G[startVert].visited = 1; /* For each vertex visited after the start vertex, mark the vertex and the edge used to get there. Stop after marking the ending vertex. */ Z = startVert; ZPrevLink = 1; do { Z = _GetNextVertexOnExternalFace(theGraph, Z, &ZPrevLink); ZPrevArc = gp_GetArc(theGraph, Z, ZPrevLink); theGraph->G[ZPrevArc].visited = 1; theGraph->G[gp_GetTwinArc(theGraph, ZPrevArc)].visited = 1; theGraph->G[Z].visited = 1; } while (Z != endVert); return OK; }
int _PopAndUnmarkVerticesAndEdges(graphP theGraph, int Z, int stackBottom) { int V, e; // Pop vertex/edge pairs until all have been popped from the stack, // and all that's left is what was under the pairs, or until... while (sp_GetCurrentSize(theGraph->theStack) > stackBottom) { sp_Pop(theGraph->theStack, V); // If we pop the terminating vertex Z, then put it back and break if (V == Z) { sp_Push(theGraph->theStack, V); break; } // Otherwise, pop the edge part of the vertex/edge pair sp_Pop(theGraph->theStack, e); // Now unmark the vertex and edge (i.e. revert to "unvisited") theGraph->G[V].visited = 0; theGraph->G[e].visited = 0; theGraph->G[gp_GetTwinArc(theGraph, e)].visited = 0; } return OK; }
int _MarkPathAlongBicompExtFace(graphP theGraph, int startVert, int endVert) { int Z, ZPrevLink, ZPrevArc; /* Mark the start vertex (and if it is a root copy, mark the parent copy too. */ gp_SetVertexVisited(theGraph, startVert); /* For each vertex visited after the start vertex, mark the vertex and the edge used to get there. Stop after marking the ending vertex. */ Z = startVert; ZPrevLink = 1; do { Z = _GetNeighborOnExtFace(theGraph, Z, &ZPrevLink); ZPrevArc = gp_GetArc(theGraph, Z, ZPrevLink); gp_SetEdgeVisited(theGraph, ZPrevArc); gp_SetEdgeVisited(theGraph, gp_GetTwinArc(theGraph, ZPrevArc)); gp_SetVertexVisited(theGraph, Z); } while (Z != endVert); return OK; }
int _ComputeEdgeRanges(DrawPlanarContext *context) { graphP theEmbedding = context->theGraph; int e, J, JTwin, v1, v2, pos1, pos2; for (e = 0; e < theEmbedding->M; e++) { J = theEmbedding->edgeOffset + 2*e; JTwin = gp_GetTwinArc(theEmbedding, J); v1 = theEmbedding->G[J].v; v2 = theEmbedding->G[JTwin].v; pos1 = context->G[v1].pos; pos2 = context->G[v2].pos; if (pos1 < pos2) { context->G[J].start = pos1; context->G[J].end = pos2; } else { context->G[J].start = pos2; context->G[J].end = pos1; } context->G[JTwin].start = context->G[J].start; context->G[JTwin].end = context->G[J].end; } return OK; }
/**************************************************************************** _MarkDFSPath() Sets visited flags of vertices and edges from descendant to ancestor, including root copy vertices, and including the step of hopping from a root copy to its parent copy. At each vertex, the edge record is obtained whose type indicates that it leads to the DFS parent. An earlier implementation just used the DFS parent member of the vertex, but then had to find the edge to mark anyway. This method is more generalized because some extension algorithms reduce DFS paths to single DFS tree edges, in which case the edge record with type EDGE_TYPE_PARENT may indicate the DFS paent or an ancestor. ****************************************************************************/ int _MarkDFSPath(graphP theGraph, int ancestor, int descendant) { int e, parent; // If we are marking from a root (virtual) vertex upward, then go up to the parent // copy before starting the loop if (gp_IsVirtualVertex(theGraph, descendant)) descendant = gp_GetPrimaryVertexFromRoot(theGraph, descendant); // Mark the lowest vertex (the one with the highest number). gp_SetVertexVisited(theGraph, descendant); // Mark all ancestors of the lowest vertex, and the edges used to reach // them, up to the given ancestor vertex. while (descendant != ancestor) { if (gp_IsNotVertex(descendant)) return NOTOK; // If we are at a bicomp root, then ascend to its parent copy and // mark it as visited. if (gp_IsVirtualVertex(theGraph, descendant)) { parent = gp_GetPrimaryVertexFromRoot(theGraph, descendant); } // If we are on a regular, non-virtual vertex then get the edge to the parent, // mark the edge, then fall through to the code that marks the parent vertex. else { // Scan the edges for the one marked as the DFS parent parent = NIL; e = gp_GetFirstArc(theGraph, descendant); while (gp_IsArc(e)) { if (gp_GetEdgeType(theGraph, e) == EDGE_TYPE_PARENT) { parent = gp_GetNeighbor(theGraph, e); break; } e = gp_GetNextArc(theGraph, e); } // Sanity check on the data structure integrity if (gp_IsNotVertex(parent)) return NOTOK; // Mark the edge gp_SetEdgeVisited(theGraph, e); gp_SetEdgeVisited(theGraph, gp_GetTwinArc(theGraph, e)); } // Mark the parent, then hop to the parent and reiterate gp_SetVertexVisited(theGraph, parent); descendant = parent; } return OK; }
int _MarkDFSPath(graphP theGraph, int ancestor, int descendant) { int J, parent, Z, N; N = theGraph->N; /* If we are marking from a root vertex upward, then go up to the parent copy before starting the loop */ if (descendant >= N) descendant = theGraph->V[descendant-N].DFSParent; /* Mark the lowest vertex (i.e. the descendant with the highest number) */ theGraph->G[descendant].visited = 1; /* Mark all ancestors of the lowest vertex, and the edges used to reach them, up to the given ancestor vertex. */ while (descendant != ancestor) { /* Get the parent vertex */ parent = theGraph->V[descendant].DFSParent; /* If the descendant was a DFS tree root, then obviously we aren't going to find the ancestor, so something is wrong.*/ if (parent == NIL || parent == descendant) return NOTOK; /* Find the edge from descendant that leads either to parent or to a root copy of the parent. When the edge is found, mark it and break the loop */ J = gp_GetFirstArc(theGraph, descendant); while (gp_IsArc(theGraph, J)) { Z = theGraph->G[J].v; if ((Z < N && Z == parent) || (Z >= N && theGraph->V[Z-N].DFSParent == parent)) { theGraph->G[J].visited = 1; theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1; break; } J = gp_GetNextArc(theGraph, J); } /* Mark the parent copy of the DFS parent */ theGraph->G[parent].visited = 1; /* Hop to the parent */ descendant = parent; } return OK; }
void _MarkExternalFaceVertices(graphP theGraph, int startVertex) { int nextVertex = startVertex; int e = gp_GetFirstArc(theGraph, nextVertex); int eTwin; // Handle the case of an isolated vertex if (gp_IsNotArc(e)) { gp_SetVertexVisited(theGraph, startVertex); return; } // Process a non-trivial connected component do { gp_SetVertexVisited(theGraph, nextVertex); // The arc out of the vertex just visited points to the next vertex nextVertex = gp_GetNeighbor(theGraph, e); // Arc used to enter the next vertex is needed so we can get the // next edge in rotation order. // Note: for bicomps, first and last arcs of all external face vertices // indicate the edges that hold them to the external face // But _JoinBicomps() has already occurred, so cut vertices // will have external face edges other than the first and last arcs // Hence we need this more sophisticated traversal method eTwin = gp_GetTwinArc(theGraph, e); // Now we get the next arc in rotation order as the new arc out to the // vertex after nextVertex. This sets us up for the next iteration. // Note: We cannot simply follow the chain of nextVertex first arcs // as we started out doing at the top of this method. This is // because we are no longer dealing with bicomps only. // Since _JoinBicomps() has already been invoked, there may now // be cut vertices on the external face whose adjacency lists // contain external face arcs in positions other than the first and // and last arcs. We will visit those vertices multiple times, // which is OK (just that we have to explain why we're calculating // jout in this way). e = gp_GetNextArcCircular(theGraph, eTwin); // Now things get really interesting. The DFS root (startVertex) may // itself be a cut vertex to which multiple bicomps have been joined. // So we cannot simply stop when the external face walk gets back to // startVertex. We must actually get back to startVertex using its // last arc. This ensures that we've looped down into all the DFS // subtrees rooted at startVertex and walked their external faces. // Since we started the whole external face walk with the first arc // of startVertex, we need to proceed until we reenter startVertex // using its last arc. } while (eTwin != gp_GetLastArc(theGraph, startVertex)); }
void _AddBackEdge(graphP theGraph, int ancestor, int descendant) { int fwdArc, backArc; /* We get the two edge records of the back edge to embed. */ fwdArc = theGraph->V[ancestor].fwdArcList; while (gp_IsArc(theGraph, fwdArc)) { if (theGraph->G[fwdArc].v == descendant) break; fwdArc = gp_GetNextArc(theGraph, fwdArc); if (fwdArc == theGraph->V[ancestor].fwdArcList) fwdArc = NIL; } if (fwdArc == NIL) return; backArc = gp_GetTwinArc(theGraph, fwdArc); /* The forward arc is removed from the fwdArcList of the ancestor. */ if (theGraph->V[ancestor].fwdArcList == fwdArc) { if (gp_GetNextArc(theGraph, fwdArc) == fwdArc) theGraph->V[ancestor].fwdArcList = NIL; else theGraph->V[ancestor].fwdArcList = gp_GetNextArc(theGraph, fwdArc); } gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, fwdArc), gp_GetNextArc(theGraph, fwdArc)); gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, fwdArc), gp_GetPrevArc(theGraph, fwdArc)); /* The forward arc is added to the adjacency list of the ancestor. */ gp_SetPrevArc(theGraph, fwdArc, gp_AdjacencyListEndMark(ancestor)); gp_SetNextArc(theGraph, fwdArc, gp_GetFirstArc(theGraph, ancestor)); gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, ancestor), fwdArc); gp_SetFirstArc(theGraph, ancestor, fwdArc); /* The back arc is added to the adjacency list of the descendant. */ gp_SetPrevArc(theGraph, backArc, gp_AdjacencyListEndMark(descendant)); gp_SetNextArc(theGraph, backArc, gp_GetFirstArc(theGraph, descendant)); gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, descendant), backArc); gp_SetFirstArc(theGraph, descendant, backArc); theGraph->G[backArc].v = ancestor; }
void _AddBackEdge(graphP theGraph, int ancestor, int descendant) { int fwdArc, backArc; /* We get the two edge records of the back edge to embed. */ fwdArc = gp_GetVertexFwdArcList(theGraph, ancestor); while (gp_IsArc(fwdArc)) { if (gp_GetNeighbor(theGraph, fwdArc) == descendant) break; fwdArc = gp_GetNextArc(theGraph, fwdArc); if (fwdArc == gp_GetVertexFwdArcList(theGraph, ancestor)) fwdArc = NIL; } if (gp_IsNotArc(fwdArc)) return; backArc = gp_GetTwinArc(theGraph, fwdArc); /* The forward arc is removed from the fwdArcList of the ancestor. */ if (gp_GetVertexFwdArcList(theGraph, ancestor) == fwdArc) { if (gp_GetNextArc(theGraph, fwdArc) == fwdArc) gp_SetVertexFwdArcList(theGraph, ancestor, NIL); else gp_SetVertexFwdArcList(theGraph, ancestor, gp_GetNextArc(theGraph, fwdArc)); } gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, fwdArc), gp_GetNextArc(theGraph, fwdArc)); gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, fwdArc), gp_GetPrevArc(theGraph, fwdArc)); /* The forward arc is added to the adjacency list of the ancestor. */ gp_SetPrevArc(theGraph, fwdArc, NIL); gp_SetNextArc(theGraph, fwdArc, gp_GetFirstArc(theGraph, ancestor)); gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, ancestor), fwdArc); gp_SetFirstArc(theGraph, ancestor, fwdArc); /* The back arc is added to the adjacency list of the descendant. */ gp_SetPrevArc(theGraph, backArc, NIL); gp_SetNextArc(theGraph, backArc, gp_GetFirstArc(theGraph, descendant)); gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, descendant), backArc); gp_SetFirstArc(theGraph, descendant, backArc); gp_SetNeighbor(theGraph, backArc, ancestor); }
void _MarkPath(graphP theGraph, int e) { int eTwin, nextVertex; nextVertex = gp_GetNeighbor(theGraph, e); // while nextVertex is strictly degree 2 while (gp_IsArc(gp_GetFirstArc(theGraph, nextVertex)) && gp_IsArc(gp_GetLastArc(theGraph, nextVertex)) && gp_GetNextArc(theGraph, gp_GetFirstArc(theGraph, nextVertex)) == gp_GetLastArc(theGraph, nextVertex)) { gp_SetVertexVisited(theGraph, nextVertex); eTwin = gp_GetTwinArc(theGraph, e); e = gp_GetFirstArc(theGraph, nextVertex); if (e == eTwin) e = gp_GetLastArc(theGraph, nextVertex); nextVertex = gp_GetNeighbor(theGraph, e); } }
/******************************************************************** _LogEdgeList() Used to show the progressive calculation of the edge position list. ********************************************************************/ void _LogEdgeList(graphP theEmbedding, listCollectionP edgeList, int edgeListHead) { int e = edgeListHead, J, JTwin; gp_Log("EdgeList: [ "); while (e != NIL) { J = theEmbedding->edgeOffset + 2*e; JTwin = gp_GetTwinArc(theEmbedding, J); gp_Log(gp_MakeLogStr2("(%d, %d) ", theEmbedding->G[theEmbedding->G[J].v].v, theEmbedding->G[theEmbedding->G[JTwin].v].v)); e = LCGetNext(edgeList, edgeListHead, e); } gp_LogLine("]"); }
int _TryPath(graphP theGraph, int e, int V) { int eTwin, nextVertex; nextVertex = gp_GetNeighbor(theGraph, e); // while nextVertex is strictly degree 2 while (gp_IsArc(gp_GetFirstArc(theGraph, nextVertex)) && gp_IsArc(gp_GetLastArc(theGraph, nextVertex)) && gp_GetNextArc(theGraph, gp_GetFirstArc(theGraph, nextVertex)) == gp_GetLastArc(theGraph, nextVertex)) { eTwin = gp_GetTwinArc(theGraph, e); e = gp_GetFirstArc(theGraph, nextVertex); if (e == eTwin) e = gp_GetLastArc(theGraph, nextVertex); nextVertex = gp_GetNeighbor(theGraph, e); } return nextVertex == V ? TRUE : FALSE; }
/******************************************************************** _CreateBackArcLists() ********************************************************************/ void _CreateBackArcLists(graphP theGraph, K33SearchContext *context) { int v, e, eTwin, ancestor; for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { e = gp_GetVertexFwdArcList(theGraph, v); while (gp_IsArc(e)) { // Get the ancestor endpoint and the associated back arc ancestor = gp_GetNeighbor(theGraph, e); eTwin = gp_GetTwinArc(theGraph, e); // Put it into the back arc list of the ancestor if (gp_IsNotArc(context->VI[ancestor].backArcList)) { context->VI[ancestor].backArcList = eTwin; gp_SetPrevArc(theGraph, eTwin, eTwin); gp_SetNextArc(theGraph, eTwin, eTwin); } else { int eHead = context->VI[ancestor].backArcList; int eTail = gp_GetPrevArc(theGraph, eHead); gp_SetPrevArc(theGraph, eTwin, eTail); gp_SetNextArc(theGraph, eTwin, eHead); gp_SetPrevArc(theGraph, eHead, eTwin); gp_SetNextArc(theGraph, eTail, eTwin); } // Advance to the next forward edge e = gp_GetNextArc(theGraph, e); if (e == gp_GetVertexFwdArcList(theGraph, v)) e = NIL; } } }
int gp_CreateDFSTree(graphP theGraph) { stackP theStack; int N, DFI = 0, I, uparent, u, e, J; #ifdef PROFILE platform_time start, end; platform_GetTime(start); #endif if (theGraph==NULL) return NOTOK; if (theGraph->internalFlags & FLAGS_DFSNUMBERED) return OK; gp_LogLine("\ngraphPreprocess.c/gp_CreateDFSTree() start"); N = theGraph->N; theStack = theGraph->theStack; /* There are 2M edge records (arcs) and for each we can push 2 integers, so a stack of 2 * arcCapacity integers suffices. This is already in theGraph structure, so we make sure it's empty, then clear all visited flags in prep for the Depth first search. */ if (sp_GetCapacity(theStack) < 2*gp_GetArcCapacity(theGraph)) return NOTOK; sp_ClearStack(theStack); for (I=0; I < N; I++) theGraph->G[I].visited = 0; /* This outer loop causes the connected subgraphs of a disconnected graph to be numbered */ for (I=0; I < N && DFI < N; I++) { if (theGraph->V[I].DFSParent != NIL) continue; sp_Push2(theStack, NIL, NIL); while (sp_NonEmpty(theStack)) { sp_Pop2(theStack, uparent, e); u = uparent == NIL ? I : theGraph->G[e].v; if (!theGraph->G[u].visited) { gp_LogLine(gp_MakeLogStr3("V=%d, DFI=%d, Parent=%d", u, DFI, uparent)); theGraph->G[u].visited = 1; theGraph->G[u].v = DFI++; theGraph->V[u].DFSParent = uparent; if (e != NIL) { theGraph->G[e].type = EDGE_DFSCHILD; theGraph->G[gp_GetTwinArc(theGraph, e)].type = EDGE_DFSPARENT; // We want the child arcs to be at the beginning // of the adjacency list. gp_MoveArcToFirst(theGraph, uparent, e); } /* Push edges to all unvisited neighbors. These will be either tree edges to children or forward arcs of back edges */ J = gp_GetFirstArc(theGraph, u); while (gp_IsArc(theGraph, J)) { if (!theGraph->G[theGraph->G[J].v].visited) sp_Push2(theStack, u, J); J = gp_GetNextArc(theGraph, J); } } else { // If the edge leads to a visited vertex, then it is // the forward arc of a back edge. theGraph->G[e].type = EDGE_FORWARD; theGraph->G[gp_GetTwinArc(theGraph, e)].type = EDGE_BACK; // We want all of the forward edges to descendants to // be at the end of the adjacency list. // The tree edge to the parent and the back edges to ancestors // are in the middle, between the child edges and forward edges. gp_MoveArcToLast(theGraph, uparent, e); } } } gp_LogLine("graphPreprocess.c/gp_CreateDFSTree() end\n"); theGraph->internalFlags |= FLAGS_DFSNUMBERED; #ifdef PROFILE platform_GetTime(end); printf("DFS in %.3lf seconds.\n", platform_GetDuration(start,end)); #endif return OK; }
int _CheckEmbeddingFacialIntegrity(graphP theGraph) { stackP theStack = theGraph->theStack; int EsizeOccupied, v, e, eTwin, eStart, eNext, NumFaces, connectedComponents; if (theGraph == NULL) return NOTOK; /* The stack need only contain 2M entries, one for each edge record. With max M at 3N, this amounts to 6N integers of space. The embedding structure already contains this stack, so we just make sure it starts out empty. */ sp_ClearStack(theStack); /* Push all arcs and set them to unvisited */ EsizeOccupied = gp_EdgeInUseIndexBound(theGraph); for (e = gp_GetFirstEdge(theGraph); e < EsizeOccupied; e+=2) { // Except skip edge holes if (gp_EdgeInUse(theGraph, e)) { sp_Push(theStack, e); gp_ClearEdgeVisited(theGraph, e); eTwin = gp_GetTwinArc(theGraph, e); sp_Push(theStack, eTwin); gp_ClearEdgeVisited(theGraph, eTwin); } } // There are M edges, so we better have pushed 2M arcs just now // i.e. testing that the continue above skipped only edge holes if (sp_GetCurrentSize(theStack) != 2*theGraph->M) return NOTOK; /* Read faces until every arc is used */ NumFaces = 0; while (sp_NonEmpty(theStack)) { /* Get an arc; if it has already been used by a face, then don't use it to traverse a new face */ sp_Pop(theStack, eStart); if (gp_GetEdgeVisited(theGraph, eStart)) continue; e = eStart; do { eNext = gp_GetNextArcCircular(theGraph, gp_GetTwinArc(theGraph, e)); if (gp_GetEdgeVisited(theGraph, eNext)) return NOTOK; gp_SetEdgeVisited(theGraph, eNext); e = eNext; } while (e != eStart); NumFaces++; } /* Count the external face once rather than once per connected component; each connected component is detected by the fact that it has no DFS parent, except in the case of isolated vertices, no face was counted so we do not subtract one. */ connectedComponents = 0; for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { if (gp_IsDFSTreeRoot(theGraph, v)) { if (gp_GetVertexDegree(theGraph, v) > 0) NumFaces--; connectedComponents++; } } NumFaces++; /* Test number of faces using the extended Euler's formula. For connected components, Euler's formula is f=m-n+2, but for disconnected graphs it is extended to f=m-n+1+c where c is the number of connected components.*/ return NumFaces == theGraph->M - theGraph->N + 1 + connectedComponents ? OK : NOTOK; }
int _ComputeEdgePositions(DrawPlanarContext *context) { graphP theEmbedding = context->theGraph; int *vertexOrder = NULL; listCollectionP edgeList = NULL; int edgeListHead, edgeListInsertPoint; int I, J, Jcur, e, v, vpos; int eIndex, JTwin; gp_LogLine("\ngraphDrawPlanar.c/_ComputeEdgePositions() start"); // Sort the vertices by vertical position (in linear time) if ((vertexOrder = (int *) malloc(theEmbedding->N * sizeof(int))) == NULL) return NOTOK; for (I = 0; I < theEmbedding->N; I++) vertexOrder[context->G[I].pos] = I; // Allocate the edge list of size M. // This is an array of (prev, next) pointers. // An edge at position X corresponds to the edge // at position X in the graph structure, which is // represented by a pair of adjacent graph nodes // starting at index 2N + 2X. if (theEmbedding->M > 0 && (edgeList = LCNew(theEmbedding->M)) == NULL) { free(vertexOrder); return NOTOK; } edgeListHead = NIL; // Each vertex starts out with a NIL generator edge. for (I=0; I < theEmbedding->N; I++) theEmbedding->G[I].visited = NIL; // Perform the vertical sweep of the combinatorial embedding, using // the vertex ordering to guide the sweep. // For each vertex, each edge leading to a vertex with a higher number in // the vertex order is recorded as the "generator edge", or the edge of // first discovery of that higher numbered vertex, unless the vertex already has // a recorded generator edge for (vpos=0; vpos < theEmbedding->N; vpos++) { // Get the vertex associated with the position v = vertexOrder[vpos]; gp_LogLine(gp_MakeLogStr3("Processing vertex %d with DFI=%d at position=%d", theEmbedding->G[v].v, v, vpos)); // The DFS tree root of a connected component is always the least // number vertex in the vertex ordering. We have to give it a // false generator edge so that it is still "visited" and then // all of its edges are generators for its neighbor vertices because // they all have greater numbers in the vertex order. if (theEmbedding->V[v].DFSParent == NIL) { // False generator edge, so the vertex is distinguishable from // a vertex with no generator edge when its neighbors are visited // This way, an edge from a neighbor won't get recorded as the // generator edge of the DFS tree root. theEmbedding->G[v].visited = 1; // Now we traverse the adjacency list of the DFS tree root and // record each edge as the generator edge of the neighbors J = gp_GetFirstArc(theEmbedding, v); while (gp_IsArc(theGraph, J)) { e = (J - theEmbedding->edgeOffset) / 2; edgeListHead = LCAppend(edgeList, edgeListHead, e); gp_LogLine(gp_MakeLogStr2("Append generator edge (%d, %d) to edgeList", theEmbedding->G[v].v, theEmbedding->G[theEmbedding->G[J].v].v)); // Set the generator edge for the root's neighbor theEmbedding->G[theEmbedding->G[J].v].visited = J; // Go to the next node of the root's adj list J = gp_GetNextArc(theEmbedding, J); } } // Else, if we are not on a DFS tree root... else { // Get the generator edge of the vertex if ((JTwin = theEmbedding->G[v].visited) == NIL) return NOTOK; J = gp_GetTwinArc(theEmbedding, JTwin); // Traverse the edges of the vertex, starting // from the generator edge and going counterclockwise... e = (J - theEmbedding->edgeOffset) / 2; edgeListInsertPoint = e; Jcur = gp_GetNextArcCircular(theEmbedding, J); while (Jcur != J) { // If the neighboring vertex's position is greater // than the current vertex (meaning it is lower in the // diagram), then add that edge to the edge order. if (context->G[theEmbedding->G[Jcur].v].pos > vpos) { e = (Jcur - theEmbedding->edgeOffset) / 2; LCInsertAfter(edgeList, edgeListInsertPoint, e); gp_LogLine(gp_MakeLogStr4("Insert (%d, %d) after (%d, %d)", theEmbedding->G[v].v, theEmbedding->G[theEmbedding->G[Jcur].v].v, theEmbedding->G[theEmbedding->G[gp_GetTwinArc(theEmbedding, J)].v].v, theEmbedding->G[theEmbedding->G[J].v].v)); edgeListInsertPoint = e; // If the vertex does not yet have a generator edge, then set it. if (theEmbedding->G[theEmbedding->G[Jcur].v].visited == NIL) { theEmbedding->G[theEmbedding->G[Jcur].v].visited = Jcur; gp_LogLine(gp_MakeLogStr2("Generator edge (%d, %d)", theEmbedding->G[theEmbedding->G[gp_GetTwinArc(theEmbedding, J)].v].v, theEmbedding->G[theEmbedding->G[Jcur].v].v)); } } // Go to the next node in v's adjacency list Jcur = gp_GetNextArcCircular(theEmbedding, Jcur); } } #ifdef LOGGING _LogEdgeList(theEmbedding, edgeList, edgeListHead); #endif } // Now iterate through the edgeList and assign positions to the edges. eIndex = 0; e = edgeListHead; while (e != NIL) { J = theEmbedding->edgeOffset + 2*e; JTwin = gp_GetTwinArc(theEmbedding, J); context->G[J].pos = context->G[JTwin].pos = eIndex; eIndex++; e = LCGetNext(edgeList, edgeListHead, e); } // Clean up and return LCFree(&edgeList); free(vertexOrder); gp_LogLine("graphDrawPlanar.c/_ComputeEdgePositions() end\n"); return OK; }
int _K33Search_CreateFwdArcLists(graphP theGraph) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context == NULL) return NOTOK; // For isolating a K_{3,3} homeomorph, we need the forward edges // of each vertex to be in sorted order by DFI of descendants. // Otherwise we just drop through to the normal processing... if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { int I, Jcur, Jnext, ancestor; // for each vertex v in order, we follow each of its back edges // to the twin forward edge in an ancestor u, then we move // the forward edge to the fwdArcList of u. Since this loop // processes vertices in order, the fwdArcList of each vertex // will be in order by the neighbor indicated by the forward edges. for (I=0; I < theGraph->N; I++) { // Skip this vertex if it has no edges Jnext = gp_GetLastArc(theGraph, I); if (!gp_IsArc(theGraph, Jnext)) continue; // Skip the forward edges, which are in succession at the // end of the arc list (last and its predecessors) while (theGraph->G[Jnext].type == EDGE_FORWARD) Jnext = gp_GetPrevArc(theGraph, Jnext); // Now we want to put all the back arcs in a backArcList, too. // Since we've already skipped past the forward arcs, we continue // with the predecessor arcs until we either run out of arcs or // we find a DFS child arc (the DFS child arcs are in succession // at the beginning of the arc list, so when a child arc is // encountered in the predecessor direction, then there won't be // any more back arcs. while (gp_IsArc(theGraph, Jnext) && theGraph->G[Jnext].type != EDGE_DFSCHILD) { Jcur = Jnext; Jnext = gp_GetPrevArc(theGraph, Jnext); if (theGraph->G[Jcur].type == EDGE_BACK) { // Remove the back arc from I's adjacency list gp_DetachArc(theGraph, Jcur); // Put the back arc in the backArcList if (context->V[I].backArcList == NIL) { context->V[I].backArcList = Jcur; gp_SetPrevArc(theGraph, Jcur, Jcur); gp_SetNextArc(theGraph, Jcur, Jcur); } else { gp_AttachArc(theGraph, NIL, context->V[I].backArcList, 1, Jcur); } // Determine the ancestor of vertex I to which Jcur connects ancestor = theGraph->G[Jcur].v; // Go to the forward arc in the ancestor Jcur = gp_GetTwinArc(theGraph, Jcur); // Remove the forward arc from the ancestor's adjacency list gp_DetachArc(theGraph, Jcur); // Add the forward arc to the end of the fwdArcList. if (theGraph->V[ancestor].fwdArcList == NIL) { theGraph->V[ancestor].fwdArcList = Jcur; gp_SetPrevArc(theGraph, Jcur, Jcur); gp_SetNextArc(theGraph, Jcur, Jcur); } else { gp_AttachArc(theGraph, NIL, theGraph->V[ancestor].fwdArcList, 1, Jcur); } } } } // Since the fwdArcLists have been created, we do not fall through // to run the superclass implementation return OK; } // If we're not actually running a K3,3 search, then we just run the // superclass implementation return context->functions.fpCreateFwdArcLists(theGraph); }
int _CheckVisibilityRepresentationIntegrity(DrawPlanarContext *context) { graphP theEmbedding = context->theGraph; int I, e, J, JTwin, JPos, JIndex; if (sp_NonEmpty(context->theGraph->edgeHoles)) return NOTOK; _FillVisitedFlags(theEmbedding, 0); /* Test whether the vertex values make sense and whether the vertex positions are unique. */ for (I = 0; I < theEmbedding->N; I++) { if (theEmbedding->M > 0) { if (context->G[I].pos < 0 || context->G[I].pos >= theEmbedding->N || context->G[I].start < 0 || context->G[I].start > context->G[I].end || context->G[I].end >= theEmbedding->M) return NOTOK; } // Has the vertex position (context->G[I].pos) been used by a // vertex before vertex I? if (theEmbedding->G[context->G[I].pos].visited) return NOTOK; // Mark the vertex position as used by vertex I. // Note that this marking is made on some other vertex unrelated to I // We're just reusing the vertex visited array as cheap storage for a // detector of reusing vertex position integers. theEmbedding->G[context->G[I].pos].visited = 1; } /* Test whether the edge values make sense and whether the edge positions are unique */ for (e = 0; e < theEmbedding->M; e++) { /* Each edge has an index location J in the graph structure */ J = theEmbedding->edgeOffset + 2*e; JTwin = gp_GetTwinArc(theEmbedding, J); if (context->G[J].pos != context->G[JTwin].pos || context->G[J].start != context->G[JTwin].start || context->G[J].end != context->G[JTwin].end || context->G[J].pos < 0 || context->G[J].pos >= theEmbedding->M || context->G[J].start < 0 || context->G[J].start > context->G[J].end || context->G[J].end >= theEmbedding->N) return NOTOK; /* Get the recorded horizontal position of that edge, a number between 0 and M-1 */ JPos = context->G[J].pos; /* Convert that to an index in the graph structure so we can use the visited flags in the graph's edges to tell us whether the positions are being reused. */ JIndex = theEmbedding->edgeOffset + 2*JPos; JTwin = gp_GetTwinArc(theEmbedding, JIndex); if (theEmbedding->G[JIndex].visited || theEmbedding->G[JTwin].visited) return NOTOK; theEmbedding->G[JIndex].visited = theEmbedding->G[JTwin].visited = 1; } /* Test whether any edge intersects any vertex position for a vertex that is not an endpoint of the edge. */ for (e = 0; e < theEmbedding->M; e++) { J = theEmbedding->edgeOffset + 2*e; JTwin = gp_GetTwinArc(theEmbedding, J); for (I = 0; I < theEmbedding->N; I++) { /* If the vertex is an endpoint of the edge, then... */ if (theEmbedding->G[J].v == I || theEmbedding->G[JTwin].v == I) { /* The vertical position of the vertex must be at the top or bottom of the edge, */ if (context->G[J].start != context->G[I].pos && context->G[J].end != context->G[I].pos) return NOTOK; /* The horizontal edge position must be in the range of the vertex */ if (context->G[J].pos < context->G[I].start || context->G[J].pos > context->G[I].end) return NOTOK; } /* If the vertex is not an endpoint of the edge... */ else // if (theEmbedding->G[J].v != I && theEmbedding->G[JTwin].v != I) { /* If the vertical position of the vertex is in the vertical range of the edge ... */ if (context->G[J].start <= context->G[I].pos && context->G[J].end >= context->G[I].pos) { /* And if the horizontal position of the edge is in the horizontal range of the vertex, then return an error. */ if (context->G[I].start <= context->G[J].pos && context->G[I].end >= context->G[J].pos) return NOTOK; } } } } /* All tests passed */ return OK; }
int _MarkZtoRPath(graphP theGraph) { int ZPrevArc, ZNextArc, Z, R, Px, Py; /* Initialize */ R = theGraph->IC.r; Px = theGraph->IC.px; Py = theGraph->IC.py; theGraph->IC.z = NIL; /* Begin at Px and search its adjacency list for the edge leading to the first internal vertex of the X-Y path. */ Z = Px; ZNextArc = gp_GetLastArc(theGraph, Z); while (ZNextArc != gp_GetFirstArc(theGraph, Z)) { if (theGraph->G[ZNextArc].visited) break; ZNextArc = gp_GetPrevArc(theGraph, ZNextArc); } if (!theGraph->G[ZNextArc].visited) return NOTOK; /* For each internal vertex Z, determine whether it has a path to root. */ while (theGraph->G[ZNextArc].visited) { ZPrevArc = gp_GetTwinArc(theGraph, ZNextArc); ZNextArc = gp_GetPrevArcCircular(theGraph, ZPrevArc); } ZPrevArc = gp_GetTwinArc(theGraph, ZNextArc); Z = theGraph->G[ZPrevArc].v; /* If there is no Z to R path, return */ if (Z == Py) return OK; /* Otherwise, store Z in the isolation context */ theGraph->IC.z = Z; /* Walk the proper face starting with (Z, ZNextArc) until we reach R, marking the vertices and edges encountered along the way, then Return OK. */ while (Z != R) { /* If we ever encounter a non-internal vertex (other than the root R), then corruption has occured, so we return NOTOK */ if (theGraph->G[Z].type != TYPE_UNKNOWN) return NOTOK; /* Go to the next vertex indicated by ZNextArc */ Z = theGraph->G[ZNextArc].v; /* Mark the next vertex and the edge leading to it as visited. */ theGraph->G[ZNextArc].visited = 1; theGraph->G[ZPrevArc].visited = 1; theGraph->G[Z].visited = 1; /* Go to the next edge in the proper face */ ZNextArc = gp_GetPrevArcCircular(theGraph, ZPrevArc); ZPrevArc = gp_GetTwinArc(theGraph, ZNextArc); } /* Found Z to R path, so indicate as much to caller */ return OK; }
int _MarkHighestXYPath(graphP theGraph) { int J, Z; int R, X, Y, W; int stackBottom1, stackBottom2; /* Initialization */ R = theGraph->IC.r; X = theGraph->IC.x; Y = theGraph->IC.y; W = theGraph->IC.w; theGraph->IC.px = theGraph->IC.py = NIL; /* Save the stack bottom before we start hiding internal edges, so we will know how many edges to restore */ stackBottom1 = sp_GetCurrentSize(theGraph->theStack); /* Remove the internal edges incident to vertex R */ if (_HideInternalEdges(theGraph, R) != OK) return NOTOK; /* Now we're going to use the stack to collect the vertices of potential * X-Y paths, so we need to store where the hidden internal edges are * located because we must, at times, pop the collected vertices if * the path being collected doesn't work out. */ stackBottom2 = sp_GetCurrentSize(theGraph->theStack); /* Walk the proper face containing R to find and mark the highest X-Y path. Note that if W is encountered, then there is no intervening X-Y path, so we would return FALSE in that case. */ Z = R; // This setting of J is the arc equivalent of prevLink=1 // As loop progresses, J indicates the arc used to enter Z, not the exit arc J = gp_GetLastArc(theGraph, R); while (theGraph->G[Z].type != VERTEX_HIGH_RYW && theGraph->G[Z].type != VERTEX_LOW_RYW) { /* Advance J and Z along the proper face containing R */ J = gp_GetPrevArcCircular(theGraph, J); Z = theGraph->G[J].v; J = gp_GetTwinArc(theGraph, J); /* If Z is already visited, then pop everything since the last time we visited Z because its all part of a separable component. */ if (theGraph->G[Z].visited) { if (_PopAndUnmarkVerticesAndEdges(theGraph, Z, stackBottom2) != OK) return NOTOK; } /* If we have not visited this vertex before... */ else { /* If we find W, then there is no X-Y path. Never happens for Kuratowski subgraph isolator, but this routine is also used to test for certain X-Y paths. So, we clean up and bail out in that case. */ if (Z == W) { if (_PopAndUnmarkVerticesAndEdges(theGraph, NIL, stackBottom2) != OK) return NOTOK; break; } /* If we found another vertex along the RXW path, then blow off all the vertices we visited so far because they're not part of the obstructing path */ if (theGraph->G[Z].type == VERTEX_HIGH_RXW || theGraph->G[Z].type == VERTEX_LOW_RXW) { theGraph->IC.px = Z; if (_PopAndUnmarkVerticesAndEdges(theGraph, NIL, stackBottom2) != OK) return NOTOK; } /* Push the current vertex onto the stack of vertices visited since the last RXW vertex was encountered */ sp_Push(theGraph->theStack, J); sp_Push(theGraph->theStack, Z); /* Mark the vertex Z as visited as well as its edge of entry (except the entry edge for P_x).*/ theGraph->G[Z].visited = 1; if (Z != theGraph->IC.px) { theGraph->G[J].visited = 1; theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1; } /* If we found an RYW vertex, then we have successfully finished identifying the highest X-Y path, so we record the point of attachment and break the loop. */ if (theGraph->G[Z].type == VERTEX_HIGH_RYW || theGraph->G[Z].type == VERTEX_LOW_RYW) { theGraph->IC.py = Z; break; } } } /* Remove any remaining vertex-edge pairs on the top of the stack, then Restore the internal edges incident to R that were previously removed. */ sp_SetCurrentSize(theGraph->theStack, stackBottom2); if (_RestoreInternalEdges(theGraph, stackBottom1) != OK) return NOTOK; /* Return the result */ return theGraph->IC.py==NIL ? FALSE : TRUE; }
int _K33Search_MarkDFSPath(graphP theGraph, int ancestor, int descendant) { int J, parent, N; N = theGraph->N; /* If we are marking from a root vertex upward, then go up to the parent copy before starting the loop */ if (descendant >= N) descendant = theGraph->V[descendant-N].DFSParent; /* Mark the lowest vertex (the one with the highest number). */ theGraph->G[descendant].visited = 1; /* Mark all ancestors of the lowest vertex, and the edges used to reach them, up to the given ancestor vertex. */ while (descendant != ancestor) { if (descendant == NIL) return NOTOK; /* If we are at a bicomp root, then ascend to its parent copy and mark it as visited. */ if (descendant >= N) { parent = theGraph->V[descendant-N].DFSParent; } /* If we are on a regular, non-virtual vertex then get the edge to the parent, mark the edge, then fall through to the code that marks the parent vertex. */ else { /* Scan the edges for the one marked as the DFS parent */ parent = NIL; J = gp_GetFirstArc(theGraph, descendant); while (gp_IsArc(theGraph, J)) { if (theGraph->G[J].type == EDGE_DFSPARENT) { parent = theGraph->G[J].v; break; } J = gp_GetNextArc(theGraph, J); } /* If the desired edge was not found, then the data structure is corrupt, so bail out. */ if (parent == NIL) return NOTOK; /* Mark the edge */ theGraph->G[J].visited = 1; theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1; } /* Mark the parent, then hop to the parent and reiterate */ theGraph->G[parent].visited = 1; descendant = parent; } return OK; }