]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/auxiliar/show_skyline_command.py
Imported Upstream version 2.18.0
[lilypond.git] / scripts / auxiliar / show_skyline_command.py
diff --git a/scripts/auxiliar/show_skyline_command.py b/scripts/auxiliar/show_skyline_command.py
new file mode 100644 (file)
index 0000000..6fc6314
--- /dev/null
@@ -0,0 +1,156 @@
+# This file is part of LilyPond, the GNU music typesetter.
+#
+# Copyright (C) 2012 Joe Neeman <joeneeman@gmail.com>
+#
+# LilyPond is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# LilyPond is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+
+# A gdb plugin debugging skylines.  To use the plugin, make sure that
+# skyline_viewer.py is in your PATH, then add
+# source /path/to/show_skyline_command.py
+# to your .gdbinit file.  The 'vsky' and 'hsky' commands for
+# drawing skylines will then be available in gdb.
+
+import gdb
+from subprocess import Popen, PIPE
+from math import isinf
+
+SKYLINE_VIEWER = 'skyline_viewer.py'
+
+# Function taken from GCC
+def find_type(orig, name):
+    typ = orig.strip_typedefs()
+    while True:
+        search = str(typ) + '::' + name
+        try:
+            return gdb.lookup_type(search)
+        except RuntimeError:
+            pass
+        # The type was not found, so try the superclass.    We only need
+        # to check the first superclass, so we don't bother with
+        # anything fancier here.
+        field = typ.fields()[0]
+        if not field.is_base_class:
+            raise ValueError, "Cannot find type %s::%s" % (str(orig), name)
+        typ = field.type
+
+# Class adapted from GCC
+class ListIterator:
+    def __init__ (self, val):
+        self.val = val
+        self.nodetype = find_type (val.type, '_Node')
+        self.nodetype = self.nodetype.strip_typedefs ().pointer ()
+
+        head = val['_M_impl']['_M_node']
+        self.base = head['_M_next']
+        self.head = head.address
+
+    def __iter__ (self):
+        return self
+
+    def next (self):
+        if self.base == self.head:
+                raise StopIteration
+        elt = self.base.cast (self.nodetype).dereference ()
+        self.base = elt['_M_next']
+        return elt['_M_data']
+
+def to_list (list_val):
+    return list (ListIterator (list_val))
+
+def skyline_to_lines (sky_value):
+    """Turns a gdb.Value into a list of line segments."""
+    sky_d = int (sky_value['sky_'])
+    buildings = to_list (sky_value['buildings_'])
+
+    def bld_to_line (bld):
+        y_intercept = float (bld['y_intercept_']) * sky_d
+        slope = float (bld['slope_']) * sky_d
+        x1 = float (bld['start_'])
+        x2 = float (bld['end_'])
+
+        if isinf (y_intercept) or isinf (x1) or isinf (x2):
+            return None
+        return (x1, y_intercept + slope * x1, x2, y_intercept + slope * x2)
+
+    ret = map (bld_to_line, buildings)
+    return [r for r in ret if r is not None]
+
+viewer = Popen(SKYLINE_VIEWER, stdin=PIPE)
+def add_skyline(lines):
+    global viewer
+    try:
+        for line in lines:
+            x1, y1, x2, y2 = line
+            viewer.stdin.write('(%f,%f) (%f,%f)\n' % (x1, y1, x2, y2))
+        viewer.stdin.write('\n')
+    except IOError:
+        # If the pipe is broken, it probably means that someone closed
+        # the viewer window. Open another one.
+        viewer = Popen(SKYLINE_VIEWER, stdin=PIPE)
+        add_skyline(lines)
+
+class ShowSkylineCommand (gdb.Command):
+    "Show a skyline graphically."
+
+    def __init__ (self, command_name):
+        super (ShowSkylineCommand, self).__init__ (command_name,
+                                                 gdb.COMMAND_DATA,
+                                                 gdb.COMPLETE_SYMBOL, False)
+
+    def to_lines (self, skyline):
+        pass
+
+    def invoke (self, arg, from_tty):
+        global plot
+
+        val = gdb.parse_and_eval (arg)
+        typ = val.type
+
+        # If they passed in a reference or pointer to a skyline,
+        # dereference it.
+        if typ.code == gdb.TYPE_CODE_PTR or typ.code == gdb.TYPE_CODE_REF:
+            val = val.referenced_value ()
+            typ = val.type
+
+        if typ.tag == 'Skyline_pair':
+            sky = val['skylines_']
+            arr = sky['array_']
+            add_skyline (self.to_lines (arr[0]))
+            add_skyline (self.to_lines (arr[1]))
+
+        elif typ.tag == 'Skyline':
+            add_skyline (self.to_lines (val))
+
+class ShowVSkylineCommand (ShowSkylineCommand):
+    "Show a vertical skyline."
+
+    def __init__ (self):
+        super (ShowVSkylineCommand, self).__init__ ("vsky")
+
+    def to_lines (self, skyline):
+        return skyline_to_lines (skyline)
+
+class ShowHSkylineCommand (ShowSkylineCommand):
+    "Show a horizontal skyline."
+
+    def __init__ (self):
+        super (ShowHSkylineCommand, self).__init__ ("hsky")
+
+    def to_lines (self, skyline):
+        lines = skyline_to_lines (skyline)
+        # Because it is a horizontal skyline, reflect around the line y=x.
+        return [(y1, x1, y2, x2) for (x1, y1, x2, y2) in lines]
+
+ShowHSkylineCommand()
+ShowVSkylineCommand()