]> git.donarmstrong.com Git - lilypond.git/blob - lily/lookup.cc
''
[lilypond.git] / lily / lookup.cc
1 /*
2   lookup.cc -- implement simple Lookup methods.
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7
8   Jan Nieuwenhuizen <janneke@gnu.org>
9
10   TODO
11       Glissando
12 */
13 #include <math.h>
14 #include <ctype.h>
15
16 #include "warn.hh"
17 #include "dimensions.hh"
18 #include "bezier.hh"
19 #include "string-convert.hh"
20 #include "file-path.hh"
21 #include "main.hh"
22 #include "lily-guile.hh"
23 #include "molecule.hh"
24 #include "lookup.hh"
25 #include "font-metric.hh"
26
27 Molecule 
28 Lookup::beam (Real slope, Real width, Real thick) 
29 {
30   Real height = slope * width; 
31   Real min_y = (0 <? height) - thick/2;
32   Real max_y = (0 >? height) + thick/2;
33
34   
35
36   Box b (Interval (0, width),
37          Interval (min_y, max_y));
38
39   
40   SCM at = scm_list_n (ly_symbol2scm ("beam"),
41                     gh_double2scm (width),
42                     gh_double2scm (slope),
43                     gh_double2scm (thick),
44                     SCM_UNDEFINED);
45   return Molecule (b, at);
46 }
47
48 Molecule
49 Lookup::dashed_slur (Bezier b, Real thick, Real dash)
50 {
51   SCM l = SCM_EOL;
52
53   for (int i= 4; i -- ;)
54     {
55       l = gh_cons (ly_offset2scm (b.control_[i]), l);
56     }
57
58   SCM at = (scm_list_n (ly_symbol2scm ("dashed-slur"),
59                                gh_double2scm (thick), 
60                                gh_double2scm (dash),
61                                ly_quote_scm (l),
62                                SCM_UNDEFINED));
63
64   Box box (Interval (0,0),Interval (0,0));
65   return   Molecule (box, at);
66 }
67
68 Molecule
69 Lookup::line (Real th, Offset f, Offset t)
70 {
71   SCM at = (scm_list_n (ly_symbol2scm ("draw-line"),
72                         gh_double2scm (th), 
73                         gh_double2scm (f[X_AXIS]),
74                         gh_double2scm (f[Y_AXIS]),
75                         gh_double2scm (t[X_AXIS]),
76                         gh_double2scm (t[Y_AXIS]),
77                         SCM_UNDEFINED));
78
79   Box box;
80   box.add_point (f);
81   box.add_point (t);
82
83   box[X_AXIS].widen (th/2);
84   box[Y_AXIS].widen (th/2);  
85
86   return Molecule (box, at);
87 }
88
89
90 Molecule
91 Lookup::blank (Box b) 
92 {
93   return Molecule (b, SCM_EOL);
94 }
95
96 Molecule
97 Lookup::filledbox (Box b) 
98 {
99   SCM  at  = (scm_list_n (ly_symbol2scm ("filledbox"),
100                      gh_double2scm (-b[X_AXIS][LEFT]),
101                      gh_double2scm (b[X_AXIS][RIGHT]),                 
102                      gh_double2scm (-b[Y_AXIS][DOWN]),
103                      gh_double2scm (b[Y_AXIS][UP]),                    
104                      SCM_UNDEFINED));
105
106   return Molecule (b,at);
107 }
108
109 /*
110  * round filled box:
111  *
112  *   __________________________________
113  *  /     \  ^           /     \      ^
114  * |         |blot              |     |
115  * |       | |dia       |       |     |
116  * |         |meter             |     |
117  * |\ _ _ /  v           \ _ _ /|     |
118  * |                            |     |
119  * |                            |     | Box
120  * |                    <------>|     | extent
121  * |                      blot  |     | (Y_AXIS)
122  * |                    diameter|     |
123  * |                            |     |
124  * |  _ _                  _ _  |     |
125  * |/     \              /     \|     |
126  * |                            |     |
127  * |       |            |       |     |
128  * |                            |     |
129  * x\_____/______________\_____/|_____v
130  * |(0,0)                       |
131  * |                            |
132  * |                            |
133  * |<-------------------------->|
134  *       Box extent(X_AXIS)
135  */
136 Molecule
137 Lookup::roundfilledbox (Box b, Real blotdiameter)
138 {
139   if (b.x ().length () < blotdiameter)
140     {
141       programming_error (_f ("round filled box horizontal extent smaller than blot; decreasing blot"));
142       blotdiameter = b.x ().length ();
143     }
144   if (b.y ().length () < blotdiameter)
145     {
146       programming_error (_f ("round filled box vertical extent smaller than blot; decreasing blot"));
147       blotdiameter = b.y ().length ();
148     }
149
150   SCM at = (scm_list_n (ly_symbol2scm ("roundfilledbox"),
151                         gh_double2scm (-b[X_AXIS][LEFT]),
152                         gh_double2scm (b[X_AXIS][RIGHT]),
153                         gh_double2scm (-b[Y_AXIS][DOWN]),
154                         gh_double2scm (b[Y_AXIS][UP]),
155                         gh_double2scm (blotdiameter),
156                         SCM_UNDEFINED));
157
158   return Molecule (b,at);
159 }
160
161 Molecule
162 Lookup::frame (Box b, Real thick)
163 {
164   Molecule m;
165   Direction d = LEFT;
166   Axis a = X_AXIS;
167   while (a < NO_AXES)
168     {
169       do
170         {
171           Axis o = Axis ((a+1)%NO_AXES);
172
173           Box edges;
174           edges[a] = b[a][d] + 0.5 * thick * Interval (-1, 1);
175           edges[o][DOWN] = b[o][DOWN] - thick/2;
176           edges[o][UP] = b[o][UP] + thick/2;      
177           
178           m.add_molecule (filledbox (edges));
179         }
180       while (flip (&d) != LEFT);
181     }
182   return m;
183   
184 }
185
186 /*
187   Make a smooth curve along the points 
188  */
189 Molecule
190 Lookup::slur (Bezier curve, Real curvethick, Real linethick) 
191 {
192   Real alpha = (curve.control_[3] - curve.control_[0]).arg ();
193   Bezier back = curve;
194   Offset perp = curvethick * complex_exp (Offset (0, alpha + M_PI/2)) * 0.5;
195   back.reverse ();
196   back.control_[1] += perp;
197   back.control_[2] += perp;
198
199   curve.control_[1] -= perp;
200   curve.control_[2] -= perp;
201   
202   SCM scontrols[8];
203
204   for (int i=4; i--;)
205     scontrols[ i ] = ly_offset2scm (back.control_[i]);
206   for (int i=4 ; i--;)
207     scontrols[i+4] = ly_offset2scm (curve.control_[i]);
208
209   /*
210     Need the weird order b.o. the way PS want its arguments  
211    */
212   int indices[]= {5, 6, 7, 4, 1, 2, 3, 0};
213   SCM list = SCM_EOL;
214   for (int i= 8; i--;)
215     {
216       list = gh_cons (scontrols[indices[i]], list);
217     }
218   
219   
220   SCM at = (scm_list_n (ly_symbol2scm ("bezier-sandwich"),
221                      ly_quote_scm (list),
222                      gh_double2scm (linethick),
223                      SCM_UNDEFINED));
224   Box b(curve.extent (X_AXIS),
225         curve.extent (Y_AXIS));
226
227   b[X_AXIS].unite (back.extent (X_AXIS));
228   b[Y_AXIS].unite (back.extent (Y_AXIS));
229
230   return Molecule (b, at);
231 }
232
233 /*
234  * Bezier Sandwich:
235  *
236  *                               .|
237  *                        .       |
238  *              top .             |
239  *              . curve           |
240  *          .                     |
241  *       .                        |
242  *     .                          |
243  *    |                           |
244  *    |                          .|
245  *    |                     .
246  *    |         bottom .
247  *    |            . curve
248  *    |         .
249  *    |      .
250  *    |   .
251  *    | .
252  *    |.
253  *    |
254  *
255  */
256 Molecule
257 Lookup::bezier_sandwich (Bezier top_curve, Bezier bottom_curve)
258 {
259   /*
260     Need the weird order b.o. the way PS want its arguments  
261    */
262   SCM list = SCM_EOL;
263   list = gh_cons (ly_offset2scm (bottom_curve.control_[3]), list);
264   list = gh_cons (ly_offset2scm (bottom_curve.control_[0]), list);
265   list = gh_cons (ly_offset2scm (bottom_curve.control_[1]), list);
266   list = gh_cons (ly_offset2scm (bottom_curve.control_[2]), list);
267   list = gh_cons (ly_offset2scm (top_curve.control_[0]), list);
268   list = gh_cons (ly_offset2scm (top_curve.control_[3]), list);
269   list = gh_cons (ly_offset2scm (top_curve.control_[2]), list);
270   list = gh_cons (ly_offset2scm (top_curve.control_[1]), list);
271
272   SCM horizontal_bend = scm_list_n (ly_symbol2scm ("bezier-sandwich"),
273                                     ly_quote_scm (list),
274                                     gh_double2scm (0.0),
275                                     SCM_UNDEFINED);
276
277   Interval x_extent = top_curve.extent (X_AXIS);
278   x_extent.unite (bottom_curve.extent (X_AXIS));
279   Interval y_extent = top_curve.extent (Y_AXIS);
280   y_extent.unite (bottom_curve.extent (Y_AXIS));
281   Box b (x_extent, y_extent);
282
283   return Molecule (b, horizontal_bend);
284 }
285
286 /*
287  * Horizontal Slope:
288  *
289  *            /|   ^
290  *           / |   |
291  *          /  |   | height
292  *         /   |   |
293  *        /    |   v
294  *       |    /
295  *       |   /
296  * (0,0) x  /slope=dy/dx
297  *       | /
298  *       |/
299  *
300  *       <----->
301  *        width
302  */
303 Molecule
304 Lookup::horizontal_slope (Real width, Real slope, Real height)
305 {
306   SCM width_scm = gh_double2scm (width);
307   SCM slope_scm = gh_double2scm (slope);
308   SCM height_scm = gh_double2scm (height);
309   SCM horizontal_slope = scm_list_n (ly_symbol2scm ("beam"),
310                                      width_scm, slope_scm,
311                                      height_scm, SCM_UNDEFINED);
312   Box b (Interval (0, width),
313          Interval (-height/2, height/2 + width*slope));
314   return Molecule (b, horizontal_slope);
315 }
316
317 /*
318   TODO: junk me.
319  */
320 Molecule
321 Lookup::accordion (SCM s, Real staff_space, Font_metric *fm) 
322 {
323   Molecule m;
324   String sym = ly_scm2string (ly_car (s));
325   String reg = ly_scm2string (ly_car (ly_cdr (s)));
326
327   if (sym == "Discant")
328     {
329       Molecule r = fm->find_by_name ("accordion-accDiscant");
330       m.add_molecule (r);
331       if (reg.left_str (1) == "F")
332         {
333           Molecule d = fm->find_by_name ("accordion-accDot");
334           d.translate_axis (staff_space * 2.5 PT, Y_AXIS);
335           m.add_molecule (d);
336           reg = reg.right_str (reg.length_i ()-1);
337         }
338       int eflag = 0x00;
339       if (reg.left_str (3) == "EEE")
340         {
341           eflag = 0x07;
342           reg = reg.right_str (reg.length_i ()-3);
343         }
344       else if (reg.left_str (2) == "EE")
345         {
346           eflag = 0x05;
347           reg = reg.right_str (reg.length_i ()-2);
348         }
349       else if (reg.left_str (2) == "Eh")
350         {
351           eflag = 0x04;
352           reg = reg.right_str (reg.length_i ()-2);
353         }
354       else if (reg.left_str (1) == "E")
355         {
356           eflag = 0x02;
357           reg = reg.right_str (reg.length_i ()-1);
358         }
359       if (eflag & 0x02)
360         {
361           Molecule d = fm->find_by_name ("accordion-accDot");
362           d.translate_axis (staff_space * 1.5 PT, Y_AXIS);
363           m.add_molecule (d);
364         }
365       if (eflag & 0x04)
366         {
367           Molecule d = fm->find_by_name ("accordion-accDot");
368           d.translate_axis (staff_space * 1.5 PT, Y_AXIS);
369           d.translate_axis (0.8 * staff_space PT, X_AXIS);
370           m.add_molecule (d);
371         }
372       if (eflag & 0x01)
373         {
374           Molecule d = fm->find_by_name ("accordion-accDot");
375           d.translate_axis (staff_space * 1.5 PT, Y_AXIS);
376           d.translate_axis (-0.8 * staff_space PT, X_AXIS);
377           m.add_molecule (d);
378         }
379       if (reg.left_str (2) == "SS")
380         {
381           Molecule d = fm->find_by_name ("accordion-accDot");
382           d.translate_axis (0.5 * staff_space PT, Y_AXIS);
383           d.translate_axis (0.4 * staff_space PT, X_AXIS);
384           m.add_molecule (d);
385           d.translate_axis (-0.8 * staff_space PT, X_AXIS);
386           m.add_molecule (d);
387           reg = reg.right_str (reg.length_i ()-2);
388         }
389       if (reg.left_str (1) == "S")
390         {
391           Molecule d = fm->find_by_name ("accordion-accDot");
392           d.translate_axis (0.5 * staff_space PT, Y_AXIS);
393           m.add_molecule (d);
394           reg = reg.right_str (reg.length_i ()-1);
395         }
396     }
397   else if (sym == "Freebase")
398     {
399       Molecule r = fm->find_by_name ("accordion-accFreebase");
400       m.add_molecule (r);
401       if (reg.left_str (1) == "F")
402         {
403           Molecule d = fm->find_by_name ("accordion-accDot");
404           d.translate_axis (staff_space * 1.5 PT, Y_AXIS);
405           m.add_molecule (d);
406           reg = reg.right_str (reg.length_i ()-1);
407         }
408       if (reg == "E")
409         {
410           Molecule d = fm->find_by_name ("accordion-accDot");
411           d.translate_axis (staff_space * 0.5 PT, Y_AXIS);
412           m.add_molecule (d);
413         }
414     }
415   else if (sym == "Bayanbase")
416     {
417       Molecule r = fm->find_by_name ("accordion-accBayanbase");
418       m.add_molecule (r);
419       if (reg.left_str (1) == "T")
420         {
421           Molecule d = fm->find_by_name ("accordion-accDot");
422           d.translate_axis (staff_space * 2.5 PT, Y_AXIS);
423           m.add_molecule (d);
424           reg = reg.right_str (reg.length_i ()-1);
425         }
426       /* include 4' reed just for completeness. You don't want to use this. */
427       if (reg.left_str (1) == "F")
428         {
429           Molecule d = fm->find_by_name ("accordion-accDot");
430           d.translate_axis (staff_space * 1.5 PT, Y_AXIS);
431           m.add_molecule (d);
432           reg = reg.right_str (reg.length_i ()-1);
433         }
434       if (reg.left_str (2) == "EE")
435         {
436           Molecule d = fm->find_by_name ("accordion-accDot");
437           d.translate_axis (staff_space * 0.5 PT, Y_AXIS);
438           d.translate_axis (0.4 * staff_space PT, X_AXIS);
439           m.add_molecule (d);
440           d.translate_axis (-0.8 * staff_space PT, X_AXIS);
441           m.add_molecule (d);
442           reg = reg.right_str (reg.length_i ()-2);
443         }
444       if (reg.left_str (1) == "E")
445         {
446           Molecule d = fm->find_by_name ("accordion-accDot");
447           d.translate_axis (staff_space * 0.5 PT, Y_AXIS);
448           m.add_molecule (d);
449           reg = reg.right_str (reg.length_i ()-1);
450         }
451     }
452   else if (sym == "Stdbase")
453     {
454       Molecule r = fm->find_by_name ("accordion-accStdbase");
455       m.add_molecule (r);
456       if (reg.left_str (1) == "T")
457         {
458           Molecule d = fm->find_by_name ("accordion-accDot");
459           d.translate_axis (staff_space * 3.5 PT, Y_AXIS);
460           m.add_molecule (d);
461           reg = reg.right_str (reg.length_i ()-1);
462         }
463       if (reg.left_str (1) == "F")
464         {
465           Molecule d = fm->find_by_name ("accordion-accDot");
466           d.translate_axis (staff_space * 2.5 PT, Y_AXIS);
467           m.add_molecule (d);
468           reg = reg.right_str (reg.length_i ()-1);
469         }
470       if (reg.left_str (1) == "M")
471         {
472           Molecule d = fm->find_by_name ("accordion-accDot");
473           d.translate_axis (staff_space * 2 PT, Y_AXIS);
474           d.translate_axis (staff_space PT, X_AXIS);
475           m.add_molecule (d);
476           reg = reg.right_str (reg.length_i ()-1);
477         }
478       if (reg.left_str (1) == "E")
479         {
480           Molecule d = fm->find_by_name ("accordion-accDot");
481           d.translate_axis (staff_space * 1.5 PT, Y_AXIS);
482           m.add_molecule (d);
483           reg = reg.right_str (reg.length_i ()-1);
484         }
485       if (reg.left_str (1) == "S")
486         {
487           Molecule d = fm->find_by_name ("accordion-accDot");
488           d.translate_axis (staff_space * 0.5 PT, Y_AXIS);
489           m.add_molecule (d);
490           reg = reg.right_str (reg.length_i ()-1);
491         }
492     }
493   /* ugh maybe try to use regular font for S.B. and B.B and only use one font
494      for the rectangle */
495   else if (sym == "SB")
496     {
497       Molecule r = fm->find_by_name ("accordion-accSB");
498       m.add_molecule (r);
499     }
500   else if (sym == "BB")
501     {
502       Molecule r = fm->find_by_name ("accordion-accBB");
503       m.add_molecule (r);
504     }
505   else if (sym == "OldEE")
506     {
507       Molecule r = fm->find_by_name ("accordion-accOldEE");
508       m.add_molecule (r);
509     }
510   else if (sym == "OldEES")
511     {
512       Molecule r = fm->find_by_name ("accordion-accOldEES");
513       m.add_molecule (r);
514     }
515   return m;  
516 }
517
518 Molecule
519 Lookup::repeat_slash (Real w, Real s, Real t)
520 {
521   SCM wid = gh_double2scm (w);
522   SCM sl = gh_double2scm (s);
523   SCM thick = gh_double2scm (t);
524   SCM slashnodot = scm_list_n (ly_symbol2scm ("repeat-slash"),
525                             wid, sl, thick, SCM_UNDEFINED);
526
527   Box b (Interval (0, w + sqrt (sqr(t/s) + sqr (t))),
528          Interval (0, w * s));
529
530   return Molecule (b, slashnodot); //  http://slashnodot.org
531 }
532
533 Molecule
534 Lookup::bracket (Axis a, Interval iv, Real thick, Real protude)
535 {
536   Box b;
537   Axis other = Axis((a+1)%2);
538   b[a] = iv;
539   b[other] = Interval(-1, 1) * thick * 0.5;
540   
541   Molecule m =  filledbox (b);
542
543   b[a] = Interval (iv[UP] - thick, iv[UP]);
544   Interval oi = Interval (-thick/2, thick/2 + fabs (protude)) ;
545   oi *=  sign (protude);
546   b[other] = oi;
547   m.add_molecule (filledbox (b));
548   b[a] = Interval (iv[DOWN], iv[DOWN]  +thick);
549   m.add_molecule (filledbox(b));
550
551   return m;
552 }
553
554 /*
555   TODO: use rounded boxes.
556  */
557 LY_DEFINE(ly_bracket ,"ly-bracket",
558           4, 0, 0,
559           (SCM a, SCM iv, SCM t, SCM p),
560           "Make a bracket in direction @var{a}. The extent of the bracket is
561 given by @var{iv}. The wings protude by an amount of @var{p}, which
562 may be negative. The thickness is given by @var{t}.")
563 {
564   SCM_ASSERT_TYPE(ly_axis_p (a), a, SCM_ARG1, __FUNCTION__, "axis") ;
565   SCM_ASSERT_TYPE(ly_number_pair_p (iv), iv, SCM_ARG2, __FUNCTION__, "number pair") ;
566   SCM_ASSERT_TYPE(gh_number_p (t), a, SCM_ARG3, __FUNCTION__, "number") ;
567   SCM_ASSERT_TYPE(gh_number_p(p), a, SCM_ARG4, __FUNCTION__, "number") ;
568
569
570   return Lookup::bracket ((Axis)gh_scm2int (a), ly_scm2interval (iv),
571                           gh_scm2double (t),
572                           gh_scm2double (p)).smobbed_copy ();
573 }
574