int _FindNonplanarityBicompRoot(graphP theGraph) { int R, tempChild, fwdArc, W=NIL, C=NIL, I=theGraph->IC.v; /* If the stack is non-empty, then the Walkdown stopped on a descendant bicomp, not one rooted by I. We need to get that root before the stack is destroyed by other routines. */ if (sp_NonEmpty(theGraph->theStack)) { int e; sp_Pop2(theGraph->theStack, R, e); return R; } /* Obtain the forward arc of an unembedded back edge from I to one of its descendants (edges are removed from the forward arc list as they are embedded, so the list will be empty if all edges were embedded). */ if ((fwdArc = theGraph->V[I].fwdArcList) == NIL) return NIL; W = theGraph->G[fwdArc].v; /* Find the greatest DFS child C of I that is less than W. This will give us the ancestor of W that is a child of I. Since the ancestors of I have not been processed by the planarity algorithm, the separatedDFSChildList of I contains all the children of I. */ tempChild = theGraph->V[I].separatedDFSChildList; while (tempChild != NIL) { if (tempChild > C && tempChild < W) C = tempChild; tempChild = LCGetNext(theGraph->DFSChildLists, theGraph->V[I].separatedDFSChildList, tempChild); } if (C == NIL) return NIL; /* The root vertex of a bicomp rooted by edge (I, C) is located at position C+N in our data structures */ R = C + theGraph->N; return R; }
void _CreateSeparatedDFSChildLists(graphP theGraph, K33SearchContext *context) { int *buckets; listCollectionP bin; int v, L, DFSParent, theList; buckets = context->buckets; bin = context->bin; // Initialize the bin and all the buckets to be empty LCReset(bin); for (L = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, L); L++) buckets[L] = NIL; // For each vertex, add it to the bucket whose index is equal to the lowpoint of the vertex. for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { L = gp_GetVertexLowpoint(theGraph, v); buckets[L] = LCAppend(bin, buckets[L], v); } // For each bucket, add each vertex in the bucket to the separatedDFSChildList of its DFSParent. // Since lower numbered buckets are processed before higher numbered buckets, vertices with lower // lowpoint values are added before those with higher lowpoint values, so the separatedDFSChildList // of each vertex is sorted by lowpoint for (L = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, L); L++) { v = buckets[L]; // Loop through all the vertices with lowpoint L, putting each in the list of its parent while (gp_IsVertex(v)) { DFSParent = gp_GetVertexParent(theGraph, v); if (gp_IsVertex(DFSParent) && DFSParent != v) { theList = context->VI[DFSParent].separatedDFSChildList; theList = LCAppend(context->separatedDFSChildLists, theList, v); context->VI[DFSParent].separatedDFSChildList = theList; } v = LCGetNext(bin, buckets[L], v); } } }
/******************************************************************** _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 _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 _ComputeVertexPositionsInComponent(DrawPlanarContext *context, int root, int *pIndex) { graphP theEmbedding = context->theGraph; listCollectionP theOrder = LCNew(theEmbedding->N); int W, P, C, V, J; if (theOrder == NULL) return NOTOK; // Determine the vertex order using a depth first search with // pre-order visitation. sp_ClearStack(theEmbedding->theStack); sp_Push(theEmbedding->theStack, root); while (!sp_IsEmpty(theEmbedding->theStack)) { sp_Pop(theEmbedding->theStack, W); P = theEmbedding->V[W].DFSParent; V = context->V[W].ancestor; C = context->V[W].ancestorChild; // For the special case that we just popped the DFS tree root, // we simply add the root to its own position. if (P == NIL) { // Put the DFS root in the list by itself LCAppend(theOrder, NIL, W); // The children of the DFS root have the root as their // ancestorChild and 'beyond' as the drawingFlag, so this // causes the root's children to be placed below the root context->V[W].drawingFlag = DRAWINGFLAG_BELOW; } // Determine vertex W position relative to P else { // An unresolved tie is an error if (context->V[W].drawingFlag == DRAWINGFLAG_TIE) return NOTOK; // If C below V, then P below V, so interpret W between // P and V as W above P, and interpret W beyond P relative // to V as W below P. if (context->V[C].drawingFlag == DRAWINGFLAG_BELOW) { if (context->V[W].drawingFlag == DRAWINGFLAG_BETWEEN) context->V[W].drawingFlag = DRAWINGFLAG_ABOVE; else context->V[W].drawingFlag = DRAWINGFLAG_BELOW; } // If C above V, then P above V, so interpret W between // P and V as W below P, and interpret W beyond P relative // to V as W above P. else { if (context->V[W].drawingFlag == DRAWINGFLAG_BETWEEN) context->V[W].drawingFlag = DRAWINGFLAG_BELOW; else context->V[W].drawingFlag = DRAWINGFLAG_ABOVE; } if (context->V[W].drawingFlag == DRAWINGFLAG_BELOW) LCInsertAfter(theOrder, P, W); else LCInsertBefore(theOrder, P, W); } // Push DFS children J = gp_GetFirstArc(theEmbedding, W); while (gp_IsArc(theEmbedding, J)) { if (theEmbedding->G[J].type == EDGE_DFSCHILD) sp_Push(theEmbedding->theStack, theEmbedding->G[J].v); J = gp_GetNextArc(theEmbedding, J); } } // Use the order to assign vertical positions V = root; while (V != NIL) { context->G[V].pos = *pIndex; (*pIndex)++; V = LCGetNext(theOrder, root, V); } // Clean up and return LCFree(&theOrder); return OK; }