2 slur.cc -- implement score based Slur
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
12 #include "accidental-interface.hh"
14 #include "directional-element-interface.hh"
15 #include "group-interface.hh"
16 #include "lily-guile.hh"
17 #include "new-slur.hh"
18 #include "note-column.hh"
19 #include "output-def.hh"
21 #include "slur-bezier-bow.hh"
23 #include "staff-symbol-referencer.hh"
24 #include "staff-symbol.hh"
30 Drul_array<Offset> attachment_;
34 #if DEBUG_SLUR_QUANTING
45 TODO: put in details property.,
49 struct Slur_score_parameters
52 Real HEAD_ENCOMPASS_PENALTY;
53 Real STEM_ENCOMPASS_PENALTY;
54 Real CLOSENESS_FACTOR;
55 Real EDGE_ATTRACTION_FACTOR;
56 Real SAME_SLOPE_PENALTY;
57 Real STEEPER_SLOPE_FACTOR;
58 Real NON_HORIZONTAL_PENALTY;
59 Real HEAD_STRICT_FREE_SPACE;
61 Real MAX_SLOPE_FACTOR;
62 Real EXTRA_OBJECT_COLLISION;
63 Real ACCIDENTAL_COLLISION;
64 Real FREE_HEAD_DISTANCE;
65 Slur_score_parameters ();
71 - curve around flag for y coordinate
73 - short-cut: try a smaller region first.
74 - collisions with accidentals
75 - collisions with articulations (staccato, portato, sforzato, ...)
100 Interval slur_head_extent_;
119 score_extra_encompass (Grob *me, Grob *common[],
120 Slur_score_parameters *score_param,
121 Drul_array<Bound_info> ,
123 Array<Slur_score> * scores);
124 static void score_slopes (Grob *me, Grob *common[],
125 Slur_score_parameters *score_param,
126 Drul_array<Bound_info>,
127 Drul_array<Offset> base_attach,
128 Array<Slur_score> *scores);
130 static void score_edges (Grob *me, Grob *common[],
131 Slur_score_parameters *score_param,
132 Drul_array<Bound_info> extremes,
133 Drul_array<Offset> base_attach,
134 Array<Slur_score> *scores);
135 static void score_encompass (Grob *me, Grob *common[],
136 Slur_score_parameters*,
137 Drul_array<Bound_info>,
138 Drul_array<Offset>, Array<Slur_score> *scores);
139 static Bezier avoid_staff_line (Grob *me, Grob **common,
140 Drul_array<Bound_info> extremes,
143 static Encompass_info get_encompass_info (Grob *me,
146 static Bezier get_bezier (Grob *me, Drul_array<Offset>, Real, Real);
147 static Direction get_default_dir (Grob *me);
149 static void set_end_points (Grob *);
150 static Real broken_trend_y (Grob *me, Grob **, Direction dir);
151 static Drul_array<Bound_info> get_bound_info (Spanner *me, Grob **common);
153 static void generate_curves (Grob *me,
155 Drul_array<Bound_info> extremes,
156 Drul_array<Offset> base_attach,
157 Array<Slur_score> *scores);
158 static Array<Slur_score> enumerate_attachments
159 (Grob *me, Grob *common[], Slur_score_parameters *score_param,
160 Drul_array<Bound_info> extremes,
161 Drul_array<Offset> base_attachment, Drul_array<Real> end_ys);
162 static Drul_array<Offset> get_base_attachments
163 (Spanner *sp, Grob **common, Drul_array<Bound_info> extremes);
164 static Drul_array<Real> get_y_attachment_range
165 (Spanner *sp, Grob **common, Drul_array<Bound_info> extremes,
166 Drul_array<Offset> base_attachment);
169 init_score_param (Slur_score_parameters *score_param)
171 score_param->SLUR_REGION_SIZE = 5;
172 score_param->HEAD_ENCOMPASS_PENALTY = 1000.0;
173 score_param->STEM_ENCOMPASS_PENALTY = 30.0;
174 score_param->CLOSENESS_FACTOR = 10;
175 score_param->EDGE_ATTRACTION_FACTOR = 4;
176 score_param->SAME_SLOPE_PENALTY = 20;
177 score_param->STEEPER_SLOPE_FACTOR = 50;
178 score_param->NON_HORIZONTAL_PENALTY = 15;
179 score_param->HEAD_STRICT_FREE_SPACE = 0.2;
180 score_param->MAX_SLOPE = 1.1;
181 score_param->MAX_SLOPE_FACTOR = 10;
182 score_param->FREE_HEAD_DISTANCE = 0.3;
183 score_param->EXTRA_OBJECT_COLLISION = 50;
184 score_param->ACCIDENTAL_COLLISION = 3;
187 Slur_score_parameters::Slur_score_parameters()
189 init_score_param (this);
192 /* HDIR indicates the direction for the slur. */
194 broken_trend_y (Grob *me, Grob **common, Direction hdir)
196 /* A broken slur should maintain the same vertical trend
197 the unbroken slur would have had. */
199 if (Spanner *mother = dynamic_cast<Spanner*> (me->original_))
201 int k = broken_spanner_index (dynamic_cast<Spanner*> (me));
203 if (j < 0 || j >= mother->broken_intos_.size ())
206 Grob *neighbor = mother->broken_intos_[j];
208 neighbor->set_property ("direction",
209 me->get_property ("direction"));
211 Spanner *common_mother
212 = dynamic_cast<Spanner*> (common[Y_AXIS]->original_);
214 = broken_spanner_index (dynamic_cast<Spanner*> (common[Y_AXIS]));
215 int common_j = common_k + hdir;
217 if (common_j < 0 || common_j >= common_mother->broken_intos_.size())
220 Grob *common_next_system = common_mother->broken_intos_[common_j];
221 Link_array<Grob> neighbor_cols
222 = Pointer_group_interface__extract_grobs (neighbor, (Grob *)0,
226 = (hdir == RIGHT) ? neighbor_cols[0] : neighbor_cols.top ();
227 Grob *neighbor_common
228 = common_next_system->common_refpoint (neighbor_col, Y_AXIS);
230 Direction vdir = get_grob_direction (me);
232 = neighbor_col->extent (neighbor_common, Y_AXIS)
233 .linear_combination (int(neighbor_cols.size()==1 ? CENTER : vdir))
234 - common_next_system->relative_coordinate (neighbor_common, Y_AXIS);
236 Link_array<Grob> my_cols
237 = Pointer_group_interface__extract_grobs (me, (Grob *)0,
240 Grob *extreme_col = (hdir == RIGHT) ? my_cols.top() : my_cols[0];
241 Real y = extreme_col->extent (common[Y_AXIS], Y_AXIS)
242 .linear_combination (int ((my_cols.size() == 1) ? CENTER : vdir));
243 by = (y*neighbor_cols.size() + neighbor_y*my_cols.size()) /
244 (my_cols.size() + neighbor_cols.size());
250 get_encompass_info (Grob *me,
254 Grob *stem = unsmob_grob (col->get_property ("stem"));
256 Direction dir = get_grob_direction (me);
260 programming_error ("No stem for note column?");
261 ei.x_ = col->relative_coordinate (common[X_AXIS], X_AXIS);
262 ei.head_ = ei.stem_ = col->extent (common[Y_AXIS],
263 Y_AXIS)[get_grob_direction (me)];
266 Direction stem_dir = get_grob_direction (stem);
268 if (Grob *head = Note_column::first_head (col))
269 ei.x_ = head->extent (common[X_AXIS], X_AXIS).center ();
271 ei.x_ = col->extent (common[X_AXIS], X_AXIS).center ();
273 Grob *h = Stem::extremal_heads (stem)[Direction (dir)];
276 ei.head_ = ei.stem_ = col->extent (common[Y_AXIS], Y_AXIS)[dir];
280 ei.head_ = h->extent (common[Y_AXIS], Y_AXIS)[dir];
282 if ((stem_dir == dir)
283 && !stem->extent (stem, Y_AXIS).is_empty ())
285 ei.stem_ = stem->extent (common[Y_AXIS], Y_AXIS)[dir];
286 if (Grob *b = Stem::get_beam (stem))
287 ei.stem_ += stem_dir * 0.5 * Beam::get_thickness (b);
288 ei.x_ = stem->extent (common[X_AXIS], X_AXIS).center ();
298 get_default_dir (Grob*me)
300 Link_array<Grob> encompasses
301 = Pointer_group_interface__extract_grobs (me, (Grob*) 0, "note-columns");
304 for (int i= 0; i < encompasses.size (); i ++)
306 if (Note_column::dir (encompasses[i]) < 0)
315 MAKE_SCHEME_CALLBACK (New_slur, after_line_breaking,1);
317 New_slur::after_line_breaking (SCM smob)
319 Spanner *me = dynamic_cast<Spanner*> (unsmob_grob (smob));
320 if (!scm_ilength (me->get_property ("note-columns")))
323 return SCM_UNSPECIFIED;
326 if (!get_grob_direction (me))
327 set_grob_direction (me, get_default_dir (me));
331 return SCM_UNSPECIFIED;
335 get_bezier (Grob *me, Drul_array<Offset> extremes, Real r_0, Real h_inf)
337 Array<Offset> encompasses;
338 encompasses.push (extremes[LEFT]);
339 encompasses.push (extremes[RIGHT]);
341 Slur_bezier_bow bb (encompasses,
342 get_grob_direction (me), h_inf, r_0);
344 return bb.get_bezier ();
347 Drul_array<Bound_info>
348 get_bound_info (Spanner* me, Grob **common)
350 Drul_array<Bound_info> extremes;
352 Direction dir = get_grob_direction (me);
356 extremes[d].bound_ = me->get_bound (d);
357 if (Note_column::has_interface (extremes[d].bound_))
359 extremes[d].note_column_ = extremes[d].bound_;
360 extremes[d].stem_ = Note_column::get_stem (extremes[d].note_column_);
361 extremes[d].stem_dir_ = get_grob_direction (extremes[d].stem_);
362 extremes[d].stem_extent_[X_AXIS]
363 = extremes[d].stem_->extent (common[X_AXIS], X_AXIS);
364 extremes[d].stem_extent_[Y_AXIS]
365 = extremes[d].stem_->extent (common[Y_AXIS], Y_AXIS);
366 extremes[d].slur_head_
367 = Stem::extremal_heads (extremes[d].stem_)[dir];
368 extremes[d].slur_head_extent_
369 = extremes[d].slur_head_->extent (common[X_AXIS], X_AXIS);
370 extremes[d].staff_ = Staff_symbol_referencer
371 ::get_staff_symbol (extremes[d].slur_head_);
372 extremes[d].staff_space_ = Staff_symbol_referencer
373 ::staff_space (extremes[d].slur_head_);
376 extremes[d].neighbor_y_ = broken_trend_y (me, common, d);
378 while (flip (&d) != LEFT);
383 set_end_points (Grob *me)
385 Link_array<Grob> columns
386 = Pointer_group_interface__extract_grobs (me, (Grob *)0, "note-columns");
387 Slur_score_parameters params;
388 if (columns.is_empty ())
394 SCM eltlist = me->get_property ("note-columns");
395 SCM extra_list = me->get_property ("encompass-objects");
396 Spanner *sp = dynamic_cast<Spanner*> (me);
398 Grob *common[] = {0, 0};
399 for (int i = X_AXIS; i < NO_AXES; i++)
402 common[a] = common_refpoint_of_list (eltlist, me, a);
403 common[a] = common_refpoint_of_list (extra_list, common[a], a);
406 common[X_AXIS] = common[X_AXIS]->common_refpoint (sp->get_bound (RIGHT),
408 common[X_AXIS] = common[X_AXIS]->common_refpoint (sp->get_bound (LEFT),
411 Drul_array<Bound_info> extremes = get_bound_info (sp, common);
412 Drul_array<Offset> base_attachment
413 = get_base_attachments (sp, common, extremes);
414 Drul_array<Real> end_ys
415 = get_y_attachment_range (sp, common, extremes, base_attachment);
416 Array<Slur_score> scores = enumerate_attachments (me, common, ¶ms,
417 extremes, base_attachment,
420 generate_curves (me, common, extremes, base_attachment, &scores);
421 score_edges (me, common, ¶ms,extremes, base_attachment, &scores);
422 score_slopes (me, common, ¶ms,extremes, base_attachment, &scores);
423 score_encompass (me, common, ¶ms,extremes, base_attachment, &scores);
424 score_extra_encompass (me, common, ¶ms,extremes, base_attachment,
430 for (int i = scores.size (); i--;)
432 if (scores[i].score_ < opt)
434 opt = scores[i].score_;
439 #if DEBUG_SLUR_QUANTING
440 SCM inspect_quants = me->get_property ("inspect-quants");
441 if (to_boolean (me->get_paper ()
442 ->lookup_variable (ly_symbol2scm ("debug-slur-quanting")))
443 && ly_c_pair_p (inspect_quants))
445 Drul_array<Real> ins = ly_scm2interval (inspect_quants);
449 for (; i < scores.size (); i ++)
451 Real d =fabs (scores[i].attachment_[LEFT][Y_AXIS] - ins[LEFT])
452 + fabs (scores[i].attachment_[RIGHT][Y_AXIS] - ins[RIGHT]);
460 programming_error ("Could not find quant.");
462 scores[opt_idx].score_card_ += to_string ("i%d", opt_idx);
465 me->set_property ("quant-score",
466 scm_makfrom0str (scores[opt_idx].score_card_.to_str0 ()));
469 Bezier b = scores[opt_idx].curve_;
470 SCM controls = SCM_EOL;
471 for (int i = 4; i--;)
473 Offset o = b.control_[i] -
474 Offset (me->relative_coordinate (common[X_AXIS], X_AXIS),
475 me->relative_coordinate (common[Y_AXIS], Y_AXIS));
477 controls = scm_cons (ly_offset2scm (o), controls);
480 me->set_property ("control-points", controls);
485 get_y_attachment_range (Spanner*me,
487 Drul_array<Bound_info> extremes,
488 Drul_array<Offset> base_attachment)
490 Drul_array<Real> end_ys;
491 Direction dir = get_grob_direction (me);
495 if (extremes[d].note_column_)
498 * ((dir * (base_attachment[d][Y_AXIS] + 4.0 * dir))
499 >? (dir * (dir + extremes[d].note_column_->extent(common[Y_AXIS],
501 >? (dir * base_attachment[-d][Y_AXIS]));
504 end_ys[d] = extremes[d].neighbor_y_ + 4.0 * dir;
506 while (flip (&d) != LEFT);
512 get_base_attachments (Spanner *me,
513 Grob **common, Drul_array<Bound_info> extremes)
515 Link_array<Grob> columns
516 = Pointer_group_interface__extract_grobs (me, (Grob *)0, "note-columns");
517 Drul_array<Offset> base_attachment;
518 Slur_score_parameters params;
519 Real staff_space = Staff_symbol_referencer::staff_space ((Grob *) me);
520 Direction dir = get_grob_direction (me);
524 Grob *stem = extremes[d].stem_;
525 Grob *head = extremes[d].slur_head_;
528 if (!extremes[d].note_column_)
530 y = extremes[d].neighbor_y_;
532 x = extremes[d].bound_->extent (common[X_AXIS], X_AXIS)[d];
534 x = me->get_broken_left_end_align ();
539 && extremes[d].stem_dir_ == dir
540 && Stem::get_beaming (stem, -d)
541 && columns.size () > 2
543 y = extremes[d].stem_extent_[Y_AXIS][dir];
545 y = head->extent (common[Y_AXIS], Y_AXIS)[dir];
546 y += dir * 0.5 * staff_space;
550 SCM scripts = stem->get_property ((dir == UP
554 /* FIXME: number of scripts, height, priority?
555 articulation scripts should be inside slur, other,
556 such as dynamics, pedals, fingering, should be
558 if (!SCM_NULLP (scripts))
559 y += dir * staff_space;
563 = (y - extremes[d].staff_->relative_coordinate (common[Y_AXIS],
565 * 2.0 / Staff_symbol::staff_space (extremes[d].staff_);
567 /* start off staffline. */
568 if (fabs (pos - round (pos)) < 0.2
569 && Staff_symbol_referencer::on_staffline (head, (int) rint (pos))
570 && Staff_symbol_referencer::line_count (head) - 1 >= rint (pos)
572 // TODO: calc from slur thick & line thick, parameter.
573 y += 1.5 * staff_space * dir / 10;
575 Grob * fh = Note_column::first_head (extremes[d].note_column_);
576 x = fh->extent (common[X_AXIS], X_AXIS).linear_combination (CENTER);
578 base_attachment[d] = Offset (x, y);
580 } while (flip (&d) != LEFT);
582 return base_attachment;
586 generate_curves (Grob *me, Grob **common,
587 Drul_array<Bound_info> extremes,
589 Array<Slur_score> *scores)
593 Real staff_space = Staff_symbol_referencer::staff_space ((Grob *) me);
594 Real r_0 = robust_scm2double (me->get_property ("ratio"), 0.33);
595 Real h_inf = staff_space * ly_scm2double (me->get_property ("height-limit"));
596 for (int i = 0; i < scores->size(); i++)
598 Bezier bez= get_bezier (me, (*scores)[i].attachment_, r_0, h_inf);
599 bez = avoid_staff_line (me, common, extremes, bez);
600 (*scores)[i].attachment_[LEFT] = bez.control_[0];
601 (*scores)[i].attachment_[RIGHT] = bez.control_[3];
602 (*scores)[i].curve_ = bez;
607 avoid_staff_line (Grob *me, Grob **common,
608 Drul_array<Bound_info> extremes,
612 Array<Real> ts = bez.solve_derivative (horiz);
613 Real lt = me->get_paper ()->get_dimension (ly_symbol2scm ("linethickness"));
614 Real thick = robust_scm2double (me->get_property ("thickness"), 1.0) * lt;
616 /* TODO: handle case of broken slur. */
618 && (extremes[LEFT].staff_ == extremes[RIGHT].staff_)
619 && extremes[LEFT].staff_ && extremes[RIGHT].staff_)
621 Real y = bez.curve_point (ts[0])[Y_AXIS];
623 Grob *staff = extremes[LEFT].staff_;
625 Real staff_space = extremes[LEFT].staff_space_;
626 Real p = 2 * (y - staff->relative_coordinate (common[Y_AXIS], Y_AXIS))
629 Real distance = fabs (round (p) - p); // in halfspaces
630 if (distance < 4 * thick
631 && (int) fabs (round (p))
632 <= 2 * Staff_symbol_referencer::staff_radius (staff) + 0.1
633 && (int (fabs (round (p))) % 2
634 != Staff_symbol_referencer::line_count (staff) % 2))
636 Direction resolution_dir =
637 (distance ? get_grob_direction (me) : Direction (sign (p - round(p))));
640 Real newp = round (p) + resolution_dir
643 Real dy = (newp - p) * staff_space / 2.0;
645 bez.translate (Offset (0, dy));
647 bez.control_[1][Y_AXIS] += dy;
648 bez.control_[2][Y_AXIS] += dy;
657 enumerate_attachments (Grob *me, Grob *common[],
658 Slur_score_parameters *score_param,
659 Drul_array<Bound_info> extremes,
660 Drul_array<Offset> base_attachment,
661 Drul_array<Real> end_ys)
665 Array<Slur_score> scores;
667 Direction dir = get_grob_direction (me);
668 Real staff_space = Staff_symbol_referencer::staff_space ((Grob *) me);
670 Drul_array<Offset> os;
671 os[LEFT] = base_attachment[LEFT];
672 Real minimum_length = staff_space
673 * robust_scm2double (me->get_property ("minimum-length"), 2.0);
675 for (int i = 0; dir * os[LEFT][Y_AXIS] <= dir * end_ys[LEFT]; i++)
677 os[RIGHT] = base_attachment[RIGHT];
678 for (int j = 0; dir * os[RIGHT][Y_AXIS] <= dir * end_ys[RIGHT]; j++)
682 Drul_array<bool> attach_to_stem (false, false);
685 os[d][X_AXIS] = base_attachment[d][X_AXIS];
686 if (extremes[d].stem_
687 && !Stem::is_invisible (extremes[d].stem_)
688 && extremes[d].stem_dir_ == dir
691 if (extremes[d].stem_extent_[Y_AXIS].contains (os[d][Y_AXIS]))
693 os[d][X_AXIS] = extremes[d].slur_head_extent_[-d]
695 attach_to_stem[d] = true;
697 else if (dir *extremes[d].stem_extent_[Y_AXIS][dir]
698 < dir * os[d][Y_AXIS])
699 os[d][X_AXIS] = extremes[d].stem_extent_[X_AXIS].center();
702 while (flip (&d) != LEFT);
705 dz = os[RIGHT] - os[LEFT];
706 if (dz[X_AXIS] < minimum_length
707 || fabs (dz[Y_AXIS] / dz[X_AXIS]) > score_param->MAX_SLOPE
712 if (extremes[d].slur_head_)
714 os[d][X_AXIS] = extremes[d].slur_head_extent_.center ();
715 attach_to_stem[d] = false;
718 while (flip (&d) != LEFT);
721 dz = os[RIGHT] - os[LEFT];
724 if (extremes[d].slur_head_
725 && !attach_to_stem[d])
727 /* Horizontally move tilted slurs a little. Move
728 more for bigger tilts.
732 -= dir * extremes[d].slur_head_extent_.length ()
733 * sin (dz.arg ()) / 3;
736 while (flip (&d) != LEFT);
741 os[RIGHT][Y_AXIS] += dir * staff_space / 2;
744 os[LEFT][Y_AXIS] += dir * staff_space / 2;
750 score_encompass (Grob *me, Grob *common[],
751 Slur_score_parameters *score_param,
752 Drul_array<Bound_info> extremes,
753 Drul_array<Offset> base_attach,
754 Array<Slur_score> *scores)
759 Link_array<Grob> encompasses
760 = Pointer_group_interface__extract_grobs (me, (Grob *)0, "note-columns");
761 Direction dir = get_grob_direction (me);
763 Array<Encompass_info> infos;
765 for (int i = 0; i < encompasses.size(); i++)
766 infos.push (get_encompass_info (me, encompasses[i], common));
768 for (int i = 0; i < scores->size (); i++)
770 Bezier const &bez (scores->elem (i).curve_);
772 for (int j = 0; j < infos.size(); j++)
774 Real x = infos[j].x_;
777 bool r_edge = j==infos.size()-1;
778 bool edge = l_edge || r_edge;
780 if (!(x < scores->elem (i).attachment_[RIGHT][X_AXIS]
781 && x > scores->elem (i).attachment_[LEFT][X_AXIS]))
784 Real y = bez.get_other_coordinate (X_AXIS, x);
787 Real head_dy = (y - infos[j].head_);
788 if (dir * head_dy < 0)
789 demerit += score_param->HEAD_ENCOMPASS_PENALTY;
793 ? (1 / fabs (head_dy) - 1 / score_param->FREE_HEAD_DISTANCE)
794 : score_param->HEAD_ENCOMPASS_PENALTY;
795 hd = (hd >? 0)<? score_param->HEAD_ENCOMPASS_PENALTY;
801 if (dir * (y - infos[j].stem_) < 0)
803 Real stem_dem =score_param->STEM_ENCOMPASS_PENALTY ;
804 if ((l_edge && dir == UP)
805 || (r_edge && dir == DOWN))
813 ext.add_point (infos[j].stem_);
814 ext.add_point (infos[j].head_);
817 demerit += -score_param->CLOSENESS_FACTOR
819 * (y - (ext[dir] + dir * score_param->FREE_HEAD_DISTANCE))
825 #if DEBUG_SLUR_QUANTING
826 (*scores)[i].score_card_ += to_string ("C%.2f", demerit);
829 (*scores)[i].score_ += demerit;
834 score_extra_encompass (Grob *me, Grob *common[],
835 Slur_score_parameters *score_param,
836 Drul_array<Bound_info> extremes,
837 Drul_array<Offset> base_attach,
838 Array<Slur_score> *scores)
843 Link_array<Grob> encompasses
844 = Pointer_group_interface__extract_grobs (me, (Grob *)0,
845 "encompass-objects");
846 Direction dir = get_grob_direction (me);
847 Real staff_space = Staff_symbol_referencer::staff_space ((Grob *) me);
848 Real lt = me->get_paper ()->get_dimension (ly_symbol2scm ("linethickness"));
849 Real thick = robust_scm2double (me->get_property ("thickness"), 1.0) * lt;
851 /* FIXME: use actual height of script?
853 ugh: see slur-script.ly
854 must be <= 0.75 for b-.( b-. BUT
855 must be >= 0.9 for b-- ( b-)
857 both settings break the other. */
858 Real y_padding = 0.9 * staff_space;
861 Array<Interval> yexts;
862 for (int i = 0; i < encompasses.size (); i++)
864 Grob *g = encompasses [i];
865 Interval xe = g->extent (common[X_AXIS], X_AXIS);
866 Interval ye = g->extent (common[Y_AXIS], Y_AXIS);
870 if (Accidental_interface::has_interface (g))
872 /* Begin copy accidental.cc */
874 if (to_boolean (g->get_property ("cautionary")))
876 SCM cstyle = g->get_property ("cautionary-style");
877 parens = ly_c_equal_p (cstyle, ly_symbol2scm ("parentheses"));
880 SCM accs = g->get_property ("accidentals");
881 SCM scm_style = g->get_property ("style");
882 if (!ly_c_symbol_p (scm_style)
884 && scm_ilength (accs) == 1)
886 /* End copy accidental.cc */
887 switch (ly_scm2int (ly_car (accs)))
902 xs.push (xe.linear_combination (xp));
903 ye.widen (thick * 0.5);
904 ye[dir] += dir * y_padding;
908 for (int i = 0; i < scores->size (); i++)
910 Bezier const &bez (scores->elem (i).curve_);
912 for (int j = 0; j < xs.size(); j++)
915 if ((x < scores->elem (i).attachment_[RIGHT][X_AXIS]
916 && x > scores->elem (i).attachment_[LEFT][X_AXIS]))
918 Real y = bez.get_other_coordinate (X_AXIS, x);
919 if (yexts[j].contains (y))
921 if (Accidental_interface::has_interface (encompasses[j]))
922 demerit += score_param->ACCIDENTAL_COLLISION;
924 demerit += score_param->EXTRA_OBJECT_COLLISION;
928 #if DEBUG_SLUR_QUANTING
929 (*scores)[i].score_card_ += to_string ("X%.2f", demerit);
931 (*scores)[i].score_ += demerit;
936 score_edges (Grob *me, Grob *common[],
937 Slur_score_parameters * score_param,
938 Drul_array<Bound_info> extremes,
939 Drul_array<Offset> base_attach,
940 Array<Slur_score> *scores)
943 Direction dir = get_grob_direction (me);
945 for (int i = 0; i < scores->size (); i++)
950 Real y = scores->elem (i).attachment_[d][Y_AXIS];
951 Real dy = fabs (y - base_attach[d][Y_AXIS]);
953 Real factor = score_param->EDGE_ATTRACTION_FACTOR;
954 Real demerit = factor * dy;
955 if (extremes[d].stem_
956 && extremes[d].stem_dir_ == dir
957 && !Stem::get_beaming (extremes[d].stem_, -d)
961 (*scores)[i].score_ += demerit;
962 #if DEBUG_SLUR_QUANTING
963 (*scores)[i].score_card_ += to_string ("E%.2f", demerit);
966 while (flip (&d) != LEFT);
971 score_slopes (Grob *me, Grob *common[],
972 Slur_score_parameters *score_param,
973 Drul_array<Bound_info> extremes,
974 Drul_array<Offset> base_attach,
975 Array<Slur_score> * scores)
984 if (extremes[d].slur_head_)
985 ys[d] = extremes[d].slur_head_->relative_coordinate (common[Y_AXIS],
988 ys[d] = extremes[d].neighbor_y_;
990 while (flip (&d) != LEFT);
993 = (extremes[LEFT].stem_ && Stem::get_beam (extremes[LEFT].stem_))
994 || (extremes[RIGHT].stem_ && Stem::get_beam (extremes[RIGHT].stem_));
996 Real dy = ys[RIGHT] - ys[LEFT];
997 for (int i = 0; i < scores->size (); i++)
999 Offset slur_dz = (*scores)[i].attachment_[RIGHT]
1000 - (*scores)[i].attachment_[LEFT];
1001 Real slur_dy = slur_dz[Y_AXIS];
1004 demerit += ((fabs (slur_dy / slur_dz[X_AXIS])
1005 - score_param->MAX_SLOPE) >? 0)
1006 * score_param->MAX_SLOPE_FACTOR;
1008 /* 0.2: account for staffline offset. */
1009 Real max_dy = (fabs (dy) + 0.2);
1013 demerit += score_param->STEEPER_SLOPE_FACTOR
1014 * ((fabs (slur_dy) -max_dy) >? 0);
1016 demerit += ((fabs (slur_dy/slur_dz[X_AXIS])
1017 - score_param->MAX_SLOPE) >? 0)
1018 * score_param->MAX_SLOPE_FACTOR;
1021 && sign (slur_dy) != 0)
1022 demerit += score_param->NON_HORIZONTAL_PENALTY;
1026 && sign (slur_dy) != sign (dy))
1027 demerit += has_beams
1028 ? score_param->SAME_SLOPE_PENALTY / 10
1029 : score_param->SAME_SLOPE_PENALTY;
1031 #if DEBUG_SLUR_QUANTING
1032 (*scores)[i].score_card_ += to_string ("S%.2f", d);
1034 (*scores)[i].score_ += demerit;