From b8991734f29f7487f62f9b5172e04b3cbfc00c39 Mon Sep 17 00:00:00 2001
From: Han-Wen Nienhuys <hanwen@xs4all.nl>
Date: Sun, 21 Jul 2002 23:19:19 +0000
Subject: [PATCH] * lily/accidental-placement.cc (position_accidentals):
 document two bugcases.

* lily/skyline.cc (skyline_meshing_distance): bugfixes.
---
 ChangeLog                                | 11 ++++
 input/regression/accidental-placement.ly |  2 +-
 lily/accidental-placement.cc             | 58 +++++++++++++--------
 lily/accidental.cc                       | 65 +++++++++++++++++++++---
 lily/include/accidental-interface.hh     | 26 ++++++++++
 lily/skyline.cc                          | 20 +++++---
 mf/feta-toevallig.mf                     |  2 +-
 7 files changed, 148 insertions(+), 36 deletions(-)
 create mode 100644 lily/include/accidental-interface.hh

diff --git a/ChangeLog b/ChangeLog
index c37fee0484..edcfb73721 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+
+2002-07-22  Han-Wen  <hanwen@cs.uu.nl>
+
+	* lily/accidental-placement.cc (position_accidentals): document
+	two bugcases.
+
+	* lily/skyline.cc (skyline_meshing_distance): bugfixes.
+
 2002-07-22  Jan Nieuwenhuizen  <janneke@gnu.org>
 
 	* scripts/lilypond-book.py (make_pixmap): Don't use quiet_system,
@@ -11,6 +19,9 @@
 
 2002-07-21  Han-Wen  <hanwen@cs.uu.nl>
 
+	* lily/accidental.cc (accurate_boxes): add function to represent
+	flat with 2 boxes. Improves flat-flat accidental spacing. 
+
 	* lily/accidental-placement.cc (stagger_apes): try to arrange accs
 	in a C form, with the top accidental closet to the chord.
 
diff --git a/input/regression/accidental-placement.ly b/input/regression/accidental-placement.ly
index 6011fcc201..ce86f02981 100644
--- a/input/regression/accidental-placement.ly
+++ b/input/regression/accidental-placement.ly
@@ -13,7 +13,7 @@ flats in a sixth shoudl be staggered.  "
   <bis4 es gis>
   <es! as!>
   <gis! cis!>
-  <g! des!>
+  <g! des'>
   <ges! es'!>
 }    
     <cis4 d es fis gis ases bes ces d dis >
diff --git a/lily/accidental-placement.cc b/lily/accidental-placement.cc
index 1f102415c5..eae952d0eb 100644
--- a/lily/accidental-placement.cc
+++ b/lily/accidental-placement.cc
@@ -18,6 +18,7 @@ source file of the GNU LilyPond music typesetter
 #include "note-column.hh"
 #include "group-interface.hh"
 #include "note-collision.hh"
+#include "accidental-interface.hh"
 
 MAKE_SCHEME_CALLBACK(Accidental_placement,extent_callback, 2);
 SCM
@@ -186,11 +187,9 @@ stagger_apes (Link_array<Accidental_placement_entry> *apes)
    The naturals should be left of the C as well; they should
    be separate accs.
 
-   TODO: Try to combine Apes before sorting them: this will allow a
-   better placement.
+   Note that this placement problem looks NP hard, so we just use a
+   simple strategy, not an optimal choice.
 
-   Note that this placement problem is almost certainly NP hard, so we
-   just use a simple strategy, not an optimal choice.
 */
 
 SCM
@@ -198,6 +197,10 @@ Accidental_placement::position_accidentals (Grob * me)
 {
   SCM accs = me->get_grob_property ("accidentals");
 
+  /*
+    TODO: there is a bug in this code. If two accs are on the same
+    Y-position, they share an Ape, and will be pritned in overstrike.
+   */
   Link_array<Accidental_placement_entry> apes;
   for (SCM s = accs; gh_pair_p (s); s =gh_cdr (s))
     {
@@ -211,7 +214,7 @@ Accidental_placement::position_accidentals (Grob * me)
     }
 
 
-  Grob *commony =0 ;
+  Grob *common[] = {me, 0};
 
   /*
     First we must extract *all* pointers. We can only determine
@@ -224,8 +227,12 @@ Accidental_placement::position_accidentals (Grob * me)
       for (int j = ape->grobs_.size(); j--;)
 	{
 	  Grob * a = ape->grobs_[j];
+
+	  if (common[Y_AXIS])
+	    common[Y_AXIS] = common[Y_AXIS]->common_refpoint (a, Y_AXIS);
+	  else
+	    common[Y_AXIS] = a;
 	  
-	  commony = commony->common_refpoint (a, Y_AXIS);
 	  Grob *head = a->get_parent (Y_AXIS);
 
 	  Grob * col = head->get_parent (X_AXIS);
@@ -261,7 +268,7 @@ Accidental_placement::position_accidentals (Grob * me)
     }
   heads.default_sort();
   heads.uniq();
-  commony = common_refpoint_of_array (heads, commony, Y_AXIS);
+  common[Y_AXIS] = common_refpoint_of_array (heads, common[Y_AXIS], Y_AXIS);
 
   
   for (int i= apes.size (); i--;)
@@ -273,18 +280,15 @@ Accidental_placement::position_accidentals (Grob * me)
       for (int j = apes[i]->grobs_.size(); j--;)
 	{
 	  Grob * a = apes[i]->grobs_[j];
-	  Box b;
-	  b[X_AXIS] = a->extent (me, X_AXIS);
-	  b[Y_AXIS] = a->extent (commony, Y_AXIS);
 
-	  ape->extents_.push (b);
+	  Array<Box> boxes = Accidental_interface::accurate_boxes (a, common);
 	  
-	  /*
-	    TODO: replace the extents of a flat by combination of two
-	    bboxes, so that we use the shape of the flat better.
-	  */
-	  insert_extent_into_skyline (&ape->left_skyline_, b, Y_AXIS, LEFT);
-	  insert_extent_into_skyline (&ape->right_skyline_ , b,Y_AXIS, RIGHT);
+	  ape->extents_.concat (boxes);
+	  for (int j  = boxes.size(); j--;)
+	    {
+	      insert_extent_into_skyline (&ape->left_skyline_, boxes[j], Y_AXIS, LEFT);
+	      insert_extent_into_skyline (&ape->right_skyline_ , boxes[j], Y_AXIS, RIGHT);
+	    }
 	}
     }
 
@@ -305,13 +309,13 @@ Accidental_placement::position_accidentals (Grob * me)
   stagger_apes (&apes);
 
   Accidental_placement_entry * head_ape = new Accidental_placement_entry;
-  Grob *commonx = common_refpoint_of_array (heads, me, X_AXIS);  
+  common[X_AXIS] = common_refpoint_of_array (heads, common[X_AXIS], X_AXIS);  
   Array<Skyline_entry> head_skyline (empty_skyline (LEFT));
   Array<Box> head_extents;
   for (int i = heads.size(); i--;)
     {
-      Box b(heads[i]->extent (commonx, X_AXIS),
-	    heads[i]->extent (commony, Y_AXIS));
+      Box b(heads[i]->extent (common[X_AXIS] , X_AXIS),
+	    heads[i]->extent (common[Y_AXIS], Y_AXIS));
 
       insert_extent_into_skyline (&head_skyline, b , Y_AXIS, LEFT);
     }
@@ -328,7 +332,19 @@ Accidental_placement::position_accidentals (Grob * me)
   SCM spad = me->get_grob_property ("padding");
   if (gh_number_p (spad))
     padding = gh_scm2double (spad);
-  
+
+
+  /*
+    TODO:
+
+    There is a bug in this code: the left_skylines should be
+    accumulated, otherwise the b will collide with bb in
+
+      bb
+    b 
+      n 
+    
+   */
   apes.push (head_ape);
   for (int i= apes.size () -1 ; i-- > 0;)
     {
diff --git a/lily/accidental.cc b/lily/accidental.cc
index 3792933d87..39d43277c4 100644
--- a/lily/accidental.cc
+++ b/lily/accidental.cc
@@ -1,6 +1,7 @@
 #include "font-interface.hh"
 #include "item.hh"
 #include "molecule.hh"
+#include "accidental-interface.hh"
 
 /*
   TODO: insert support for smaller cautionaries, tie-break-reminders.
@@ -10,13 +11,7 @@
   accidental-placement.cc
 
 */
-class Accidental_interface
-{
-public:
-  DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM));
-  DECLARE_SCHEME_CALLBACK (after_line_breaking, (SCM));  
-  static bool has_interface (Grob*);
-};
+
 
 Molecule
 parenthesize (Grob*me, Molecule m)
@@ -43,7 +38,63 @@ Accidental_interface::after_line_breaking (SCM smob)
     }
   return SCM_UNSPECIFIED;
 }
+
+Array<Box>
+Accidental_interface::accurate_boxes (Grob *a,Grob**common)
+{
+  Box b;
+  b[X_AXIS] = a->extent (a, X_AXIS);
+  b[Y_AXIS] = a->extent (a, Y_AXIS);
+
+  Array<Box> boxes;
+  
+  bool parens = false;
+  if (to_boolean (a->get_grob_property ("cautionary")))
+    {
+      SCM cstyle = a->get_grob_property ("cautionary-style");
+      parens = gh_equal_p (cstyle, ly_symbol2scm ("parentheses"));
+
+    }
+
+  SCM accs = a->get_grob_property ("accidentals");
+  SCM scm_style = a->get_grob_property ("style");
+  if (!gh_symbol_p (scm_style)
+      && !parens
+      && scm_ilength (accs) == 1)
+    {
+      if (gh_scm2int (gh_car (accs)) == -1)
+	{
+	  Box stem = b;
+	  Box bulb = b;
+
+	  /*
+	    we could make the stem thinner, but that places the flats
+	    really close.
+	  */
+	  stem[X_AXIS][RIGHT] *= .5;
+	  bulb[Y_AXIS][UP] *= .35;
+
+	  boxes.push (bulb);
+	  boxes.push (stem);
+	}
+      /*
+	TODO: add support for natural, double flat.
+       */
+    }
+
+  if (!boxes.size())
+    boxes.push (b);
+
+  Offset o (a->relative_coordinate (common[X_AXIS],  X_AXIS),
+	    a->relative_coordinate (common[Y_AXIS],  Y_AXIS));
+  for(int i = boxes.size(); i--;)
+    {
+      boxes[i].translate(o);
+    }
   
+  return boxes;
+}
+
 MAKE_SCHEME_CALLBACK (Accidental_interface,brew_molecule,1);
 SCM
 Accidental_interface::brew_molecule (SCM smob)
diff --git a/lily/include/accidental-interface.hh b/lily/include/accidental-interface.hh
new file mode 100644
index 0000000000..c2dd022327
--- /dev/null
+++ b/lily/include/accidental-interface.hh
@@ -0,0 +1,26 @@
+/*   
+accidental-interface.hh -- declare  Accidental_interface
+
+source file of the GNU LilyPond music typesetter
+
+(c) 2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ */
+
+#ifndef ACCIDENTAL_INTERFACE_HH
+#define ACCIDENTAL_INTERFACE_HH
+
+#include "grob.hh"
+
+class Accidental_interface
+{
+public:
+  DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM));
+  DECLARE_SCHEME_CALLBACK (after_line_breaking, (SCM));  
+  static bool has_interface (Grob*);
+  
+  static Array<Box> Accidental_interface::accurate_boxes (Grob *me,Grob**common);
+};
+
+
+#endif
diff --git a/lily/skyline.cc b/lily/skyline.cc
index 9857fe4955..5fa51eed62 100644
--- a/lily/skyline.cc
+++ b/lily/skyline.cc
@@ -38,6 +38,8 @@
  */
 
 
+const Real EPS = 1e-12;  
+
 /*
   TODO: avoid unnecessary fragmentation.
 
@@ -53,27 +55,33 @@ insert_extent_into_skyline (Array<Skyline_entry> *line, Box b, Axis line_axis,
     return;
   
   Real stick_out = b[other_axis (line_axis)][d];
-  
+
+  /*
+    Intersect each segment of LINE with EXTENT, and if non-empty, insert relevant segments. 
+   */
   for (int i = line->size(); i--;)
     {
       Interval w = line->elem(i).width_;
-      if (extent[LEFT] > w[RIGHT])
+      w.intersect (extent);
+
+      if (extent[LEFT] >= w[RIGHT])
 	break;
       
-      w.intersect (extent);
       Real my_height = line->elem(i).height_;
 
-      if (!w.empty_b () && d* (my_height - stick_out) < 0)
+      if (!w.empty_b () &&
+	  w.length() > EPS
+	  && d* (my_height - stick_out) < 0)
 	{
 	  Interval e1 (line->elem(i).width_[LEFT], extent[LEFT]);
 	  Interval e3 (extent[RIGHT], line->elem(i).width_[RIGHT]);
 
-	  if (!e3.empty_b ())
+	  if (!e3.empty_b () && e3.length() > EPS)
 	    line->insert (Skyline_entry (e3, my_height), i+1);
 
 	  line->elem_ref(i).height_ = stick_out;
 	  line->elem_ref(i).width_ = w;
-	  if (!e1.empty_b ())
+	  if (!e1.empty_b () && e1.length() > EPS)
 	    line->insert (Skyline_entry (e1, my_height), i );
 	}
 
diff --git a/mf/feta-toevallig.mf b/mf/feta-toevallig.mf
index 3363568582..b9e2b48fab 100644
--- a/mf/feta-toevallig.mf
+++ b/mf/feta-toevallig.mf
@@ -261,7 +261,7 @@ fet_beginchar("Double Flat", "-2", "flatflat")
 	left_wid = .7;
 	right_wid = .8;
 	overlap = .05;
-	set_char_box(1.2 stafflinethickness#, (left_wid + right_wid -overlap) *staff_space#, .5 staff_space#, 2 staff_space#);
+	set_char_box(1.2 stafflinethickness#, (left_wid + right_wid -overlap) *staff_space#, .6 staff_space#, 2 staff_space#);
 	draw_meta_flat(0, left_wid*  staff_space, 1/3 staff_space);
 	draw_meta_flat((left_wid - overlap) *staff_space,  
 		right_wid *staff_space, 1/3 staff_space);
-- 
2.39.5