* Rewrite stem_beams.
* Use Number_pair i.s.o Interval to represent (yl, yr).
+
*/
-
-
#include <math.h> // tanh.
#include "molecule.hh"
const int INTER_QUANT_PENALTY = 1000;
const int SECONDARY_BEAM_DEMERIT = 15;
const int STEM_LENGTH_DEMERIT_FACTOR = 5;
-const int STEM_LENGTH_LIMIT_PENALTY = 500;
+// possibly ridiculous, but too short stems just won't do
+const int STEM_LENGTH_LIMIT_PENALTY = 5000;
const int DAMPING_DIRECTIION_PENALTY = 800;
const int MUSICAL_DIRECTION_FACTOR = 400;
const int IDEAL_SLOPE_FACTOR = 10;
+const int REGION_SIZE = 2;
static Real
}
/* Call list of y-dy-callbacks, that handle setting of
- grob-properties y, dy.
-
- User may set grob-properties: y-position-hs and height-hs
- (to be fixed) that override the calculated y and dy.
-
- Because y and dy cannot be calculated and quanted separately, we
- always calculate both, then check for user override. */
+ grob-properties
+
+*/
MAKE_SCHEME_CALLBACK (Beam, after_line_breaking, 1);
SCM
Beam::after_line_breaking (SCM smob)
for (int i= 0; i < stems.size(); i++)
{
Grob*s = stems[i];
- stem_infos.push( Stem::calc_stem_info (s));
+ stem_infos.push (Stem::calc_stem_info (s));
+ dirs_found[stem_infos.top ().dir_] = true;
- Real b = calc_stem_y (me, s, Interval (1,0));
+ Real b = calc_stem_y (me, s, Interval (1,0), false);
lbase_lengths.push (b);
- b = calc_stem_y (me, s, Interval (0,1));
- rbase_lengths.push (b);
-
- dirs_found [stem_infos.top().dir_] = true;
+ Real a = calc_stem_y (me, s, Interval (0,1), false);
+ rbase_lengths.push (a);
}
Direction ldir = Direction (stem_infos[0].dir_);
Direction rdir = Direction (stem_infos.top ().dir_);
bool knee_b = dirs_found[LEFT] && dirs_found[RIGHT];
-
- int REGION_SIZE = 2;
+ int region_size = REGION_SIZE;
/*
Knees are harder, lets try some more possibilities for knees.
*/
if (knee_b)
- REGION_SIZE += 2 ;
+ region_size += 2;
- for (int i = -REGION_SIZE ; i < REGION_SIZE; i++)
+ for (int i = -region_size ; i < region_size; i++)
for (int j = 0; j < num_quants; j++)
{
quantsl.push (i + quants[j] + int (yl));
{
Real demerit_score = 0.0 ;
Real pen = STEM_LENGTH_LIMIT_PENALTY;
- if (knee)
- pen = sqrt(pen);
-
+
for (int i=0; i < stems.size (); i++)
{
Grob* s = stems[i];
Stem_info info = stem_infos[i];
Direction d = info.dir_;
- demerit_score += pen * ( 0 >? (info.dir_ *(info.shortest_y_ - current_y)));
+ demerit_score += pen
+ * ( 0 >? (info.dir_ * (info.shortest_y_ - current_y)));
+
demerit_score += STEM_LENGTH_DEMERIT_FACTOR
* shrink_extra_weight (d * current_y - info.dir_ * info.ideal_y_);
}
Interval ideal (Stem::calc_stem_info (first_visible_stem (me)).ideal_y_,
Stem::calc_stem_info (last_visible_stem (me)).ideal_y_);
+
+
+
+ Array<Real> x_posns ;
+ Link_array<Item> stems=
+ Pointer_group_interface__extract_grobs (me, (Item*)0, "stems");
+ Grob *common = stems[0];
+ for (int i=1; i < stems.size (); i++)
+ common = stems[i]->common_refpoint (common, X_AXIS);
+
+ Real x0 = first_visible_stem (me)->relative_coordinate (common, X_AXIS);
+ for (int i=0; i < stems.size (); i++)
+ {
+ Item* s = stems[i];
+
+ Real x = s->relative_coordinate (common, X_AXIS) - x0;
+ x_posns.push (x);
+ }
+ Real dx = last_visible_stem (me)->relative_coordinate (common, X_AXIS) - x0;
+
+ Real y =0;
+ Real dydx = 0;
+ Real dy = 0;
if (!ideal.delta ())
{
/*
- TODO : use scoring for this.
+ TODO -- use scoring for this.
complicated, because we take stem-info.ideal for determining
beam slopes.
-
*/
/* Make simple beam on middle line have small tilt */
if (!ideal[LEFT] && chord.delta () && count == 2)
{
pos = ideal;
}
+
+ y = pos[LEFT];
+ dy = pos[RIGHT]- y;
+ dydx = dy/dx;
}
else
{
Array<Offset> ideals;
-
- // ugh -> use commonx
- Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS);
- Link_array<Item> stems=
- Pointer_group_interface__extract_grobs (me, (Item*)0, "stems");
-
for (int i=0; i < stems.size (); i++)
{
Item* s = stems[i];
if (Stem::invisible_b (s))
continue;
- ideals.push (Offset (s->relative_coordinate (0, X_AXIS) - x0,
+ ideals.push (Offset (x_posns[i],
Stem::calc_stem_info (s).ideal_y_));
}
- Real y;
- Real dydx;
minimise_least_squares (&dydx, &y, ideals);
- Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0;
- Real dy = dydx * dx;
+ dy = dydx * dx;
me->set_grob_property ("least-squares-dy", gh_double2scm (dy));
-
pos = Interval (y, (y+dy));
}
me->set_grob_property ("positions", ly_interval2scm (pos));
+
return SCM_UNSPECIFIED;
}
+
+/*
+ We can't combine with previous function, since check concave and
+ slope damping comes first.
+ */
+MAKE_SCHEME_CALLBACK (Beam, shift_region_to_valid, 1);
+SCM
+Beam::shift_region_to_valid (SCM grob)
+{
+ Grob *me = unsmob_grob (grob);
+ /*
+ Code dup.
+ */
+ Array<Real> x_posns ;
+ Link_array<Item> stems=
+ Pointer_group_interface__extract_grobs (me, (Item*)0, "stems");
+ Grob *common = stems[0];
+ for (int i=1; i < stems.size (); i++)
+ common = stems[i]->common_refpoint (common, X_AXIS);
+
+ Grob *fvs = first_visible_stem (me);
+
+ if (!fvs)
+ return SCM_UNSPECIFIED;
+
+ Real x0 =fvs->relative_coordinate (common, X_AXIS);
+ for (int i=0; i < stems.size (); i++)
+ {
+ Item* s = stems[i];
+
+ Real x = s->relative_coordinate (common, X_AXIS) - x0;
+ x_posns.push (x);
+ }
+
+ Grob *lvs = last_visible_stem (me);
+ if (!lvs)
+ return SCM_UNSPECIFIED;
+
+ Real dx = lvs->relative_coordinate (common, X_AXIS) - x0;
+
+ Interval pos = ly_scm2interval ( me->get_grob_property ("positions"));
+ Real dy = pos.delta();
+ Real y = pos[LEFT];
+ Real dydx =dy/dx;
+
+
+ /*
+ Shift the positions so that we have a chance of finding good
+ quants (i.e. no short stem failures.)
+ */
+ Interval feasible_left_point;
+ feasible_left_point.set_full ();
+ for (int i=0; i < stems.size (); i++)
+ {
+ Item* s = stems[i];
+ if (Stem::invisible_b (s))
+ continue;
+
+
+ Direction d = Stem::get_direction (s);
+
+
+ Real left_y = Stem::calc_stem_info (s).shortest_y_
+ - dydx * x_posns [i];
+
+ Interval flp ;
+ flp.set_full ();
+ flp[-d] = left_y;
+
+ feasible_left_point.intersect (flp);
+ }
+
+ if (feasible_left_point.empty_b())
+ {
+ warning (_("Not sure that we can find a nice beam slope (no viable initial configuration found)."));
+ }
+ else if (!feasible_left_point.elem_b(y))
+ {
+ if (isinf (feasible_left_point[DOWN]))
+ y = feasible_left_point[UP] - REGION_SIZE;
+ else if (isinf (feasible_left_point[UP]))
+ y = feasible_left_point[DOWN]+ REGION_SIZE;
+ else
+ y = feasible_left_point.center ();
+ }
+ pos = Interval (y, (y+dy));
+ me->set_grob_property ("positions", ly_interval2scm (pos));
+ return SCM_UNSPECIFIED;
+}
+
+
MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
SCM
Beam::check_concave (SCM smob)
/*
Calculate the Y position of the stem-end, given the Y-left, Y-right
in POS, and for stem S.
+
+ If CORRECT, correct for multiplicity of beam in case of knees.
+
+
+ TODO: junk CORRECT from this.
*/
Real
-Beam::calc_stem_y (Grob *me, Grob* s, Interval pos)
+Beam::calc_stem_y (Grob *me, Grob* s, Interval pos, bool correct)
{
int beam_multiplicity = get_multiplicity (me);
int stem_multiplicity = (Stem::duration_log (s) - 2) >? 0;
+
Real thick = gh_scm2double (me->get_grob_property ("thickness"));
Real interbeam = get_interbeam (me);
// ugh -> use commonx
- Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS);
- Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0;
+ Grob * fvs = first_visible_stem (me);
+ Grob *lvs = last_visible_stem (me);
+
+ Real x0 = fvs ? fvs->relative_coordinate (0, X_AXIS) : 0.0;
+ Real dx = fvs ? lvs->relative_coordinate (0, X_AXIS) - x0 : 0.0;
+ Real r = s->relative_coordinate (0, X_AXIS) - x0;
Real dy = pos.delta ();
Real stem_y = (dy && dx
- ? (s->relative_coordinate (0, X_AXIS) - x0) / dx
+ ? r / dx
* dy
: 0) + pos[LEFT];
-
- Direction first_dir = Directional_element_interface::get (first_visible_stem (me));
Direction my_dir = Directional_element_interface::get (s);
+ Direction first_dir = fvs? Directional_element_interface::get (fvs) : my_dir;
- if (my_dir != first_dir)
+ if (correct && my_dir != first_dir)
{
/*
WTF is happening here ?
--hwn.
*/
+
+ // FIXME, hairy stuff
stem_y += my_dir * (thick / 2 + (beam_multiplicity - 1) * interbeam);
// huh, why not for first visible?
else
programming_error ("No last visible stem");
}
-
return stem_y;
}
if (Stem::invisible_b (s))
continue;
- Real stem_y = calc_stem_y (me, s, pos);
+ Real stem_y = calc_stem_y (me, s, pos, true);
#if 0
// doesn't play well with dvips
Real dydx = dy && dx ? dy/dx : 0;
- Direction firstdir = Directional_element_interface::get ( Beam::first_visible_stem (me) );
-
for (int i=0; i < stems.size (); i++)
{
Item *item = stems[i];
Real x = item->relative_coordinate (0, X_AXIS) - x0;
sb.translate (Offset (x, x * dydx + pos[LEFT]));
- Direction sd = Stem::get_direction (item);
+
mol.add_molecule (sb);
}