def pt_DFS(v): global G, reached S = Stack() if reached[v] == 0: reached[v] = 1 S.Push(v) while S.IsNotEmpty(): v = S.Pop() for w in G.adj_nodes(v): if reached[w] == 0: reached[w] = 1 S.Push(w)
def strongly_planar(e0, Att): # We now come to the heart of the planarity test: procedure strongly_planar. # It takes a tree edge e0=(x,y) and tests whether the segment S(e0) is # strongly planar. # If successful it returns (in Att) the ordered list of attachments of S(e0) # (excluding x); high DFS-numbers are at the front of the list. # In alpha it records the placement of the subsegments. # # strongly_planar operates in three phases. # It first constructs the cycle C(e0) underlying the segment S(e0). # It then constructs the interlacing graph for the segments emanating >from the # spine of the cycle. # If this graph is non-bipartite then the segment S(e0) is non-planar. # If it is bipartite then the segment is planar. # In this case the third phase checks whether the segment is strongly planar # and, if so, computes its list of attachments. global G, alpha, dfsnum, parent #-------------------------------------------------------------- # DETERMINE THE CYCLE C(e0) # We determine the cycle "C(e0)" by following first edges until a back # edge is encountered. # |wk| will be the last node on the tree path and |w0| # is the destination of the back edge. x = source(e0) y = target(e0) e = G.first_adj_edge(y) wk = y while dfsnum[target(e)] > dfsnum[wk]: # e is a tree edge wk = target(e) e = G.first_adj_edge(wk) w0 = target(e) #-------------------------------------------------------------- #-------------------------------------------------------------- # PROCESS ALL EDGES LEAVING THE SPINE # The second phase of |strongly_planar| constructs the connected # components of the interlacing graph of the segments emananating # from the the spine of the cycle "C(e0)". # We call a connected component a "block". # For each block we store the segments comprising its left and # right side (lists |Lseg| and |Rseg| contain the edges defining # these segments) and the ordered list of attachments of the segments # in the block; # lists |Latt| and |Ratt| contain the DFS-numbers of the attachments; # high DFS-numbers are at the front of the list. # # We process the edges leaving the spine of "S(e0)" starting at # node |wk| and working backwards. # The interlacing graph of the segments emanating from # the cycle is represented as a stack |S| of blocks. w = wk S = Stack() while w != x: count = 0 for e in G.adj_edges(w): count = count + 1 if count != 1: # no action for first edge # TEST RECURSIVELY # Let "e" be any edge leaving the spine. # We need to test whether "S(e)" is strongly planar # and if so compute its list |A| of attachments. # If "e" is a tree edge we call our procedure recursively # and if "e" is a back edge then "S(e)" is certainly strongly # planar and |target(e)| is the only attachment. # If we detect non-planarity we return false and free # the storage allocated for the blocks of stack |S|. A = List() if dfsnum[w] < dfsnum[target(e)]: # tree edge if not (strongly_planar(e, A)): while S.IsNotEmpty(): S.Pop() return 0 else: A.append(dfsnum[target(e)]) # a back edge # UPDATE STACK |S| OF ATTACHMENTS # The list |A| contains the ordered list of attachments # of segment "S(e)". # We create an new block consisting only of segment "S(e)" # (in its L-part) and then combine this block with the # topmost block of stack |S| as long as there is interlacing. # We check for interlacing with the L-part. # If there is interlacing then we flip the two sides of the # topmost block. # If there is still interlacing with the left side then the # interlacing graph is non-bipartite and we declare the graph # non-planar (and also free the storage allocated for the # blocks). # Otherwise we check for interlacing with the R-part. # If there is interlacing then we combine |B| with the topmost # block and repeat the process with the new topmost block. # If there is no interlacing then we push block |B| onto |S|. B = block(e, A) while 1: if B.left_interlace(S): (S.contents[-1]).flip() if B.left_interlace(S): del B while S.IsNotEmpty(): S.Pop() return 0 if B.right_interlace(S): B.combine(S.Pop()) else: break S.Push(B) # PREPARE FOR NEXT ITERATION # We have now processed all edges emanating from vertex |w|. # Before starting to process edges emanating from vertex # |parent[w]| we remove |parent[w]| from the list of attachments # of the topmost # block of stack |S|. # If this block becomes empty then we pop it from the stack and # record the placement for all segments in the block in array # |alpha|. while (S.IsNotEmpty() and (S.contents[-1]).clean(dfsnum[parent[w]], alpha, dfsnum)): S.Pop() w = parent[w] #-------------------------------------------------------------- #-------------------------------------------------------------- # TEST STRONG PLANARITY AND COMPUTE Att # We test the strong planarity of the segment "S(e0)". # We know at this point that the interlacing graph is bipartite. # Also for each of its connected components the corresponding block # on stack |S| contains the list of attachments below |x|. # Let |B| be the topmost block of |S|. # If both sides of |B| have an attachment above |w0| then # "S(e0)" is not strongly planar. # We free the storage allocated for the blocks and return false. # Otherwise (cf. procedure |add_to_Att|) we first make sure that # the right side of |B| attaches only to |w0| (if at all) and then # add the two sides of |B| to the output list |Att|. # We also record the placements of the subsegments in |alpha|. Att.clear() while S.IsNotEmpty(): B = S.Pop() if (not (B.empty_Latt()) and not (B.empty_Ratt()) and B.head_of_Latt() > dfsnum[w0] and B.head_of_Ratt() > dfsnum[w0]): del B while S.IsNotEmpty(): S.Pop() return 0 B.add_to_Att(Att, dfsnum[w0], alpha, dfsnum) del B # Let's not forget that "w0" is an attachment # of "S(e0)" except if w0 = x. if w0 != x: Att.append(dfsnum[w0]) return 1
def TreeCoords(G, root, orientation): S = Stack() visited = {} d = {} leaves = [] number_of_leaves = 0 height = 0 nodes = {} children = {} father = {} for v in G.vertices: visited[v] = 0 visited[root] = 1 S.Push(root) d[root] = 0 nodes[0] = [] children[root] = [] father[root] = None while S.IsNotEmpty(): v = S.Pop() if orientation=="vertical": nodes[d[v]].insert(0,v) if v!=root: children[father[v]].insert(0,v) else: nodes[d[v]].append(v) if v!=root: children[father[v]].append(v) isleaf = 1 for w in G.InOutNeighbors(v): if visited[w] == 0: isleaf = 0 visited[w] = 1 d[w] = d[v] + 1 children[w] = [] father[w] = v if d[w]>height: height = d[w] nodes[height] = [] S.Push(w) if isleaf: number_of_leaves = number_of_leaves + 1 if orientation=="vertical": leaves.insert(0,v) else: leaves.append(v) # Test whether the graph is connected and # acyclic.(=test whether the graph is a tree) for v in G.vertices: if visited[v]==0: showwarning("Warning", "Graph is not a tree,\n" "not connected !!!") return 0 ch_len = len(children[v]) if v!=root: ch_len = ch_len + 1 if ch_len<len(G.InOutNeighbors(v)): showwarning("Warning", "Graph is not a tree,\n" "contains cycles !!!") return 0 if number_of_leaves<=19: dist1 = 50 else: dist1 = 900 / (number_of_leaves-1) if height+1<=19: dist2 = 50 else: dist2 = 900 / height if dist1<25 or dist2<30: showwarning("Warning", "Tree-Layout not possible,\n" "the tree is too large !!!") return 0 Coord1 = {} Coord2 = {} i = 0 for v in leaves: Coord1[v] = 50 + i * dist1 Coord2[v] = 50 + d[v] * dist2 i = i + 1 i = height - 1 while i>=0: for v in nodes[i]: if children[v]!=[]: Coord2[v] = 50 + d[v] * dist2 if len(children[v])==1: Coord1[v] = Coord1[children[v][0]] else: Coord1[v] = ( Coord1[children[v][0]] + (Coord1[children[v][-1]] - Coord1[children[v][0]]) / 2) i=i-1 if orientation=="vertical": G.xCoord=Coord1 G.yCoord=Coord2 else: G.xCoord=Coord2 G.yCoord=Coord1 return 1