]> git.donarmstrong.com Git - lilypond.git/blob - scripts/auxiliar/show_skyline_command.py
Add '-dcrop' option to ps and svg backends
[lilypond.git] / scripts / auxiliar / show_skyline_command.py
1 # This file is part of LilyPond, the GNU music typesetter.
2 #
3 # Copyright (C) 2012 Joe Neeman <joeneeman@gmail.com>
4 #
5 # LilyPond is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # LilyPond is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
17
18 # A gdb plugin debugging skylines.  To use the plugin, make sure that
19 # skyline_viewer.py is in your PATH, then add
20 # source /path/to/show_skyline_command.py
21 # to your .gdbinit file.  The 'vsky' and 'hsky' commands for
22 # drawing skylines will then be available in gdb.
23
24 import gdb
25 from subprocess import Popen, PIPE
26 from math import isinf
27
28 SKYLINE_VIEWER = 'skyline_viewer.py'
29
30 # Function taken from GCC
31 def find_type(orig, name):
32     typ = orig.strip_typedefs()
33     while True:
34         search = str(typ) + '::' + name
35         try:
36             return gdb.lookup_type(search)
37         except RuntimeError:
38             pass
39         # The type was not found, so try the superclass.    We only need
40         # to check the first superclass, so we don't bother with
41         # anything fancier here.
42         field = typ.fields()[0]
43         if not field.is_base_class:
44             raise ValueError, "Cannot find type %s::%s" % (str(orig), name)
45         typ = field.type
46
47 # Class adapted from GCC
48 class ListIterator:
49     def __init__ (self, val):
50         self.val = val
51         self.nodetype = find_type (val.type, '_Node')
52         self.nodetype = self.nodetype.strip_typedefs ().pointer ()
53
54         head = val['_M_impl']['_M_node']
55         self.base = head['_M_next']
56         self.head = head.address
57
58     def __iter__ (self):
59         return self
60
61     def next (self):
62         if self.base == self.head:
63                 raise StopIteration
64         elt = self.base.cast (self.nodetype).dereference ()
65         self.base = elt['_M_next']
66         return elt['_M_data']
67
68 def to_list (list_val):
69     return list (ListIterator (list_val))
70
71 def skyline_to_lines (sky_value):
72     """Turns a gdb.Value into a list of line segments."""
73     sky_d = int (sky_value['sky_'])
74     buildings = to_list (sky_value['buildings_'])
75
76     def bld_to_line (bld):
77         y_intercept = float (bld['y_intercept_']) * sky_d
78         slope = float (bld['slope_']) * sky_d
79         x1 = float (bld['start_'])
80         x2 = float (bld['end_'])
81
82         if isinf (y_intercept) or isinf (x1) or isinf (x2):
83             return None
84         return (x1, y_intercept + slope * x1, x2, y_intercept + slope * x2)
85
86     ret = map (bld_to_line, buildings)
87     return [r for r in ret if r is not None]
88
89 viewer = Popen(SKYLINE_VIEWER, stdin=PIPE)
90 def add_skyline(lines):
91     global viewer
92     try:
93         for line in lines:
94             x1, y1, x2, y2 = line
95             viewer.stdin.write('(%f,%f) (%f,%f)\n' % (x1, y1, x2, y2))
96         viewer.stdin.write('\n')
97     except IOError:
98         # If the pipe is broken, it probably means that someone closed
99         # the viewer window. Open another one.
100         viewer = Popen(SKYLINE_VIEWER, stdin=PIPE)
101         add_skyline(lines)
102
103 class ShowSkylineCommand (gdb.Command):
104     "Show a skyline graphically."
105
106     def __init__ (self, command_name):
107         super (ShowSkylineCommand, self).__init__ (command_name,
108                                                  gdb.COMMAND_DATA,
109                                                  gdb.COMPLETE_SYMBOL, False)
110
111     def to_lines (self, skyline):
112         pass
113
114     def invoke (self, arg, from_tty):
115         global plot
116
117         val = gdb.parse_and_eval (arg)
118         typ = val.type
119
120         # If they passed in a reference or pointer to a skyline,
121         # dereference it.
122         if typ.code == gdb.TYPE_CODE_PTR or typ.code == gdb.TYPE_CODE_REF:
123             val = val.referenced_value ()
124             typ = val.type
125
126         if typ.tag == 'Skyline_pair':
127             sky = val['skylines_']
128             arr = sky['array_']
129             add_skyline (self.to_lines (arr[0]))
130             add_skyline (self.to_lines (arr[1]))
131
132         elif typ.tag == 'Skyline':
133             add_skyline (self.to_lines (val))
134
135 class ShowVSkylineCommand (ShowSkylineCommand):
136     "Show a vertical skyline."
137
138     def __init__ (self):
139         super (ShowVSkylineCommand, self).__init__ ("vsky")
140
141     def to_lines (self, skyline):
142         return skyline_to_lines (skyline)
143
144 class ShowHSkylineCommand (ShowSkylineCommand):
145     "Show a horizontal skyline."
146
147     def __init__ (self):
148         super (ShowHSkylineCommand, self).__init__ ("hsky")
149
150     def to_lines (self, skyline):
151         lines = skyline_to_lines (skyline)
152         # Because it is a horizontal skyline, reflect around the line y=x.
153         return [(y1, x1, y2, x2) for (x1, y1, x2, y2) in lines]
154
155 ShowHSkylineCommand()
156 ShowVSkylineCommand()