2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2010 Han-Wen Nienhuys <hanwen@xs4all.nl>
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.
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.
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/>.
24 #include "directional-element-interface.hh"
25 #include "font-interface.hh"
26 #include "grob-array.hh"
28 #include "note-head.hh"
29 #include "output-def.hh"
30 #include "paper-column.hh"
31 #include "pointer-group-interface.hh"
32 #include "rhythmic-head.hh"
34 #include "staff-symbol-referencer.hh"
36 #include "text-interface.hh"
37 #include "tie-column.hh"
38 #include "tie-configuration.hh"
39 #include "tie-formatting-problem.hh"
41 #include "semi-tie-column.hh"
44 Tie::less (Grob
*const &s1
, Grob
*const &s2
)
46 return Tie::get_position (s1
) < Tie::get_position (s2
);
50 Tie::set_head (Grob
*me
, Direction d
, Grob
*h
)
52 dynamic_cast<Spanner
*> (me
)->set_bound (d
, h
);
56 Tie::head (Grob
*me
, Direction d
)
58 if (is_direction (me
->get_property ("head-direction")))
60 Direction hd
= to_dir (me
->get_property ("head-direction"));
63 ? unsmob_grob (me
->get_object ("note-head"))
67 Item
*it
= dynamic_cast<Spanner
*> (me
)->get_bound (d
);
68 if (Note_head::has_interface (it
))
75 Tie::get_column_rank (Grob
*me
, Direction d
)
77 Spanner
*span
= dynamic_cast<Spanner
*> (me
);
78 Grob
*h
= head (me
, d
);
80 h
= span
->get_bound (d
);
82 Grob
*col
= dynamic_cast<Item
*> (h
)->get_column ();
83 return Paper_column::get_rank (col
);
87 Tie::get_position (Grob
*me
)
92 Grob
*h
= head (me
, d
);
94 return (int) rint (Staff_symbol_referencer::get_position (h
));
96 while (flip (&d
) != LEFT
);
99 TODO: this is theoretically possible for ties across more than 2
100 systems.. We should look at the first broken copy.
103 programming_error ("Tie without heads. Suicide");
109 Default: Put the tie oppositie of the stem [Wanske p231]
111 In case of chords: Tie_column takes over
113 The direction of the Tie is more complicated (See [Ross] p136 and
116 (what about linebreaks? )
119 Tie::get_default_dir (Grob
*me
)
121 Drul_array
<Grob
*> stems
;
125 Grob
*one_head
= head (me
, d
);
126 if (!one_head
&& dynamic_cast<Spanner
*> (me
))
127 one_head
= Tie::head (dynamic_cast<Spanner
*> (me
)->broken_neighbor (d
), d
);
129 Grob
*stem
= one_head
? Rhythmic_head::get_stem (one_head
) : 0;
131 stem
= Stem::is_invisible (stem
) ? 0 : stem
;
135 while (flip (&d
) != LEFT
);
137 if (stems
[LEFT
] && stems
[RIGHT
])
139 if (get_grob_direction (stems
[LEFT
]) == UP
140 && get_grob_direction (stems
[RIGHT
]) == UP
)
143 else if (stems
[LEFT
] || stems
[RIGHT
])
145 Grob
*s
= stems
[LEFT
] ? stems
[LEFT
] : stems
[RIGHT
];
146 return -get_grob_direction (s
);
148 else if (int p
= get_position (me
))
149 return Direction (sign (p
));
151 return to_dir (me
->get_property ("neutral-direction"));
154 MAKE_SCHEME_CALLBACK (Tie
, calc_direction
, 1);
156 Tie::calc_direction (SCM smob
)
158 Grob
*me
= unsmob_grob (smob
);
159 Grob
*yparent
= me
->get_parent (Y_AXIS
);
160 if ((Tie_column::has_interface (yparent
)
161 || Semi_tie_column::has_interface (yparent
))
162 && unsmob_grob_array (yparent
->get_object ("ties"))
163 // && unsmob_grob_array (yparent->get_object ("ties"))->size () > 1
166 /* trigger positioning. */
167 (void) yparent
->get_property ("positioning-done");
169 return me
->get_property_data ("direction");
172 return scm_from_int (Tie::get_default_dir (me
));
176 Tie::get_default_control_points (Grob
*me_grob
)
178 Spanner
*me
= dynamic_cast<Spanner
*> (me_grob
);
180 common
= me
->get_bound (LEFT
)->common_refpoint (common
, X_AXIS
);
181 common
= me
->get_bound (RIGHT
)->common_refpoint (common
, X_AXIS
);
183 Tie_formatting_problem problem
;
184 problem
.from_tie (me
);
186 Tie_specification spec
= problem
.get_tie_specification (0);
190 Ties_configuration conf
191 = problem
.generate_optimal_configuration ();
193 return get_control_points (me
, problem
.common_x_refpoint (),
194 conf
[0], problem
.details_
);
198 Tie::get_control_points (Grob
*me
,
200 Tie_configuration
const &conf
,
201 Tie_details
const &details
)
203 Bezier b
= conf
.get_transformed_bezier (details
);
204 b
.translate (Offset (- me
->relative_coordinate (common
, X_AXIS
), 0));
206 SCM controls
= SCM_EOL
;
207 for (int i
= 4; i
--;)
209 if (!b
.control_
[i
].is_sane ())
210 programming_error ("Insane offset");
211 controls
= scm_cons (ly_offset2scm (b
.control_
[i
]), controls
);
216 MAKE_SCHEME_CALLBACK (Tie
, calc_control_points
, 1);
218 Tie::calc_control_points (SCM smob
)
220 Grob
*me
= unsmob_grob (smob
);
222 Grob
*yparent
= me
->get_parent (Y_AXIS
);
223 if ((Tie_column::has_interface (yparent
)
224 || Semi_tie_column::has_interface (yparent
))
225 && unsmob_grob_array (yparent
->get_object ("ties")))
227 extract_grob_set (yparent
, "ties", ties
);
228 if (me
->original () && ties
.size () == 1
229 && !to_dir (me
->get_property_data ("direction")))
231 assert (ties
[0] == me
);
232 set_grob_direction (me
, Tie::get_default_dir (me
));
234 /* trigger positioning. */
235 (void) yparent
->get_property ("positioning-done");
238 SCM cp
= me
->get_property_data ("control-points");
239 if (!scm_is_pair (cp
))
240 cp
= get_default_control_points (me
);
246 TODO: merge with Slur::print.
248 MAKE_SCHEME_CALLBACK (Tie
, print
, 1);
250 Tie::print (SCM smob
)
252 Grob
*me
= unsmob_grob (smob
);
254 SCM cp
= me
->get_property ("control-points");
256 Real staff_thick
= Staff_symbol_referencer::line_thickness (me
);
257 Real base_thick
= staff_thick
* robust_scm2double (me
->get_property ("thickness"), 1);
258 Real line_thick
= staff_thick
* robust_scm2double (me
->get_property ("line-thickness"), 1);
262 for (SCM s
= cp
; scm_is_pair (s
); s
= scm_cdr (s
))
264 b
.control_
[i
] = ly_scm2offset (scm_car (s
));
270 SCM dash_definition
= me
->get_property ("dash-definition");
272 get_grob_direction (me
) * base_thick
,
276 #if DEBUG_TIE_SCORING
277 SCM annotation
= me
->get_property ("annotation");
278 if (!scm_is_string (annotation
))
280 SCM debug
= me
->layout ()->lookup_variable (ly_symbol2scm ("debug-tie-scoring"));
281 if (to_boolean (debug
))
282 annotation
= me
->get_property ("quant-score");
284 if (scm_is_string (annotation
))
287 SCM properties
= Font_interface::text_font_alist_chain (me
);
289 Stencil tm
= *unsmob_stencil (Text_interface::interpret_markup
290 (me
->layout ()->self_scm (), properties
,
292 tm
.translate (Offset (b
.control_
[3][X_AXIS
] + 0.5,
293 b
.control_
[0][Y_AXIS
] * 2));
294 tm
= tm
.in_color (1, 0, 0);
297 It would be nice if we could put this in a different layer,
298 but alas, this must be done with a Tie override.
304 return a
.smobbed_copy ();
308 "A horizontal curve connecting two noteheads.",
312 "avoid-slur " // UGH.