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 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 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 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 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 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 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 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