void proc_str (PLStream *pls, EscText *args) { PLFLT *t = args->xform; PLFLT a1, alpha, ft_ht, angle, ref; PLDev *dev = (PLDev *) pls->dev; PLINT clxmin, clxmax, clymin, clymax; int jst, font; /* font height */ ft_ht = pls->chrht * 72.0/25.4; /* ft_ht in points. ht is in mm */ /* calculate baseline text angle */ angle = pls->diorot * 90.; a1 = acos(t[0]) * 180. / PI; if (t[2] > 0.) alpha = a1 - angle; else alpha = 360. - a1 - angle; alpha = alpha * PI / 180.; /* TODO: parse string for format (escape) characters */ /* parse_str(args->string, return_string);*/ /* apply transformations */ difilt(&args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax); /* check clip limits. For now, only the reference point of the string is checked; but the the whole string should be checked -- using a postscript construct such as gsave/clip/grestore. This method can also be applied to the xfig and pstex drivers. Zoom side effect: the font size must be adjusted! */ if ( args->x < clxmin || args->x > clxmax || args->y < clymin || args->y > clymax) return; /* * Text justification. Left, center and right justification, which * are the more common options, are supported; variable justification is * only approximate, based on plplot computation of it's string lenght */ if (args->just == 0.5) jst = 1; /* center */ else if (args->just == 1.) jst = 2; /* right */ else { jst = 0; /* left */ args->x = args->refx; /* use hints provided by plplot */ args->y = args->refy; } /* * Reference point (center baseline of string, not latex character reference point). * If base = 0, it is aligned with the center of the text box * If base = 1, it is aligned with the baseline of the text box * If base = 2, it is aligned with the top of the text box * Currently plplot only uses base=0 * xfig use base=1 */ if (args->base == 2) /* not supported by plplot */ ref = - DPI/72. * ft_ht / 2.; /* half font height in xfig unities (1/1200 inches) */ else if (args->base == 1) ref = 0.; else ref = DPI/72. * ft_ht / 2.; /* rotate point in xfig is lower left corner, compensate */ args->y = offset + dev->ymax * (int)dev->xscale_dev - (args->y - ref*cos(alpha)); args->x = args->x + ref*sin(alpha); /* * font family, serie and shape. Currently not supported by plplot * * Use Postscript Times * 1: Normal font * 2: Roman font * 3: Italic font * 4: sans serif */ switch (pls->cfont) { case (1): font = 0; break; case (2): font = 1; break; case (3): font = 3; break; case (4): font = 4; break; default: font = 0; } fprintf(pls->OutFile,"4 %d %d 50 0 %d %f %f 4 1 1 %d %d %s\\001\n", jst, curcol, font, 1.8 /*!*/ * ft_ht, alpha, args->x, args->y, args->string); }
void proc_str (PLStream *pls, EscText *args) { PLFLT *t = args->xform, tt[4]; /* Transform matrices */ PLFLT theta; /* Rotation angle and shear from the matrix */ PLFLT ft_ht, offset; /* Font height and offset */ PLFLT cs,sn,l1,l2; PSDev *dev = (PSDev *) pls->dev; char *font, esc; /* Be generous. Used to store lots of font changes which take * 3 characters per change.*/ #define PROC_STR_STRING_LENGTH 1000 unsigned char *strp, str[PROC_STR_STRING_LENGTH], *cur_strp, cur_str[PROC_STR_STRING_LENGTH]; float font_factor = 1.4; PLINT clxmin, clxmax, clymin, clymax; /* Clip limits */ PLINT clipx[4],clipy[4]; /* Current clip limits */ PLFLT scale = 1., up = 0.; /* Font scaling and shifting parameters */ int i=0; /* String index */ short text_len; /* unicode only! so test for it. */ if (args->unicode_array_len>0) { int j,s,f; char *fonts[PROC_STR_STRING_LENGTH]; int nlookup; const Unicode_to_Type1_table *lookup; const PLUNICODE *cur_text; const PLUNICODE *cur_text_limit; PLUNICODE fci; /* translate from unicode into type 1 font index. */ /* * Choose the font family, style, variant, and weight using * the FCI (font characterization integer). */ plgesc(&esc); plgfci(&fci); font = plP_FCI2FontName(fci, Type1Lookup, N_Type1Lookup); if (font == NULL) { fprintf(stderr, "fci = 0x%x, font name pointer = NULL \n", fci); plabort("proc_str: FCI inconsistent with Type1Lookup; " "internal PLplot error"); return; } /*pldebug("proc_str", "fci = 0x%x, font name = %s\n", fci, font);*/ if (!strcmp(font, "Symbol")) { nlookup = number_of_entries_in_unicode_to_symbol_table; lookup = unicode_to_symbol_lookup_table; } else { nlookup = number_of_entries_in_unicode_to_standard_table; lookup = unicode_to_standard_lookup_table; } cur_text = args->unicode_array; for (f=s=j=0; j < args->unicode_array_len; j++) { if (cur_text[j] & PL_FCI_MARK) { /* process an FCI by saving it and escaping cur_str * with an escff to make it a 2-character escape * that is not used in legacy Hershey code */ if ((f < PROC_STR_STRING_LENGTH) && (s+3 < PROC_STR_STRING_LENGTH)) { fonts[f] = plP_FCI2FontName(cur_text[j], Type1Lookup, N_Type1Lookup); if (fonts[f] == NULL) { fprintf(stderr, "string-supplied FCI = 0x%x, font name pointer = NULL \n", cur_text[j]); plabort("proc_str: string-supplied FCI inconsistent with Type1Lookup;"); return; } /*pldebug("proc_str", "string-supplied FCI = 0x%x, font name = %s\n", cur_text[j], fonts[f]);*/ if (!strcmp(fonts[f++], "Symbol")) { lookup = unicode_to_symbol_lookup_table; nlookup = number_of_entries_in_unicode_to_symbol_table; } else { lookup = unicode_to_standard_lookup_table; nlookup = number_of_entries_in_unicode_to_standard_table; } cur_str[s++] = esc; cur_str[s++] = 'f'; cur_str[s++] = 'f'; } } else if (s+1 < PROC_STR_STRING_LENGTH) { cur_str[s++] = plunicode2type1(cur_text[j], lookup, nlookup); /*pldebug("proc_str", "unicode = 0x%x, type 1 code = %d\n", cur_text[j], cur_str[j]);*/ } } cur_str[s] = '\0'; /* finish previous polyline */ dev->xold = PL_UNDEFINED; dev->yold = PL_UNDEFINED; /* Determine the font height */ ft_ht = pls->chrht * 72.0/25.4; /* ft_ht in points, ht is in mm */ /* The transform matrix has only rotations and shears; extract them */ theta = acos(t[0]) * 180. / PI; /* Determine the rotation (in degrees)... */ if (t[2] < 0.) theta *= -1.; /* ... and sign ... */ cs = cos(theta*PI/180.); sn = sin(theta*PI/180.); tt[0] = t[0]*cs + t[2]*sn; tt[1] = t[1]*cs + t[3]*sn; tt[2] = -t[0]*sn + t[2]*cs; tt[3] = -t[1]*sn + t[3]*cs; /* * Reference point conventions: * If base = 0, it is aligned with the center of the text box * If base = 1, it is aligned with the baseline of the text box * If base = 2, it is aligned with the top of the text box * * Currently plplot only uses base=0 * Postscript uses base=1 * * We must calculate the difference between the two and apply the offset. */ if (args->base == 2) /* not supported by plplot */ offset = ENLARGE * ft_ht / 2.; /* half font height */ else if (args->base == 1) offset = 0.; else offset = -ENLARGE * ft_ht / 2.; args->y += offset*cos(theta*PI/180.); args->x -= offset*sin(theta*PI/180.); /* Apply plplot difilt transformations */ difilt(&args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax); /* ps driver is rotated by default */ plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &(args->x), &(args->y)); /* Determine the adjustment for page orientation */ theta += 90. - 90.*pls->diorot; /* Output */ /* Set clipping */ clipx[0]=pls->clpxmi; clipx[2]=pls->clpxma; clipy[0]=pls->clpymi; clipy[2]=pls->clpyma; clipx[1]=clipx[2]; clipy[1]=clipy[0]; clipx[3]=clipx[0]; clipy[3]=clipy[2]; difilt(clipx, clipy, 4, &clxmin, &clxmax, &clymin, &clymax); plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &clipx[0], &clipy[0]); plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &clipx[1], &clipy[1]); plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &clipx[2], &clipy[2]); plRotPhy(ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &clipx[3], &clipy[3]); fprintf(OF," gsave %d %d %d %d %d %d %d %d CL\n",clipx[0],clipy[0],clipx[1],clipy[1],clipx[2],clipy[2],clipx[3],clipy[3]); /* move to string reference point */ fprintf(OF, " %d %d M\n", args->x, args->y ); /* Save the current position and set the string rotation */ fprintf(OF, "gsave %.3f R\n",theta); /* Purge escape sequences from string, so that postscript can find it's * length. The string length is computed with the current font, and can * thus be wrong if there are font change escape sequences in the string */ esc_purge(str, cur_str); fprintf(OF, "/%s %.3f SF\n", font,font_factor * ENLARGE * ft_ht); /* Output string, while escaping the '(', ')' and '\' characters. * this string is output for measurement purposes only. */ fprintf(OF, "%.3f (", - args->just); while (str[i]!='\0') { if (str[i]=='(' || str[i]==')' || str[i]=='\\') fprintf(OF,"\\%c",str[i]); else fprintf(OF,"%c",str[i]); i++; } fprintf(OF,") SW\n"); /* Parse string for PLplot escape sequences and print everything out */ cur_strp = cur_str; f = 0; do { strp = str; if (*cur_strp == esc) { cur_strp++; if (*cur_strp == esc) { /* <esc><esc> */ *strp++ = *cur_strp++; } else if (*cur_strp == 'f') { cur_strp++; if (*cur_strp++ != 'f') { /* escff occurs because of logic above. But any suffix * other than "f" should never happen. */ plabort("proc_str, internal PLplot logic error;" "wrong escf escape sequence"); return; } font = fonts[f++]; /*pldebug("proc_str", "string-specified fci = 0x%x, font name = %s\n", fci, font);*/ continue; } else switch (*cur_strp++) { case 'd': case 'D': if(up>0.) scale *= 1.25; /* Subscript scaling parameter */ else scale *= 0.8; /* Subscript scaling parameter */ up -= font_factor * ENLARGE * ft_ht / 2.; break; case 'u': case 'U': if(up<0.) scale *= 1.25; /* Subscript scaling parameter */ else scale *= 0.8; /* Subscript scaling parameter */ up += font_factor * ENLARGE * ft_ht / 2.; break; /* ignore the next sequences */ case '+': case '-': case 'b': case 'B': plwarn("'+', '-', and 'b/B' text escape sequences not processed."); break; } } /* copy from current to next token, adding a postscript escape * char '\' if necessary */ while(*cur_strp && *cur_strp != esc) { if (*cur_strp == '(' || *cur_strp == ')' || *cur_strp == '\\') *strp++ = '\\'; *strp++ = *cur_strp++; } *strp = '\0'; if(fabs(up)<0.001) up = 0.; /* Watch out for small differences */ /* Apply the scaling and the shear */ fprintf(OF, "/%s [%.3f %.3f %.3f %.3f 0 0] SF\n", font, tt[0]*font_factor * ENLARGE * ft_ht * scale, tt[2]*font_factor * ENLARGE * ft_ht * scale, tt[1]*font_factor * ENLARGE * ft_ht * scale, tt[3]*font_factor * ENLARGE * ft_ht * scale); /* if up/down escape sequences, save current point and adjust baseline; * take the shear into account */ if(up!=0.) fprintf(OF, "gsave %.3f %.3f rmoveto\n",up*tt[1],up*tt[3]); /* print the string */ fprintf(OF, "(%s) show\n", str); /* back to baseline */ if (up!=0.) fprintf(OF, "grestore (%s) stringwidth rmoveto\n", str); }while(*cur_strp); fprintf(OF, "grestore\n"); fprintf(OF, "grestore\n"); /* * keep driver happy -- needed for background and orientation. * arghhh! can't calculate it, as I only have the string reference * point, not its extent! * Still a hack - but at least it takes into account the string * length and justification. Character width is assumed to be * 0.6 * character height. Add on an extra 1.5 * character height * for safety. */ cs = cos(theta/180.*PI); sn = sin(theta/180.*PI); l1 = -i*args->just; l2 = i*(1.-args->just); /* Factor of 0.6 is an empirical fudge to convert character * height to average character width */ l1 *= 0.6; l2 *= 0.6; dev->llx = MIN(dev->llx, args->x + (MIN(l1*cs,l2*cs)-1.5) * font_factor * ft_ht * ENLARGE ); dev->lly = MIN(dev->lly, args->y + (MIN(l1*sn,l2*sn)-1.5) * font_factor * ft_ht * ENLARGE ); dev->urx = MAX(dev->urx, args->x + (MAX(l1*cs,l2*cs)+1.5) * font_factor * ft_ht * ENLARGE ); dev->ury = MAX(dev->ury, args->y + (MAX(l1*sn,l2*sn)+1.5) * font_factor * ft_ht * ENLARGE ); } }