xref: /plan9/sys/src/cmd/postscript/common/bbox.c (revision 14f51593fd82e19ba95969a8c07ff71131015979)
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