1219b2ee8SDavid du Colombier /*
2219b2ee8SDavid du Colombier * Boundingbox code for PostScript translators. The boundingbox for each page
3219b2ee8SDavid du Colombier * is accumulated in bbox - the one for the whole document goes in docbbox. A
4219b2ee8SDavid du Colombier * call to writebbox() puts out an appropriate comment, updates docbbox, and
5219b2ee8SDavid du Colombier * resets bbox for the next page. The assumption made at the end of writebbox()
6219b2ee8SDavid du Colombier * is that we're really printing the current page only if output is now going
7219b2ee8SDavid du Colombier * to stdout - a valid assumption for all supplied translators. Needs the math
8219b2ee8SDavid du Colombier * library.
9219b2ee8SDavid du Colombier */
10219b2ee8SDavid du Colombier
11*14f51593SDavid du Colombier #define _RESEARCH_SOURCE
12*14f51593SDavid du Colombier
13219b2ee8SDavid du Colombier #include <stdio.h>
14*14f51593SDavid du Colombier #include <stdlib.h>
15*14f51593SDavid du Colombier #include <string.h>
16219b2ee8SDavid du Colombier #include <ctype.h>
17219b2ee8SDavid du Colombier #include <sys/types.h>
18219b2ee8SDavid du Colombier #include <fcntl.h>
19219b2ee8SDavid du Colombier #include <math.h>
20219b2ee8SDavid du Colombier
21219b2ee8SDavid du Colombier #include "comments.h" /* PostScript file structuring comments */
22219b2ee8SDavid du Colombier #include "gen.h" /* a few general purpose definitions */
23219b2ee8SDavid du Colombier #include "ext.h" /* external variable declarations */
24219b2ee8SDavid du Colombier
25219b2ee8SDavid du Colombier typedef struct bbox {
26219b2ee8SDavid du Colombier int set;
27219b2ee8SDavid du Colombier double llx, lly;
28219b2ee8SDavid du Colombier double urx, ury;
29219b2ee8SDavid du Colombier } Bbox;
30219b2ee8SDavid du Colombier
31219b2ee8SDavid du Colombier Bbox bbox = {FALSE, 0.0, 0.0, 0.0, 0.0};
32219b2ee8SDavid du Colombier Bbox docbbox = {FALSE, 0.0, 0.0, 0.0, 0.0};
33219b2ee8SDavid du Colombier
34219b2ee8SDavid du Colombier double ctm[6] = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
35219b2ee8SDavid du Colombier double matrix1[6], matrix2[6];
36219b2ee8SDavid du Colombier
37*14f51593SDavid du Colombier void concat(double []);
38*14f51593SDavid du Colombier void resetbbox(int);
39*14f51593SDavid du Colombier void rotate(double);
40*14f51593SDavid du Colombier void scale(double, double);
41*14f51593SDavid du Colombier void translate(double, double);
42*14f51593SDavid du Colombier void writebbox(FILE *, char *, int);
43219b2ee8SDavid du Colombier
44*14f51593SDavid du Colombier void
cover(x,y)45219b2ee8SDavid du Colombier cover(x, y)
46219b2ee8SDavid du Colombier double x, y;
47219b2ee8SDavid du Colombier {
48219b2ee8SDavid du Colombier /*
49219b2ee8SDavid du Colombier * Adds point (x, y) to bbox. Coordinates are in user space - the transformation
50219b2ee8SDavid du Colombier * to default coordinates happens in writebbox().
51219b2ee8SDavid du Colombier */
52219b2ee8SDavid du Colombier
53219b2ee8SDavid du Colombier if ( bbox.set == FALSE ) {
54219b2ee8SDavid du Colombier bbox.llx = bbox.urx = x;
55219b2ee8SDavid du Colombier bbox.lly = bbox.ury = y;
56219b2ee8SDavid du Colombier bbox.set = TRUE;
57219b2ee8SDavid du Colombier } else {
58219b2ee8SDavid du Colombier if ( x < bbox.llx )
59219b2ee8SDavid du Colombier bbox.llx = x;
60219b2ee8SDavid du Colombier if ( y < bbox.lly )
61219b2ee8SDavid du Colombier bbox.lly = y;
62219b2ee8SDavid du Colombier if ( x > bbox.urx )
63219b2ee8SDavid du Colombier bbox.urx = x;
64219b2ee8SDavid du Colombier if ( y > bbox.ury )
65219b2ee8SDavid du Colombier bbox.ury = y;
66*14f51593SDavid du Colombier }
67*14f51593SDavid du Colombier }
68219b2ee8SDavid du Colombier
69*14f51593SDavid du Colombier void
writebbox(fp,keyword,slop)70219b2ee8SDavid du Colombier writebbox(fp, keyword, slop)
71219b2ee8SDavid du Colombier FILE *fp; /* the comment is written here */
72219b2ee8SDavid du Colombier char *keyword; /* the boundingbox comment string */
73219b2ee8SDavid du Colombier int slop; /* expand (or contract?) the box a bit */
74219b2ee8SDavid du Colombier {
75219b2ee8SDavid du Colombier Bbox ubbox; /* user space bounding box */
76219b2ee8SDavid du Colombier double x, y;
77219b2ee8SDavid du Colombier
78219b2ee8SDavid du Colombier /*
79219b2ee8SDavid du Colombier * Transforms the numbers in the bbox[] using ctm[], adjusts the corners a bit
80219b2ee8SDavid du Colombier * (depending on slop) and then writes comment. If *keyword is BoundingBox use
81219b2ee8SDavid du Colombier * whatever's been saved in docbbox, otherwise assume the comment is just for
82219b2ee8SDavid du Colombier * the current page.
83219b2ee8SDavid du Colombier */
84219b2ee8SDavid du Colombier
85219b2ee8SDavid du Colombier if ( strcmp(keyword, BOUNDINGBOX) == 0 )
86219b2ee8SDavid du Colombier bbox = docbbox;
87219b2ee8SDavid du Colombier
88219b2ee8SDavid du Colombier if ( bbox.set == TRUE ) {
89219b2ee8SDavid du Colombier ubbox = bbox;
90219b2ee8SDavid du Colombier bbox.set = FALSE; /* so cover() works properly */
91219b2ee8SDavid du Colombier x = ctm[0] * ubbox.llx + ctm[2] * ubbox.lly + ctm[4];
92219b2ee8SDavid du Colombier y = ctm[1] * ubbox.llx + ctm[3] * ubbox.lly + ctm[5];
93219b2ee8SDavid du Colombier cover(x, y);
94219b2ee8SDavid du Colombier x = ctm[0] * ubbox.llx + ctm[2] * ubbox.ury + ctm[4];
95219b2ee8SDavid du Colombier y = ctm[1] * ubbox.llx + ctm[3] * ubbox.ury + ctm[5];
96219b2ee8SDavid du Colombier cover(x, y);
97219b2ee8SDavid du Colombier x = ctm[0] * ubbox.urx + ctm[2] * ubbox.ury + ctm[4];
98219b2ee8SDavid du Colombier y = ctm[1] * ubbox.urx + ctm[3] * ubbox.ury + ctm[5];
99219b2ee8SDavid du Colombier cover(x, y);
100219b2ee8SDavid du Colombier x = ctm[0] * ubbox.urx + ctm[2] * ubbox.lly + ctm[4];
101219b2ee8SDavid du Colombier y = ctm[1] * ubbox.urx + ctm[3] * ubbox.lly + ctm[5];
102219b2ee8SDavid du Colombier cover(x, y);
103219b2ee8SDavid du Colombier bbox.llx -= slop + 0.5;
104219b2ee8SDavid du Colombier bbox.lly -= slop + 0.5;
105219b2ee8SDavid du Colombier bbox.urx += slop + 0.5;
106219b2ee8SDavid du Colombier bbox.ury += slop + 0.5;
107*14f51593SDavid du Colombier fprintf(fp, "%s %d %d %d %d\n", keyword, (int)bbox.llx, (int)bbox.lly,
108*14f51593SDavid du Colombier (int)bbox.urx, (int)bbox.ury);
109219b2ee8SDavid du Colombier bbox = ubbox;
110*14f51593SDavid du Colombier }
111*14f51593SDavid du Colombier resetbbox(fp == stdout);
112*14f51593SDavid du Colombier }
113219b2ee8SDavid du Colombier
114*14f51593SDavid du Colombier void
resetbbox(int output)115*14f51593SDavid du Colombier resetbbox(int output)
116219b2ee8SDavid du Colombier {
117219b2ee8SDavid du Colombier /*
118219b2ee8SDavid du Colombier * Adds bbox to docbbox and resets bbox for the next page. Only update docbbox
119219b2ee8SDavid du Colombier * if we really did output on the last page.
120219b2ee8SDavid du Colombier */
121219b2ee8SDavid du Colombier
122219b2ee8SDavid du Colombier if ( docbbox.set == TRUE ) {
123219b2ee8SDavid du Colombier cover(docbbox.llx, docbbox.lly);
124219b2ee8SDavid du Colombier cover(docbbox.urx, docbbox.ury);
125*14f51593SDavid du Colombier }
126219b2ee8SDavid du Colombier
127219b2ee8SDavid du Colombier if ( output == TRUE ) {
128219b2ee8SDavid du Colombier docbbox = bbox;
129219b2ee8SDavid du Colombier docbbox.set = TRUE;
130*14f51593SDavid du Colombier }
131219b2ee8SDavid du Colombier
132219b2ee8SDavid du Colombier bbox.set = FALSE;
133*14f51593SDavid du Colombier }
134219b2ee8SDavid du Colombier
135*14f51593SDavid du Colombier void
scale(double sx,double sy)136*14f51593SDavid du Colombier scale(double sx, double sy)
137219b2ee8SDavid du Colombier {
138219b2ee8SDavid du Colombier /*
139219b2ee8SDavid du Colombier * Scales the default matrix.
140219b2ee8SDavid du Colombier */
141219b2ee8SDavid du Colombier
142219b2ee8SDavid du Colombier matrix1[0] = sx;
143219b2ee8SDavid du Colombier matrix1[1] = 0;
144219b2ee8SDavid du Colombier matrix1[2] = 0;
145219b2ee8SDavid du Colombier matrix1[3] = sy;
146219b2ee8SDavid du Colombier matrix1[4] = 0;
147219b2ee8SDavid du Colombier matrix1[5] = 0;
148219b2ee8SDavid du Colombier
149219b2ee8SDavid du Colombier concat(matrix1);
150*14f51593SDavid du Colombier }
151219b2ee8SDavid du Colombier
152*14f51593SDavid du Colombier void
translate(double tx,double ty)153*14f51593SDavid du Colombier translate(double tx, double ty)
154219b2ee8SDavid du Colombier {
155219b2ee8SDavid du Colombier /*
156219b2ee8SDavid du Colombier * Translates the default matrix.
157219b2ee8SDavid du Colombier */
158219b2ee8SDavid du Colombier
159219b2ee8SDavid du Colombier matrix1[0] = 1.0;
160219b2ee8SDavid du Colombier matrix1[1] = 0.0;
161219b2ee8SDavid du Colombier matrix1[2] = 0.0;
162219b2ee8SDavid du Colombier matrix1[3] = 1.0;
163219b2ee8SDavid du Colombier matrix1[4] = tx;
164219b2ee8SDavid du Colombier matrix1[5] = ty;
165219b2ee8SDavid du Colombier
166219b2ee8SDavid du Colombier concat(matrix1);
167*14f51593SDavid du Colombier }
168219b2ee8SDavid du Colombier
169*14f51593SDavid du Colombier void
rotate(double angle)170*14f51593SDavid du Colombier rotate(double angle)
171219b2ee8SDavid du Colombier {
172219b2ee8SDavid du Colombier
173219b2ee8SDavid du Colombier /*
174219b2ee8SDavid du Colombier * Rotates by angle degrees.
175219b2ee8SDavid du Colombier */
176219b2ee8SDavid du Colombier
177*14f51593SDavid du Colombier angle *= M_PI / 180;
178219b2ee8SDavid du Colombier
179219b2ee8SDavid du Colombier matrix1[0] = matrix1[3] = cos(angle);
180219b2ee8SDavid du Colombier matrix1[1] = sin(angle);
181219b2ee8SDavid du Colombier matrix1[2] = -matrix1[1];
182219b2ee8SDavid du Colombier matrix1[4] = 0.0;
183219b2ee8SDavid du Colombier matrix1[5] = 0.0;
184219b2ee8SDavid du Colombier
185219b2ee8SDavid du Colombier concat(matrix1);
186*14f51593SDavid du Colombier }
187219b2ee8SDavid du Colombier
188*14f51593SDavid du Colombier void
concat(double m1[])189*14f51593SDavid du Colombier concat(double m1[])
190219b2ee8SDavid du Colombier {
191219b2ee8SDavid du Colombier double m2[6];
192219b2ee8SDavid du Colombier
193219b2ee8SDavid du Colombier /*
194219b2ee8SDavid du Colombier * Replaces the ctm[] by the result of the matrix multiplication m1[] x ctm[].
195219b2ee8SDavid du Colombier */
196219b2ee8SDavid du Colombier
197219b2ee8SDavid du Colombier m2[0] = ctm[0];
198219b2ee8SDavid du Colombier m2[1] = ctm[1];
199219b2ee8SDavid du Colombier m2[2] = ctm[2];
200219b2ee8SDavid du Colombier m2[3] = ctm[3];
201219b2ee8SDavid du Colombier m2[4] = ctm[4];
202219b2ee8SDavid du Colombier m2[5] = ctm[5];
203219b2ee8SDavid du Colombier
204219b2ee8SDavid du Colombier ctm[0] = m1[0] * m2[0] + m1[1] * m2[2];
205219b2ee8SDavid du Colombier ctm[1] = m1[0] * m2[1] + m1[1] * m2[3];
206219b2ee8SDavid du Colombier ctm[2] = m1[2] * m2[0] + m1[3] * m2[2];
207219b2ee8SDavid du Colombier ctm[3] = m1[2] * m2[1] + m1[3] * m2[3];
208219b2ee8SDavid du Colombier ctm[4] = m1[4] * m2[0] + m1[5] * m2[2] + m2[4];
209219b2ee8SDavid du Colombier ctm[5] = m1[4] * m2[1] + m1[5] * m2[3] + m2[5];
210*14f51593SDavid du Colombier }
211