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