Kirill Simonov avatar Kirill Simonov committed b9ef922

Implemented uniform node dimensions.

Comments (0)

Files changed (4)

demo/example-regress.py

 
 from grrdrr.model import build, WithGraphStyle, WithNodeLabel, WithArcLabel, WithArcWeight
-from grrdrr.draw import measure, draw, draw_smooth
+from grrdrr.draw import measure, measure_uniform, draw, draw_smooth
 from grrdrr.algorithm import rank, layer, order, place
 
 
 example.add_arc(rd_program_requirement, rd_classification).set_weight(1.0)
 
 example.freeze()
-measure(example)
+measure_uniform(example)
 rank(example)
 layer(example)
 order(example)

demo/example-schema.py

 
 from grrdrr.model import WithGraphStyle
-from grrdrr.draw import measure, draw_smooth
+from grrdrr.draw import measure, measure_uniform, draw_smooth, draw_smooth_cut
 from grrdrr.algorithm import rank, layer, order, place
 from grrdrr.database import build_schema
 from grrdrr.graphviz import draw_graphviz
 example.freeze()
 
 print "MEASURING..."
-measure(example)
+measure_uniform(example)
 print "RANKING..."
 rank(example)
 print "LAYERING..."
 
 filename = "%s.sugiyama.png" % basename
 stream = open(filename, 'wb')
-draw_smooth(example, stream)
+draw_smooth_cut(example, stream)
 stream.close()
 print "Sugiyama rendering is written to: %s" % filename
 

src/grrdrr/database.py

         for table in schema.tables:
             origin = node_by_table[table]
             for foreign_key in table.foreign_keys:
-                target_schema = catalog.schemas[foreign_key.target_schema_name]
-                target_table = target_schema.tables[foreign_key.target_name]
-                target = node_by_table[target_table]
-                is_parental = (target_table.primary_key is not None and
-                               all(column_name in target_table.primary_key.origin_column_names
-                                   for column_name in foreign_key.origin_column_names))
+                target = node_by_table[foreign_key.target]
+                is_parental = (foreign_key.target.primary_key is not None and
+                               all(column in table.columns
+                                   for column in foreign_key.origin_columns))
                 if is_parental:
                     weight = 1.0
                 else:

src/grrdrr/draw.py

     return graph
 
 
+def measure_uniform(graph):
+    ensure(graph.readonly(WithGraphStyle, WithNodeLabel), "without graph style or node labels", graph)
+    ensure(not graph.readable(WithNodeDimensions), "already with node dimensions", graph)
+    ensure(not graph.readable(WithGraphMargins), "already with graph margins", graph)
+    graph.upgrade(WithNodeDimensions)
+    graph.upgrade(WithGraphMargins)
+
+    dummy_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1)
+    dummy_context = cairo.Context(dummy_surface)
+    dummy_context.set_font_size(graph.style.font_size)
+
+    extents = dummy_context.text_extents('M')
+    x_bearing, y_bearing, width, height, x_advance, y_advance = extents
+    m_width = width
+    m_height = height
+    graph.set_margins(int(3*m_width), int(3*m_height))
+
+    widths = []
+    heights = []
+    for node in graph.nodes:
+        extents = dummy_context.text_extents(node.label.text)
+        x_bearing, y_bearing, width, height, x_advance, y_advance = extents
+        widths.append(width)
+        heights.append(height)
+    widths.sort()
+    heights.sort()
+    width = min(1.5*widths[len(graph.nodes)/2], widths[-1])
+    height = min(1.5*heights[len(graph.nodes)/2], heights[-1])
+    node_width = int(width+m_width*2)
+    node_height = int(height+m_height*2)
+
+    for node in graph.nodes:
+        node.set_dimensions(node_width, node_height)
+
+    graph.freeze(WithNodeDimensions)
+    graph.freeze(WithGraphMargins)
+
+    return graph
+
+
 def draw(graph, stream):
     ensure(graph.readonly(WithGraphStyle), "without graph style", graph)
     ensure(graph.readonly(WithGraphSize), "without graph size", graph)
     return graph
 
 
+def draw_smooth_cut(graph, stream):
+    ensure(graph.readonly(WithGraphStyle), "without graph style", graph)
+    ensure(graph.readonly(WithGraphSize), "without graph size", graph)
+    ensure(graph.readonly(WithNodePosition), "without node positions", graph)
+    ensure(graph.readonly(WithArcVertices), "without arc vertices", graph)
+
+    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, graph.size.width, graph.size.height)
+    context = cairo.Context(surface)
+    context.set_font_size(graph.style.font_size)
+
+    context.set_source_rgb(*graph.style.background_color)
+    context.rectangle(0, 0, graph.size.width, graph.size.height)
+    context.fill()
+
+    context.set_source_rgb(*graph.style.arc_color)
+    context.set_line_width(graph.style.arc_width)
+    for arc in graph.arcs:
+        context.new_path()
+        if len(arc.vertices) > 2:
+            vertex = arc.vertices[0]
+            context.move_to(vertex.x, vertex.y)
+            for idx in range(1, len(arc.vertices)-1):
+                if idx == 1:
+                    vertex = arc.vertices[0]
+                    s_x, s_y = vertex.x, vertex.y
+                else:
+                    vertex1 = arc.vertices[idx-1]
+                    vertex2 = arc.vertices[idx]
+                    s_x, s_y = (vertex1.x+vertex2.x)/2, (vertex1.y+vertex2.y)/2
+                if idx == len(arc.vertices)-2:
+                    vertex = arc.vertices[-1]
+                    e_x, e_y = vertex.x, vertex.y
+                else:
+                    vertex1 = arc.vertices[idx]
+                    vertex2 = arc.vertices[idx+1]
+                    e_x, e_y = (vertex1.x+vertex2.x)/2, (vertex1.y+vertex2.y)/2
+                vertex = arc.vertices[idx]
+                q_x, q_y = vertex.x, vertex.y
+                x1, y1 = 1.0/3.0*s_x+2.0/3.0*q_x, 1.0/3.0*s_y+2.0/3.0*q_y
+                x2, y2 = 1.0/3.0*e_x+2.0/3.0*q_x, 1.0/3.0*e_y+2.0/3.0*q_y
+                x3, y3 = e_x, e_y
+                context.curve_to(x1, y1, x2, y2, x3, y3)
+        else:
+            vertex = arc.vertices[0]
+            context.move_to(vertex.x, vertex.y)
+            for vertex in arc.vertices[1:]:
+                context.line_to(vertex.x, vertex.y)
+        context.stroke()
+
+    context.set_source_rgb(*graph.style.node_color)
+    for node in graph.nodes:
+        context.new_path()
+        context.rectangle(node.position.x, node.position.y, node.position.w, node.position.h)
+        context.fill()
+
+    context.set_source_rgb(*graph.style.border_color)
+    context.set_line_width(graph.style.border_width)
+    for node in graph.nodes:
+        context.new_path()
+        context.rectangle(node.position.x, node.position.y, node.position.w, node.position.h)
+        context.stroke()
+
+    if graph.readonly(WithNodeLabel):
+        context.set_source_rgb(*graph.style.text_color)
+        for node in graph.nodes:
+            if node.label is not None:
+                cx = node.position.x + node.position.w/2
+                cy = node.position.y + node.position.h/2
+                text = node.label.text
+                extents = context.text_extents(text)
+                x_bearing, y_bearing, width, height, x_advance, y_advance = extents
+                if width >= node.dimensions.width:
+                    hellip = '\xe2\x80\xa6'
+                    while width >= node.dimensions.width and len(text) > 1:
+                        text = text[:-1]
+                        extents = context.text_extents(text+hellip)
+                        x_bearing, y_bearing, width, height, x_advance, y_advance = extents
+                    text = text+hellip
+                x = cx - (width/2 + x_bearing)
+                y = cy - (height/2 + y_bearing)
+                context.move_to(x, y)
+                context.show_text(text)
+
+    surface.write_to_png(stream)
+
+    return graph
+
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.