2 dot-column.cc -- implement Dot_column
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 #include "dot-column.hh"
17 #include "rhythmic-head.hh"
18 #include "staff-symbol-referencer.hh"
19 #include "directional-element-interface.hh"
20 #include "side-position-interface.hh"
21 #include "axis-group-interface.hh"
23 #include "pointer-group-interface.hh"
26 TODO: let Dot_column communicate with stem via Note_column.
29 MAKE_SCHEME_CALLBACK (Dot_column
, side_position
, 1);
31 Dot_column::side_position (SCM smob
)
33 Grob
*me
= unsmob_grob (smob
);
34 extract_grob_set (me
, "dots", dots
);
36 for (vsize i
= 0; i
< dots
.size (); i
++)
38 Grob
*head
= dots
[i
]->get_parent (Y_AXIS
);
39 Grob
*stem
= head
? unsmob_grob (head
->get_object ("stem")) : 0;
41 && !Stem::get_beam (stem
)
42 && Stem::duration_log (stem
) > 2
43 && !Stem::is_invisible (stem
))
46 trigger stem end & direction calculation.
48 This will add the stem to the support if a flag collision happens.
50 stem
->get_property ("stem-end-position");
54 return Side_position_interface::x_aligned_side (smob
, SCM_EOL
);
72 typedef map
<int, Dot_position
> Dot_configuration
;
78 dot_config_badness (Dot_configuration
const &cfg
)
81 for (Dot_configuration::const_iterator
i (cfg
.begin ());
85 int demerit
= sqr (p
- i
->second
.pos_
) * 2;
87 int dot_move_dir
= sign (p
- i
->second
.pos_
);
88 if (i
->second
.extremal_head_
)
91 && dot_move_dir
!= i
->second
.dir_
)
93 else if (dot_move_dir
!= UP
)
96 else if (dot_move_dir
!= UP
)
106 print_dot_configuration (Dot_configuration
const &cfg
)
108 printf ("dotconf { ");
109 for (Dot_configuration::const_iterator
i (cfg
.begin ());
110 i
!= cfg
.end (); i
++)
111 printf ("%d, ", i
->first
);
116 Shift K and following (preceding) entries up (down) as necessary to
117 prevent staffline collisions if D is up (down).
119 If K is in CFG, then do nothing.
123 shift_one (Dot_configuration
const &cfg
,
126 Dot_configuration new_cfg
;
131 for (Dot_configuration::const_iterator
i (cfg
.begin ());
132 i
!= cfg
.end (); i
++)
137 if (Staff_symbol_referencer::on_line (i
->second
.dot_
, p
))
144 new_cfg
[p
] = i
->second
;
148 if (new_cfg
.find (p
) == new_cfg
.end ())
150 new_cfg
[p
+ offset
] = i
->second
;
156 Dot_configuration::const_iterator
i (cfg
.end ());
164 if (Staff_symbol_referencer::on_line (i
->second
.dot_
, p
))
171 new_cfg
[p
] = i
->second
;
175 if (new_cfg
.find (p
) == new_cfg
.end ())
178 new_cfg
[p
+ offset
] = i
->second
;
181 while (i
!= cfg
.begin ());
188 Remove the collision in CFG either by shifting up or down, whichever
192 remove_collision (Dot_configuration
&cfg
, int p
)
194 bool collide
= cfg
.find (p
) != cfg
.end ();
198 Dot_configuration cfg_up
= shift_one (cfg
, p
, UP
);
199 Dot_configuration cfg_down
= shift_one (cfg
, p
, DOWN
);
201 int b_up
= dot_config_badness (cfg_up
);
202 int b_down
= dot_config_badness (cfg_down
);
204 cfg
= (b_up
< b_down
) ? cfg_up
: cfg_down
;
208 MAKE_SCHEME_CALLBACK(Dot_column
, calc_positioning_done
, 1);
210 Dot_column::calc_positioning_done (SCM smob
)
212 Grob
*me
= unsmob_grob (smob
);
214 = extract_grob_array (me
, "dots");
217 Trigger note collision resolution first, since that may kill off
221 for (vsize i
= dots
.size (); i
--;)
223 Grob
*n
= dots
[i
]->get_parent (Y_AXIS
);
225 c
= n
->common_refpoint (c
, X_AXIS
);
229 for (vsize i
= dots
.size (); i
--;)
231 Grob
*n
= dots
[i
]->get_parent (Y_AXIS
);
232 n
->relative_coordinate (c
, X_AXIS
);
236 vector_sort (dots
, position_less
);
237 for (vsize i
= dots
.size (); i
--;)
238 if (!dots
[i
]->is_live ())
239 dots
.erase (dots
.begin () + i
);
241 Dot_configuration cfg
;
242 for (vsize i
= 0;i
< dots
.size (); i
++)
247 Grob
*note
= dots
[i
]->get_parent (Y_AXIS
);
250 Grob
*stem
= unsmob_grob (note
->get_object ("stem"));
252 dp
.extremal_head_
= Stem::first_head (stem
) == note
;
255 int p
= Staff_symbol_referencer::get_rounded_position (dp
.dot_
);
258 if (dp
.extremal_head_
)
259 dp
.dir_
= to_dir (dp
.dot_
->get_property ("direction"));
261 remove_collision (cfg
, p
);
263 if (Staff_symbol_referencer::on_line (dp
.dot_
, p
))
264 remove_collision (cfg
, p
);
267 for (Dot_configuration::const_iterator
i (cfg
.begin ());
268 i
!= cfg
.end (); i
++)
273 Staff_symbol_referencer::set_position (i
->second
.dot_
, i
->first
);
279 Dot_column::add_head (Grob
*me
, Grob
*rh
)
281 Grob
*d
= unsmob_grob (rh
->get_object ("dot"));
284 Side_position_interface::add_support (me
, rh
);
286 Pointer_group_interface::add_grob (me
, ly_symbol2scm ("dots"), d
);
287 d
->set_property ("Y-offset", Grob::x_parent_positioning_proc
);
288 Axis_group_interface::add_element (me
, d
);
292 ADD_INTERFACE (Dot_column
,
293 "dot-column-interface",
295 "Groups dot objects so they form a column, and position dots so they do not "
296 "clash with staff lines ",