int _InitializeNonplanarityContext(graphP theGraph, int I, int R) { int singleBicompMode = (R == NIL) ? FALSE : TRUE; // Blank out the isolator context, then assign the input graph reference // and the current vertext I into the context. _ClearIsolatorContext(theGraph); theGraph->IC.v = I; // The Walkdown halted on one or more bicomps without embedding all back // edges to descendants of the root(s) of said bicomp(s). // If the bicomp root has not been provided, we now find the root of one such bicomp. if (!singleBicompMode) R = _FindNonplanarityBicompRoot(theGraph); // When in singleBicompMode, the bicomp root provided was the one on which // the WalkDown was performed, but in the case of Minor A, the central bicomp // of the minor is at the top of the stack, so R must be changed to that value. else if (sp_NonEmpty(theGraph->theStack)) R = _FindNonplanarityBicompRoot(theGraph); if (R == NIL) return NOTOK; theGraph->IC.r = R; // A number of subroutines require the main bicomp of the minor to be // consistently oriented and its visited flags clear. if (_OrientVerticesInBicomp(theGraph, R, 1) != OK) return NOTOK; // In singleBicompMode, clear the visited members of all vertex and edge records. if (singleBicompMode) { if (_FillVisitedFlagsInBicomp(theGraph, R, 0) != OK) return NOTOK; } // Now we find the active vertices along both external face paths // extending from R. _FindActiveVertices(theGraph, R, &theGraph->IC.x, &theGraph->IC.y); // Now, we obtain the pertinent vertex W on the lower external face // path between X and Y (that path that does not include R). theGraph->IC.w = _FindPertinentVertex(theGraph); // Now we can classify the vertices along the external face of the bicomp // rooted at R as 'high RXW', 'low RXW', 'high RXY', 'low RXY' if (_SetVertexTypesForMarkingXYPath(theGraph) != OK) return NOTOK; // All work is done, so return success return OK; }
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; }
int _ComputeVisibilityRepresentation(DrawPlanarContext *context) { if (sp_NonEmpty(context->theGraph->edgeHoles)) return NOTOK; if (_ComputeVertexPositions(context) != OK) return NOTOK; if (_ComputeEdgePositions(context) != OK) return NOTOK; if (_ComputeVertexRanges(context) != OK) return NOTOK; if (_ComputeEdgeRanges(context) != OK) return NOTOK; return OK; }
int gp_ColorVertices(graphP theGraph) { ColorVerticesContext *context = NULL; int v, deg; int u=0, w=0, contractible; // Attach the algorithm if it is not already attached if (gp_AttachColorVertices(theGraph) != OK) return NOTOK; // Ensure there is enough stack to perform this operation. // At a maximum, the graph reduction will push 7N+M integers. // One integer is pushed per edge that is hidden. Plus, whether // a vertex is hidden or identified with another vertex, 7 integers // are used to store enough information to restore it. if (sp_NonEmpty(theGraph->theStack)) return NOTOK; if (sp_GetCapacity(theGraph->theStack) < 7*theGraph->N + theGraph->M) { stackP newStack = sp_New(7*theGraph->N + theGraph->M); if (newStack == NULL) return NOTOK; sp_Free(&theGraph->theStack); theGraph->theStack = newStack; } // Get the extension context and reinitialize it if necessary gp_FindExtension(theGraph, COLORVERTICES_ID, (void *)&context); if (context->color[0] > -1) _ColorVertices_Reinitialize(context); // Initialize the degree lists, and provide a color for any trivial vertices for (v = 0; v < theGraph->N; v++) { deg = gp_GetVertexDegree(theGraph, v); _AddVertexToDegList(context, theGraph, v, deg); if (deg == 0) context->color[v] = 0; } // Initialize the visited flags so they can be used during reductions _FillVisitedFlags(theGraph, 0); // Reduce the graph using minimum degree selection while (context->numVerticesToReduce > 0) { v = _GetVertexToReduce(context, theGraph); // Find out if v is contractible and the neighbors to contract contractible = _GetContractibleNeighbors(context, v, &u, &w); // Remove the vertex from the graph. This calls the fpHideEdge // overload, which performs the correct _RemoveVertexFromDegList() // and _AddVertexToDegList() operations on v and its neighbors. if (gp_HideVertex(theGraph, v) != OK) return NOTOK; // If v was contractibile, then identify u and w if (contractible) { if (gp_IdentifyVertices(theGraph, u, w, NIL) != OK) return NOTOK; } } // Restore the graph one vertex at a time, coloring each vertex distinctly // from its neighbors as it is restored. context->colorDetector = (int *) calloc(theGraph->N, sizeof(int)); if (context->colorDetector == NULL) return NOTOK; if (gp_RestoreVertices(theGraph) != OK) return NOTOK; free(context->colorDetector); context->colorDetector = NULL; return OK; }
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; }
char *_RenderToString(graphP theEmbedding) { DrawPlanarContext *context = NULL; gp_FindExtension(theEmbedding, DRAWPLANAR_ID, (void *) &context); if (context != NULL) { int N = theEmbedding->N; int M = theEmbedding->M; int I, J, e, Mid, Pos; char *visRep = (char *) malloc(sizeof(char) * ((M+1) * 2*N + 1)); char numBuffer[32]; if (visRep == NULL) return NULL; if (sp_NonEmpty(context->theGraph->edgeHoles)) { free(visRep); return NULL; } // Clear the space for (I = 0; I < N; I++) { for (J=0; J < M; J++) { visRep[(2*I) * (M+1) + J] = ' '; visRep[(2*I+1) * (M+1) + J] = ' '; } visRep[(2*I) * (M+1) + M] = '\n'; visRep[(2*I+1) * (M+1) + M] = '\n'; } // Draw the vertices for (I = 0; I < N; I++) { Pos = context->G[I].pos; for (J=context->G[I].start; J<=context->G[I].end; J++) visRep[(2*Pos) * (M+1) + J] = '-'; // Draw vertex label Mid = (context->G[I].start + context->G[I].end)/2; sprintf(numBuffer, "%d", I); if ((unsigned)(context->G[I].end - context->G[I].start + 1) >= strlen(numBuffer)) { strncpy(visRep + (2*Pos) * (M+1) + Mid, numBuffer, strlen(numBuffer)); } // If the vertex width is less than the label width, then fail gracefully else { if (strlen(numBuffer)==2) visRep[(2*Pos) * (M+1) + Mid] = numBuffer[0]; else visRep[(2*Pos) * (M+1) + Mid] = '*'; visRep[(2*Pos+1) * (M+1) + Mid] = numBuffer[strlen(numBuffer)-1]; } } // Draw the edges for (e=0; e<M; e++) { J = 2*N + 2*e; Pos = context->G[J].pos; for (I=context->G[J].start; I<context->G[J].end; I++) { if (I > context->G[J].start) visRep[(2*I) * (M+1) + Pos] = '|'; visRep[(2*I+1) * (M+1) + Pos] = '|'; } } // Null terminate string and return it visRep[(M+1) * 2*N] = '\0'; return visRep; } return NULL; }
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 gp_LowpointAndLeastAncestor(graphP theGraph) { stackP theStack = theGraph->theStack; int I, u, uneighbor, J, L, leastAncestor; int totalVisited = 0; #ifdef PROFILE platform_time start, end; platform_GetTime(start); #endif sp_ClearStack(theStack); for (I=0; I < theGraph->N; I++) theGraph->G[I].visited = 0; /* This outer loop causes the connected subgraphs of a disconnected graph to be processed */ for (I=0; I < theGraph->N && totalVisited < theGraph->N; I++) { if (theGraph->G[I].visited) continue; sp_Push(theStack, I); while (sp_NonEmpty(theStack)) { sp_Pop(theStack, u); if (!theGraph->G[u].visited) { /* Mark u as visited, then push it back on the stack */ theGraph->G[u].visited = 1; totalVisited++; sp_Push(theStack, u); /* Push DFS children */ J = gp_GetFirstArc(theGraph, u); while (gp_IsArc(theGraph, J)) { if (theGraph->G[J].type == EDGE_DFSCHILD) { sp_Push(theStack, theGraph->G[J].v); } else break; J = gp_GetNextArc(theGraph, J); } } else { /* Start with high values because we are doing a min function */ L = leastAncestor = u; /* Compute L and leastAncestor */ J = gp_GetFirstArc(theGraph, u); while (gp_IsArc(theGraph, J)) { uneighbor = theGraph->G[J].v; if (theGraph->G[J].type == EDGE_DFSCHILD) { if (L > theGraph->V[uneighbor].Lowpoint) L = theGraph->V[uneighbor].Lowpoint; } else if (theGraph->G[J].type == EDGE_BACK) { if (leastAncestor > uneighbor) leastAncestor = uneighbor; } else if (theGraph->G[J].type == EDGE_FORWARD) break; J = gp_GetNextArc(theGraph, J); } /* Assign leastAncestor and Lowpoint to the vertex */ theGraph->V[u].leastAncestor = leastAncestor; theGraph->V[u].Lowpoint = leastAncestor < L ? leastAncestor : L; } } } #ifdef PROFILE platform_GetTime(end); printf("Lowpoint 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; }