예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #5
0
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;
}
예제 #6
0
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;
}
예제 #7
0
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;
}
예제 #8
0
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;
}