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>
14 #include "font-interface.hh"
15 #include "text-item.hh"
16 #include "directional-element-interface.hh"
17 #include "group-interface.hh"
18 #include "lily-guile.hh"
20 #include "note-column.hh"
21 #include "output-def.hh"
23 #include "slur-bezier-bow.hh"
26 #include "staff-symbol-referencer.hh"
27 #include "staff-symbol.hh"
36 - avoid collision with staff line
37 - curve around flag/stem for x coordinate
41 struct Encompass_info {
62 Interval slur_head_extent_;
76 TODO: put in details property.
78 struct Slur_score_parameters
80 int SLUR_REGION_SIZE ;
81 Real HEAD_ENCOMPASS_PENALTY ;
82 Real STEM_ENCOMPASS_PENALTY ;
83 Real CLOSENESS_FACTOR ;
84 Real EDGE_ATTRACTION_FACTOR ;
85 Real SAME_SLOPE_PENALTY ;
86 Real STEEPER_SLOPE_FACTOR ;
87 Real NON_HORIZONTAL_PENALTY ;
88 Real HEAD_STRICT_FREE_SPACE ;
90 Real MAX_SLOPE_FACTOR ;
91 Real FREE_HEAD_DISTANCE ;
92 Slur_score_parameters ();
96 init_score_param (Slur_score_parameters *score_param)
98 score_param->SLUR_REGION_SIZE = 5;
99 score_param->HEAD_ENCOMPASS_PENALTY = 1000.0;
100 score_param->STEM_ENCOMPASS_PENALTY = 30.0;
101 score_param->CLOSENESS_FACTOR = 10;
102 score_param->EDGE_ATTRACTION_FACTOR = 4;
103 score_param->SAME_SLOPE_PENALTY = 20;
104 score_param->STEEPER_SLOPE_FACTOR = 50;
105 score_param->NON_HORIZONTAL_PENALTY = 15;
106 score_param->HEAD_STRICT_FREE_SPACE = 0.2;
107 score_param->MAX_SLOPE = 1.1;
108 score_param->MAX_SLOPE_FACTOR = 10;
109 score_param->FREE_HEAD_DISTANCE = 0.3 ;
112 Slur_score_parameters::Slur_score_parameters()
114 init_score_param (this);
117 #define DEBUG_SLUR_QUANTING 1
120 Drul_array<Offset> attachment_;
124 #if DEBUG_SLUR_QUANTING
136 static void add_column (Grob *me, Grob *col);
137 DECLARE_SCHEME_CALLBACK (print, (SCM));
138 static void score_slopes (Grob * me, Grob *common[],
139 Slur_score_parameters * score_param,
141 Drul_array<Bound_info>,
142 Drul_array<Offset> base_attach,
143 Array<Slur_score> * scores);
145 static void score_edges (Grob * me, Grob *common[],
146 Slur_score_parameters * score_param,
148 Drul_array<Bound_info> extremes,
149 Drul_array<Offset> base_attach,
150 Array<Slur_score> * scores);
151 static void score_encompass (Grob * me, Grob *common[],
152 Slur_score_parameters*,
153 Drul_array<Bound_info>,
154 Drul_array<Offset>, Array<Slur_score> * scores);
156 static Encompass_info get_encompass_info (Grob *me,
159 static void set_interface (Grob*);
160 static bool has_interface (Grob*);
161 static Bezier get_curve (Grob *me);
162 static Bezier get_bezier (Grob *me, Drul_array<Offset>,Real,Real);
163 static Direction get_default_dir (Grob *me);
164 DECLARE_SCHEME_CALLBACK (after_line_breaking, (SCM));
165 DECLARE_SCHEME_CALLBACK (height, (SCM,SCM));
167 static void set_end_points (Grob*);
168 static Real get_boundary_notecolumn_y (Grob *me, Direction dir);
169 static Real broken_trend_y (Grob *me, Grob**, Direction dir);
170 static void set_control_points (Grob *me);
171 static Drul_array<Bound_info> get_bound_info (Spanner* me,
174 static void generate_curves (Grob*me, Array<Slur_score> *scores);
175 static Array<Slur_score> enumerate_attachments (Grob * me, Grob *common[],
176 Slur_score_parameters * score_param,
177 Drul_array<Bound_info> extremes,
178 Drul_array<Offset> base_attachment, Drul_array<Real> end_ys);
180 static Drul_array<Offset> get_base_attachments (Spanner*sp,
183 Drul_array<Bound_info> extremes);
185 static Drul_array<Real> get_y_attachment_range (Spanner*sp,
188 Drul_array<Bound_info> extremes,
189 Drul_array<Offset> base_attachment);
193 New_slur::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.
200 if (Spanner *mother = dynamic_cast<Spanner*> (me->original_))
202 int k = broken_spanner_index (dynamic_cast<Spanner*> (me));
204 if (j < 0 || j >= mother->broken_intos_.size ())
207 Grob *neighbor = mother->broken_intos_[j];
209 neighbor->set_property ("direction",
210 me->get_property ("direction"));
212 Spanner * common_mother = dynamic_cast<Spanner*> (common[Y_AXIS]->original_);
213 int common_k = broken_spanner_index (dynamic_cast<Spanner*> (common[Y_AXIS]));
214 int common_j = common_k + hdir;
216 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, "note-columns");
224 Grob * neighbor_col = (hdir == RIGHT) ? neighbor_cols[0] : neighbor_cols.top ();
225 Grob * neighbor_common = common_next_system->common_refpoint (neighbor_col, Y_AXIS);
227 Direction vdir = get_grob_direction (me);
229 neighbor_col->extent (neighbor_common, Y_AXIS)
230 .linear_combination (int(neighbor_cols.size()==1 ? CENTER : vdir))
231 - common_next_system->relative_coordinate (neighbor_common, Y_AXIS);
233 Link_array<Grob> my_cols =
234 Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-columns");
236 Grob *extreme_col = (hdir == RIGHT) ? my_cols.top() : my_cols[0];
237 Real y = extreme_col->extent (common[Y_AXIS], Y_AXIS).linear_combination (vdir);
239 by = (y*neighbor_cols.size() + neighbor_y*my_cols.size()) /
240 (my_cols.size() + neighbor_cols.size());
246 New_slur::set_interface (Grob*me)
248 /* Copy to mutable list. */
249 me->set_property ("attachment",
250 ly_deep_copy (me->get_property ("attachment")));
254 New_slur::add_column (Grob*me, Grob*n)
256 Pointer_group_interface::add_grob (me, ly_symbol2scm ("note-columns"), n);
257 me->add_dependency (n);
259 add_bound_item (dynamic_cast<Spanner*> (me), dynamic_cast<Item*> (n));
263 New_slur::get_encompass_info (Grob *me,
267 Grob* stem = unsmob_grob (col->get_property ("stem"));
271 Direction dir = get_grob_direction (me);
275 programming_error ("No stem for note column?");
276 ei.x_ = col->relative_coordinate (common[X_AXIS], X_AXIS);
277 ei.head_ = ei.stem_ = col->extent (common[Y_AXIS], Y_AXIS)[get_grob_direction (me)];
280 Direction stem_dir = get_grob_direction (stem);
282 if (Grob *head = Note_column::first_head (col))
283 ei.x_ = head->extent (common[X_AXIS], X_AXIS).center ();
285 ei.x_ = col->extent (common[X_AXIS], X_AXIS).center ();
287 Grob * h = Stem::extremal_heads (stem)[Direction (dir)];
290 ei.head_ = ei.stem_ = col->extent (common[Y_AXIS], Y_AXIS)[dir];
294 ei.head_ = h->extent (common[Y_AXIS], Y_AXIS)[dir];
296 if ((stem_dir == dir)
297 && !stem->extent (stem, Y_AXIS).is_empty ())
299 ei.stem_ = stem->extent (common[Y_AXIS], Y_AXIS)[dir];
300 if (Grob * b = Stem::get_beam (stem))
302 ei.stem_ += stem_dir * 0.5 *Beam::get_thickness (b);
314 New_slur::get_default_dir (Grob*me)
316 Link_array<Grob> encompasses =
317 Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-columns");
320 for (int i=0; i < encompasses.size (); i ++)
322 if (Note_column::dir (encompasses[i]) < 0)
331 MAKE_SCHEME_CALLBACK (New_slur, after_line_breaking,1);
333 New_slur::after_line_breaking (SCM smob)
335 Spanner *me = dynamic_cast<Spanner*> (unsmob_grob (smob));
336 if (!scm_ilength (me->get_property ("note-columns")))
339 return SCM_UNSPECIFIED;
342 if (!get_grob_direction (me))
343 set_grob_direction (me, get_default_dir (me));
348 return SCM_UNSPECIFIED;
352 New_slur::get_bezier (Grob *me, Drul_array<Offset> extremes,
356 Array<Offset> encompasses;
357 encompasses.push (extremes[LEFT]);
358 encompasses.push (extremes[RIGHT]);
360 Slur_bezier_bow bb (encompasses,
361 get_grob_direction (me), h_inf, r_0);
363 return bb.get_bezier ();
367 Drul_array<Bound_info>
368 New_slur::get_bound_info (Spanner* me,
371 Drul_array<Bound_info> extremes;
373 Direction dir = get_grob_direction (me);
376 extremes[d].bound_ = me->get_bound (d);
378 if (Note_column::has_interface (extremes[d].bound_))
380 extremes[d].note_column_ = extremes[d].bound_;
381 extremes[d].stem_ = Note_column::get_stem (extremes[d].note_column_);
382 extremes[d].stem_dir_ = get_grob_direction (extremes[d].stem_);
383 extremes[d].stem_extent_[X_AXIS] = extremes[d].stem_->extent (common[X_AXIS], X_AXIS);
384 extremes[d].stem_extent_[Y_AXIS] = extremes[d].stem_->extent (common[Y_AXIS], Y_AXIS);
385 extremes[d].slur_head_ = Stem::extremal_heads (extremes[d].stem_)[dir];
386 extremes[d].slur_head_extent_ = extremes[d].slur_head_->extent (common[X_AXIS], X_AXIS);
387 extremes[d].staff_ = Staff_symbol_referencer::get_staff_symbol (extremes[d].slur_head_);
391 extremes[d].neighbor_y_ = broken_trend_y (me, common, d);
393 } while (flip (&d) != LEFT);
399 New_slur::set_end_points (Grob *me)
401 Link_array<Grob> columns =
402 Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-columns");
404 Slur_score_parameters params;
406 if (columns.is_empty ())
412 SCM eltlist = me->get_property ("note-columns");
413 Grob *common[] = {common_refpoint_of_list (eltlist, me, X_AXIS),
414 common_refpoint_of_list (eltlist, me, Y_AXIS)};
417 Spanner* sp = dynamic_cast<Spanner*> (me);
418 common[X_AXIS] = common[X_AXIS]->common_refpoint (sp->get_bound (RIGHT), X_AXIS);
419 common[X_AXIS] = common[X_AXIS]->common_refpoint (sp->get_bound (LEFT), X_AXIS);
422 Drul_array<Bound_info> extremes = get_bound_info (sp, common);
423 Drul_array<Offset> base_attachment = get_base_attachments (sp, common, extremes);
424 Drul_array<Real> end_ys = get_y_attachment_range (sp, common, extremes, base_attachment);
425 Array<Slur_score> scores = enumerate_attachments (me, common,
426 ¶ms, extremes, base_attachment, end_ys);
427 generate_curves (me, &scores);
429 score_edges (me, common, ¶ms,extremes, base_attachment, &scores);
430 score_slopes (me, common, ¶ms,extremes, base_attachment, &scores);
431 score_encompass (me, common, ¶ms,extremes, base_attachment, &scores);
435 for (int i = scores.size (); i--;)
437 if (scores[i].score_ < opt)
439 opt = scores[i].score_;
444 #if DEBUG_SLUR_QUANTING
445 SCM inspect_quants = me->get_property ("inspect-quants");
446 if (to_boolean (me->get_paper ()->lookup_variable (ly_symbol2scm ("debug-slur-quanting")))
447 && ly_c_pair_p (inspect_quants))
449 Drul_array<Real> ins = ly_scm2interval (inspect_quants);
453 for (; i < scores.size (); i ++)
455 Real d =fabs (scores[i].attachment_[LEFT][Y_AXIS] - ins[LEFT])
456 + fabs (scores[i].attachment_[RIGHT][Y_AXIS] - ins[RIGHT]);
464 programming_error ("Could not find quant.");
468 scores[opt_idx].score_card_ += to_string ("i%d", opt_idx);
471 me->set_property ("quant-score",
472 scm_makfrom0str (scores[opt_idx].score_card_.to_str0 ()));
475 Bezier const &b = scores[opt_idx].curve_;
477 SCM controls = SCM_EOL;
478 for (int i = 4; i--;)
480 Offset o = b.control_[i] -
481 Offset (me->relative_coordinate (common[X_AXIS], X_AXIS),
482 me->relative_coordinate (common[Y_AXIS], Y_AXIS));
484 controls = scm_cons (ly_offset2scm (o), controls);
487 me->set_property ("control-points", controls);
492 New_slur::get_y_attachment_range (Spanner*me,
494 Drul_array<Bound_info> extremes,
495 Drul_array<Offset> base_attachment)
497 Drul_array<Real> end_ys;
498 Direction dir = get_grob_direction (me);
501 if (extremes[d].note_column_)
503 end_ys[d] = dir * ((dir * (base_attachment[d][Y_AXIS] + 4.0 *dir))
504 >? (dir * (dir + extremes[d].note_column_->extent(common[Y_AXIS],Y_AXIS)[dir]))
505 >? (dir * base_attachment[-d][Y_AXIS])
510 end_ys[d] = extremes[d].neighbor_y_ + 4.0 * dir ;
512 } while (flip (&d) != LEFT);
518 New_slur::get_base_attachments (Spanner*me,
520 Drul_array<Bound_info> extremes)
522 Link_array<Grob> columns =
523 Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-columns");
524 Drul_array<Offset> base_attachment;
527 Slur_score_parameters params;
529 Real staff_space = Staff_symbol_referencer::staff_space ((Grob*)me);
531 Direction dir = get_grob_direction (me);
535 Grob *stem = extremes[d].stem_;
536 Grob *head = extremes[d].slur_head_;
539 if (!extremes[d].note_column_)
541 y = extremes[d].neighbor_y_;
543 x = extremes[d].bound_->extent (common[X_AXIS], X_AXIS)[d];
545 x = me->get_broken_left_end_align ();
550 && extremes[d].stem_dir_ == dir
551 && Stem::get_beaming (stem, -d)
552 && columns.size () > 2
555 y = extremes[d].stem_extent_[Y_AXIS][dir];
559 y = head->extent (common[Y_AXIS], Y_AXIS)[dir];
561 y += dir * 0.5 * staff_space;
563 Real pos = 2.0 * (y - extremes[d].staff_->relative_coordinate (common[Y_AXIS], Y_AXIS))
564 / Staff_symbol::staff_space (extremes[d].staff_);
569 if (fabs (pos - round (pos)) < 0.2
570 && Staff_symbol_referencer::on_staffline (head, (int) rint (pos))
571 && Staff_symbol_referencer::line_count (head) -1 >= rint (pos)
573 y += 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;
588 New_slur::generate_curves (Grob*me, Array<Slur_score> *scores)
592 Real staff_space = Staff_symbol_referencer::staff_space ((Grob*)me);
594 Real r_0 = robust_scm2double (me->get_property ("ratio"), 1);
595 Real h_inf = staff_space * ly_scm2double (me->get_property ("height-limit"));
596 for (int i = scores->size(); i-- ;)
598 (*scores)[i].curve_ = get_bezier (me, (*scores)[i].attachment_,
604 New_slur::enumerate_attachments (Grob * me, Grob *common[],
605 Slur_score_parameters * score_param,
606 Drul_array<Bound_info> extremes,
607 Drul_array<Offset> base_attachment,
608 Drul_array<Real> end_ys)
611 Array<Slur_score> scores;
613 Direction dir = get_grob_direction (me);
614 Real staff_space = Staff_symbol_referencer::staff_space ((Grob*)me);
616 Drul_array<Offset> os;
617 os[LEFT] = base_attachment[LEFT];
618 Real minimum_length = staff_space * robust_scm2double (me->get_property ("minimum-length"),
621 for (int i = 0; dir * os[LEFT][Y_AXIS] <= dir * end_ys[LEFT]; i++)
623 os[RIGHT] = base_attachment[RIGHT];
624 for (int j = 0; dir *os[RIGHT][Y_AXIS] <= dir * end_ys[RIGHT]; j++)
631 os[d][X_AXIS] = base_attachment[d][X_AXIS];
632 if (extremes[d].stem_
633 && !Stem::is_invisible (extremes[d].stem_)
634 && extremes[d].stem_dir_ == dir
637 if (extremes[d].stem_extent_[Y_AXIS].contains (os[d][Y_AXIS]))
639 os[d][X_AXIS] = extremes[d].slur_head_extent_[-d]
642 else if (dir *extremes[d].stem_extent_[Y_AXIS][dir] < dir * os[d][Y_AXIS])
644 os[d][X_AXIS] = extremes[d].stem_extent_[X_AXIS].center();
647 } while (flip (&d) != LEFT);
649 Offset dz = os[RIGHT] - os[LEFT];
650 if (dz[X_AXIS] < minimum_length
651 || fabs (dz[Y_AXIS] / dz[X_AXIS]) > score_param->MAX_SLOPE
655 if (extremes[d].slur_head_)
656 os[d][X_AXIS] = extremes[d].slur_head_extent_.center ();
657 } while (flip (&d) != LEFT);
663 os[RIGHT][Y_AXIS] += dir * staff_space / 2;
666 os[LEFT][Y_AXIS] += dir * staff_space /2 ;
674 New_slur::score_encompass (Grob * me, Grob *common[],
675 Slur_score_parameters * score_param,
677 Drul_array<Bound_info> extremes,
678 Drul_array<Offset> base_attach,
679 Array<Slur_score> * scores)
681 Link_array<Grob> encompasses =
682 Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-columns");
683 Direction dir = get_grob_direction (me);
685 Array<Encompass_info> infos;
687 for (int i = 0; i < encompasses.size(); i++)
688 infos.push (get_encompass_info (me, encompasses[i], common));
690 for (int i =0 ; i < scores->size (); i++)
692 Bezier const &bez (scores->elem (i).curve_);
694 for (int j = 0; j < infos.size(); j++)
696 Real x = infos[j].x_;
698 if (!(x < scores->elem (i).attachment_[RIGHT][X_AXIS]
699 && x > scores->elem (i).attachment_[LEFT][X_AXIS]))
702 Real y = bez.get_other_coordinate (X_AXIS, x);
704 if (j && j < infos.size () -1)
706 Real head_dy = (y - infos[j].head_);
707 if (dir * head_dy < 0)
709 demerit += score_param->HEAD_ENCOMPASS_PENALTY;
714 (head_dy) ? (1/fabs (head_dy) - 1/score_param->FREE_HEAD_DISTANCE)
715 : score_param->HEAD_ENCOMPASS_PENALTY;
716 hd = (hd >? 0)<? score_param->HEAD_ENCOMPASS_PENALTY;
721 if (dir * (y - infos[j].stem_) < 0)
722 demerit += score_param->STEM_ENCOMPASS_PENALTY;
723 else if (j && j < encompasses.size () - 1)
726 ext.add_point (infos[j].stem_);
727 ext.add_point (infos[j].head_);
729 demerit += - score_param->CLOSENESS_FACTOR * (dir * (y - (ext[dir] + dir * score_param->FREE_HEAD_DISTANCE)) <? 0) /
734 #if DEBUG_SLUR_QUANTING
735 (*scores)[i].score_card_ += to_string ("C%.2f", demerit);
738 (*scores)[i].score_ += demerit;
744 New_slur::score_edges (Grob * me, Grob *common[],
745 Slur_score_parameters * score_param,
747 Drul_array<Bound_info> extremes,
748 Drul_array<Offset> base_attach,
749 Array<Slur_score> * scores)
751 Direction dir = get_grob_direction (me);
753 for (int i =0 ; i < scores->size (); i++)
758 Real y = scores->elem (i).attachment_[d][Y_AXIS];
759 Real dy = fabs (y - base_attach[d][Y_AXIS]);
761 Real factor = score_param->EDGE_ATTRACTION_FACTOR;
764 score_param->EDGE_ATTRACTION_FACTOR
765 * fabs (scores->elem (i).attachment_[d][Y_AXIS] - base_attach[d][Y_AXIS]);
767 if (extremes[d].stem_
768 && extremes[d].stem_dir_ == dir
769 && !Stem::get_beaming (extremes[d].stem_, -d)
773 (*scores)[i].score_ += demerit;
774 #if DEBUG_SLUR_QUANTING
775 (*scores)[i].score_card_ += to_string ("E%.2f", demerit);
777 } while (flip (&d) != LEFT);
782 New_slur::score_slopes (Grob * me, Grob *common[],
783 Slur_score_parameters*score_param,
784 Drul_array<Bound_info> extremes,
785 Drul_array<Offset> base_attach,
786 Array<Slur_score> * scores)
788 Direction dir = get_grob_direction (me);
794 if (extremes[d].slur_head_)
795 ys[d] = extremes[d].slur_head_ ->relative_coordinate (common[Y_AXIS], Y_AXIS);
797 ys[d] = extremes[d].neighbor_y_;
798 } while (flip (&d) != LEFT);
801 (extremes[LEFT].stem_ && Stem::get_beam (extremes[LEFT].stem_))
802 || (extremes[RIGHT].stem_ && Stem::get_beam (extremes[RIGHT].stem_));
804 Real dy = ys[RIGHT] - ys[LEFT];
805 for (int i =0 ; i < scores->size (); i++)
807 Offset slur_dz = (*scores)[i].attachment_[RIGHT]
808 - (*scores)[i].attachment_[LEFT];
810 Real slur_dy = slur_dz[Y_AXIS];
817 0.2: account for staffline offset.
819 demerit += score_param->STEEPER_SLOPE_FACTOR * (dir * (fabs (slur_dy) - fabs (dy + 0.2)) >? 0);
821 demerit += ((fabs (slur_dy/slur_dz[X_AXIS]) - score_param->MAX_SLOPE)>?0) * score_param->MAX_SLOPE_FACTOR;
823 if (sign (dy) == 0 &&
825 demerit += score_param->NON_HORIZONTAL_PENALTY;
829 && sign (slur_dy) != sign (dy))
831 has_beams ? score_param->SAME_SLOPE_PENALTY/10 : score_param->SAME_SLOPE_PENALTY;
833 #if DEBUG_SLUR_QUANTING
834 (*scores)[i].score_card_ += to_string ("S%.2f",d);
836 (*scores)[i].score_ += demerit;
842 New_slur::get_curve (Grob*me)
846 for (SCM s= me->get_property ("control-points"); s != SCM_EOL; s = ly_cdr (s))
848 b.control_[i++] = ly_scm2offset (ly_car (s));
855 MAKE_SCHEME_CALLBACK (New_slur, height, 2);
857 New_slur::height (SCM smob, SCM ax)
859 Axis a = (Axis)ly_scm2int (ax);
860 Grob * me = unsmob_grob (smob);
861 assert (a == Y_AXIS);
863 SCM mol = me->get_uncached_stencil ();
865 if (Stencil * m = unsmob_stencil (mol))
867 return ly_interval2scm (ext);
871 Ugh should have dash-length + dash-period
873 MAKE_SCHEME_CALLBACK (New_slur, print,1);
875 New_slur::print (SCM smob)
877 Grob * me = unsmob_grob (smob);
878 if (!scm_ilength (me->get_property ("note-columns")))
884 Real base_thick = robust_scm2double (me->get_property ("thickness"), 1);
885 Real thick = base_thick * Staff_symbol_referencer::line_thickness (me);
887 Real ss = Staff_symbol_referencer::staff_space (me);
888 Bezier one = get_curve (me);
893 TODO: replace dashed with generic property.
895 SCM d = me->get_property ("dashed");
896 if (ly_c_number_p (d))
897 a = Lookup::dashed_slur (one, thick, thick * robust_scm2double (d, 0));
899 a = Lookup::slur (one, get_grob_direction (me) * base_thick * ss / 10.0,
902 #if DEBUG_SLUR_QUANTING
903 SCM quant_score = me->get_property ("quant-score");
905 if (to_boolean (me->get_paper ()->lookup_variable (ly_symbol2scm ("debug-slur-quanting"))) &&
906 ly_c_string_p (quant_score))
909 SCM properties = Font_interface::text_font_alist_chain (me);
911 Stencil tm = *unsmob_stencil (Text_item::interpret_markup
912 (me->get_paper ()->self_scm (), properties, quant_score));
913 a.add_at_edge (Y_AXIS, get_grob_direction (me), tm, 1.0, 0);
917 return a.smobbed_copy ();
924 ADD_INTERFACE (New_slur, "new-slur-interface",
926 "control-points dashed details direction height-limit note-columns ratio slope-limit thickness");