2 collision.cc -- implement Collision
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "collision.hh"
10 #include "note-column.hh"
11 #include "rhythmic-head.hh"
12 #include "paper-def.hh"
13 #include "axis-group-interface.hh"
17 MAKE_SCHEME_CALLBACK(Collision
,force_shift_callback
,2);
19 Collision::force_shift_callback (SCM element_smob
, SCM axis
)
21 Grob
*me
= unsmob_grob (element_smob
);
22 Axis a
= (Axis
) gh_scm2int (axis
);
25 me
= me
->parent_l (a
);
27 ugh. the way DONE is done is not clean
29 if (!unsmob_grob (me
->get_grob_property ("done")))
31 me
->set_grob_property ("done", me
->self_scm ());
35 return gh_double2scm (0.0);
39 TODO: make callback of this.
42 Collision::do_shifts(Grob
* me
)
44 SCM
autos (automatic_shift (me
));
45 SCM
hand (forced_shift (me
));
47 Link_array
<Grob
> done
;
50 = gh_scm2double (me
->get_grob_property ("note-width"));
52 for (; gh_pair_p (hand
); hand
=gh_cdr (hand
))
54 Grob
* s
= unsmob_grob (gh_caar (hand
));
55 Real amount
= gh_scm2double (gh_cdar (hand
));
57 s
->translate_axis (amount
*wid
, X_AXIS
);
60 for (; gh_pair_p (autos
); autos
=gh_cdr (autos
))
62 Grob
* s
= unsmob_grob (gh_caar (autos
));
63 Real amount
= gh_scm2double (gh_cdar (autos
));
66 s
->translate_axis (amount
* wid
, X_AXIS
);
70 /** This complicated routine moves note columns around horizontally to
71 ensure that notes don't clash.
73 This should be put into Scheme.
76 Collision::automatic_shift (Grob
*me
)
78 Drul_array
<Link_array
<Grob
> > clash_groups
;
79 Drul_array
<Array
<int> > shifts
;
82 SCM s
= me
->get_grob_property ("elements");
83 for (; gh_pair_p (s
); s
= gh_cdr (s
))
87 Grob
* se
= unsmob_grob (car
);
88 if (Note_column::has_interface (se
))
89 clash_groups
[Note_column::dir (se
)].push (se
);
96 Array
<int> & shift (shifts
[d
]);
97 Link_array
<Grob
> & clashes (clash_groups
[d
]);
99 clashes
.sort (Note_column::shift_compare
);
101 for (int i
=0; i
< clashes
.size (); i
++)
104 = clashes
[i
]->get_grob_property ("horizontal-shift");
106 if (gh_number_p (sh
))
107 shift
.push (gh_scm2int (sh
));
112 for (int i
=1; i
< shift
.size (); i
++)
114 if (shift
[i
-1] == shift
[i
])
116 warning (_ ("Too many clashing notecolumns. Ignoring them."));
121 while ((flip (&d
))!= UP
);
123 Drul_array
< Array
< Slice
> > extents
;
124 Drul_array
< Array
< Real
> > offsets
;
128 for (int i
=0; i
< clash_groups
[d
].size (); i
++)
130 Slice
s(Note_column::head_positions_interval (clash_groups
[d
][i
]));
134 offsets
[d
].push (d
* 0.5 * i
);
137 while ((flip (&d
))!= UP
);
141 for (int i
=1; i
< clash_groups
[d
].size (); i
++)
143 Slice prev
=extents
[d
][i
-1];
144 prev
.intersect (extents
[d
][i
]);
145 if (prev
.length ()> 0 ||
146 (extents
[-d
].size () && d
* (extents
[d
][i
][-d
] - extents
[-d
][0][d
]) < 0))
147 for (int j
= i
; j
< clash_groups
[d
].size (); j
++)
148 offsets
[d
][j
] += d
* 0.5;
151 while ((flip (&d
))!= UP
);
154 if the up and down version are close, and can not be merged, move
155 all of them again. */
156 if (extents
[UP
].size () && extents
[DOWN
].size ())
158 Grob
*cu_l
=clash_groups
[UP
][0];
159 Grob
*cd_l
=clash_groups
[DOWN
][0];
165 Grob
* nu_l
= Note_column::first_head(cu_l
);
166 Grob
* nd_l
= Note_column::first_head(cd_l
);
168 int downpos
= Note_column::head_positions_interval (cd_l
)[BIGGER
];
169 int uppos
= Note_column::head_positions_interval (cu_l
)[SMALLER
];
173 && Rhythmic_head::balltype_i (nu_l
) == Rhythmic_head::balltype_i (nd_l
);
176 if (!to_boolean (me
->get_grob_property ("merge-differently-dotted")))
177 merge
= merge
&& Rhythmic_head::dot_count (nu_l
) == Rhythmic_head::dot_count (nd_l
);
180 notes are close, but can not be merged. Shift
182 if (abs(uppos
- downpos
) < 2 && !merge
)
185 for (int i
=0; i
< clash_groups
[d
].size (); i
++)
187 offsets
[d
][i
] -= d
* 0.5;
190 while ((flip (&d
))!= UP
);
195 for (int i
=0; i
< clash_groups
[d
].size (); i
++)
196 tups
= gh_cons (gh_cons (clash_groups
[d
][i
]->self_scm (), gh_double2scm (offsets
[d
][i
])),
199 while (flip (&d
) != UP
);
205 Collision::forced_shift (Grob
*me
)
209 SCM s
= me
->get_grob_property ("elements");
210 for (; gh_pair_p (s
); s
= gh_cdr (s
))
212 Grob
* se
= unsmob_grob (gh_car (s
));
214 SCM force
= se
->remove_grob_property ("force-hshift");
215 if (gh_number_p (force
))
217 tups
= gh_cons (gh_cons (se
->self_scm (), force
),
228 Collision::add_column (Grob
*me
,Grob
* ncol_l
)
230 ncol_l
->add_offset_callback (Collision::force_shift_callback_proc
, X_AXIS
);
231 Axis_group_interface::add_element (me
, ncol_l
);
232 me
->add_dependency (ncol_l
);