1 /*
2 * Boundingbox code for PostScript translators. The boundingbox for each page
3 * is accumulated in bbox - the one for the whole document goes in docbbox. A
4 * call to writebbox() puts out an appropriate comment, updates docbbox, and
5 * resets bbox for the next page. The assumption made at the end of writebbox()
6 * is that we're really printing the current page only if output is now going
7 * to stdout - a valid assumption for all supplied translators. Needs the math
8 * library.
9 */
10
11 #define _RESEARCH_SOURCE
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <sys/types.h>
18 #include <fcntl.h>
19 #include <math.h>
20
21 #include "comments.h" /* PostScript file structuring comments */
22 #include "gen.h" /* a few general purpose definitions */
23 #include "ext.h" /* external variable declarations */
24
25 typedef struct bbox {
26 int set;
27 double llx, lly;
28 double urx, ury;
29 } Bbox;
30
31 Bbox bbox = {FALSE, 0.0, 0.0, 0.0, 0.0};
32 Bbox docbbox = {FALSE, 0.0, 0.0, 0.0, 0.0};
33
34 double ctm[6] = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
35 double matrix1[6], matrix2[6];
36
37 void concat(double []);
38 void resetbbox(int);
39 void rotate(double);
40 void scale(double, double);
41 void translate(double, double);
42 void writebbox(FILE *, char *, int);
43
44 void
cover(x,y)45 cover(x, y)
46 double x, y;
47 {
48 /*
49 * Adds point (x, y) to bbox. Coordinates are in user space - the transformation
50 * to default coordinates happens in writebbox().
51 */
52
53 if ( bbox.set == FALSE ) {
54 bbox.llx = bbox.urx = x;
55 bbox.lly = bbox.ury = y;
56 bbox.set = TRUE;
57 } else {
58 if ( x < bbox.llx )
59 bbox.llx = x;
60 if ( y < bbox.lly )
61 bbox.lly = y;
62 if ( x > bbox.urx )
63 bbox.urx = x;
64 if ( y > bbox.ury )
65 bbox.ury = y;
66 }
67 }
68
69 void
writebbox(fp,keyword,slop)70 writebbox(fp, keyword, slop)
71 FILE *fp; /* the comment is written here */
72 char *keyword; /* the boundingbox comment string */
73 int slop; /* expand (or contract?) the box a bit */
74 {
75 Bbox ubbox; /* user space bounding box */
76 double x, y;
77
78 /*
79 * Transforms the numbers in the bbox[] using ctm[], adjusts the corners a bit
80 * (depending on slop) and then writes comment. If *keyword is BoundingBox use
81 * whatever's been saved in docbbox, otherwise assume the comment is just for
82 * the current page.
83 */
84
85 if ( strcmp(keyword, BOUNDINGBOX) == 0 )
86 bbox = docbbox;
87
88 if ( bbox.set == TRUE ) {
89 ubbox = bbox;
90 bbox.set = FALSE; /* so cover() works properly */
91 x = ctm[0] * ubbox.llx + ctm[2] * ubbox.lly + ctm[4];
92 y = ctm[1] * ubbox.llx + ctm[3] * ubbox.lly + ctm[5];
93 cover(x, y);
94 x = ctm[0] * ubbox.llx + ctm[2] * ubbox.ury + ctm[4];
95 y = ctm[1] * ubbox.llx + ctm[3] * ubbox.ury + ctm[5];
96 cover(x, y);
97 x = ctm[0] * ubbox.urx + ctm[2] * ubbox.ury + ctm[4];
98 y = ctm[1] * ubbox.urx + ctm[3] * ubbox.ury + ctm[5];
99 cover(x, y);
100 x = ctm[0] * ubbox.urx + ctm[2] * ubbox.lly + ctm[4];
101 y = ctm[1] * ubbox.urx + ctm[3] * ubbox.lly + ctm[5];
102 cover(x, y);
103 bbox.llx -= slop + 0.5;
104 bbox.lly -= slop + 0.5;
105 bbox.urx += slop + 0.5;
106 bbox.ury += slop + 0.5;
107 fprintf(fp, "%s %d %d %d %d\n", keyword, (int)bbox.llx, (int)bbox.lly,
108 (int)bbox.urx, (int)bbox.ury);
109 bbox = ubbox;
110 }
111 resetbbox(fp == stdout);
112 }
113
114 void
resetbbox(int output)115 resetbbox(int output)
116 {
117 /*
118 * Adds bbox to docbbox and resets bbox for the next page. Only update docbbox
119 * if we really did output on the last page.
120 */
121
122 if ( docbbox.set == TRUE ) {
123 cover(docbbox.llx, docbbox.lly);
124 cover(docbbox.urx, docbbox.ury);
125 }
126
127 if ( output == TRUE ) {
128 docbbox = bbox;
129 docbbox.set = TRUE;
130 }
131
132 bbox.set = FALSE;
133 }
134
135 void
scale(double sx,double sy)136 scale(double sx, double sy)
137 {
138 /*
139 * Scales the default matrix.
140 */
141
142 matrix1[0] = sx;
143 matrix1[1] = 0;
144 matrix1[2] = 0;
145 matrix1[3] = sy;
146 matrix1[4] = 0;
147 matrix1[5] = 0;
148
149 concat(matrix1);
150 }
151
152 void
translate(double tx,double ty)153 translate(double tx, double ty)
154 {
155 /*
156 * Translates the default matrix.
157 */
158
159 matrix1[0] = 1.0;
160 matrix1[1] = 0.0;
161 matrix1[2] = 0.0;
162 matrix1[3] = 1.0;
163 matrix1[4] = tx;
164 matrix1[5] = ty;
165
166 concat(matrix1);
167 }
168
169 void
rotate(double angle)170 rotate(double angle)
171 {
172
173 /*
174 * Rotates by angle degrees.
175 */
176
177 angle *= M_PI / 180;
178
179 matrix1[0] = matrix1[3] = cos(angle);
180 matrix1[1] = sin(angle);
181 matrix1[2] = -matrix1[1];
182 matrix1[4] = 0.0;
183 matrix1[5] = 0.0;
184
185 concat(matrix1);
186 }
187
188 void
concat(double m1[])189 concat(double m1[])
190 {
191 double m2[6];
192
193 /*
194 * Replaces the ctm[] by the result of the matrix multiplication m1[] x ctm[].
195 */
196
197 m2[0] = ctm[0];
198 m2[1] = ctm[1];
199 m2[2] = ctm[2];
200 m2[3] = ctm[3];
201 m2[4] = ctm[4];
202 m2[5] = ctm[5];
203
204 ctm[0] = m1[0] * m2[0] + m1[1] * m2[2];
205 ctm[1] = m1[0] * m2[1] + m1[1] * m2[3];
206 ctm[2] = m1[2] * m2[0] + m1[3] * m2[2];
207 ctm[3] = m1[2] * m2[1] + m1[3] * m2[3];
208 ctm[4] = m1[4] * m2[0] + m1[5] * m2[2] + m2[4];
209 ctm[5] = m1[4] * m2[1] + m1[5] * m2[3] + m2[5];
210 }
211