2 line-interface.cc -- implement Line_interface
4 source file of the GNU LilyPond music typesetter
6 (c) 2004--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 #include "line-interface.hh"
11 #include "staff-symbol-referencer.hh"
13 #include "output-def.hh"
15 #include "font-interface.hh"
18 Line_interface::make_arrow (Offset begin
, Offset end
,
20 Real length
, Real width
)
22 Real angle
= (end
- begin
).arg ();
23 vector
<Offset
> points
;
25 points
.push_back (Offset (0, 0));
26 points
.push_back (Offset (-length
, width
));
27 points
.push_back (Offset (-length
, -width
));
29 for (vsize i
= 0; i
< points
.size (); i
++)
30 points
[i
] = points
[i
] * complex_exp (Offset (0, angle
)) + end
;
32 return Lookup::round_filled_polygon (points
, thick
);
36 Line_interface::make_trill_line (Grob
*me
,
40 Offset dz
= (to
-from
);
41 SCM alist_chain
= Font_interface::text_font_alist_chain (me
);
42 SCM style_alist
= scm_list_n (scm_cons (ly_symbol2scm ("font-encoding"),
43 ly_symbol2scm ("fetaMusic")),
46 Font_metric
*fm
= select_font (me
->layout (),
47 scm_cons (style_alist
,
50 Stencil elt
= fm
->find_by_name ("scripts.trill_element");
51 elt
.align_to (Y_AXIS
, CENTER
);
52 Real elt_len
= elt
.extent (X_AXIS
).length ();
55 programming_error ("can't find scripts.trill_element");
63 line
.add_at_edge (X_AXIS
, RIGHT
, elt
, 0);
64 len
= line
.extent (X_AXIS
).length ();
66 while (len
+ elt_len
< dz
.length ());
68 line
.rotate (dz
.arg (), Offset (LEFT
, CENTER
));
69 line
.translate (from
);
76 Line_interface::make_zigzag_line (Grob
*me
,
82 Real thick
= Staff_symbol_referencer::line_thickness (me
);
83 thick
*= robust_scm2double (me
->get_property ("thickness"), 1.0); // todo: staff sym referencer?
85 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
87 Real w
= robust_scm2double (me
->get_property ("zigzag-width"), 1) * staff_space
;
88 int count
= (int) ceil (dz
.length () / w
);
89 w
= dz
.length () / count
;
91 Real l
= robust_scm2double (me
->get_property ("zigzag-length"), 1) * w
;
92 Real h
= l
> w
/ 2 ? sqrt (l
* l
- w
* w
/ 4) : 0;
94 Offset rotation_factor
= complex_exp (Offset (0, dz
.arg ()));
97 points
[0] = Offset (0, -h
/ 2);
98 points
[1] = Offset (w
/ 2, h
/ 2);
99 points
[2] = Offset (w
, -h
/ 2);
100 for (int i
= 0; i
< 3; i
++)
101 points
[i
] = complex_multiply (points
[i
], rotation_factor
);
103 Stencil
squiggle (Line_interface::make_line (thick
, points
[0], points
[1]));
104 squiggle
.add_stencil (Line_interface::make_line (thick
, points
[1], points
[2]));
107 for (int i
= 0; i
< count
; i
++)
109 Stencil
moved_squiggle (squiggle
);
110 moved_squiggle
.translate (from
+ Offset (i
* w
, 0) * rotation_factor
);
111 total
.add_stencil (moved_squiggle
);
119 Line_interface::make_dashed_line (Real thick
, Offset from
, Offset to
,
120 Real dash_period
, Real dash_fraction
)
122 dash_fraction
= min (max (dash_fraction
, 0.0), 1.0);
123 Real on
= dash_fraction
* dash_period
+ thick
;
124 Real off
= max (0.0, dash_period
- on
);
126 SCM at
= scm_list_n (ly_symbol2scm ("dashed-line"),
127 scm_from_double (thick
),
128 scm_from_double (on
),
129 scm_from_double (off
),
130 scm_from_double (to
[X_AXIS
] - from
[X_AXIS
]),
131 scm_from_double (to
[Y_AXIS
] - from
[Y_AXIS
]),
132 scm_from_double (0.0),
136 box
.add_point (Offset (0, 0));
137 box
.add_point (to
- from
);
139 box
[X_AXIS
].widen (thick
/ 2);
140 box
[Y_AXIS
].widen (thick
/ 2);
142 Stencil m
= Stencil (box
, at
);
148 Line_interface::make_line (Real th
, Offset from
, Offset to
)
150 SCM at
= scm_list_n (ly_symbol2scm ("draw-line"),
151 scm_from_double (th
),
152 scm_from_double (from
[X_AXIS
]),
153 scm_from_double (from
[Y_AXIS
]),
154 scm_from_double (to
[X_AXIS
]),
155 scm_from_double (to
[Y_AXIS
]),
159 box
.add_point (from
);
162 box
[X_AXIS
].widen (th
/ 2);
163 box
[Y_AXIS
].widen (th
/ 2);
165 return Stencil (box
, at
);
169 Line_interface::arrows (Grob
*me
, Offset from
, Offset to
,
174 if (from_arrow
|| to_arrow
)
176 Real thick
= Staff_symbol_referencer::line_thickness (me
)
177 * robust_scm2double (me
->get_property ("thickness"), 1);
178 Real ss
= Staff_symbol_referencer::staff_space (me
);
180 Real len
= robust_scm2double (me
->get_property ("arrow-length"), 1.3 * ss
);
181 Real wid
= robust_scm2double (me
->get_property ("arrow-width"), 0.5 * ss
);
184 a
.add_stencil (make_arrow (from
, to
, thick
, len
, wid
));
187 a
.add_stencil (make_arrow (to
, from
, thick
, len
, wid
));
194 Line_interface::line (Grob
*me
, Offset from
, Offset to
)
196 Real thick
= Staff_symbol_referencer::line_thickness (me
)
197 * robust_scm2double (me
->get_property ("thickness"), 1);
199 SCM type
= me
->get_property ("style");
200 if (type
== ly_symbol2scm ("zigzag"))
202 return make_zigzag_line (me
, from
, to
);
204 else if (type
== ly_symbol2scm ("trill"))
205 return make_trill_line (me
, from
, to
);
209 if (type
== ly_symbol2scm ("dashed-line") || type
== ly_symbol2scm ("dotted-line"))
213 = type
== ly_symbol2scm ("dotted-line")
215 : robust_scm2double (me
->get_property ("dash-fraction"), 0.4);
217 fraction
= min (max (fraction
, 0.0), 1.0);
218 Real period
= Staff_symbol_referencer::staff_space (me
)
219 * robust_scm2double (me
->get_property ("dash-period"), 1.0);
224 Real len
= (to
-from
).length ();
226 int n
= (int) rint ((len
- period
* fraction
) / period
);
231 TODO: figure out something intelligent for really short
234 period
= ((to
-from
).length () - period
* fraction
) / n
;
236 stencil
= make_dashed_line (thick
, from
, to
, period
, fraction
);
239 stencil
= make_line (thick
, from
, to
);
244 ADD_INTERFACE (Line_interface
,
245 "Generic line objects. Any object using lines supports this."
246 " The property @code{style} can be @code{line},"
247 " @code{dashed-line}, @code{trill}, @code{dotted-line} or"
250 "For @code{dashed-line}, the length of the dashes is tuned"
251 " with @code{dash-fraction}. If the latter is set to@tie{}0, a"
252 " dotted line is produced. If @code{dash-period} is negative,"
253 " the line is made transparent.",