source: tags/initial/fig2dev/dev/genpic.c

Last change on this file was 2, checked in by oldcode, 24 years ago

Initial revision

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1/*
2 * TransFig: Facility for Translating Fig code
3 * Copyright (c) 1985 Supoj Sutantavibul
4 * Copyright (c) 1991 Micah Beck
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation. The authors make no representations about the suitability
11 * of this software for any purpose.  It is provided "as is" without express
12 * or implied warranty.
13 *
14 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 */
23
24/*
25 *      genpic : PIC driver for fig2dev
26 *
27 *      Author: Conrad Kwok, UC Davis, 12/88
28 *      Modified: Richard Auletta, George Mason Univ., 6/21/89
29 *      Added code comments are marked with "rja".
30 *      Added: Support for native pic arrowheads.
31 *      Added: Support for arrowheads at both ends of lines, arc, splines.
32 *
33 *      Modified: Stuart Kemp & Dave Bonnell, July, 1991
34 *                James Cook University,
35 *                Australia
36 *      Changes:
37 *              Added T_ARC_BOX to genpic_line()
38 *              Added 'thickness' attribute all over
39 *              Added 'fill' attribute to ellipse
40 *              Cleaned up the code
41 */
42
43#include <stdio.h>
44#include <math.h>
45#include "object.h"
46#include "fig2dev.h"
47#include "picfonts.h"
48#include "picpsfonts.h"
49
50void genpic_ctl_spline(), genpic_itp_spline();
51void genpic_open_spline(), genpic_closed_spline();
52
53#define                 TOP     10.5    /* top of page is 10.5 inch */
54static double           ppi;
55static int              CONV = 0;
56static int LineThickness = 0;
57static int OptArcBox = 0;               /* Conditional use */
58static int OptLineThick = 0;
59static int OptEllipseFill = 0;
60static int OptNoUnps = 0;    /* prohibit unpsfont() */
61
62void
63genpic_option(opt, optarg)
64char opt, *optarg;
65{
66        switch (opt) {
67
68        case 'f':               /* set default text font */
69                {   int i;
70
71                    for ( i = 1; i <= MAX_FONT; i++ )
72                        if ( !strcmp(optarg, picfontnames[i]) ) break;
73
74                    if ( i > MAX_FONT)
75                        fprintf(stderr,
76                        "warning: non-standard font name %s\n", optarg);
77                }
78               
79                picfontnames[0] = picfontnames[1] = optarg;
80                break;
81
82        case 's':
83                if (font_size <= 0 || font_size > MAXFONTSIZE) {
84                        fprintf(stderr,
85                                "warning: font size %d out of bounds\n", font_size);
86                }
87                break;
88
89        case 'm':
90        case 'L':
91                break;
92
93        case 'p':
94                if (strcmp(optarg, "all") == 0)
95                  OptArcBox = OptLineThick = OptEllipseFill = 1;
96                else
97                  if (strcmp(optarg, "arc") == 0)
98                    OptArcBox = 1;
99                  else
100                    if (strcmp(optarg, "line") == 0)
101                      OptLineThick = 1;
102                    else
103                      if (strcmp(optarg, "fill") == 0)
104                        OptEllipseFill = 1;
105                      else
106                        if (strcmp(optarg, "psfont") == 0)
107                          OptNoUnps = 1;
108                        else
109                          if (strcmp(optarg, "allps") == 0)
110                            OptArcBox =
111                              OptLineThick =
112                                OptEllipseFill =
113                                  OptNoUnps = 1;
114                          else
115                            { fprintf(stderr, "Invalid option: %s\n", optarg);
116                              exit(1);
117                            }
118                break;
119              default:
120                put_msg(Err_badarg, opt, "pic");
121                exit(1);
122        }
123}
124
125static
126double convy(a)
127double  a;
128{
129        return((double)(CONV ? TOP-a : a));
130}
131
132void
133genpic_start(objects)
134F_compound      *objects;
135{
136        int             coord_system;
137
138        ppi = objects->nwcorner.x/mag;
139        coord_system = objects->nwcorner.y;
140        if (coord_system == 2) CONV = 1;
141
142        fprintf(tfp, ".PS\n.ps %d\n", font_size);       /* PIC preamble */
143}
144
145void
146genpic_end()
147{
148        fprintf(tfp, ".PE\n");                          /* PIC ending */
149}
150
151/*
152The line thickness is, unfortunately, multiple of pixel.
153One pixel thickness is a little too thick on the hard copy
154so I scale it with 0.7; i.e., it's a kludge.  The best way is
155to allow thickness in fraction of pixel.
156
157Note that the current version of psdit (a ditroff to postcript filter)
158won't take the legitimate line thickness command.
159*/
160static
161set_linewidth(w)
162int     w;
163{
164        static int      cur_thickness = -1;
165
166        LineThickness = w;
167
168        /*
169        if (w == 0) return;
170        if (w != cur_thickness) {
171            cur_thickness = w;
172            fprintf(tfp, "\"\\D't %.5fi'\"\n", 0.7 * cur_thickness / ppi);
173            }
174        */
175}
176
177static void
178AddThickness()
179{
180  if (OptLineThick && LineThickness)
181    fprintf(tfp, " thickness %d", LineThickness);
182}
183
184static void
185set_style(s, v)
186int     s;
187float   v;
188{
189        static float    style_val = -1;
190
191        if (s == DASH_LINE || s == DOTTED_LINE) {
192            if (v == style_val) return;
193            if (v == 0.0) return;
194            style_val = v;
195            fprintf(tfp, "dashwid = %.3fi\n", style_val/ppi);
196            }
197}
198
199/*
200 * Makes use of the PIC 'box' command
201 *
202 * Returns 0 if command failed, else non-zero.
203 *
204 */
205
206static int
207genpic_box(l)
208F_line *l;
209{
210  int count, minx, miny, maxx, maxy;
211  int Valid;            /* Valid box */
212  double width, height;
213  F_point *p, *q;
214       
215  p = l->points;
216  q = p->next;
217  count = 1;            /* Just a sanity check */
218  minx = maxx = p->x;
219  miny = maxy = p->y;
220
221  /* Find the boundaries */
222  while (q != NULL)
223  { count++;
224    if (q->x < minx) minx = q->x;
225    else
226      if (q->x > maxx) maxx = q->x;
227
228    if (q->y < miny) miny = q->y;
229    else
230      if (q->y > maxy) maxy = q->y;
231
232    q = q->next;
233  }
234
235  if (Valid = (count == 5))             /* Valid box? */
236  { fprintf(tfp, "box");
237    if (l->thickness == 0)
238      fprintf(tfp, " invis");
239    else
240      if (l->style_val > 0.0)
241      { if (l->style == DASH_LINE)
242          fprintf(tfp, " dashed");
243        else if (l->style == DOTTED_LINE)
244          fprintf(tfp, " dotted");
245      }
246
247    /* Should have a #define somewhere for the # of fill patterns */
248    if (l->area_fill > 0)
249      fprintf(tfp, " fill %.2f", ((double) (l->area_fill - 1)) / 20);
250
251    fprintf(tfp, " with .sw at (%.2f,%.2f) ",
252            minx / ppi, convy(maxy / ppi));
253
254    width = (maxx - minx) / ppi;
255    if (width < 0.0) width = -width;
256    height = convy(maxy / ppi) - convy(miny / ppi);
257    if (height < 0.0) height = -height;
258
259    fprintf(tfp, "width %.2f height %.2f", width, height);
260
261    if (OptArcBox && l->type == T_ARC_BOX)
262      fprintf(tfp, " rad %.2f", l->radius/ppi);
263
264    AddThickness();
265
266    fprintf(tfp, "\n");
267  }
268
269  return(Valid);
270}
271
272void
273genpic_line(l)
274F_line  *l;
275{
276        F_point         *p, *q;
277
278        if (l->type == T_ARC_BOX && !OptArcBox)
279        { fprintf(stderr, "Arc box not implemented; substituting box.\n");
280          l->type = T_BOX;
281        }
282
283        set_linewidth(l->thickness);
284        set_style(l->style, l->style_val);
285        p = l->points;
286        q = p->next;
287        if (q == NULL)  /* A single point line */
288        {   fprintf(tfp, "line from %.3f,%.3f to %.3f,%.3f",
289                        p->x/ppi, convy(p->y/ppi), p->x/ppi, convy(p->y/ppi));
290            AddThickness();
291            fprintf(tfp, "\n");
292            return;
293        }
294
295        if (l->type == T_BOX || l->type == T_ARC_BOX)
296        { if (genpic_box(l)) return;
297          fprintf(stderr, "Invalid T_BOX or T_ARC_BOX in fig file\n");
298          fprintf(stderr, "  Using 'line' instead\n");
299        }
300
301        fprintf(tfp, "line");
302
303        if (l->style_val > 0.0)
304        { if (l->style == DASH_LINE)
305            fprintf(tfp, " dashed");
306          else
307            if (l->style == DOTTED_LINE)
308              fprintf(tfp, " dotted");
309        }
310
311        /*rja: Place arrowheads or lack there of on the line*/
312        if ((l->for_arrow) && (l->back_arrow))
313            fprintf(tfp, " <->");
314        else if (l->back_arrow)
315            fprintf(tfp, " <-");
316        else if (l->for_arrow)
317            fprintf(tfp, " ->");
318
319        fprintf(tfp, " from %.3f,%.3f", p->x/ppi, convy(p->y/ppi));
320        do
321        { fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
322          q = q->next;
323        } while (q != NULL);
324
325        AddThickness();
326
327        fprintf(tfp, "\n");
328}
329
330void
331genpic_spline(s)
332F_spline        *s;
333{
334        if (int_spline(s))
335            genpic_itp_spline(s);
336        else
337            genpic_ctl_spline(s);
338        }
339
340void
341genpic_ctl_spline(s)
342F_spline        *s;
343{
344        if (closed_spline(s))
345            genpic_closed_spline(s);
346        else
347            genpic_open_spline(s);
348        }
349
350void
351genpic_open_spline(s)
352F_spline        *s;
353{
354        double          x1, y1, x2, y2;
355        F_point         *p, *q;
356
357        p = s->points;
358        x1 = p->x/ppi; y1 = convy(p->y/ppi);
359        p = p->next;
360        x2 = p->x/ppi; y2 = convy(p->y/ppi);
361
362
363        /* Pic's spline supports only solid line style */
364        /* set_linewidth(s->thickness); */
365
366        if (p->next == NULL) {
367            fprintf(tfp, "line");
368
369           /*rja: Attach arrowhead as required */
370            if ((s->for_arrow) && (s->back_arrow))
371               fprintf(tfp, " <->");
372            else if (s->back_arrow)
373               fprintf(tfp, " <-");
374            else if (s->for_arrow)
375               fprintf(tfp, " ->");
376
377            fprintf(tfp, " from %.3f,%.3f to %.3f,%.3f", x1, y1, x2, y2);
378
379            AddThickness();
380
381            fprintf(tfp, "\n");
382
383            return;
384            }
385
386        fprintf(tfp, "spline"); 
387
388           /*rja: Attach arrowhead as required */
389            if ((s->for_arrow) && (s->back_arrow))
390               fprintf(tfp, " <->");
391            else if (s->back_arrow)
392               fprintf(tfp, " <-");
393            else if (s->for_arrow)
394               fprintf(tfp, " ->");
395
396        fprintf(tfp, " from %.3f,%.3f to %.3f,%.3f", x1, y1, x2, y2);
397
398        for (q = p->next; q->next != NULL; p = q, q = q->next)
399            fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
400        fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
401
402        AddThickness();
403
404        fprintf(tfp, "\n");
405}
406
407void
408genpic_ellipse(e)
409F_ellipse       *e;
410{
411        set_linewidth(e->thickness);
412        if (e->type == 3 || e->type == 4)
413          fprintf(tfp, "circle at %.3f,%.3f rad %.3f",
414                e->center.x/ppi, convy(e->center.y/ppi),
415                e->radiuses.x/ppi);
416        else
417          fprintf(tfp, "ellipse at %.3f,%.3f wid %.3f ht %.3f",
418                e->center.x/ppi, convy(e->center.y/ppi),
419                2 * e->radiuses.x/ppi, 2 * e->radiuses.y/ppi);
420
421        if ( OptEllipseFill && e->area_fill > 0)
422          fprintf(tfp, " fill %.2f", ((double)(e->area_fill - 1)) / 20);
423
424        AddThickness();
425
426        fprintf(tfp, "\n");
427}
428
429/*
430Text is display on the screen with the base line starting at
431(base_x, base_y); some characters extend below this line.
432Pic displays the center of the height of text at the given
433coordinate. HT_OFFSET is use to compensate all the above factors
434so text position in fig 1.4 should be at the same position on
435the screen as on the hard copy.
436*/
437#define                 HT_OFFSET       (0.2 / 72.0)
438
439void
440genpic_text(t)
441F_text  *t;
442{
443        float   y;
444        char *tpos;
445
446        if (!OptNoUnps) {
447          unpsfont(t);
448          fprintf(tfp, "\"\\s%d\\f%s", PICFONTMAG(t) ,
449                  PICFONT(t->font) );
450        } else {
451          fprintf(tfp, ".ps\n.ps %d\n", PICFONTMAG(t) );
452          fprintf(tfp, ".ft\n.ft %s\n", PICPSFONT(t) );
453        }
454
455        switch (t->type) {
456        case T_LEFT_JUSTIFIED:
457        case DEFAULT:
458            tpos = "ljust";
459            break;
460        case T_CENTER_JUSTIFIED:
461            tpos = "";
462            break;
463        case T_RIGHT_JUSTIFIED:
464            tpos = "rjust";
465            break;
466        default:
467            fprintf(stderr, "unknown text position type\n");
468            exit(1);
469        }   
470        y = convy(t->base_y/ppi) +
471            PICFONTMAG(t) *
472             HT_OFFSET;
473        if (!OptNoUnps)
474            fprintf(tfp, "%s\\fP\" at %.3f,%.3f %s\n",
475                        t->cstring, t->base_x/ppi, y, tpos);
476        else
477            fprintf(tfp, "\"%s\" at %.3f,%.3f %s\n.ft \n.ps \n",
478                        t->cstring, t->base_x/ppi, y, tpos);
479        }
480
481void
482genpic_arc(a)
483F_arc   *a;
484{
485        double          x, y;
486        double          cx, cy, sx, sy, ex, ey;
487
488        cx = a->center.x/ppi; cy = convy(a->center.y/ppi);
489        sx = a->point[0].x/ppi; sy = convy(a->point[0].y/ppi);
490        ex = a->point[2].x/ppi; ey = convy(a->point[2].y/ppi);
491
492        set_linewidth(a->thickness);
493
494        fprintf(tfp, "arc ");
495
496        /*rja: Attach arrowhead as required */
497        if ((a->for_arrow) && (a->back_arrow))
498          fprintf(tfp, " <->");
499        else if (a->back_arrow)
500          fprintf(tfp, " <-");
501        else if (a->for_arrow)
502          fprintf(tfp, " ->");
503
504
505        fprintf(tfp, " at %.3f,%.3f from %.3f,%.3f to %.3f,%.3f",
506                cx, cy, sx, sy, ex, ey);
507
508        if (!a->direction)
509          fprintf(tfp, " cw");
510
511        if (a->area_fill > 0.0)
512          fprintf(stderr, "PIC does not support filled arcs ... ignoring 'fill' directive\n");
513
514        AddThickness();
515        fprintf(tfp, "\n");
516}
517
518void
519arc_tangent(x1, y1, x2, y2, direction, x, y)
520double  x1, y1, x2, y2, *x, *y;
521int     direction;
522{
523        if (direction)  /* counter clockwise  */
524        {   *x = x2 + (y2 - y1);
525            *y = y2 - (x2 - x1);
526        }
527        else
528        {   *x = x2 - (y2 - y1);
529            *y = y2 + (x2 - x1);
530        }
531}
532
533/*      draw arrow heading from (x1, y1) to (x2, y2)    */
534
535draw_arrow_head(x1, y1, x2, y2, arrowht, arrowwid)
536double  x1, y1, x2, y2, arrowht, arrowwid;
537{
538        double  x, y, xb, yb, dx, dy, l, sina, cosa;
539        double  xc, yc, xd, yd;
540
541        dx = x2 - x1;  dy = y1 - y2;
542        l = sqrt((dx*dx + dy*dy));
543        if (l == 0) {
544             return;
545        }
546        else {
547             sina = dy / l;  cosa = dx / l;
548        }
549        xb = x2*cosa - y2*sina;
550        yb = x2*sina + y2*cosa;
551        x = xb - arrowht;
552        y = yb - arrowwid / 2;
553        xc = x*cosa + y*sina;
554        yc = -x*sina + y*cosa;
555        y = yb + arrowwid / 2;
556        xd = x*cosa + y*sina;
557        yd = -x*sina + y*cosa;
558        fprintf(tfp, "line from %.3f,%.3f to %.3f,%.3f to %.3f,%.3f\n",
559                xc, yc, x2, y2, xd, yd);
560        }
561
562#define         THRESHOLD       .05     /* inch */
563
564quadratic_spline(a1, b1, a2, b2, a3, b3, a4, b4)
565double  a1, b1, a2, b2, a3, b3, a4, b4;
566{
567        double  x1, y1, x4, y4;
568        double  xmid, ymid;
569
570        x1 = a1; y1 = b1;
571        x4 = a4; y4 = b4;
572
573        xmid = (a2 + a3) / 2;
574        ymid = (b2 + b3) / 2;
575        if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD)
576        { fprintf(tfp, " to %.3f,%.3f", xmid, ymid);
577        }
578        else {
579            quadratic_spline(x1, y1, ((x1+a2)/2), ((y1+b2)/2),
580                        ((3*a2+a3)/4), ((3*b2+b3)/4), xmid, ymid);
581            }
582
583        if (fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD)
584        { fprintf(tfp, " to %.3f,%.3f", x4, y4);
585        }
586        else {
587            quadratic_spline(xmid, ymid, ((a2+3*a3)/4), ((b2+3*b3)/4),
588                        ((a3+x4)/2), ((b3+y4)/2), x4, y4);
589            }
590        }
591
592void
593genpic_closed_spline(s)
594F_spline        *s;
595{
596        F_point *p;
597        double  cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
598        double  x1, y1, x2, y2;
599
600        p = s->points;
601        x1 = p->x/ppi;  y1 = convy(p->y/ppi);
602        p = p->next;
603        x2 = p->x/ppi;  y2 = convy(p->y/ppi);
604        cx1 = (x1 + x2) / 2;      cy1 = (y1 + y2) / 2;
605        cx2 = (x1 + 3 * x2) / 4;  cy2 = (y1 + 3 * y2) / 4;
606
607        for (p = p->next; p != NULL; p = p->next) {
608            fprintf(tfp, "line from %.3f,%.3f ", cx1, cy1);
609            x1 = x2;  y1 = y2;
610            x2 = p->x/ppi;  y2 = convy(p->y/ppi);
611            cx3 = (3 * x1 + x2) / 4;  cy3 = (3 * y1 + y2) / 4;
612            cx4 = (x1 + x2) / 2;      cy4 = (y1 + y2) / 2;
613            quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
614            AddThickness();
615            fprintf(tfp, "\n");
616            cx1 = cx4;  cy1 = cy4;
617            cx2 = (x1 + 3 * x2) / 4;  cy2 = (y1 + 3 * y2) / 4;
618            }
619        x1 = x2;  y1 = y2;
620        p = s->points->next;
621        x2 = p->x/ppi;  y2 = convy(p->y/ppi);
622        cx3 = (3 * x1 + x2) / 4;  cy3 = (3 * y1 + y2) / 4;
623        cx4 = (x1 + x2) / 2;      cy4 = (y1 + y2) / 2;
624        fprintf(tfp, "line from %.3f,%.3f ", cx1, cy1);
625        quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
626        AddThickness();
627        fprintf(tfp, "\n");
628}
629
630void
631genpic_itp_spline(s)
632F_spline        *s;
633{
634        F_point         *p1, *p2, *pfirst;
635        F_control       *cp1, *cp2;
636        double          x1, x2, y1, y2;
637
638        p1 = s->points;
639        cp1 = s->controls;
640        cp2 = cp1->next;
641        x2 = p1->x/ppi; y2 = convy(p1->y/ppi);
642
643         pfirst = p1->next;/*save first to test in loop*/
644        for (p2 = p1->next, cp2 = cp1->next; p2 != NULL;
645                p1 = p2, cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
646
647            fprintf(tfp, "line ");
648
649           /*rja: Attach arrowhead as required */
650
651            if ((s->back_arrow) && (p2 == pfirst))
652               fprintf(tfp, " <- ");
653            else if ((s->for_arrow) && (p2->next == NULL))
654               fprintf(tfp, " -> ");
655
656            fprintf(tfp, " from %.3f,%.3f", x2, y2);
657
658            x1 = x2; y1 = y2;
659            x2 = p2->x/ppi; y2 = convy(p2->y/ppi);
660            bezier_spline(x1, y1, (double)cp1->rx/ppi, convy(cp1->ry/ppi),
661                (double)cp2->lx/ppi, convy(cp2->ly/ppi), x2, y2);
662            AddThickness();
663            fprintf(tfp, "\n");
664            }
665
666        }
667
668bezier_spline(a0, b0, a1, b1, a2, b2, a3, b3)
669double  a0, b0, a1, b1, a2, b2, a3, b3;
670{
671        double  x0, y0, x3, y3;
672        double  sx1, sy1, sx2, sy2, tx, ty, tx1, ty1, tx2, ty2, xmid, ymid;
673
674        x0 = a0; y0 = b0;
675        x3 = a3; y3 = b3;
676        if (fabs(x0 - x3) < THRESHOLD && fabs(y0 - y3) < THRESHOLD)
677        { fprintf(tfp, " to %.3f,%.3f", x3, y3);
678        }
679        else {
680            tx = (a1 + a2) / 2;         ty = (b1 + b2) / 2;
681            sx1 = (x0 + a1) / 2;        sy1 = (y0 + b1) / 2;
682            sx2 = (sx1 + tx) / 2;       sy2 = (sy1 + ty) / 2;
683            tx2 = (a2 + x3) / 2;        ty2 = (b2 + y3) / 2;
684            tx1 = (tx2 + tx) / 2;       ty1 = (ty2 + ty) / 2;
685            xmid = (sx2 + tx1) / 2;     ymid = (sy2 + ty1) / 2;
686
687            bezier_spline(x0, y0, sx1, sy1, sx2, sy2, xmid, ymid);
688            bezier_spline(xmid, ymid, tx1, ty1, tx2, ty2, x3, y3);
689            }
690        }
691
692struct driver dev_pic = {
693        genpic_option,
694        genpic_start,
695        genpic_arc,
696        genpic_ellipse,
697        genpic_line,
698        genpic_spline,
699        genpic_text,
700        genpic_end,
701        INCLUDE_TEXT
702};
Note: See TracBrowser for help on using the repository browser.