]> git.donarmstrong.com Git - lilypond.git/blob - lily/line-interface.cc
Add obsoletion warning for minimum-Y-extent.
[lilypond.git] / lily / line-interface.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2004--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "line-interface.hh"
21
22 #include "staff-symbol-referencer.hh"
23 #include "lookup.hh"
24 #include "output-def.hh"
25 #include "grob.hh"
26 #include "font-interface.hh"
27
28 Stencil
29 Line_interface::make_arrow (Offset begin, Offset end,
30                             Real thick,
31                             Real length, Real width)
32 {
33   Real angle = (end - begin).arg ();
34   vector<Offset> points;
35
36   points.push_back (Offset (0, 0));
37   points.push_back (Offset (-length, width));
38   points.push_back (Offset (-length, -width));
39
40   for (vsize i = 0; i < points.size (); i++)
41     points[i] = points[i] * complex_exp (Offset (0, angle)) + end;
42
43   return Lookup::round_filled_polygon (points, thick);
44 }
45
46 Stencil
47 Line_interface::make_trill_line (Grob *me,
48                                  Offset from,
49                                  Offset to)
50 {
51   Offset dz = (to-from);
52   SCM alist_chain = Font_interface::text_font_alist_chain (me);
53   SCM style_alist = scm_list_n (scm_cons (ly_symbol2scm ("font-encoding"),
54                                           ly_symbol2scm ("fetaMusic")),
55                                 SCM_UNDEFINED);
56
57   Font_metric *fm = select_font (me->layout (),
58                                  scm_cons (style_alist,
59                                            alist_chain));
60
61   Stencil elt = fm->find_by_name ("scripts.trill_element");
62   elt.align_to (Y_AXIS, CENTER);
63   Real elt_len = elt.extent (X_AXIS).length ();
64   if (elt_len <= 0.0)
65     {
66       programming_error ("can't find scripts.trill_element");
67       return Stencil ();
68     }
69       
70   Stencil line;
71   Real len = 0.0;
72   do
73     {
74       line.add_at_edge (X_AXIS, RIGHT, elt, 0);
75       len = line.extent (X_AXIS).length ();
76     }
77   while (len + elt_len < dz.length ());
78
79   line.rotate (dz.arg (), Offset (LEFT, CENTER));
80   line.translate (from);
81
82   return line; 
83 }
84
85
86 Stencil
87 Line_interface::make_zigzag_line (Grob *me,
88                                   Offset from,
89                                   Offset to)
90 {
91   Offset dz = to -from;
92
93   Real thick = Staff_symbol_referencer::line_thickness (me);
94   thick *= robust_scm2double (me->get_property ("thickness"), 1.0); // todo: staff sym referencer? 
95
96   Real staff_space = Staff_symbol_referencer::staff_space (me);
97
98   Real w = robust_scm2double (me->get_property ("zigzag-width"), 1) * staff_space;
99   int count = (int) ceil (dz.length () / w);
100   w = dz.length () / count;
101
102   Real l = robust_scm2double (me->get_property ("zigzag-length"), 1) * w;
103   Real h = l > w / 2 ? sqrt (l * l - w * w / 4) : 0;
104
105   Offset rotation_factor = complex_exp (Offset (0, dz.arg ()));
106
107   Offset points[3];
108   points[0] = Offset (0, -h / 2);
109   points[1] = Offset (w / 2, h / 2);
110   points[2] = Offset (w, -h / 2);
111   for (int i = 0; i < 3; i++)
112     points[i] = complex_multiply (points[i], rotation_factor);
113
114   Stencil squiggle (Line_interface::make_line (thick, points[0], points[1]));
115   squiggle.add_stencil (Line_interface::make_line (thick, points[1], points[2]));
116
117   Stencil total;
118   for (int i = 0; i < count; i++)
119     {
120       Stencil moved_squiggle (squiggle);
121       moved_squiggle.translate (from + Offset (i * w, 0) * rotation_factor);
122       total.add_stencil (moved_squiggle);
123     }
124
125   return total;
126 }
127
128
129 Stencil
130 Line_interface::make_dashed_line (Real thick, Offset from, Offset to,
131                                   Real dash_period, Real dash_fraction)
132 {
133   dash_fraction = min (max (dash_fraction, 0.0), 1.0);
134   Real on = dash_fraction * dash_period + thick;
135   Real off = max (0.0, dash_period - on);
136
137   SCM at = scm_list_n (ly_symbol2scm ("dashed-line"),
138                        scm_from_double (thick),
139                        scm_from_double (on),
140                        scm_from_double (off),
141                        scm_from_double (to[X_AXIS] - from[X_AXIS]),
142                        scm_from_double (to[Y_AXIS] - from[Y_AXIS]),
143                        scm_from_double (0.0),
144                        SCM_UNDEFINED);
145
146   Box box;
147   box.add_point (Offset (0, 0));
148   box.add_point (to - from);
149
150   box[X_AXIS].widen (thick / 2);
151   box[Y_AXIS].widen (thick / 2);
152
153   Stencil m = Stencil (box, at);
154   m.translate (from);
155   return m;
156 }
157
158 Stencil
159 Line_interface::make_line (Real th, Offset from, Offset to)
160 {
161   SCM at = scm_list_n (ly_symbol2scm ("draw-line"),
162                        scm_from_double (th),
163                        scm_from_double (from[X_AXIS]),
164                        scm_from_double (from[Y_AXIS]),
165                        scm_from_double (to[X_AXIS]),
166                        scm_from_double (to[Y_AXIS]),
167                        SCM_UNDEFINED);
168
169   Box box;
170   box.add_point (from);
171   box.add_point (to);
172
173   box[X_AXIS].widen (th / 2);
174   box[Y_AXIS].widen (th / 2);
175
176   return Stencil (box, at);
177 }
178
179 Stencil
180 Line_interface::arrows (Grob *me, Offset from, Offset to,
181                         bool from_arrow,
182                         bool to_arrow)
183 {
184   Stencil a;
185   if (from_arrow || to_arrow)
186     {
187       Real thick = Staff_symbol_referencer::line_thickness (me)
188         * robust_scm2double (me->get_property ("thickness"), 1);
189       Real ss = Staff_symbol_referencer::staff_space (me);
190
191       Real len = robust_scm2double (me->get_property ("arrow-length"), 1.3 * ss);
192       Real wid = robust_scm2double (me->get_property ("arrow-width"), 0.5 * ss);
193
194       if (to_arrow)
195         a.add_stencil (make_arrow (from, to, thick, len, wid));
196
197       if (from_arrow)
198         a.add_stencil (make_arrow (to, from, thick, len, wid));
199     }
200
201   return a;
202 }
203
204 Stencil
205 Line_interface::line (Grob *me, Offset from, Offset to)
206 {
207   Real thick = Staff_symbol_referencer::line_thickness (me)
208     * robust_scm2double (me->get_property ("thickness"), 1);
209
210   SCM type = me->get_property ("style");
211   if (type == ly_symbol2scm ("zigzag"))
212     {
213       return make_zigzag_line (me, from, to);
214     }
215   else if (type == ly_symbol2scm ("trill"))
216     return make_trill_line (me, from, to);
217   
218   Stencil stencil;
219
220   if (type == ly_symbol2scm ("dashed-line") || type == ly_symbol2scm ("dotted-line"))
221     {
222
223       Real fraction
224         = type == ly_symbol2scm ("dotted-line")
225         ? 0.0
226         : robust_scm2double (me->get_property ("dash-fraction"), 0.4);
227
228       fraction = min (max (fraction, 0.0), 1.0);
229       Real period = Staff_symbol_referencer::staff_space (me)
230         * robust_scm2double (me->get_property ("dash-period"), 1.0);
231
232       if (period <= 0)
233         return Stencil ();
234
235       Real len = (to-from).length ();
236       
237       int n = (int) rint ((len - period * fraction) / period);
238       n = max (0, n);
239       if (n > 0)
240         {
241           /*
242             TODO: figure out something intelligent for really short
243             sections.
244            */
245           period = ((to-from).length () - period * fraction) / n;
246         }
247       stencil = make_dashed_line (thick, from, to, period, fraction);
248     }
249   else
250     stencil = make_line (thick, from, to);
251
252   return stencil;
253 }
254
255 ADD_INTERFACE (Line_interface,
256                "Generic line objects.  Any object using lines supports this."
257                "  The property @code{style} can be @code{line},"
258                " @code{dashed-line}, @code{trill}, @code{dotted-line} or"
259                " @code{zigzag}.\n"
260                "\n"
261                "For @code{dashed-line}, the length of the dashes is tuned"
262                " with @code{dash-fraction}.  If the latter is set to@tie{}0, a"
263                " dotted line is produced.  If @code{dash-period} is negative,"
264                " the line is made transparent.",
265
266                /* properties */
267                "dash-period "
268                "dash-fraction "
269                "thickness "
270                "style "
271                "zigzag-length "
272                "zigzag-width "
273                "arrow-length "
274                "arrow-width ")
275