Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / mf / feta-macros.mf
blob5bd97d36a06ee0216b39d623b356e8a0aca6d285
1 % Feta (not the Font-En-Tja) music font -- auxiliary macros for both feta and parmesan fonts
2 % This file is part of LilyPond, the GNU music typesetter.
4 % Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 % LilyPond is free software: you can redistribute it and/or modify
7 % it under the terms of the GNU General Public License as published by
8 % the Free Software Foundation, either version 3 of the License, or
9 % (at your option) any later version.
11 % LilyPond is distributed in the hope that it will be useful,
12 % but WITHOUT ANY WARRANTY; without even the implied warranty of
13 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 % GNU General Public License for more details.
16 % You should have received a copy of the GNU General Public License
17 % along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
21 % debugging
24 def print_penpos (suffix $) =
25         message
26           "z" & str$ & "l = (" & decimal x.$.l & ", " &decimal y.$.l & ");"
27           & " z" & str$ & "r = (" & decimal x.$.r & ", " & decimal y.$.r & ");";
28 enddef;
31 def test_grid =
32         if test > 1:
33                 proofrulethickness 1pt#;
35                 makegrid
36                   (0pt, 0pt for i := -5pt step 1pt until 5pt: , i endfor)
37                   (0pt, 0pt for i := -5pt step 1pt until 5pt: , i endfor);
39                 proofrulethickness .1pt#;
41                 makegrid
42                   (0pt, 0pt for i := -4.8pt step .2pt until 4.8pt: , i endfor)
43                   (0pt, 0pt for i := -4.8pt step .2pt until 4.8pt: , i endfor);
44         fi;
45 enddef;
48 def treq =
49         tracingequations := tracingonline := 1;
50 enddef;
53 def draw_staff (expr first, last, offset) =
54         if test <> 0:
55                 pickup pencircle scaled stafflinethickness;
57                 for i := first step 1 until last:
58                         draw (-staff_space,
59                               (i + offset) * staff_space_rounded)
60                              -- (4 staff_space,
61                                  (i + offset) * staff_space_rounded);
62                 endfor;
63         fi;
64 enddef;
68 % Draw the outline of the stafflines.  For fine tuning.
71 def draw_staff_outline (expr first, last, offset) =
72         if test <> 0:
73                 save p;
74                 path p;
76                 pickup pencircle scaled 2;
78                 for i := first step 1 until last:
79                         p := (-staff_space,
80                               (i + offset) * staff_space_rounded)
81                              -- (4 staff_space,
82                                  (i + offset) * staff_space_rounded);
84                         draw p shifted (0, .5 stafflinethickness);
85                         draw p shifted (0, -.5 stafflinethickness);
86                 endfor;
87         fi;
88 enddef;
92 % Transformations
95 def scaledabout (expr point, scale) =
96         shifted -point scaled scale shifted point
97 enddef;
101 % make a local (restored after endgroup) copy of t_var
104 def local_copy (text type, t_var) =
105         save copy_temp;
106         type copy_temp;
107         copy_temp := t_var;
108         save t_var;
109         type t_var;
110         t_var := copy_temp;
111 enddef;
115 % Urgh! Want to do parametric types
118 def del_picture_stack =
119         save save_picture_stack, picture_stack_idx;
120 enddef;
124 % better versions of Taupin/Egler savepic cmds
127 def make_picture_stack =
128         % override previous stack
129         del_picture_stack;
130         picture save_picture_stack[];
131         numeric picture_stack_idx;
132         picture_stack_idx := 0;
134         def push_picture (expr p) =
135                 save_picture_stack[picture_stack_idx] := p;
136                 picture_stack_idx := picture_stack_idx + 1;
137         enddef;
139         def pop_picture = save_picture_stack[decr picture_stack_idx] enddef;
140         def top_picture = save_picture_stack[picture_stack_idx] enddef;
141 enddef;
145 % save/restore pens
146 % why can't I delete individual pens?
149 def make_pen_stack =
150         del_pen_stack;
151         pen save_pen_stack[];
152         numeric pen_stack_idx;
153         pen_stack_idx := 0;
154         def push_pen (expr p) =
155                 save_pen_stack[pen_stack_idx] := p;
156                 pen_stack_idx := pen_stack_idx + 1;
157         enddef;
158         def pop_pen = save_pen_stack[decr pen_stack_idx] enddef;
159         def top_pen = save_pen_stack[pen_stack_idx] enddef;
160 enddef;
163 def del_pen_stack =
164         save save_pen_stack, pen_stack_idx;
165 enddef;
169 % drawing
172 def soft_penstroke text t =
173         forsuffixes e = l, r:
174                 path_.e := t;
175         endfor;
177         if cycle path_.l:
178                 cyclestroke_;
179         else:
180                 fill path_.l
181                 ..tension1.5.. reverse path_.r
182                 ..tension1.5.. cycle;
183         fi;
184 enddef;
187 def soft_start_penstroke text t =
188         forsuffixes e = l, r:
189                 path_.e := t;
190         endfor;
192         if cycle path_.l:
193                 cyclestroke_;
194         else:
195                 fill path_.l
196                 -- reverse path_.r
197                 ..tension1.5.. cycle;
198         fi;
199 enddef;
202 def soft_end_penstroke text t =
203         forsuffixes e = l, r:
204                 path_.e := t;
205         endfor;
207         if cycle path_.l:
208                 cyclestroke_;
209         else:
210                 fill path_.l
211                 ..tension1.5.. reverse path_.r
212                 -- cycle;
213         fi;
214 enddef;
218 % Make a round path segment going from P to Q.  2*A is the angle that the
219 % path should take.
222 def simple_serif (expr p, q, a) =
223         p{dir (angle (q - p) - a)}
224         .. q{-dir (angle (p - q) + a)}
225 enddef;
229 % Draw an axis aligned block making sure that edges are on pixels.
232 def draw_rounded_block (expr bottom_left, top_right, roundness) =
233 begingroup;
234         save size;
235         save x, y;
237         % Originally, there was `floor' instead of `round', but this is
238         % not correct because pens use `round' also.
239         size = round min (roundness,
240                           xpart (top_right - bottom_left),
241                           ypart (top_right - bottom_left));
243         z2 + (size / 2, size / 2) = top_right;
244         z4 - (size / 2, size / 2) = bottom_left;
245         y3 = y2;
246         y4 = y1;
247         x2 = x1;
248         x4 = x3;
250         pickup pencircle scaled size;
252         fill bot z1{right}
253              .. rt z1{up}
254              -- rt z2{up}
255              .. top z2{left}
256              -- top z3{left}
257              .. lft z3{down}
258              -- lft z4{down}
259              .. bot z4{right}
260              -- cycle;
261 endgroup;
262 enddef;
265 def draw_block (expr bottom_left, top_right) =
266         draw_rounded_block (bottom_left, top_right, blot_diameter);
267 enddef;
270 def draw_square_block (expr bottom_left, top_right) =
271         save x, y;
273         x1 = xpart bottom_left;
274         y1 = ypart bottom_left;
275         x2 = xpart top_right;
276         y2 = ypart top_right;
278         fill (x1, y1)
279              -- (x2, y1)
280              -- (x2, y2)
281              -- (x1, y2)
282              -- cycle;
283 enddef;
286 def draw_gridline (expr bottom_left, top_right, thickness) =
287         draw_rounded_block (bottom_left - (thickness / 2, thickness / 2),
288                             top_right + (thickness / 2, thickness / 2),
289                             thickness);
290 enddef;
293 def draw_brush (expr a, w, b, v) =
294         save x, y;
296         z1 = a;
297         z2 = b;
298         z3 = z4 = z1;
299         z5 = z6 = z2;
301         penpos3 (w, angle (z2 - z1) + 90);
302         penpos4 (w, angle (z2 - z1));
303         penpos5 (v, angle (z1 - z2) + 90);
304         penpos6 (v, angle (z1 - z2));
306         fill z3r{z3r - z5l}
307              .. z4l
308              .. {z5r - z3l}z3l
309              .. z5r{z5r - z3l}
310              .. z6l
311              .. {z3r - z5l}z5l
312              .. cycle;
313 enddef;
317 % Make a superellipsoid segment going from FROM to TO, with SUPERNESS.
318 % Take superness = sqrt(2)/2 to get a circle segment.
320 % See Knuth, p. 267 and p.126.
322 def super_curvelet (expr from, to, superness, dir) =
323         if dir = 1:
324                 (superness [xpart to, xpart from],
325                  superness [ypart from, ypart to]){to - from}
326         else:
327                 (superness [xpart from, xpart to],
328                  superness [ypart to, ypart from]){to - from}
329         fi
330 enddef;
334 % Bulb with smooth inside curve.
336 % alpha = start direction
337 % beta = which side to turn to
338 % flare = diameter of the bulb
339 % line = diameter of line attachment
340 % direction = is ink on left or right side (1 or -1)
342 % Note that `currentpen' must be set correctly -- only circular pens
343 % are supported properly.
345 def flare_path (expr pos, alpha, beta, line, flare, direction) =
346 begingroup;
347         save thick;
349         thick = pen_top + pen_bot;
351         clearxy;
353         penpos1' (line - thick, 180 + beta + alpha);
354         top z1'r = pos;
356         penpos2' (flare - thick, 180 + beta + alpha);
357         z2' = z3';
359         penpos3' (flare - thick, 0 + alpha);
360         rt x3'l = hround (x1'r
361                           + (1/2 + 0.43) * flare * xpart dir (alpha + beta));
362         bot y2'l = vround (y1'r
363                            + (1 + 0.43) * flare * ypart dir (alpha + beta));
365         rt x4' = x2'r - line * xpart dir (alpha);
366         y4' = y2'r - line * ypart dir (alpha);
368         penlabels (1', 2', 3', 4');
370         save t, p;
371         t = 0.833;
372         path p;
374         p := z1'r{dir (alpha)}
375              .. z3'r{dir (180 + alpha - beta)}
376              .. z2'l{dir (alpha + 180)}
377              .. z3'l{dir (180 + alpha + beta)}
378              ..tension t.. z4'{dir (180 + alpha + beta)}
379              .. z1'l{dir (alpha + 180)};
381         if direction <> 1:
382                 p := reverse p;
383         fi;
386 endgroup
387 enddef;
390 def brush (expr a, w, b, v) =
391 begingroup;
392         draw_brush (a, w, b, v);
393         penlabels (3, 4, 5, 6);
394 endgroup;
395 enddef;
399 % Draw a (rest) crook, starting at thickness STEM in point A,
400 % ending a ball W to the left, diameter BALLDIAM.
401 % ypart of the center of the ball is BALLDIAM/4 lower than ypart A.
404 def balled_crook (expr a, w, balldiam, stem) =
405 begingroup;
406         save x, y;
408         penpos1 (balldiam / 2, -90);
409         penpos2 (balldiam / 2, 0);
410         penpos3 (balldiam / 2, 90);
411         penpos4 (balldiam / 2, 180);
413         x4r = xpart a - w;
414         y3r = ypart a + balldiam / 4;
415         x1l = x2l = x3l = x4l;
416         y1l = y2l = y3l = y4l;
418         penpos5 (stem, 250);
419         x5 = x4r + 9/8 balldiam;
420         y5r = y1r;
422         penpos6 (stem, 260);
423         x6l = xpart a;
424         y6l = ypart a;
426         penstroke z1e
427                   .. z2e
428                   .. z3e
429                   .. z4e
430                   .. z1e
431                   .. z5e{right}
432                   .. z6e;
434         penlabels (1, 2, 3, 4, 5, 6);
435 endgroup;
436 enddef;
439 def y_mirror_char =
440         currentpicture := currentpicture yscaled -1;
442         set_char_box (charbp, charwd, charht, chardp);
443 enddef;
446 def xy_mirror_char =
447         currentpicture := currentpicture scaled -1;
449         set_char_box (charwd, charbp, charht, chardp);
450 enddef;
454 % center_factor: typically .5; the larger, the larger the radius of the bulb
455 % radius factor: how much the bulb curves inward
458 def draw_bulb (expr turndir, zl, zr, bulb_rad, radius_factor)=
459 begingroup;
460         save rad, ang, pat;
461         path pat;
463         clearxy;
465         ang = angle (zr - zl);
467         % don't get near infinity
468         % z0 = zr + bulb_rad * (zl - zr) / length (zr - zl);
469         z0' = zr + bulb_rad / length (zr - zl) * (zl - zr);
471         rad = bulb_rad;
473         z1' = z0' + radius_factor * rad * dir (ang + turndir * 100);
474         z2' = z0' + rad * dir (ang + turndir * 300);
476         labels (0', 1', 2');
478         pat = zr{dir (ang + turndir * 90)}
479                .. z1'
480                .. z2'
481                .. cycle;
483         % avoid grazing outlines
484         fill subpath (0, 2.5) of pat
485              -- cycle;
486 endgroup
487 enddef;
490 pi := 3.14159;
494 % To get symmetry at low resolutions we need to shift some points and
495 % paths, but not if mf2pt1 is used.
498 if known miterlimit:
499         vardef hfloor primary x = x enddef;
500         vardef vfloor primary y = y enddef;
501         vardef hceiling primary x = x enddef;
502         vardef vceiling primary y = y enddef;
503 else:
504         vardef hfloor primary x = floor x enddef;
505         vardef vfloor primary y = (floor y.o_)_o_ enddef;
506         vardef hceiling primary x = ceiling x enddef;
507         vardef vceiling primary y = (ceiling y.o_)_o_ enddef;