]> git.donarmstrong.com Git - lilypond.git/blob - lily/line-interface.cc
Issue 4550 (1/2) Avoid "using namespace std;" in included files
[lilypond.git] / lily / line-interface.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2004--2015 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 "font-interface.hh"
23 #include "grob.hh"
24 #include "lookup.hh"
25 #include "output-def.hh"
26 #include "staff-symbol-referencer.hh"
27
28 using std::vector;
29
30 Stencil
31 Line_interface::make_arrow (Offset begin, Offset end,
32                             Real thick,
33                             Real length, Real width)
34 {
35   Offset dir = (end - begin).direction ();
36   vector<Offset> points;
37
38   points.push_back (Offset (0, 0));
39   points.push_back (Offset (-length, width));
40   points.push_back (Offset (-length, -width));
41
42   for (vsize i = 0; i < points.size (); i++)
43     points[i] = points[i] * dir + end;
44
45   return Lookup::round_filled_polygon (points, thick);
46 }
47
48 Stencil
49 Line_interface::make_trill_line (Grob *me,
50                                  Offset from,
51                                  Offset to)
52 {
53   Offset dz = (to - from);
54
55   Font_metric *fm = Font_interface::get_default_font (me);
56
57   Stencil elt = fm->find_by_name ("scripts.trill_element");
58   elt.align_to (Y_AXIS, CENTER);
59   Real elt_len = elt.extent (X_AXIS).length ();
60   if (elt_len <= 0.0)
61     {
62       programming_error ("can't find scripts.trill_element");
63       return Stencil ();
64     }
65
66   Stencil line;
67   Real len = 0.0;
68   do
69     {
70       line.add_at_edge (X_AXIS, RIGHT, elt, 0);
71       len = line.extent (X_AXIS).length ();
72     }
73   while (len + elt_len < dz.length ());
74
75   line.rotate (dz.arg (), Offset (LEFT, CENTER));
76   line.translate (from);
77
78   return line;
79 }
80
81 Stencil
82 Line_interface::make_zigzag_line (Grob *me,
83                                   Offset from,
84                                   Offset to)
85 {
86   Offset dz = to - from;
87
88   Real thick = Staff_symbol_referencer::line_thickness (me);
89   thick *= robust_scm2double (me->get_property ("thickness"), 1.0); // todo: staff sym referencer?
90
91   Real staff_space = Staff_symbol_referencer::staff_space (me);
92
93   Real w = robust_scm2double (me->get_property ("zigzag-width"), 1) * staff_space;
94   int count = (int) ceil (dz.length () / w);
95   w = dz.length () / count;
96
97   Real l = robust_scm2double (me->get_property ("zigzag-length"), 1) * w;
98   Real h = l > w / 2 ? sqrt (l * l - w * w / 4) : 0;
99
100   Offset rotation_factor = dz.direction ();
101
102   Offset points[3];
103   points[0] = Offset (0, -h / 2);
104   points[1] = Offset (w / 2, h / 2);
105   points[2] = Offset (w, -h / 2);
106   for (int i = 0; i < 3; i++)
107     points[i] = complex_multiply (points[i], rotation_factor);
108
109   Stencil squiggle (Line_interface::make_line (thick, points[0], points[1]));
110   squiggle.add_stencil (Line_interface::make_line (thick, points[1], points[2]));
111
112   Stencil total;
113   for (int i = 0; i < count; i++)
114     {
115       Stencil moved_squiggle (squiggle);
116       moved_squiggle.translate (from + Offset (i * w, 0) * rotation_factor);
117       total.add_stencil (moved_squiggle);
118     }
119
120   return total;
121 }
122
123 Stencil
124 Line_interface::make_dashed_line (Real thick, Offset from, Offset to,
125                                   Real dash_period, Real dash_fraction)
126 {
127   dash_fraction = min (max (dash_fraction, 0.0), 1.0);
128   Real on = dash_fraction * dash_period + thick;
129   Real off = max (0.0, dash_period - on);
130
131   SCM at = scm_list_n (ly_symbol2scm ("dashed-line"),
132                        scm_from_double (thick),
133                        scm_from_double (on),
134                        scm_from_double (off),
135                        scm_from_double (to[X_AXIS] - from[X_AXIS]),
136                        scm_from_double (to[Y_AXIS] - from[Y_AXIS]),
137                        scm_from_double (0.0),
138                        SCM_UNDEFINED);
139
140   Box box;
141   box.add_point (Offset (0, 0));
142   box.add_point (to - from);
143
144   box[X_AXIS].widen (thick / 2);
145   box[Y_AXIS].widen (thick / 2);
146
147   Stencil m = Stencil (box, at);
148   m.translate (from);
149   return m;
150 }
151
152 Stencil
153 Line_interface::make_line (Real th, Offset from, Offset to)
154 {
155   SCM at = scm_list_n (ly_symbol2scm ("draw-line"),
156                        scm_from_double (th),
157                        scm_from_double (from[X_AXIS]),
158                        scm_from_double (from[Y_AXIS]),
159                        scm_from_double (to[X_AXIS]),
160                        scm_from_double (to[Y_AXIS]),
161                        SCM_UNDEFINED);
162
163   Box box;
164   box.add_point (from);
165   box.add_point (to);
166
167   box[X_AXIS].widen (th / 2);
168   box[Y_AXIS].widen (th / 2);
169
170   return Stencil (box, at);
171 }
172
173 Stencil
174 Line_interface::arrows (Grob *me, Offset from, Offset to,
175                         bool from_arrow,
176                         bool to_arrow)
177 {
178   Stencil a;
179   if (from_arrow || to_arrow)
180     {
181       Real thick = Staff_symbol_referencer::line_thickness (me)
182                    * robust_scm2double (me->get_property ("thickness"), 1);
183       Real ss = Staff_symbol_referencer::staff_space (me);
184
185       Real len = robust_scm2double (me->get_property ("arrow-length"), 1.3 * ss);
186       Real wid = robust_scm2double (me->get_property ("arrow-width"), 0.5 * ss);
187
188       if (to_arrow)
189         a.add_stencil (make_arrow (from, to, thick, len, wid));
190
191       if (from_arrow)
192         a.add_stencil (make_arrow (to, from, thick, len, wid));
193     }
194
195   return a;
196 }
197
198 Stencil
199 Line_interface::line (Grob *me, Offset from, Offset to)
200 {
201   Real thick = Staff_symbol_referencer::line_thickness (me)
202                * robust_scm2double (me->get_property ("thickness"), 1);
203
204   SCM type = me->get_property ("style");
205   if (scm_is_eq (type, ly_symbol2scm ("zigzag")))
206     return make_zigzag_line (me, from, to);
207   else if (scm_is_eq (type, ly_symbol2scm ("trill")))
208     return make_trill_line (me, from, to);
209   else if (scm_is_eq (type, ly_symbol2scm ("none")))
210     return Stencil ();
211
212   Stencil stencil;
213
214   if (scm_is_eq (type, ly_symbol2scm ("dashed-line"))
215       || scm_is_eq (type, ly_symbol2scm ("dotted-line")))
216     {
217
218       Real fraction
219         = scm_is_eq (type, ly_symbol2scm ("dotted-line"))
220           ? 0.0
221           : robust_scm2double (me->get_property ("dash-fraction"), 0.4);
222
223       fraction = min (max (fraction, 0.0), 1.0);
224       Real period = Staff_symbol_referencer::staff_space (me)
225                     * robust_scm2double (me->get_property ("dash-period"), 1.0);
226
227       if (period <= 0)
228         return Stencil ();
229
230       Real len = (to - from).length ();
231
232       int n = (int) rint ((len - period * fraction) / period);
233       n = max (0, n);
234       if (n > 0)
235         {
236           /*
237             TODO: figure out something intelligent for really short
238             sections.
239            */
240           period = ((to - from).length () - period * fraction) / n;
241         }
242       stencil = make_dashed_line (thick, from, to, period, fraction);
243     }
244   else
245     stencil = make_line (thick, from, to);
246
247   return stencil;
248 }
249
250 ADD_INTERFACE (Line_interface,
251                "Generic line objects.  Any object using lines supports this."
252                "  The property @code{style} can be @code{line},"
253                " @code{dashed-line}, @code{trill}, @code{dotted-line},"
254                " @code{zigzag} or @code{none} (a transparent line).\n"
255                "\n"
256                "For @code{dashed-line}, the length of the dashes is tuned"
257                " with @code{dash-fraction}.  If the latter is set to@tie{}0, a"
258                " dotted line is produced.",
259
260                /* properties */
261                "arrow-length "
262                "arrow-width "
263                "dash-fraction "
264                "dash-period "
265                "style "
266                "thickness "
267                "zigzag-length "
268                "zigzag-width "
269               );