2 /* Copyright (c) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* functions for printing endings, pedal marks, phrase marks, etc */
11 /* width of tapered curve at endpoint relative to maximum width */
12 #define TAPERWID (0.4)
16 * Define a structure for storing points of a curve, whether generated (like
17 * for phrase marks) or user-specified. It also stores information used in
18 * calculating Bezier curves that will be drawn between each pair of
19 * neighboring points. The "control points" are points 1 and 2 for the
20 * Bezier curve going from this point to the next point. These structures
21 * get their x and y filled in from CURVE or CRVLIST structures.
24 float x, y; /* point's coords */
25 float len; /* length of line segment from here to next point */
26 float ang; /* angle between the 2 segments at this point */
27 int bend; /* bend direction at point: 1=clockwise, -1=counter */
28 float slopetan; /* slope of line "tangent" to this point if axes are */
29 /* rotated such that segment starting here is horiz. */
30 float x1, y1; /* control point 1 for segment starting at this point */
31 float x2, y2; /* control point 2 for segment starting at this point */
34 /* static functions */
35 static void do_endings P((struct MAINLL *first_p, struct MAINLL *last_p,
36 char *endlabel, int carryout));
37 static void draw_ending P((int staffno, double ry, struct MAINLL *first_p,
38 struct MAINLL *last_p, char *endlabel, int carryout));
39 static void pr_endlabel P((double x, double y, char *label));
40 static void pr_end_line P((double begin_x, double end_x, double y,
42 static int is_top_visible_in_range P((int staffno, int top));
43 static void calccurve P((struct CURVEINFO v[], int num));
44 static void findcontrol P((struct CURVEINFO v[], int num));
48 /* whenever we hit a FEED, draw any endings associated with the score */
51 pr_endings(main_feed_p)
53 struct MAINLL *main_feed_p; /* FEED */
56 static char *endlabel = (char *) 0;/* ending label if had to carry over
58 struct MAINLL *curr_p; /* where we are in main list */
59 struct MAINLL *first_p; /* where an ending begins */
60 struct MAINLL *last_bar_p = 0; /* points to last bar on score so far */
63 debug(512, "pr_endings");
65 first_p = (struct MAINLL *) 0;
67 /* go through the entire score line. For every set of measures that have
68 * endings, draw them. */
69 for (curr_p = main_feed_p->next; curr_p != (struct MAINLL *) 0;
70 curr_p = curr_p->next) {
72 /* go just to end of current score */
73 if (curr_p->str == S_FEED) {
77 /* if there is a pseudo bar, see if it is in an ending */
78 if (curr_p->str == S_CLEFSIG) {
79 if (curr_p->u.clefsig_p->bar_p != (struct BAR *) 0 &&
80 curr_p->u.clefsig_p->bar_p->endingloc
83 endlabel = curr_p->u.clefsig_p->bar_p->endinglabel;
88 /* for each bar, check its endingloc and act accordingly */
89 else if (curr_p->str == S_BAR) {
91 switch(curr_p->u.bar_p->endingloc) {
94 if (first_p == (struct MAINLL *) 0) {
95 pfatal("ending without beginning");
99 /* if we were doing an ending, we reached the
100 * end of it, so handle it */
101 if (first_p != (struct MAINLL *) 0) {
102 /* it doesn't seem like it should be
103 * possible to get inside this IF for
104 * the NOITEM case, but it doesn't
105 * hurt anything to have to code as it
106 * is, and I don't want to change it for
107 * fear it would break some obscure
108 * circumstance I've forgotten about */
109 do_endings(first_p, curr_p, endlabel, NO);
110 endlabel = (char *) 0;
111 first_p = (struct MAINLL *) 0;
116 /* if we are also implictly ending a previous
117 * ending, do that first. In any case, keep
118 * track of where this ending begins. */
119 if (first_p != (struct MAINLL *) 0) {
120 do_endings(first_p, curr_p,
125 endlabel = curr_p->u.bar_p->endinglabel;
133 pfatal("bad endingloc value");
141 /* we must be at the end of the score. If we are in the middle
142 * of an ending, draw this score's portion of it now */
143 if ( (first_p != (struct MAINLL *) 0)
144 && (last_bar_p != (struct MAINLL *) 0)) {
145 do_endings(first_p, last_bar_p, endlabel,
146 last_bar_p->u.bar_p->endingloc
147 == INITEM ? YES : NO);
152 /* now that we have identified an ending, print it above each
153 * staff that is supposed to get endings */
156 do_endings(first_p, last_p, endlabel, carryout)
158 struct MAINLL *first_p; /* where to begin drawing endings */
159 struct MAINLL *last_p; /* where to end the endings */
160 char *endlabel; /* if ending has a label, this will be
161 * that label, otherwise NULL */
162 int carryout; /* YES if will carry over to next staff */
165 struct MARKCOORD *markc_p; /* info about where to draw ending */
168 /* for each staff that is supposed to have endings,
170 if (first_p->str == S_CLEFSIG) {
172 markc_p = first_p->u.clefsig_p->bar_p->ending_p;
176 markc_p = first_p->u.bar_p->ending_p;
179 /* if this is an endending and the bar line at the end is an ordinary
180 * bar or an invisbar, then set the carryout flag so that the final
181 * vertical line doesn't get drawn. */
182 if (last_p->u.bar_p->endingloc == ENDITEM
183 && (last_p->u.bar_p->bartype == SINGLEBAR ||
184 last_p->u.bar_p->bartype == INVISBAR)) {
185 /* But if this is the very end of the piece,
186 * then we *do* want to draw the final vertical */
187 struct MAINLL* mll_p;
188 for (mll_p = last_p->next; mll_p != 0; mll_p = mll_p->next) {
189 if (mll_p->str == S_STAFF) {
198 /* draw an ending for each item in MARKCOORD list */
199 for ( ; markc_p != (struct MARKCOORD *) 0; markc_p = markc_p->next) {
200 draw_ending(markc_p->staffno, (double) markc_p->ry,
201 first_p, last_p, endlabel, carryout);
206 /* draw ending marks over specified staff */
209 draw_ending(staffno, ry, first_p, last_p, endlabel, carryout)
211 int staffno; /* which staff to draw over */
212 double ry; /* relative y */
213 struct MAINLL *first_p; /* draw ending starting from here */
214 struct MAINLL *last_p; /* ending end here */
215 char *endlabel; /* if has label, this is the label, else is NULL */
216 int carryout; /* if YES, will carry over to next score */
219 float begin_x; /* x coord of beginning and end of ending */
220 float y; /* vertical location of ending */
223 /* first_p can point to either a CLEFSIG (if carrying over an
224 * ending) or to a BAR. Find appropriate x coordinate */
225 switch (first_p->str) {
228 begin_x = first_p->u.clefsig_p->bar_p->c[AX];
232 begin_x = first_p->u.bar_p->c[AX];
236 /* shut up compilers that erroneously thinks begin_x
237 * could get used without being set. */
239 pfatal("bad struct type passed to draw_ending");
244 /* get vertical position */
245 y = Staffs_y[staffno] + ry;
247 /* now we know where to put it, so draw it */
248 do_linetype(L_NORMAL);
250 /* print the beginning vertical and label now if appropriate */
251 if (endlabel != (char *) 0) {
252 pr_endlabel( (double) begin_x, (double) y, endlabel);
255 pr_end_line ( (double) begin_x, (double) last_p->u.bar_p->c[AX],
256 (double) y, carryout);
260 /* print label at the beginning of an ending, along with the vertical line
261 * to the left of the label */
264 pr_endlabel(x, y, label)
266 double x; /* coordinate of beginning of ending */
268 char *label; /* the ending label or NULL */
271 /* if there is a label, this is the beginning of an ending, so
272 * print a vertical line followed by the label */
273 if (label != (char *) 0) {
275 draw_line(x, y + STDPAD, x, y + ENDINGHEIGHT - STDPAD);
276 pr_string(x + (3.0 * STDPAD), y + (2.0 * STDPAD), label, J_LEFT,
282 /* print horizontal line above ending, possibly with ending vertical line */
285 pr_end_line(begin_x, end_x, y, carryout)
287 double begin_x; /* horizontal coordinates of ending line */
289 double y; /* vertical position */
290 int carryout; /* if YES, continued on next score, so no end vertical */
293 /* adjust to allow a little padding */
294 begin_x += (2.0 * STDPAD);
295 end_x -= (2.0 * STDPAD);
296 y += ENDINGHEIGHT - STDPAD;
298 /* draw the horizontal line above the ending */
299 draw_line(begin_x, y, end_x, y);
301 /* if the ending ends here, draw vertical line at end */
302 if (carryout == NO) {
303 draw_line(end_x, y, end_x, y - ENDINGHEIGHT + (2.0 * STDPAD));
308 /* function to tell whether a given staff should have ending put on it. Returns
309 * YES if it does, NO if it doesn't */
314 int staffno; /* which staff to check */
317 register int s; /* index through barstlist */
320 /* if staff is invisible, ending doesn't count */
321 if ( svpath(staffno, VISIBLE)->visible == NO) {
325 switch ( Score.endingstyle ) {
328 /* if there is an earlier staff that is visible, then no
329 * ending on this one. Otherwise there is */
330 return( is_top_visible_in_range(staffno, 1) );
333 /* go through barstlist. If this
334 * staff is within a range and any staffs above it are
335 * invisible at the moment, it gets an ending. */
336 for (s = 0; s < Score.nbarst; s++) {
338 if ((staffno >= Score.barstlist[s].top) && (staffno
339 <= Score.barstlist[s].bottom)) {
341 return( is_top_visible_in_range(staffno,
342 Score.barstlist[s].top));
346 /* if wasn't in any of the ranges, then it must be barred
351 /* go through brace and bracket list. If the top visible
352 * of any of them match the given score, it gets an ending */
353 for (s = 0; s < Score.nbrace; s++) {
355 if ((staffno >= Score.bracelist[s].topstaff)
357 <= Score.bracelist[s].botstaff)) {
359 return( is_top_visible_in_range(staffno,
360 Score.bracelist[s].topstaff));
364 for (s = 0; s < Score.nbrack; s++) {
366 if ((staffno >= Score.bracklist[s].topstaff)
368 <= Score.bracklist[s].botstaff)) {
370 return( is_top_visible_in_range(staffno,
371 Score.bracklist[s].topstaff));
375 /* wasn't in either list, so it probably shouldn't have an
376 * ending. However, if it happens to be the top staff, we
377 * better put one on anyway, because the top staff should
378 * always get an ending. */
379 return( is_top_visible_in_range(staffno, 1) );
382 pfatal("unknown endingstyle");
389 /* given a staff number and the top of a range of staffs, return YES if the
390 * given staff is the top visible staff in the range, otherwise return NO.
391 * Assume that staffno itself is for a visible staff */
394 is_top_visible_in_range(staffno, top)
396 int staffno; /* which staff to check */
397 int top; /* top of range to check */
400 for (staffno--; staffno >= top; staffno--) {
401 if ( svpath(staffno, VISIBLE)->visible == YES) {
402 /* something above it is visible */
410 /* functions for printing piano pedals marks */
412 /* keep track of where last coordinate of pedal mark was for each staff.
413 * If no pedal currently on a staff, set to 0.0 */
414 static float Last_ped_x[MAXSTAFFS + 1];
415 static float Last_ped_y[MAXSTAFFS + 1];
418 /* return the distance to offset the 'P' of "Ped." from the group X to
419 * center it on the group. The first time called, calculate the width,
420 * after that, just return it */
426 static double width = 0.0;
430 /* first time, make string with just P and get width of that */
431 (void) strncpy(pstr, Ped_start, 3);
433 width = strwidth(pstr) / 2.0;
439 /* when we encounter a ST_PEDAL, print the pedal character and save the
440 * east boundary as the last pedal x value, for later use. If is endped,
441 * set this last pedal x value to 0.0 */
444 pr_ped_char(stuff_p, staffno)
446 struct STUFF *stuff_p; /* pedal info */
447 int staffno; /* which staff */
453 int pedstyle; /* P_PEDSTAR or P_ALTPEDSTAR or P_LINE */
454 int pedchar; /* pedal music character code */
455 double overlap; /* to avoid tiny gaps in pedal line due to roundoff */
456 char *adj_pstart; /* Ped_start adjusted for Staffscale */
457 char *adj_pstop; /* Ped_stop adjusted for Staffscale */
460 if (stuff_p->string == (char *) 0) {
461 /* must be a pedal mark carried over from a previous
462 * score. Just need to save away the coordinate. */
463 Last_ped_x[staffno] = stuff_p->c[AX];
464 Last_ped_y[staffno] = stuff_p->c[AY];
468 pedstyle = svpath(staffno, PEDSTYLE)->pedstyle;
470 /* extract the pedal character to be printed */
471 font = stuff_p->string[0];
472 size = stuff_p->string[1];
473 string = stuff_p->string + 2;
474 pedchar = next_str_char(&string, &font, &size) & 0xff;
476 /* overlap lines just slightly with pedal characters, to compensate
477 * for any rounding of the bounding box which might cause a tiny
478 * gap to appear between the line and the pedal character */
479 overlap = Stdpad / 3.0;
481 /* draw line from previous pedal character, if any, to this one */
482 if (pedstyle == P_LINE && Last_ped_x[staffno] != 0.0) {
483 if (stuff_p->c[AW] + overlap - Last_ped_x[staffno] > 0) {
484 do_linetype(L_NORMAL);
485 draw_line(Last_ped_x[staffno], stuff_p->c[AY],
486 stuff_p->c[AW] + overlap, stuff_p->c[AY]);
490 Last_ped_y[staffno] = stuff_p->c[AY];
495 if (Last_ped_x[staffno] != 0.0) {
496 /* This used to be a pfatal, because it should
497 * never happen. But it can happen
498 * due to user error: if user does something like
504 * Having two repeatends without an intervening
505 * repeatstart is illegal.
506 * It has never shown up as a true pfatal in millions
507 * of test runs, so if it is ever hit,
508 * it's probably the user error case.
510 ufatal("got begin pedal when already doing pedal, staff %d", staffno);
512 Last_ped_x[staffno] = stuff_p->c[AE] - overlap;
516 if (Last_ped_x[staffno] == 0.0) {
517 pfatal("got pedal without begped, staff %d", staffno);
519 Last_ped_x[staffno] = stuff_p->c[AE] - overlap;
523 if (Last_ped_x[staffno] == 0.0) {
524 pfatal("got endped without begped, staff %d", staffno);
526 Last_ped_x[staffno] = 0.0;
530 pfatal("bad character 0x%x in pedal string", pedchar);
535 /* now print the appropriate pedal character */
536 if (pedstyle == P_LINE) {
537 /* We used to print the pedal characters from FONT_MUSIC,
538 * but Ghostscript sometimes misaligned them with the
539 * pedal lines, so now we draw the characters "manually."
541 do_linetype(L_NORMAL);
544 draw_line(stuff_p->c[AX], stuff_p->c[AN],
545 stuff_p->c[AX], stuff_p->c[AY]);
546 draw_line(stuff_p->c[AX], stuff_p->c[AY],
547 stuff_p->c[AE] + overlap, stuff_p->c[AY]);
550 draw_line(stuff_p->c[AW], stuff_p->c[AY],
551 stuff_p->c[AX], stuff_p->c[AN]);
552 draw_line(stuff_p->c[AX], stuff_p->c[AN],
553 stuff_p->c[AE], stuff_p->c[AY]);
556 draw_line(stuff_p->c[AW] - overlap, stuff_p->c[AY],
557 stuff_p->c[AX], stuff_p->c[AY]);
558 draw_line(stuff_p->c[AX], stuff_p->c[AN],
559 stuff_p->c[AX], stuff_p->c[AY]);
566 /* If we need to adjust for Staffscale, make a temp copy */
567 if (Staffscale != 1.0) {
568 adj_pstart = copy_string(Ped_start + 2,
570 adj_size( (int) Ped_start[1], Staffscale,
572 adj_pstop = copy_string(Ped_stop + 2,
574 adj_size( (int) Ped_stop[1], Staffscale,
578 adj_pstart = Ped_start;
579 adj_pstop = Ped_stop;
582 /* In alt pedstar style, a PEDAL is treated exactly like
583 * a BEGPED, so pretend that's what we got. */
584 if (pedstyle == P_ALTPEDSTAR && pedchar == C_PEDAL) {
591 pr_string(stuff_p->c[AX] - (strwidth(adj_pstart) / 2.0),
592 stuff_p->c[AY], adj_pstart,
593 J_CENTER, stuff_p->inputfile,
594 stuff_p->inputlineno);
598 pr_string(stuff_p->c[AX] - strwidth(adj_pstop)
599 - ped_offset() * Staffscale,
600 stuff_p->c[AY], adj_pstop,
601 J_RIGHT, stuff_p->inputfile,
602 stuff_p->inputlineno);
603 pr_string(stuff_p->c[AX] - ped_offset() * Staffscale,
604 stuff_p->c[AY], adj_pstart,
605 J_LEFT, stuff_p->inputfile,
606 stuff_p->inputlineno);
610 pr_string(stuff_p->c[AX] - (strwidth(adj_pstop) / 2.0),
611 stuff_p->c[AY], adj_pstop,
612 J_CENTER, stuff_p->inputfile,
613 stuff_p->inputlineno);
617 pfatal("bad character 0x%x in pedal string", pedchar);
622 /* If we had to make a temp copy to account for Staffscale,
623 * free the temp copy. */
624 if (Staffscale != 1.0) {
632 /* when we hit a bar line, extend any pedal marks to the bar line. Since things
633 * are stored in units of bars, easier to do this than keep track of the
634 * entire length and have to worry about page feeds, etc. This is just for
635 * normal bars, not pseudo-bars. They are handled separately. */
638 pr_ped_bar(mll_p, bar_p)
640 struct MAINLL *mll_p; /* print pedal mark up to bar hangs off of here */
641 struct BAR *bar_p; /* print pedal marks up to this bar */
645 float endadj; /* adjustment for endings */
648 /* for each staff that has pedal marks pending, draw an extension
649 * line to where this bar line is and reset Last_ped_x */
650 for (s = 1; s <= Score.staffs; s++) {
652 if (Last_ped_x[s] != 0.0) {
654 if (Last_ped_y[s] <= 0.0) {
655 pfatal("don't have y coordinate for drawing pedal mark");
659 if (svpath(s, PEDSTYLE)->pedstyle == P_LINE) {
660 do_linetype(L_NORMAL);
661 if (Ped_snapshot[0] == YES &&
662 bar_p->endingloc == STARTITEM) {
664 /* going into 2nd ending, so shorten
665 * this pedal to not reach bar */
666 endadj = (2.0 * STEPSIZE);
667 /* if line length is positive,
669 if (bar_p->c[AX] - endadj
672 draw_line(Last_ped_x[s],
674 bar_p->c[AX] - endadj,
679 if (bar_p->c[AX] - STDPAD >
681 draw_line(Last_ped_x[s],
689 endadj = -(bar_p->c[AX]
695 Last_ped_x[s] = bar_p->c[AX] + endadj;
698 saveped(mll_p, bar_p);
702 /* handle pedal going into endings. When we hit a first ending, save the
703 * state of the pedal for all staffs. On subsequent endings in the set,
704 * reset the pedal state to what it was at the beginning of the first ending.
705 * At the endending, go back to normal operation. */
708 saveped(mll_p, bar_p)
710 struct MAINLL *mll_p; /* bar is connected here */
714 register int s; /* staff index */
717 if (mll_p == (struct MAINLL *) 0) {
718 pfatal("null pointer in saveped");
721 if (bar_p->endingloc == STARTITEM) {
723 if (Ped_snapshot[0] == YES) {
725 /* starting 2nd ending: restore pedal state as it was
726 * at beginning of first ending */
727 for (s = 1; s <= Score.staffs; s++) {
728 if (Ped_snapshot[s] == YES) {
729 Last_ped_x[s] = bar_p->c[AX]
739 /* starting a set of endings,
740 * need to save pedal state at this
741 * point so we can carry it into subsequent endings */
742 for (s = 1; s <= Score.staffs; s++) {
743 /* set to YES if pedal is on */
744 Ped_snapshot[s] = (Last_ped_x[s] == 0.0 ? NO : YES);
746 /* make sure any remaining staffs are set to pedal off,
747 * in case user increases the number of staffs
748 * during the endings... */
749 for ( ; s <= MAXSTAFFS; s++) {
750 Ped_snapshot[s] = NO;
753 /* mark that we now have a snapshot */
754 Ped_snapshot[0] = YES;
758 else if (bar_p->endingloc == ENDITEM) {
759 /* at end of endings, discard snapshot of pedal states.
760 * However, we have to make sure this is really the end of
761 * endings, and not just a bar that was marked as end
762 * because the start of the next was moved from here to
763 * the pseudo bar. So we search forward, if we find a
764 * clefsig with pseudo-bar before finding a chhead,
765 * and that pseudo bar endingloc is STARTITEM, then this
766 * isn't really the end of endings, and should be ignored. */
767 for ( ; mll_p != (struct MAINLL *) 0; mll_p = mll_p->next) {
768 if (mll_p->str == S_CHHEAD) {
769 /* is end of endings */
772 else if (mll_p->str == S_CLEFSIG &&
773 mll_p->u.clefsig_p->bar_p !=
775 mll_p->u.clefsig_p->bar_p->endingloc
777 /* not really end of endings */
781 Ped_snapshot[0] = NO;
786 /* given a list of phrase mark curve coordinates, print the curve */
787 /* output each x,y, coordinate pair, then the number of coordinates and
788 * finally the "curve" function name */
791 pr_phrase(crvlist_p, linetype, tapered, staffno)
793 struct CRVLIST *crvlist_p; /* the curve to print */
794 int linetype; /* if not tapered, may be L_DOTTED or L_DASHED*/
795 int tapered; /* YES or NO */
796 int staffno; /* which staff, to get staffscale */
801 float *xlist,* ylist;
803 /* count up number of coordinates */
804 for (n = 0, c_p = crvlist_p; c_p != (struct CRVLIST *) 0;
809 MALLOCA(float, xlist, n);
810 MALLOCA(float, ylist, n);
811 for (n = 0, c_p = crvlist_p; c_p != (struct CRVLIST *) 0;
812 c_p = c_p->next, n++) {
817 do_linetype(linetype);
819 pr_allcurve(xlist, ylist, n,
820 svpath(staffno, STAFFSCALE)->staffscale * W_MEDIUM / PPI,
827 * Name: pr_allcurve()
829 * Abstract: Print a curve, either generated (e.g., tie) or user-defined.
833 * Description: This function is given an array of CURVEINFOs, one for each
834 * point of a curve, where x and y have been filled in. It fills
835 * the rest of the items in the structures, and prints PostScript
836 * commands for drawing the curve. If the curve is to be dashed
837 * or dotted, the calling function must put out the PostScript
838 * commands for that. It does not handle "wavy".
843 pr_allcurve(x, y, num, cwid, tapered)
845 float x[], y[]; /* coordinates of the curve's points */
846 int num; /* number of elements (points) in the array */
847 double cwid; /* (max) width of the curve, in inches */
848 int tapered; /* YES or NO */
851 struct CURVEINFO *v; /* malloc structs for holding point info */
852 float *slen; /* malloc length of each segment */
853 float *xoff; /* malloc x offset of curve boundary from mid*/
854 float *yoff; /* malloc y offset of curve boundary from mid*/
855 float *off; /* malloc total offset of curve boundary */
856 float totlen; /* len of curve, along segments */
857 float maxplace; /* distance from end where a tapered curve */
858 /* reaches its maximum thickness */
859 float cumlen, remlen, fromend; /* used in tapering curve */
860 float dx, dy; /* for finding x and y offsets */
861 float temp; /* temp variable */
862 int n; /* loop through points */
866 * If the curve is not to be tapered, calculate Bezier curves joining
867 * these points, and stroke the resulting path.
870 /* load coords into structures, and calculate control points */
871 MALLOC(CURVEINFO, v, num);
872 for (n = 0; n < num; n++) {
878 /* output results in PostScript */
879 do_moveto(v[0].x, v[0].y);
881 for (n = 0; n < num - 1; n++) {
882 do_curveto( v[n].x1, v[n].y1, v[n].x2, v[n].y2,
892 * The curve is to be tapered. We're going to draw two series of
893 * Bezier curves, forming the boundaries of the whole curve, and then
894 * fill. Note that this will always result in a solid curve,
895 * regardless of any earlier request for dashes or dots.
897 /* first allocate the arrays we're going to need */
898 MALLOC(CURVEINFO, v, num);
899 MALLOCA(float, slen, num);
900 MALLOCA(float, xoff, num);
901 MALLOCA(float, yoff, num);
902 MALLOCA(float, off, num);
904 /* find and save len of each segment, and accumulate total len */
906 for (n = 0; n < num - 1; n++) {
907 slen[n] = sqrt( (double) (SQUARED(x[n+1] - x[n]) +
908 SQUARED(y[n+1] - y[n]) ) );
913 * Tapering occurs up to a max of 1/3 inches from the end of a curve.
914 * maxplace is set up such that it is normally the distance from the
915 * end where the max thickness is attained. However, if a curve is
916 * shorter than 2/3 inches, it will never attain this max thickness.
921 maxplace = totlen * (2.0/3.0);
924 cumlen = 0.0; /* none accumulated so far */
925 remlen = totlen; /* all of it remains */
926 for (n = 0; n < num; n++) {
927 /* whichever end this point is closer to, note distance */
928 if (cumlen < remlen) {
935 /* set the offset for this point for achieving tapering */
936 if (fromend > maxplace) {
941 * For curves longer than 2/3, taperwid should be only
942 * half of TAPERWID; for zero length curves, it should
943 * be full TAPERWID; in between, adjust linearly. Then,
944 * at the ends, the width is taperwid times the full
945 * standard thickness (the middle of a long curve); and
946 * ramp up linearly towards 1/3 inches from the end.
948 taperwid = totlen > 2.0/3.0 ? TAPERWID / 2.0 :
949 TAPERWID * (1.0 - 0.75 * totlen);
950 off[n] = (cwid / 2.0) *
951 ((1.0 - taperwid) * fromend / maxplace + taperwid);
955 * Break offset into x and y components, based on the slope
956 * between the two surrounding points. For the endpoints,
957 * there are not two surrounding points, so use the slope of
958 * the neighboring segment.
961 * First get deltas; x and y are switched and sign reversed
962 * on one, because we're concerned with the line perpendicular
963 * to the line joining the two points. (Its slope is the
964 * negative inverse.) Only the ratio dx/dy matters, not the
970 } else if (n == num - 1) {
971 dx = y[num-1] - y[num-2];
972 dy = x[num-2] - x[num-1];
974 dx = y[n+1] - y[n-1];
975 dy = x[n-1] - x[n+1];
978 /* get hypotenuse of something */
979 temp = off[n] / sqrt( (double) (SQUARED(dx) + SQUARED(dy)) );
981 /* get x and y offsets; may need to switch signs */
982 xoff[n] = fabs(temp * dx);
983 yoff[n] = fabs(temp * dy);
989 /* update cumulative and remaining length if not at end */
997 * Load coords into structures, and calculate control points, for one
998 * boundary of the curve.
1000 for (n = 0; n < num; n++) {
1001 v[n].x = x[n] + xoff[n];
1002 v[n].y = y[n] + yoff[n];
1007 * Move to the center of the curve's thickness at the beginning point.
1008 * Draw a perpendicular line to the curve's boundary. Then generate
1009 * the curves that form this side's boundary.
1011 do_moveto(x[0], y[0]);
1012 do_line(v[0].x, v[0].y);
1013 for (n = 0; n < num - 1; n++) {
1014 do_curveto( v[n].x1, v[n].y1, v[n].x2, v[n].y2,
1015 v[n+1].x, v[n+1].y);
1019 * Load coords into structures, and calculate control points, for the
1020 * other boundary of the curve. We're going to do this side in
1021 * reverse, back to the beginning.
1023 for (n = 0; n < num; n++) {
1024 v[n].x = x[num - 1 - n] - xoff[num - 1 - n];
1025 v[n].y = y[num - 1 - n] - yoff[num - 1 - n];
1030 * Draw a line across the curve's thickness at this end. Then
1031 * generate the curves that form this side's boundary.
1033 do_line( v[0].x, v[0].y);
1034 for (n = 0; n < num - 1; n++) {
1035 do_curveto( v[n].x1, v[n].y1, v[n].x2, v[n].y2,
1036 v[n+1].x, v[n+1].y);
1039 /* fill to form the full, solid curve */
1052 * Abstract: Calculate info for drawing cubic arcs through a curve's points.
1056 * Description: This function is given an array of CURVEINFOs, one for each
1057 * point of a curve, where x and y have been filled in. It fills
1058 * in the rest of the items in the structures. Specifically, in
1059 * each structure, (x1, y1) and (x2, y2) are the control points
1060 * for drawing a Bezier curve (using curveto) from this point to
1061 * the next one. These points are chosen in such a way that the
1062 * slopes at the end of one curve and the start of the next are
1063 * equal, to avoid a sharp corner. Also, the angles this slope
1064 * forms with straight line segments connecting the points are
1065 * equal. The angle at the start of the first curve is set equal
1066 * to the angle at the end of it, and the angle at the end of the
1067 * last curve is set equal to the angle at the beginning of it.
1068 * The other fields in the CURVEINFOs are set but aren't useful to
1069 * the caller. In the last point's CURVEINFO, some of the fields
1070 * are not used (including x1, y1, x2, y2).
1077 struct CURVEINFO v[]; /* array of curve points, x and y must be filled in */
1078 int num; /* number of elements (points) in the array */
1081 int n; /* loop through the points */
1082 float temp, delx, dely; /* temp variables */
1083 float slope, intercept; /* for equation of a segment */
1086 /* find the length of each segment connecting neighboring points */
1087 for (n = 0; n < num - 1; n++) {
1088 /* use Pythagorean theorem; put result in 1st point's "len" */
1089 delx = v[n+1].x - v[n].x;
1090 dely = v[n+1].y - v[n].y;
1091 v[n].len = sqrt( (double) (SQUARED(delx) + SQUARED(dely)) );
1093 ufatal("two curve points are equal");
1096 /* find the angle at each point other than the endpoints */
1097 for (n = 1; n < num - 1; n++) {
1099 * Use the law of cosines on the triangle formed by this point
1100 * and the preceding and following points. First get the delta
1101 * from the preceding point to the following point.
1103 delx = v[n+1].x - v[n-1].x;
1104 dely = v[n+1].y - v[n-1].y;
1107 * The law of cosines: c^2 = a^2 + b^2 - 2 a b cos(C).
1108 * Solve this for the cosine of our point's angle (angle "C").
1110 temp = ( SQUARED(v[n-1].len) + SQUARED(v[n].len) -
1111 (SQUARED(delx) + SQUARED(dely)) ) /
1112 ( 2.0 * v[n-1].len * v[n].len );
1114 /* if angle is 180, should be -1, but guard against roundoff */
1116 temp = -1; /* should have been exactly -1 */
1118 /* if angle is 0, this is not allowed in our curve */
1120 ufatal("curve bends all the way back on itself");
1122 v[n].ang = acos(temp);
1125 /* set the bend direction at each point other than the endpoints */
1126 for (n = 1; n < num - 1; n++) {
1127 /* handle special case where previous segment is vertical */
1128 if (v[n-1].x == v[n].x) {
1129 if (v[n-1].y < v[n].y) {
1130 if (v[n+1].x >= v[n].x)
1135 if (v[n+1].x >= v[n].x)
1140 continue; /* go to next loop iteration */
1144 * Find the equation of the previous segment. Plug the
1145 * following point's x into that equation to get where its y
1146 * would have been if the angle were 180. Comparing that y to
1147 * the actual y, we can determine the bend direction.
1149 slope = (v[n].y - v[n-1].y) / (v[n].x - v[n-1].x);
1150 intercept = v[n-1].y - slope * v[n-1].x;
1151 temp = slope * v[n+1].x + intercept;
1153 if (v[n].x > v[n-1].x) {
1154 if (v[n+1].y < temp)
1159 if (v[n+1].y < temp)
1167 * At the endpoints, there is only one segment, so no angle or bend
1168 * direction is defined. But we need to have something. So we semi-
1169 * arbitrarily set these to the same value as their neighboring points.
1171 v[0].ang = v[1].ang;
1172 v[0].bend = v[1].bend;
1173 v[num-1].ang = v[num-2].ang;
1174 v[num-1].bend = v[num-2].bend;
1177 * For all points, set the slope of the line tangent to the curves
1178 * we're going to draw, in the coordinate system where the segment
1179 * starting at this point is horizontal. (This is the coordinate
1180 * system that findcontrol() uses.) Since the angle between segments
1181 * is not allowed to be 0, this slope is never vertical (infinity).
1183 for (n = 0; n < num; n++)
1184 v[n].slopetan = -v[n].bend * tan( v[n].ang / 2 + PI / 2);
1187 * For each segment, calculate control points to define a Bezier curve
1188 * connecting the endpoints, according to the specifications.
1190 for (n = 0; n < num - 1; n++)
1195 * Name: findcontrol()
1197 * Abstract: Find Bezier control points for one segment of the curve.
1201 * Description: This function is given an array of CURVEINFOs, one for each
1202 * point, with everything filled in except the control points. It
1203 * calculates them and fills them in.
1210 struct CURVEINFO v[];
1214 float costheta, sintheta; /* for rotating axes by theta */
1217 * All of the following variables refer to the rotated/translated
1218 * position of the segment (see comment below). Point 0 is the
1219 * starting point, point 3 is the ending point, and points 1 and 2
1220 * are the Bezier control points.
1222 float x1, x2, y1, y2; /* control points */
1223 float x3; /* end point (y3 is always 0) */
1224 float slope0, slope3; /* slope of tangent lines at endpoints */
1225 float b, c; /* some coefficients of cubic y = f(x) */
1226 float cx, by, cy; /* Bezier coefficients */
1230 * Rotate and translate the axes so that the starting point (point 0)
1231 * is at the origin, and the ending point (3) is on the positive
1232 * x axis. Their coords are (0, 0) and (v[n].len, 0). We are going
1233 * to find a cubic equation that intersects the endpoints, and has the
1234 * necessary slope at those points such that the tangent line's slope
1235 * is halfway between horizontal (this segment) and the slope of the
1236 * neighboring segment. The equation is
1237 * y = a x^3 + b x^2 + c x + d
1239 * y' = 3 a x^2 + 2 b x + c
1240 * By plugging the two points into these, you get 4 equations in the 4
1241 * unknowns a, b, c, d.
1245 /* find the slope of the tangent lines at the first & second points */
1246 slope0 = v[n].slopetan;
1247 slope3 = -v[n+1].slopetan;
1249 /* set values of a, b, c (d turns out to be always 0) */
1250 /* a = (slope0 + slope3) / SQUARED(x3); don't really need this one */
1251 b = (-2 * slope0 - slope3) / x3;
1255 * For Bezier version of this, let x = t / x3, and for y, plug this
1256 * into the cubic we have found. This gives us the Bezier coeff.:
1257 * x = ax t^3 + bx t^2 + cx t + x0
1258 * y = ay t^3 + by t^2 + cy t + y0
1260 /* ax and bx are always 0 */
1262 /* ay = a * CUBED(x3); this one is not needed */
1263 by = b * SQUARED(x3);
1266 /* get control points 1 and 2 from Bezier coefficients & endpoints */
1270 y2 = y1 + (by + cy) / 3;
1273 * Rotate and translate the axes back to where they really were. Store
1274 * these real positions of the control points.
1276 costheta = (v[n+1].x - v[n].x) / v[n].len;
1277 sintheta = (v[n+1].y - v[n].y) / v[n].len;
1279 v[n].x1 = v[n].x + x1 * costheta - y1 * sintheta;
1280 v[n].x2 = v[n].x + x2 * costheta - y2 * sintheta;
1281 v[n].y1 = v[n].y + y1 * costheta + x1 * sintheta;
1282 v[n].y2 = v[n].y + y2 * costheta + x2 * sintheta;
1286 /* draw a V-shaped bend indicator by drawing two line segments */
1291 struct CRVLIST *crvlist_p;
1294 if (crvlist_p == (struct CRVLIST *) 0
1295 || crvlist_p->next == (struct CRVLIST *) 0
1296 || crvlist_p->next->next == (struct CRVLIST *) 0) {
1297 pfatal("invalid bend crvlist");
1300 do_linetype(L_NORMAL);
1301 draw_line(crvlist_p->x, crvlist_p->y, crvlist_p->next->x, crvlist_p->next->y);
1302 draw_line(crvlist_p->next->x, crvlist_p->next->y,
1303 crvlist_p->next->next->x, crvlist_p->next->next->y);
1307 /* draw a slide for a tab or tabnote staff. Slides are stored internally
1308 * like slurs. Here we just draw a line between the appropriate coordinates */
1311 pr_tabslur(crvlist_p, ts_style)
1313 struct CRVLIST *crvlist_p;
1317 if (crvlist_p == (struct CRVLIST *) 0
1318 || crvlist_p->next == (struct CRVLIST *) 0) {
1319 pfatal("invalid tabslur crvlist");
1322 do_linetype(ts_style);
1323 draw_line(crvlist_p->x, crvlist_p->y, crvlist_p->next->x, crvlist_p->next->y);
1327 /* print a small curve to indicate a 1/4 step bend on a tabnote */
1332 double x, y; /* where to start the curve. This is the bottom left end */
1335 float xlist[4], ylist[4]; /* coordinates of the curve */
1338 /* fill in the relative horizontal and vertical offsets. These
1339 * are hand picked to give a nice looking curve */
1342 xlist[1] = x + 0.5 * STEPSIZE;
1343 ylist[1] = y + 0.2 * STEPSIZE;
1344 xlist[2] = x + 1.2 * STEPSIZE;
1345 ylist[2] = y + 1.2 * STEPSIZE;
1346 xlist[3] = x + 1.3 * STEPSIZE;
1347 ylist[3] = y + 1.75 * STEPSIZE;
1349 /* now print the curve */
1350 pr_allcurve(xlist, ylist, 4, W_NORMAL, NO);
1354 /* Print 'atend' grids */
1360 float x; /* of first grid of row */
1361 float y; /* of row; top line of grid */
1362 float gridx; /* x of grid being printed */
1363 float north; /* of the grid */
1364 float space; /* distance between grid lines */
1365 struct GRID *grid_p;
1366 int g; /* index through grid_p array */
1367 int staff = -1; /* always -1 to indicate atend. Using a
1368 * variable rather than hard-coding where
1369 * used just on general principles. */
1370 int column; /* how many columns printed so far in row */
1371 int rows_to_print; /* how many rows to print per page. */
1372 struct MAINLL *main_feed_p; /* for getting top/bottom blocks */
1373 struct FEED *feed_p; /* for getting top/bottom blocks */
1376 x = Atend_info.firstgrid_x;
1377 y = Atend_info.firstgrid_y;
1378 rows_to_print = Atend_info.rows_per_page;
1379 space = gridspace(staff);
1382 /* Find the last FEED. We use that to get top/bottom blocks */
1383 for (main_feed_p = Mainlltc_p; main_feed_p->str != S_FEED;
1384 main_feed_p= main_feed_p->prev) {
1387 feed_p = main_feed_p->u.feed_p;
1388 for (g = 0; g < Atend_info.grids_used; g++) {
1389 grid_p = Atend_info.grid_p[g];
1390 gridsize(grid_p, staff, &north, (float *) 0, (float *) 0, (float *) 0);
1391 /* calculate horizontal position of this grid */
1392 gridx = x + column * Atend_info.horz_sep;
1394 /* print the name of the grid */
1395 pr_string(gridx - strwidth(grid_p->name) / 2.0,
1396 y + north + strdescent(grid_p->name),
1397 grid_p->name, J_LEFT, (char *) 0, -1);
1399 /* print the grid itself */
1400 do_grid(gridx - space * (grid_p->numstr - 1) / 2.0,
1401 y, space, grid_p, staff);
1403 if (++column >= Atend_info.grids_per_row &&
1404 g < Atend_info.grids_used - 1) {
1405 /* move to next row */
1407 y -= Atend_info.vert_sep;
1409 if (Atend_info.separate_page == YES &&
1410 rows_to_print <= 0) {
1411 rows_to_print = Atend_info.rows_per_page;
1412 y = Atend_info.firstgrid_y;
1413 /* print top/bottom blocks, if any */
1414 /* use *2 blocks for any subsequent pages */
1415 feed_p->top_p = feed_p->top2_p;
1416 feed_p->bot_p = feed_p->bot2_p;
1417 pr_feed(main_feed_p);