+2006-02-21 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+ * lily/tie-column.cc (calc_positioning_done): support for
+ tie-score debugging
+
+ * lily/tie-formatting-problem.cc
+ (generate_extremal_tie_variations): factor out.
+ (score_ties_configuration): annotate all tie
+ (print_ties_configuration): new routine.
+ (generate_configuration): nudge extremal ties outside of the head
+ Y extents.
+ (score_ties_configuration): oops. convert to staff-space before
+ determining position symmetry.
+
2006-02-20 Graham Percival <gpermus@gmail.com>
- * Documentation/user/ *-notation.itely: misc minor editing,
+ * Documentation/user/*-notation.itely: misc minor editing,
shifting doc sections around.
- * Documentation/user/ *-notation-itely, global.itely,
+ * Documentation/user/*-notation-itely, global.itely,
changing-defaults.itely: added new stuff from NEWS.
2006-02-20 Heikki Junes <hjunes@cc.hut.fi>
--- /dev/null
+\header {
+
+ texidoc = "Switching on debug-tie-scoring annotates the tie scoring
+decisions made."
+
+}
+
+\paper
+{
+ ragged-right = ##t
+ debug-tie-scoring = ##t
+}
+
+\relative g' {
+ <a b e f> ~
+ <a b e f>
+}
#include "staff-symbol-referencer.hh"
#include "stem.hh"
#include "warn.hh"
+#include "main.hh"
Real
get_detail (SCM alist, SCM sym, Real def)
Real yr;
Real demerits;
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
string score_card_;
#endif
};
xstaff, ¶meters);
qscores[i].demerits += d;
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
qscores[i].score_card_ += to_string ("S%.2f", d);
#endif
}
edge_beam_counts, ldir, rdir, ¶meters);
qscores[i].demerits += d;
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
qscores[i].score_card_ += to_string (" F %.2f", d);
#endif
}
qscores[i].yl, qscores[i].yr, ¶meters);
qscores[i].demerits += d;
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
qscores[i].score_card_ += to_string (" L %.2f", d);
#endif
}
int best_idx = best_quant_score_idx (qscores);
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
SCM inspect_quants = me->get_property ("inspect-quants");
- if (to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting")))
+ if (to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring")))
&& scm_is_pair (inspect_quants))
{
Drul_array<Real> ins = ly_scm2interval (inspect_quants);
qscores[best_idx].yr);
}
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
if (best_idx >= 0
- && to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting"))))
+ && to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring"))))
{
qscores[best_idx].score_card_ += to_string ("i%d", best_idx);
#include "beaming.hh"
#include "directional-element-interface.hh"
+#include "main.hh"
#include "international.hh"
#include "interval-set.hh"
#include "item.hh"
#include "stem.hh"
#include "warn.hh"
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
#include "text-interface.hh" // debug output.
#include "font-interface.hh" // debug output.
#endif
X_AXIS);
the_beam.translate_axis (pos[LEFT], Y_AXIS);
-#if (DEBUG_QUANTING)
+#if (DEBUG_BEAM_SCORING)
SCM quant_score = me->get_property ("quant-score");
- SCM debug = me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting"));
+ SCM debug = me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring"));
if (to_boolean (debug) && scm_is_string (quant_score))
{
static int forced_stem_count (Grob *);
};
-#ifndef NDEBUG
-#define DEBUG_QUANTING 1
-#endif
#endif /* BEAM_HH */
*/
#define DEBUG_SLUR_SCORING 1
+#define DEBUG_TIE_SCORING 1
+#define DEBUG_BEAM_SCORING 1
#endif /* MAIN_HH */
int index_;
-#if DEBUG_SLUR_SCORING
string score_card_;
-#endif
Slur_configuration ();
#ifndef TIE_CONFIGURATION_HH
#define TIE_CONFIGURATION_HH
+#include "main.hh"
#include "lily-proto.hh"
#include "direction.hh"
#include "interval.hh"
class Tie_configuration
{
+#if DEBUG_SLUR_SCORING
+ string score_card_;
+#endif
+ Real score_;
+ bool scored_;
+ friend class Tie_formatting_problem;
public:
+ Real score () const { return score_; }
+ string card () const { return score_card_; }
+
int position_;
Direction dir_;
Real delta_y_;
/* computed. */
Interval attachment_x_;
-
+
+ void add_score (Real, string);
Tie_configuration ();
void center_tie_vertically (Tie_details const &);
Bezier get_transformed_bezier (Tie_details const &) const;
INSTANTIATE_COMPARE (Tie_configuration, Tie_configuration::compare);
-typedef vector<Tie_configuration> Ties_configuration;
+class Ties_configuration : public vector<Tie_configuration>
+{
+ Real score_;
+ string score_card_;
+ bool scored_;
+ vector<string> tie_score_cards_;
+
+ friend class Tie_formatting_problem;
+public:
+ Ties_configuration ();
+ void add_score (Real amount, string description);
+ void add_tie_score (Real amount, int i, string description);
+ Real score () const;
+ void reset_score ();
+ string card () const;
+ string tie_card (int i) const { return tie_score_cards_[i]; }
+};
#endif /* TIE_CONFIGURATION_HH */
/*
- tie-formatting-problem.hh -- declare
+ tie-formatting-problem.hh -- declare Tie_formatting_problem
source file of the GNU LilyPond music typesetter
#include "skyline.hh"
#include "lily-proto.hh"
#include "tie-configuration.hh"
+#include "tie-details.hh"
#include <map>
#include <set>
-struct Tie_details
-{
- Real height_limit_;
- Real ratio_;
- Real staff_space_;
- Real x_gap_;
- Real stem_gap_;
- Real between_length_limit_;
- Real wrong_direction_offset_penalty_;
- Real min_length_penalty_factor_;
- Real min_length_;
- Real tip_staff_line_clearance_;
- Real center_staff_line_clearance_;
- Real staff_line_collision_penalty_;
- Real dot_collision_clearance_;
- Real dot_collision_penalty_;
- Real tie_column_monotonicity_penalty_;
- Real tie_tie_collision_penalty_;
- Real tie_tie_collision_distance_;
- Real horizontal_distance_penalty_factor_;
- Real vertical_distance_penalty_factor_;
- Real intra_space_threshold_;
- Real outer_tie_length_symmetry_penalty_factor_;
- Real outer_tie_vertical_distance_symmetry_penalty_factor_;
-
- Grob *staff_symbol_referencer_;
-
- Tie_details ();
- void from_grob (Grob *);
-};
-
-
typedef map< pair<int, int>, Tie_configuration *> Tie_configuration_map;
struct Tie_specification
{
Drul_array< vector<Skyline_entry> > chord_outlines_;
Drul_array< Box > stem_extents_;
+ Drul_array< Box > head_extents_;
set<int> dot_positions_;
Interval dot_x_;
vector<Tie_specification> specifications_;
Grob *x_refpoint_;
- Tie_configuration *get_configuration (int position, Direction dir);
+ Tie_configuration *get_configuration (int position, Direction dir) const;
Tie_configuration *generate_configuration (int position, Direction dir) const;
- vector<Tie_configuration_variation> get_variations (Ties_configuration const &ties);
-
- Real score_configuration (Tie_configuration const &) const;
- Real score_aptitude (Tie_configuration const &, Tie_specification const &) const;
- Real score_ties_aptitude (Ties_configuration const &ties) const;
- Real score_ties_configuration (Ties_configuration const &ties) const;
+ vector<Tie_configuration_variation> generate_collision_variations (Ties_configuration const &ties) const;
+ vector<Tie_configuration_variation> generate_extremal_tie_variations (Ties_configuration const &ties) const;
+
+ void score_configuration (Tie_configuration *) const;
+ Real score_aptitude (Tie_configuration *, Tie_specification const &,
+ Ties_configuration *, int) const;
+ void score_ties_aptitude (Ties_configuration *ties) const;
+ void score_ties_configuration (Ties_configuration *ties) const;
void set_ties_config_standard_directions (Ties_configuration *tie_configs_ptr);
- Real score_ties (Ties_configuration const&) const;
- Ties_configuration generate_base_chord_configuration ();
+ void score_ties (Ties_configuration *) const;
+ Ties_configuration generate_base_chord_configuration ();
+ Ties_configuration find_best_variation (Ties_configuration const &base,
+ vector<Tie_configuration_variation> vars);
+
public:
Tie_details details_;
-
+ void print_ties_configuration (Ties_configuration const *);
public:
Tie_formatting_problem ();
~Tie_formatting_problem ();
static Grob *head (Grob *, Direction);
static int get_column_rank (Grob *, Direction);
static int get_position (Grob *);
- static Direction get_default_dir (Grob *);
-
-#if 0
- static void get_configuration (Grob *, Tie_configuration *,
- Tie_formatting_problem const &);
-#endif
-
+ static Direction get_default_dir (Grob *);
static void set_control_points (Grob *, Grob *,
Tie_configuration const&,
Tie_details const&);
#include <cmath>
+#include "output-def.hh"
#include "skyline.hh"
#include "warn.hh"
#include "paper-column.hh"
problem.details_);
set_grob_direction (ties[i],
base[i].dir_);
+
+#if DEBUG_TIE_SCORING
+ if (to_boolean (me->layout ()
+ ->lookup_variable (ly_symbol2scm ("debug-tie-scoring"))))
+ {
+ string card = to_string ("%d (%.2f): ", base[i].position_, base[i].delta_y_)
+ + base[i].card () + base.tie_card (i);
+
+
+ if (i == 0)
+ card += base.card ();
+ if (i == base.size () - 1)
+ card += to_string ("TOTAL=%.2f", base.score ());
+
+ ties[i]->set_property ("quant-score",
+ scm_makfrom0str (card.c_str ()));
+ }
+#endif
+
}
return SCM_BOOL_T;
}
dir_ = CENTER;
position_ = 0;
delta_y_ = 0.0;
+ score_ = 0.0;
+ scored_ = false;
}
return d + (2 + (a.dir_ - b.dir_));
}
+
+void
+Tie_configuration::add_score (Real s, string desc)
+{
+ assert (!scored_);
+ score_ += s;
+ if (s)
+ score_card_ += to_string ("%s=%.2f ", desc.c_str (), s);
+}
+
Real
Tie_configuration::height (Tie_details const &details) const
{
details.height_limit_,
details.ratio_).curve_point (0.5)[Y_AXIS];
}
+
+Ties_configuration::Ties_configuration()
+{
+ score_ = 0.0;
+ scored_ = false;
+}
+
+void
+Ties_configuration::reset_score ()
+{
+ score_ = 0.0;
+ scored_ = false;
+ score_card_ = "";
+ tie_score_cards_.clear ();
+}
+
+void
+Ties_configuration::add_tie_score (Real s, int i, string desc)
+{
+ assert (!scored_);
+ score_ += s;
+ if (s)
+ {
+ while (tie_score_cards_.size () < size ())
+ tie_score_cards_.push_back ("");
+
+ tie_score_cards_[i] += to_string ("%s=%.2f ", desc.c_str (), s);
+ }
+}
+
+void
+Ties_configuration::add_score (Real s, string desc)
+{
+ assert (!scored_);
+ score_ += s;
+ if (s)
+ score_card_ += to_string ("%s=%.2f ", desc.c_str (), s);
+}
+
+Real
+Ties_configuration::score () const
+{
+ return score_;
+}
+
+string
+Ties_configuration::card () const
+{
+ return score_card_;
+}
return max (- epsilon * (x - threshold) / ((x + epsilon) * threshold), 0.0);
}
+void
+Tie_formatting_problem::print_ties_configuration (Ties_configuration const *ties)
+{
+ for (vsize i = 0; i < ties->size (); i++)
+ {
+ char const *man_pos = (specifications_[i].has_manual_position_) ? "(M)" : "";
+ char const *man_dir = (specifications_[i].has_manual_dir_) ? "(M)" : "";
+ char const *dir = (ties->at (i).dir_ == UP) ? "up" : "dn";
+
+ printf ("(P%d%s, %s%s) ", ties->at (i).position_, man_pos, dir, man_dir);
+ }
+ printf ("\n");
+}
+
Interval
Tie_formatting_problem::get_attachment (Real y) const
{
void
Tie_formatting_problem::set_chord_outline (vector<Item*> bounds,
- Direction d)
+ Direction dir)
{
Real staff_space = Staff_symbol_referencer::staff_space (bounds[0]);
boxes.push_back (Box (x, y));
Grob *dots = Rhythmic_head::get_dots (head);
- if (d == LEFT && dots)
+ if (dir == LEFT && dots)
{
Interval x = dots->extent (x_refpoint_, X_AXIS);
int p = int (Staff_symbol_referencer::get_position (dots));
}
}
- chord_outlines_[d] = empty_skyline (-d);
+ chord_outlines_[dir] = empty_skyline (-dir);
if (bounds[0]->break_status_dir ())
{
- Real x = robust_relative_extent (bounds[0], x_refpoint_, X_AXIS)[-d];
- chord_outlines_[d].at (0).height_ = x;
+ Real x = robust_relative_extent (bounds[0], x_refpoint_, X_AXIS)[-dir];
+ chord_outlines_[dir].at (0).height_ = x;
}
for (vsize i = 0; i < boxes.size (); i++)
- insert_extent_into_skyline (&chord_outlines_[d] ,
- boxes[i], Y_AXIS, -d);
+ insert_extent_into_skyline (&chord_outlines_[dir] ,
+ boxes[i], Y_AXIS, -dir);
if (stem
&& !Stem::is_invisible (stem))
y.add_point (Stem::head_positions (stem)[-stemdir]
* staff_space * .5);
- insert_extent_into_skyline (&chord_outlines_[d], Box (x,y), Y_AXIS, -d);
+ insert_extent_into_skyline (&chord_outlines_[dir], Box (x,y), Y_AXIS, -dir);
- stem_extents_[d].unite (Box (x,y));
+ stem_extents_[dir].unite (Box (x,y));
- if (d == LEFT)
+ if (dir == LEFT)
{
Box flag_box = Stem::get_translated_flag (stem).extent_box ();
flag_box.translate( Offset (x[RIGHT], X_AXIS));
- insert_extent_into_skyline (&chord_outlines_[d], flag_box,
- Y_AXIS, -d);
+ insert_extent_into_skyline (&chord_outlines_[dir], flag_box,
+ Y_AXIS, -dir);
}
}
{
Box b = boundary (head_boxes, updowndir, 0);
x = b[X_AXIS];
- x[-d] = b[X_AXIS].linear_combination (-d / 2);
+ x[-dir] = b[X_AXIS].linear_combination (-dir / 2);
y[-updowndir] = b[Y_AXIS][updowndir];
y[updowndir] = updowndir * infinity_f;
}
if (!x.is_empty ())
- insert_extent_into_skyline (&chord_outlines_[d],
+ insert_extent_into_skyline (&chord_outlines_[dir],
Box (x,y),
- Y_AXIS, -d);
+ Y_AXIS, -dir);
}
while (flip (&updowndir) != DOWN);
+
+ head_extents_[dir].set_empty ();
+ for (vsize i = 0; i < head_boxes.size (); i++)
+ {
+ head_extents_[dir].unite (head_boxes[i]);
+ }
}
Tie_configuration*
-Tie_formatting_problem::get_configuration (int pos, Direction dir)
+Tie_formatting_problem::get_configuration (int pos, Direction dir) const
{
pair<int,int> key (pos, dir);
Tie_configuration_map::const_iterator f = possibilities_.find (key);
Tie_configuration *conf = generate_configuration (pos, dir);
- possibilities_[key] = conf;
+ ((Tie_formatting_problem*) this)->possibilities_[key] = conf;
return conf;
}
conf->dir_ = dir;
Real y = conf->position_ * 0.5 * details_.staff_space_;
+
+ bool y_tune = true;
if (dot_positions_.find (pos) != dot_positions_.end ())
{
conf->delta_y_ += 0.25 * details_.staff_space_;
+ y_tune = false;
}
+
+
- conf->attachment_x_ = get_attachment (y + conf->delta_y_);
-
- Real h = conf->height (details_);
-
- if (h < details_.intra_space_threshold_ * 0.5 * details_.staff_space_)
+ if (y_tune
+ && max (fabs (head_extents_[LEFT][Y_AXIS][dir] - y),
+ fabs (head_extents_[RIGHT][Y_AXIS][dir] - y)) < 0.25
+ && !Staff_symbol_referencer::on_line (details_.staff_symbol_referencer_, pos))
{
- /*
- This is less sensible for long ties, since those are more
- horizontal.
- */
- Interval close_by = get_attachment (y
- + conf->delta_y_
- + (dir * details_.intra_space_threshold_ * 0.25
- * details_.staff_space_));
-
- conf->attachment_x_.intersect (close_by);
+ conf->delta_y_ =
+ (head_extents_[LEFT][Y_AXIS][dir] - y)
+ + dir * details_.outer_tie_vertical_gap_;
}
-
- if (!conf->delta_y_)
+
+ if (y_tune)
{
+ conf->attachment_x_ = get_attachment (y + conf->delta_y_);
+ Real h = conf->height (details_);
+
/*
TODO:
}
}
- /*
- we don't recompute attachment_x_ to take changed Y (through
- delta_Y) into account. Doing would make ties go into small holes between heads, which
- means we get collisions with neighboring heads.
- */
+ conf->attachment_x_ = get_attachment (y + conf->delta_y_);
+ if (conf->height (details_) < details_.intra_space_threshold_ * 0.5 * details_.staff_space_)
+ {
+ /*
+ This is less sensible for long ties, since those are more
+ horizontal.
+ */
+ Interval close_by = get_attachment (y
+ + conf->delta_y_
+ + (dir * details_.intra_space_threshold_ * 0.25
+ * details_.staff_space_));
+
+ conf->attachment_x_.intersect (close_by);
+ }
+
conf->attachment_x_.widen ( - details_.x_gap_);
Direction d = LEFT;
return conf;
}
+/**
+ TIE_IDX and TIES_CONF are optional.
+ */
Real
-Tie_formatting_problem::score_aptitude (Tie_configuration const &conf,
- Tie_specification const &spec) const
+Tie_formatting_problem::score_aptitude (Tie_configuration *conf,
+ Tie_specification const &spec,
+ Ties_configuration *ties_conf, int tie_idx) const
{
Real penalty = 0.0;
- Real curve_y = conf.position_ * details_.staff_space_ * 0.5 + conf.delta_y_;
+ Real curve_y = conf->position_ * details_.staff_space_ * 0.5 + conf->delta_y_;
Real tie_y = spec.position_ * details_.staff_space_ * 0.5;
- if (sign (curve_y - tie_y) != conf.dir_)
- penalty += details_.wrong_direction_offset_penalty_;
-
- penalty += details_.vertical_distance_penalty_factor_ * fabs (curve_y - tie_y);
-
+ if (sign (curve_y - tie_y) != conf->dir_)
+ {
+ Real p = details_.wrong_direction_offset_penalty_;
+ if (ties_conf)
+ ties_conf->add_tie_score (p, tie_idx, "wrong dir");
+ else
+ penalty += p;
+ }
+ {
+ Real p = details_.vertical_distance_penalty_factor_ * fabs (curve_y - tie_y);
+ if (ties_conf)
+ ties_conf->add_tie_score (p, tie_idx, "vdist");
+ else
+ penalty += p;
+ }
+
Direction d = LEFT;
do
{
continue;
Interval head_x = spec.note_head_drul_[d]->extent (x_refpoint_, X_AXIS);
- Real dist = head_x.distance (conf.attachment_x_[d]);
- penalty += details_.horizontal_distance_penalty_factor_ * dist;
+ Real dist = head_x.distance (conf->attachment_x_[d]);
+
+ /*
+ TODO: flatten with log or sqrt.
+ */
+ Real p = details_.horizontal_distance_penalty_factor_ * dist;
+ if (ties_conf)
+ ties_conf->add_tie_score (p, tie_idx,
+ (d == LEFT) ? "lhdist" : "rhdist");
+ else
+ penalty += p;
}
- while (flip (&d) != LEFT);
+ while (flip (&d) != LEFT);
return penalty;
}
-Real
-Tie_formatting_problem::score_configuration (Tie_configuration const &conf) const
+void
+Tie_formatting_problem::score_configuration (Tie_configuration *conf) const
{
- Real penalty = 0.0;
- Real length = conf.attachment_x_.length ();
-
- penalty +=
- details_.min_length_penalty_factor_
- * peak_around (0.33 * details_.min_length_, details_.min_length_, length);
+ if (conf->scored_)
+ {
+ return ;
+ }
+
+ Real length = conf->attachment_x_.length ();
- Real tip_pos = conf.position_ + conf.delta_y_ / 0.5 * details_.staff_space_;
+ conf->add_score (details_.min_length_penalty_factor_
+ * peak_around (0.33 * details_.min_length_, details_.min_length_, length),
+ "minlength");
+
+ Real tip_pos = conf->position_ + conf->delta_y_ / 0.5 * details_.staff_space_;
Real tip_y = tip_pos * details_.staff_space_ * 0.5;
- Real height = conf.height (details_);
+ Real height = conf->height (details_);
- Real top_y = tip_y + conf.dir_ * height;
+ Real top_y = tip_y + conf->dir_ * height;
Real top_pos = 2 * top_y / details_.staff_space_;
Real round_top_pos = rint (top_pos);
if (Staff_symbol_referencer::on_line (details_.staff_symbol_referencer_,
int (round_top_pos))
&& Staff_symbol_referencer::staff_radius (details_.staff_symbol_referencer_) > top_y)
{
- penalty +=
+ conf->add_score (
details_.staff_line_collision_penalty_
* peak_around (0.1 * details_.center_staff_line_clearance_,
details_.center_staff_line_clearance_,
- fabs (top_pos - round_top_pos));
+ fabs (top_pos - round_top_pos)),
+ "line center");
}
if (Staff_symbol_referencer::on_line (details_.staff_symbol_referencer_,
int (rint (tip_pos))))
{
- penalty += details_.staff_line_collision_penalty_
- * peak_around (0.1 * details_.tip_staff_line_clearance_,
- details_.tip_staff_line_clearance_,
- fabs (tip_pos - rint (tip_pos)));
+ conf->add_score (details_.staff_line_collision_penalty_
+ * peak_around (0.1 * details_.tip_staff_line_clearance_,
+ details_.tip_staff_line_clearance_,
+ fabs (tip_pos - rint (tip_pos))),
+ "tipline");
}
if (!dot_x_.is_empty ())
/* use left edge? */
Real x = dot_x_.center ();
- Bezier b = conf.get_transformed_bezier (details_);
+ Bezier b = conf->get_transformed_bezier (details_);
if (b.control_point_extent (X_AXIS).contains (x))
{
Real y = b.get_other_coordinate (X_AXIS, x);
i != dot_positions_.end (); i ++)
{
int dot_pos = (*i);
- penalty +=
- details_.dot_collision_penalty_
+ conf->add_score (details_.dot_collision_penalty_
* peak_around (.1 * details_.dot_collision_clearance_,
details_.dot_collision_clearance_,
- fabs (dot_pos * details_.staff_space_ * 0.5 - y));
+ fabs (dot_pos * details_.staff_space_ * 0.5 - y)),
+ "dot collision");
}
}
}
-
- return penalty;
+
+ conf->scored_ = true;
}
Tie_configuration
int pos = spec.position_;
Direction dir = spec.manual_dir_;
- int region_size = 3;
- for (int i = 0; i < region_size; i ++)
+ for (int i = 0; i < details_.single_tie_region_size_; i ++)
{
confs.push_back (generate_configuration (pos + i * dir, dir));
}
Real best_score = 1e6;
for (vsize i = 0; i < confs.size (); i ++)
{
- Real score = 0.0;
- score += score_configuration (*confs[i]);
- score += score_aptitude (*confs[i], spec);
+ score_configuration (confs[i]);
+ Real score = score_aptitude (confs[i], spec, 0, 0)
+ + confs[i]->score ();
if (score < best_score)
{
}
-Real
-Tie_formatting_problem::score_ties_aptitude (Ties_configuration const &ties) const
+void
+Tie_formatting_problem::score_ties_aptitude (Ties_configuration *ties) const
{
- Real score = 0.0;
- if (ties.size () != specifications_.size ())
+ if (ties->size () != specifications_.size ())
{
programming_error ("Huh? Mismatch between sizes.");
- return infinity_f;
+ return;
}
- for (vsize i = 0; i < ties.size (); i++)
- score += score_aptitude (ties[i], specifications_[i]);
-
- return score;
+ for (vsize i = 0; i < ties->size (); i++)
+ score_aptitude (&ties->at (i), specifications_[i],
+ ties, i);
}
-Real
-Tie_formatting_problem::score_ties (Ties_configuration const &ties) const
+void
+Tie_formatting_problem::score_ties (Ties_configuration *ties) const
{
- return score_ties_configuration (ties)
- + score_ties_aptitude (ties);
+ if (ties->scored_)
+ return;
+
+ score_ties_configuration (ties);
+ score_ties_aptitude (ties);
+ ties->scored_ = true;
}
-Real
-Tie_formatting_problem::score_ties_configuration (Ties_configuration const &ties) const
+void
+Tie_formatting_problem::score_ties_configuration (Ties_configuration *ties) const
{
- Real score = 0.0;
- for (vsize i = 0; i < ties.size (); i++)
+ for (vsize i = 0; i < ties->size (); i++)
{
- score += score_configuration (ties[i]);
+ score_configuration (&ties->at (i));
+ ties->add_tie_score (ties->at (i).score (), i, "conf");
}
-
+
Real last_edge = 0.0;
Real last_center = 0.0;
- for (vsize i = 0; i < ties.size (); i++)
+ for (vsize i = 0; i < ties->size (); i++)
{
- Bezier b (ties[i].get_transformed_bezier (details_));
+ Bezier b (ties->at (i).get_transformed_bezier (details_));
Real center = b.curve_point (0.5)[Y_AXIS];
Real edge = b.curve_point (0.0)[Y_AXIS];
if (i)
{
if (edge <= last_edge)
- score += details_.tie_column_monotonicity_penalty_;
+ ties->add_score (details_.tie_column_monotonicity_penalty_, "monoton edge");
if (center <= last_center)
- score += details_.tie_column_monotonicity_penalty_;
-
- score +=
- details_.tie_tie_collision_penalty_ *
- peak_around (0.1 * details_.tie_tie_collision_distance_,
- details_.tie_tie_collision_distance_,
- fabs (center - last_center));
- score +=
- details_.tie_tie_collision_penalty_ *
- peak_around (0.1 * details_.tie_tie_collision_distance_,
- details_.tie_tie_collision_distance_,
- fabs (edge - last_edge));
+ ties->add_score (details_.tie_column_monotonicity_penalty_, "monoton cent");
+
+ ties->add_score (details_.tie_tie_collision_penalty_ *
+ peak_around (0.1 * details_.tie_tie_collision_distance_,
+ details_.tie_tie_collision_distance_,
+ fabs (center - last_center)),
+ "tietie center");
+ ties->add_score (details_.tie_tie_collision_penalty_ *
+ peak_around (0.1 * details_.tie_tie_collision_distance_,
+ details_.tie_tie_collision_distance_,
+ fabs (edge - last_edge)), "tietie edge");
}
last_edge = edge;
last_center = center;
}
-
- score +=
- details_.outer_tie_length_symmetry_penalty_factor_
- * fabs (ties[0].attachment_x_.length () - ties.back ().attachment_x_.length ());
-
- score +=
- details_.outer_tie_vertical_distance_symmetry_penalty_factor_
- * (fabs (specifications_[0].position_
- - (ties[0].position_ * 0.5 * details_.staff_space_ + ties[0].delta_y_))
- -
- fabs (specifications_.back ().position_
- - (ties.back ().position_ * 0.5 * details_.staff_space_ + ties.back ().delta_y_)));
+ ties->add_score (details_.outer_tie_length_symmetry_penalty_factor_
+ * fabs (ties->at (0).attachment_x_.length () - ties->back ().attachment_x_.length ()),
+ "length symm");
- return score;
+ ties->add_score (details_.outer_tie_vertical_distance_symmetry_penalty_factor_
+ * fabs (fabs (specifications_[0].position_ * 0.5 * details_.staff_space_
+ - (ties->at (0).position_ * 0.5 * details_.staff_space_
+ + ties->at (0).delta_y_))
+ -
+ fabs (specifications_.back ().position_ * 0.5 * details_.staff_space_
+ - (ties->back ().position_ * 0.5 * details_.staff_space_
+ + ties->back ().delta_y_))),
+ "pos symmetry");
}
/*
}
Ties_configuration
-Tie_formatting_problem::generate_optimal_chord_configuration ()
+Tie_formatting_problem::find_best_variation (Ties_configuration const &base,
+ vector<Tie_configuration_variation> vars)
{
- Ties_configuration base = generate_base_chord_configuration ();
- vector<Tie_configuration_variation> vars = get_variations (base);
-
Ties_configuration best = base;
- Real best_score = score_ties (best);
-
+
/*
This simply is 1-opt: we have K substitions, and we try applying
exactly every one for each.
*/
for (vsize i = 0; i < vars.size (); i++)
{
- Ties_configuration variant = base;
+ Ties_configuration variant (base);
variant[vars[i].index_] = *vars[i].suggestion_;
- Real score = score_ties (variant);
- if (score < best_score)
+ variant.reset_score ();
+ score_ties (&variant);
+
+ if (variant.score () < best.score ())
{
best = variant;
- best_score = score;
}
}
return best;
}
+
+
+
+Ties_configuration
+Tie_formatting_problem::generate_optimal_chord_configuration ()
+{
+
+ Ties_configuration base = generate_base_chord_configuration ();
+ vector<Tie_configuration_variation> vars = generate_collision_variations (base);
+
+ score_ties (&base);
+ Ties_configuration best = find_best_variation (base, vars);
+ vars = generate_extremal_tie_variations (best);
+ best = find_best_variation (best, vars);
+
+ return best;
+}
void
Tie_formatting_problem::set_ties_config_standard_directions (Ties_configuration *tie_configs)
}
vector<Tie_configuration_variation>
-Tie_formatting_problem::get_variations (Ties_configuration const &ties)
+Tie_formatting_problem::generate_extremal_tie_variations (Ties_configuration const &ties) const
+{
+ vector<Tie_configuration_variation> vars;
+ Direction d = DOWN;
+ do
+ {
+ if (boundary (ties, d, 0).dir_ == d
+ && !boundary (specifications_, d, 0).has_manual_position_)
+ for (int i = 1; i <= details_.multi_tie_region_size_; i++)
+ {
+ Tie_configuration_variation var;
+ var.index_ = (d == DOWN) ? 0 : ties.size () - 1;
+ var.suggestion_ = get_configuration (boundary (ties, d, 0).position_
+ + d * i, d);
+ vars.push_back (var);
+ }
+ }
+ while (flip (&d) != DOWN);
+
+ return vars;
+}
+
+
+vector<Tie_configuration_variation>
+Tie_formatting_problem::generate_collision_variations (Ties_configuration const &ties) const
{
Real center_distance_tolerance = 0.25;
vars.push_back (var);
}
+
+ if (i == 1 && !specifications_[i-1].has_manual_position_
+ && ties[i-1].dir_ == DOWN)
+ {
+ Tie_configuration_variation var;
+ var.index_ = i-1;
+ var.suggestion_ = get_configuration (specifications_[i-1].position_
+ - 1, DOWN);
+ vars.push_back (var);
+ }
+ if (i == ties.size() && !specifications_[i].has_manual_position_
+ && ties[i].dir_ == UP)
+ {
+ Tie_configuration_variation var;
+ var.index_ = i;
+ var.suggestion_ = get_configuration (specifications_[i].position_
+ + 1, UP);
+ vars.push_back (var);
+ }
}
else if (dot_positions_.find (ties[i].position_) != dot_positions_.end ()
&& !specifications_[i].has_manual_position_)
last_center = center;
}
- /* TODO: switch off? */
- Direction d = DOWN;
- do
- {
- if (boundary (ties, d, 0).dir_ == d)
- {
- Tie_configuration_variation var;
- var.index_ = (d == DOWN) ? 0 : ties.size () - 1;
- var.suggestion_ = get_configuration (boundary (ties, d, 0).position_
- + d, d);
- vars.push_back (var);
- }
- }
- while (flip (&d) != DOWN);
return vars;
}
-/*
- tie-helper.cc -- implement Tie_configuration, Tie_details
-
- source file of the GNU LilyPond music typesetter
-
- (c) 2005--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
-
-*/
-
-#include "tie.hh"
-#include "bezier.hh"
-#include "grob.hh"
-#include "staff-symbol-referencer.hh"
-#include "warn.hh"
-#include "tie-formatting-problem.hh"
-
-
-/*
- this is a macro because we want ly_symbol2scm()
- */
-#define get_real_detail(src, defvalue) \
- robust_scm2double(ly_assoc_get (ly_symbol2scm (src), details, SCM_EOL), defvalue)
-
-void
-Tie_details::from_grob (Grob *me)
-{
- staff_symbol_referencer_ = me;
- staff_space_ = Staff_symbol_referencer::staff_space (me);
-
- SCM details = me->get_property ("details");
-
- height_limit_ = get_real_detail("height-limit", 0.75);
- ratio_ = get_real_detail("ratio", .333);
- between_length_limit_ = get_real_detail ("between-length-limit", 1.0);
-
- wrong_direction_offset_penalty_ = get_real_detail("wrong-direction-offset-penalty", 10);
-
- min_length_ = get_real_detail("min-length", 1.0);
- min_length_penalty_factor_ = get_real_detail("min-length-penalty-factor", 1.0);
-
-
- // in half-space
- center_staff_line_clearance_ = get_real_detail ("center-staff-line-clearance", 0.4);
- tip_staff_line_clearance_ = get_real_detail ("tip-staff-line-clearance", 0.4);
- staff_line_collision_penalty_ = get_real_detail("staff-line-collision-penalty", 5);
- dot_collision_clearance_ = get_real_detail ( "dot-collision-clearance", 0.25);
- dot_collision_penalty_ = get_real_detail ( "dot-collision-penalty", 0.25);
- x_gap_ = get_real_detail ("note-head-gap", 0.2);
- stem_gap_ = get_real_detail ("stem-gap", 0.3);
- tie_column_monotonicity_penalty_ = get_real_detail ("tie-column-monotonicity-penalty", 100);
- tie_tie_collision_penalty_ = get_real_detail ("tie-tie-collision-penalty", 30);
- tie_tie_collision_distance_ = get_real_detail ("tie-tie-collision-distance", .25);
- horizontal_distance_penalty_factor_ = get_real_detail ("horizontal-distance-penalty-factor", 5);
- vertical_distance_penalty_factor_ = get_real_detail ("vertical-distance-penalty-factor", 5);
- intra_space_threshold_ = get_real_detail ("intra-space-threshold", 1.0);
- outer_tie_length_symmetry_penalty_factor_ = get_real_detail ("outer-tie-length-symmetry-penalty-factor", 3.0);
- outer_tie_vertical_distance_symmetry_penalty_factor_ = get_real_detail ("outer-tie-vertical-distance-symmetry-penalty-factor", 3.0);
-
-}
-
-Tie_details::Tie_details ()
-{
- staff_space_ = 1.0;
- height_limit_ = 1.0;
- ratio_ = .333;
-}
-
*/
#include "tie.hh"
-#include "spanner.hh"
+
+#include "main.hh"
+#include "bezier.hh"
+#include "directional-element-interface.hh"
+#include "font-interface.hh"
+#include "grob-array.hh"
#include "lookup.hh"
+#include "note-head.hh"
#include "output-def.hh"
-#include "rhythmic-head.hh"
-#include "bezier.hh"
#include "paper-column.hh"
-#include "warn.hh"
+#include "rhythmic-head.hh"
+#include "spanner.hh"
#include "staff-symbol-referencer.hh"
-#include "directional-element-interface.hh"
-#include "bezier.hh"
#include "stem.hh"
-#include "note-head.hh"
+#include "text-interface.hh"
#include "tie-column.hh"
-#include "grob-array.hh"
-#include "tie-formatting-problem.hh"
#include "tie-configuration.hh"
+#include "tie-formatting-problem.hh"
+#include "warn.hh"
int
get_grob_direction (me) * base_thick,
line_thick);
+#if DEBUG_TIE_SCORING
+ SCM quant_score = me->get_property ("quant-score");
+
+ if (to_boolean (me->layout ()
+ ->lookup_variable (ly_symbol2scm ("debug-tie-scoring")))
+ && scm_is_string (quant_score))
+ {
+ string str;
+ SCM properties = Font_interface::text_font_alist_chain (me);
+
+ Stencil tm = *unsmob_stencil (Text_interface::interpret_markup
+ (me->layout ()->self_scm (), properties,
+ quant_score));
+ tm.translate_axis (b.control_[0][Y_AXIS]*2, Y_AXIS);
+ a.add_at_edge (X_AXIS, RIGHT, tm, 1.0, 0);
+ }
+#endif
+
return a.smobbed_copy ();
}
conversions.append (((2, 7, 32), conv,
"""foobar -> foo-bar for \paper, \layout"""))
+
+def conv (str):
+ str = re.sub ('debug-beam-quanting', 'debug-beam-scoring', str)
+ return str
+
+conversions.append (((2, 7, 32), conv,
+ """debug-beam-quanting -> debug-beam-scoring"""))
(heads ,ly:grob-array? "List of note heads.")
(items-worth-living ,ly:grob-array? "A list of interesting items. If
empty in a particular staff, then that staff is erased.")
- (details ,list? "alist of parameters for detailed grob behavior.")
+ (details ,list? "alist of parameters for detailed grob behavior.
+
+more information on the allowed parameters can be found by inspecting
+lily/slur-scoring.cc, lily/beam-quanting.cc, and
+lily/tie-formatting-problem.cc. Setting @code{debug-tie-scoring},
+@code{debug-beam-scoring} or @code{debug-slur-scoring} also provides
+useful clues.
+
+")
(note-heads ,ly:grob-array? "List of note head grobs")
(note-head ,ly:grob? "A single note head")
(side-support-elements ,ly:grob-array? "the support, a list of grobs.")
. (
(avoid-slur . inside)
(cautionary-style . parentheses)
-
(stencil . ,ly:accidental-interface::print)
(after-line-breaking
. ,ly:accidental-interface::after-line-breaking)
-
(meta . ((class . Item)
(interfaces . (accidental-interface
font-interface))))))
(axes . (0 1))
(X-extent . ,ly:axis-group-interface::width)
(X-extent . ,ly:axis-group-interface::height)
-
(space-alist . (
(clef . (extra-space . 0.5))
(key-signature . (extra-space . 0.0))
(AmbitusLine
. (
-
(stencil . ,ly:ambitus::print)
-
(join-heads . #t)
(thickness . 2)
(X-offset . ,ly:self-alignment-interface::centered-on-x-parent)
-
(meta . ((class . Item)
(interfaces . (ambitus-interface
staff-symbol-referencer-interface
(X-offset . ,ly:side-position-interface::x-aligned-side)
(direction . ,LEFT)
(cautionary-style . parentheses)
-
(stencil . ,ly:accidental-interface::print)
(after-line-breaking . ,ly:accidental-interface::after-line-breaking)
(side-axis . ,X)
-
(meta . ((class . Item)
(interfaces . (item-interface
accidental-interface
(AmbitusNoteHead
. (
(duration-log . 2)
-
(stencil . ,ly:note-head::print)
(glyph-name . ,note-head::calc-glyph-name)
-
(Y-offset . ,ly:staff-symbol-referencer::callback)
(meta . ((class . Item)
(interfaces . (font-interface
(BassFigure
. (
- ;
(stencil . ,ly:text-interface::print)
-
(meta . ((class . Item)
(interfaces . (text-interface
rhythmic-grob-interface
(breakable . #t)
(X-extent . #f)
(Y-extent . #f)
-
(stencil . ,ly:line-spanner::print)
(after-line-breaking . ,ly:line-spanner::after-line-breaking)
-
-
(meta . ((class . Spanner)
(interfaces . (line-interface
line-spanner-interface))))))
(stencil . ,ly:grid-line-interface::print)
(self-alignment-X . ,CENTER)
(X-offset . ,(ly:make-simple-closure
- `(,+ ,(ly:make-simple-closure (list ly:self-alignment-interface::centered-on-x-parent))
- ,(ly:make-simple-closure (list ly:self-alignment-interface::x-aligned-on-self)))))
+ `(,+ ,(ly:make-simple-closure
+ (list ly:self-alignment-interface::centered-on-x-parent))
+ ,(ly:make-simple-closure
+ (list ly:self-alignment-interface::x-aligned-on-self)))))
(layer . 0)
(meta . ((class . Item)
(interfaces . (self-alignment-interface
(LedgerLineSpanner
. (
(springs-and-rods . ,ly:ledger-line-spanner::set-spacing-rods)
-
(stencil . ,ly:ledger-line-spanner::print)
-
(X-extent . #f)
(Y-extent . #f)
(minimum-length-fraction . 0.25)
(minimum-distance . 0.1)
(padding . 0.07)
(springs-and-rods . ,ly:hyphen-spanner::set-spacing-rods)
-
(stencil . ,ly:hyphen-spanner::print)
-
(Y-extent . (0 . 0))
(meta . ((class . Spanner)
(interfaces . (lyric-interface
(LyricExtender
. (
-
(stencil . ,ly:lyric-extender::print)
-
(thickness . 0.8) ; line-thickness
(minimum-length . 1.5)
(Y-extent . (0 . 0))
. (
(Y-offset . ,ly:side-position-interface::y-aligned-side)
(side-axis . ,Y)
-
(stencil . ,ly:measure-grouping::print)
-
(padding . 2)
(direction . ,UP)
(thickness . 1)
(thickness . 1.4)
(flexa-width . 2.0)
(stencil . ,ly:mensural-ligature::print)
-
(meta . ((class . Spanner)
(interfaces . (mensural-ligature-interface
font-interface))))))
,(ly:make-simple-closure (list ly:self-alignment-interface::x-centered-on-y-parent)))))
(Y-offset . ,ly:side-position-interface::y-aligned-side)
(side-axis . ,Y)
-
(self-alignment-X . 0)
(direction . ,UP)
(padding . 0.4)
(NoteCollision
. (
(axes . (0 1))
-
(X-extent . ,ly:axis-group-interface::width)
(Y-extent . ,ly:axis-group-interface::height)
(positioning-done . ,ly:note-collision-interface::calc-positioning-done)
-
(meta . ((class . Item)
(interfaces . (note-collision-interface
axis-group-interface))))))
(axes . (0 1))
(X-extent . ,ly:axis-group-interface::width)
(Y-extent . ,ly:axis-group-interface::height)
-
(meta . ((class . Item)
(interfaces . (axis-group-interface
note-column-interface))))))
(NoteHead
. (
-
(stencil . ,ly:note-head::print)
(stem-attachment . ,ly:note-head::calc-stem-attachment)
(glyph-name . ,note-head::calc-glyph-name)
;; Changed this from 0.75.
;; If you ever change this back, please document! --hwn
(knee-spacing-correction . 1.0)
-
(meta . ((class . Item)
(interfaces . (spacing-interface
note-spacing-interface))))))
(NoteName
. (
-
(stencil . ,ly:text-interface::print)
-
(meta . ((class . Item)
(interfaces . (note-name-interface
text-interface
,(ly:make-simple-closure (list ly:self-alignment-interface::centered-on-x-parent)))))
(Y-offset . ,ly:side-position-interface::y-aligned-side)
-
(stencil . ,ly:text-interface::print)
-
;; no Y dimensions, because of lyrics under tenor clef.
(Y-extent . (0 . 0))
(font-shape . italic)
(OttavaBracket
. (
(Y-offset . ,ly:side-position-interface::y-aligned-side)
-
(stencil . ,ly:ottava-bracket::print)
-
(font-shape . italic)
(shorten-pair . (0.0 . -0.6))
(staff-padding . 1.0)
))
(PhrasingSlur
. ((details . ,default-slur-details)
-
(control-points . ,ly:slur::calc-control-points)
(direction . ,ly:slur::calc-direction)
(springs-and-rods . ,ly:spanner::set-spacing-rods)
(Y-extent . ,ly:slur::height)
(stencil . ,ly:slur::print)
-
-
(thickness . 1.1)
(minimum-length . 1.5)
(height-limit . 2.0)
(NonMusicalPaperColumn
. (
(axes . (0))
-
(before-line-breaking . ,ly:paper-column::before-line-breaking)
(X-extent . ,ly:axis-group-interface::width)
;; (stencil . ,ly:paper-column::print)
(PercentRepeat
. (
-
(springs-and-rods . ,ly:multi-measure-rest::set-spacing-rods)
(stencil . ,ly:multi-measure-rest::percent)
-
(slope . 1.0)
(thickness . 0.48)
(font-encoding . fetaMusic)
;; an example of a text spanner
(PianoPedalBracket
. (
-
(stencil . ,ly:piano-pedal-bracket::print)
-
(style . line)
(bound-padding . 1.0)
(direction . ,DOWN)
. (
(minimum-distance . 0.75)
(positioning-done . ,ly:rest-collision::calc-positioning-done)
-
(meta . ((class . Item)
(interfaces . (rest-collision-interface))))))
(stencil . ,ly:script-interface::print)
(direction . ,ly:script-interface::calc-direction)
-
(font-encoding . fetaMusic)
(meta . ((class . Item)
(interfaces . (script-interface
(ScriptColumn
. (
-
(before-line-breaking . ,ly:script-column::before-line-breaking)
-
(meta . ((class . Item)
(interfaces . (script-column-interface))))))
(SeparatingGroupSpanner
. (
-
(springs-and-rods . ,ly:separating-group-spanner::set-spacing-rods)
-
(meta . ((class . Spanner)
(interfaces . (only-prebreak-interface
spacing-interface
(Slur
. ((details . ,default-slur-details)
-
(control-points . ,ly:slur::calc-control-points)
(direction . ,ly:slur::calc-direction)
(springs-and-rods . ,ly:spanner::set-spacing-rods)
(Y-extent . ,ly:slur::height)
(stencil . ,ly:slur::print)
-
(thickness . 1.2)
(line-thickness . 0.8)
(minimum-length . 1.5)
- ; ly:slur::height)
(height-limit . 2.0)
(ratio . 0.25)
(meta . ((class . Spanner)
(SpacingSpanner
. (
-
(springs-and-rods . ,ly:spacing-spanner::set-springs)
(average-spacing-wishes . #t)
(grace-space-factor . 0.6)
(Y-extent . ())
(layer . 0)
(breakable . #t)
-
(stencil . ,ly:span-bar::print)
(bar-size . ,ly:span-bar::calc-bar-size)
(X-extent . ,ly:span-bar::width)
(StanzaNumber
. (
(stencil . ,ly:text-interface::print)
-
(font-series . bold)
(padding . 1.0)
(X-offset . ,ly:side-position-interface::x-aligned-side)
(StringNumber
. (
-
(stencil . ,print-circled-text-callback)
-
(padding . 0.5)
(staff-padding . 0.5)
(self-alignment-X . 0)
(SostenutoPedal
. (
-
(stencil . ,ly:text-interface::print)
-
(direction . ,RIGHT)
(X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
(no-spacing-rods . #t)
(SostenutoPedalLineSpanner
. (
(axes . (1))
-
(X-extent . ,ly:axis-group-interface::height)
-
(Y-offset . ,ly:side-position-interface::y-aligned-side)
(side-axis . ,Y)
-
(padding . 1.2)
(minimum-space . 1.0)
(direction . ,DOWN)
(X-extent . ,ly:stem::width)
(Y-extent . ,ly:stem::height)
(length . ,ly:stem::calc-length)
-
(thickness . 1.3)
-
(details
. (
;; 3.5 (or 3 measured from note head) is standard length
(TabNoteHead
. (
-
(stencil . ,ly:text-interface::print)
(Y-offset . ,ly:staff-symbol-referencer::callback)
(font-size . -2)
(avoid-slur . inside)
(direction . ,ly:tie::calc-direction)
(stencil . ,ly:tie::print)
+ (font-size . -6)
(details . (
;; for a full list, see tie-helper.cc
(ratio . 0.333)
(intra-space-threshold . 1.25)
(outer-tie-vertical-distance-symmetry-penalty-factor . 10)
(outer-tie-length-symmetry-penalty-factor . 10)
+ (outer-tie-vertical-gap . 0.25)
+ (multi-tie-region-size . 1)
(between-length-limit . 1.0)))
(thickness . 1.2)
(line-thickness . 0.8)