1 | #include "mupdf/fitz.h" |
2 | |
3 | #include <math.h> |
4 | #include <float.h> |
5 | #include <limits.h> |
6 | |
7 | #define MAX4(a,b,c,d) fz_max(fz_max(a,b), fz_max(c,d)) |
8 | #define MIN4(a,b,c,d) fz_min(fz_min(a,b), fz_min(c,d)) |
9 | |
10 | /* A useful macro to add with overflow detection and clamping. |
11 | |
12 | We want to do "b = a + x", but to allow for overflow. Consider the |
13 | top bits, and the cases in which overflow occurs: |
14 | |
15 | overflow a x b ~a^x a^b (~a^x)&(a^b) |
16 | no 0 0 0 1 0 0 |
17 | yes 0 0 1 1 1 1 |
18 | no 0 1 0 0 0 0 |
19 | no 0 1 1 0 1 0 |
20 | no 1 0 0 0 1 0 |
21 | no 1 0 1 0 0 0 |
22 | yes 1 1 0 1 1 1 |
23 | no 1 1 1 1 0 0 |
24 | */ |
25 | #define ADD_WITH_SAT(b,a,x) \ |
26 | ((b) = (a) + (x), (b) = (((~(a)^(x))&((a)^(b))) < 0 ? ((x) < 0 ? INT_MIN : INT_MAX) : (b))) |
27 | |
28 | /* Matrices, points and affine transformations */ |
29 | |
30 | const fz_matrix fz_identity = { 1, 0, 0, 1, 0, 0 }; |
31 | |
32 | /* |
33 | Multiply two matrices. |
34 | |
35 | The order of the two matrices are important since matrix |
36 | multiplication is not commutative. |
37 | |
38 | Returns result. |
39 | */ |
40 | fz_matrix |
41 | fz_concat(fz_matrix one, fz_matrix two) |
42 | { |
43 | fz_matrix dst; |
44 | dst.a = one.a * two.a + one.b * two.c; |
45 | dst.b = one.a * two.b + one.b * two.d; |
46 | dst.c = one.c * two.a + one.d * two.c; |
47 | dst.d = one.c * two.b + one.d * two.d; |
48 | dst.e = one.e * two.a + one.f * two.c + two.e; |
49 | dst.f = one.e * two.b + one.f * two.d + two.f; |
50 | return dst; |
51 | } |
52 | |
53 | /* |
54 | Create a scaling matrix. |
55 | |
56 | The returned matrix is of the form [ sx 0 0 sy 0 0 ]. |
57 | |
58 | m: Pointer to the matrix to populate |
59 | |
60 | sx, sy: Scaling factors along the X- and Y-axes. A scaling |
61 | factor of 1.0 will not cause any scaling along the relevant |
62 | axis. |
63 | |
64 | Returns m. |
65 | */ |
66 | fz_matrix |
67 | fz_scale(float sx, float sy) |
68 | { |
69 | fz_matrix m; |
70 | m.a = sx; m.b = 0; |
71 | m.c = 0; m.d = sy; |
72 | m.e = 0; m.f = 0; |
73 | return m; |
74 | } |
75 | |
76 | /* |
77 | Scale a matrix by premultiplication. |
78 | |
79 | m: Pointer to the matrix to scale |
80 | |
81 | sx, sy: Scaling factors along the X- and Y-axes. A scaling |
82 | factor of 1.0 will not cause any scaling along the relevant |
83 | axis. |
84 | |
85 | Returns m (updated). |
86 | */ |
87 | fz_matrix |
88 | fz_pre_scale(fz_matrix m, float sx, float sy) |
89 | { |
90 | m.a *= sx; |
91 | m.b *= sx; |
92 | m.c *= sy; |
93 | m.d *= sy; |
94 | return m; |
95 | } |
96 | |
97 | /* |
98 | Scale a matrix by postmultiplication. |
99 | |
100 | m: Pointer to the matrix to scale |
101 | |
102 | sx, sy: Scaling factors along the X- and Y-axes. A scaling |
103 | factor of 1.0 will not cause any scaling along the relevant |
104 | axis. |
105 | |
106 | Returns m (updated). |
107 | */ |
108 | fz_matrix |
109 | fz_post_scale(fz_matrix m, float sx, float sy) |
110 | { |
111 | m.a *= sx; |
112 | m.b *= sy; |
113 | m.c *= sx; |
114 | m.d *= sy; |
115 | m.e *= sx; |
116 | m.f *= sy; |
117 | return m; |
118 | } |
119 | |
120 | /* |
121 | Create a shearing matrix. |
122 | |
123 | The returned matrix is of the form [ 1 sy sx 1 0 0 ]. |
124 | |
125 | m: pointer to place to store returned matrix |
126 | |
127 | sx, sy: Shearing factors. A shearing factor of 0.0 will not |
128 | cause any shearing along the relevant axis. |
129 | |
130 | Returns m. |
131 | */ |
132 | fz_matrix |
133 | fz_shear(float h, float v) |
134 | { |
135 | fz_matrix m; |
136 | m.a = 1; m.b = v; |
137 | m.c = h; m.d = 1; |
138 | m.e = 0; m.f = 0; |
139 | return m; |
140 | } |
141 | |
142 | /* |
143 | Premultiply a matrix with a shearing matrix. |
144 | |
145 | The shearing matrix is of the form [ 1 sy sx 1 0 0 ]. |
146 | |
147 | m: pointer to matrix to premultiply |
148 | |
149 | sx, sy: Shearing factors. A shearing factor of 0.0 will not |
150 | cause any shearing along the relevant axis. |
151 | |
152 | Returns m (updated). |
153 | */ |
154 | fz_matrix |
155 | fz_pre_shear(fz_matrix m, float h, float v) |
156 | { |
157 | float a = m.a; |
158 | float b = m.b; |
159 | m.a += v * m.c; |
160 | m.b += v * m.d; |
161 | m.c += h * a; |
162 | m.d += h * b; |
163 | return m; |
164 | } |
165 | |
166 | /* |
167 | Create a rotation matrix. |
168 | |
169 | The returned matrix is of the form |
170 | [ cos(deg) sin(deg) -sin(deg) cos(deg) 0 0 ]. |
171 | |
172 | m: Pointer to place to store matrix |
173 | |
174 | degrees: Degrees of counter clockwise rotation. Values less |
175 | than zero and greater than 360 are handled as expected. |
176 | |
177 | Returns m. |
178 | */ |
179 | fz_matrix |
180 | fz_rotate(float theta) |
181 | { |
182 | fz_matrix m; |
183 | float s; |
184 | float c; |
185 | |
186 | while (theta < 0) |
187 | theta += 360; |
188 | while (theta >= 360) |
189 | theta -= 360; |
190 | |
191 | if (fabsf(0 - theta) < FLT_EPSILON) |
192 | { |
193 | s = 0; |
194 | c = 1; |
195 | } |
196 | else if (fabsf(90.0f - theta) < FLT_EPSILON) |
197 | { |
198 | s = 1; |
199 | c = 0; |
200 | } |
201 | else if (fabsf(180.0f - theta) < FLT_EPSILON) |
202 | { |
203 | s = 0; |
204 | c = -1; |
205 | } |
206 | else if (fabsf(270.0f - theta) < FLT_EPSILON) |
207 | { |
208 | s = -1; |
209 | c = 0; |
210 | } |
211 | else |
212 | { |
213 | s = sinf(theta * FZ_PI / 180); |
214 | c = cosf(theta * FZ_PI / 180); |
215 | } |
216 | |
217 | m.a = c; m.b = s; |
218 | m.c = -s; m.d = c; |
219 | m.e = 0; m.f = 0; |
220 | return m; |
221 | } |
222 | |
223 | /* |
224 | Rotate a transformation by premultiplying. |
225 | |
226 | The premultiplied matrix is of the form |
227 | [ cos(deg) sin(deg) -sin(deg) cos(deg) 0 0 ]. |
228 | |
229 | m: Pointer to matrix to premultiply. |
230 | |
231 | degrees: Degrees of counter clockwise rotation. Values less |
232 | than zero and greater than 360 are handled as expected. |
233 | |
234 | Returns m (updated). |
235 | */ |
236 | fz_matrix |
237 | fz_pre_rotate(fz_matrix m, float theta) |
238 | { |
239 | while (theta < 0) |
240 | theta += 360; |
241 | while (theta >= 360) |
242 | theta -= 360; |
243 | |
244 | if (fabsf(0 - theta) < FLT_EPSILON) |
245 | { |
246 | /* Nothing to do */ |
247 | } |
248 | else if (fabsf(90.0f - theta) < FLT_EPSILON) |
249 | { |
250 | float a = m.a; |
251 | float b = m.b; |
252 | m.a = m.c; |
253 | m.b = m.d; |
254 | m.c = -a; |
255 | m.d = -b; |
256 | } |
257 | else if (fabsf(180.0f - theta) < FLT_EPSILON) |
258 | { |
259 | m.a = -m.a; |
260 | m.b = -m.b; |
261 | m.c = -m.c; |
262 | m.d = -m.d; |
263 | } |
264 | else if (fabsf(270.0f - theta) < FLT_EPSILON) |
265 | { |
266 | float a = m.a; |
267 | float b = m.b; |
268 | m.a = -m.c; |
269 | m.b = -m.d; |
270 | m.c = a; |
271 | m.d = b; |
272 | } |
273 | else |
274 | { |
275 | float s = sinf(theta * FZ_PI / 180); |
276 | float c = cosf(theta * FZ_PI / 180); |
277 | float a = m.a; |
278 | float b = m.b; |
279 | m.a = c * a + s * m.c; |
280 | m.b = c * b + s * m.d; |
281 | m.c =-s * a + c * m.c; |
282 | m.d =-s * b + c * m.d; |
283 | } |
284 | |
285 | return m; |
286 | } |
287 | |
288 | /* |
289 | Create a translation matrix. |
290 | |
291 | The returned matrix is of the form [ 1 0 0 1 tx ty ]. |
292 | |
293 | m: A place to store the created matrix. |
294 | |
295 | tx, ty: Translation distances along the X- and Y-axes. A |
296 | translation of 0 will not cause any translation along the |
297 | relevant axis. |
298 | |
299 | Returns m. |
300 | */ |
301 | fz_matrix |
302 | fz_translate(float tx, float ty) |
303 | { |
304 | fz_matrix m; |
305 | m.a = 1; m.b = 0; |
306 | m.c = 0; m.d = 1; |
307 | m.e = tx; m.f = ty; |
308 | return m; |
309 | } |
310 | |
311 | /* |
312 | Translate a matrix by premultiplication. |
313 | |
314 | m: The matrix to translate |
315 | |
316 | tx, ty: Translation distances along the X- and Y-axes. A |
317 | translation of 0 will not cause any translation along the |
318 | relevant axis. |
319 | |
320 | Returns m. |
321 | */ |
322 | fz_matrix |
323 | fz_pre_translate(fz_matrix m, float tx, float ty) |
324 | { |
325 | m.e += tx * m.a + ty * m.c; |
326 | m.f += tx * m.b + ty * m.d; |
327 | return m; |
328 | } |
329 | |
330 | /* |
331 | Create transform matrix to draw page |
332 | at a given resolution and rotation. Adjusts the scaling |
333 | factors so that the page covers whole number of |
334 | pixels and adjust the page origin to be at 0,0. |
335 | */ |
336 | fz_matrix |
337 | fz_transform_page(fz_rect mediabox, float resolution, float rotate) |
338 | { |
339 | float user_w, user_h, pixel_w, pixel_h; |
340 | fz_rect pixel_box; |
341 | fz_matrix matrix; |
342 | |
343 | /* Adjust scaling factors to cover whole pixels */ |
344 | user_w = mediabox.x1 - mediabox.x0; |
345 | user_h = mediabox.y1 - mediabox.y0; |
346 | pixel_w = floorf(user_w * resolution / 72 + 0.5f); |
347 | pixel_h = floorf(user_h * resolution / 72 + 0.5f); |
348 | |
349 | matrix = fz_pre_rotate(fz_scale(pixel_w / user_w, pixel_h / user_h), rotate); |
350 | |
351 | /* Adjust the page origin to sit at 0,0 after rotation */ |
352 | pixel_box = fz_transform_rect(mediabox, matrix); |
353 | matrix.e -= pixel_box.x0; |
354 | matrix.f -= pixel_box.y0; |
355 | |
356 | return matrix; |
357 | } |
358 | |
359 | /* |
360 | Create an inverse matrix. |
361 | |
362 | inverse: Place to store inverse matrix. |
363 | |
364 | matrix: Matrix to invert. A degenerate matrix, where the |
365 | determinant is equal to zero, can not be inverted and the |
366 | original matrix is returned instead. |
367 | |
368 | Returns inverse. |
369 | */ |
370 | fz_matrix |
371 | fz_invert_matrix(fz_matrix src) |
372 | { |
373 | float a = src.a; |
374 | float det = a * src.d - src.b * src.c; |
375 | if (det < -FLT_EPSILON || det > FLT_EPSILON) |
376 | { |
377 | fz_matrix dst; |
378 | float rdet = 1 / det; |
379 | dst.a = src.d * rdet; |
380 | dst.b = -src.b * rdet; |
381 | dst.c = -src.c * rdet; |
382 | dst.d = a * rdet; |
383 | a = -src.e * dst.a - src.f * dst.c; |
384 | dst.f = -src.e * dst.b - src.f * dst.d; |
385 | dst.e = a; |
386 | return dst; |
387 | } |
388 | return src; |
389 | } |
390 | |
391 | /* |
392 | Attempt to create an inverse matrix. |
393 | |
394 | inverse: Place to store inverse matrix. |
395 | |
396 | matrix: Matrix to invert. A degenerate matrix, where the |
397 | determinant is equal to zero, can not be inverted. |
398 | |
399 | Returns 1 if matrix is degenerate (singular), or 0 otherwise. |
400 | */ |
401 | int |
402 | fz_try_invert_matrix(fz_matrix *dst, fz_matrix src) |
403 | { |
404 | double sa = (double)src.a; |
405 | double sb = (double)src.b; |
406 | double sc = (double)src.c; |
407 | double sd = (double)src.d; |
408 | double da, db, dc, dd; |
409 | double det = sa * sd - sb * sc; |
410 | if (det >= -DBL_EPSILON && det <= DBL_EPSILON) |
411 | return 1; |
412 | det = 1 / det; |
413 | da = sd * det; |
414 | dst->a = (float)da; |
415 | db = -sb * det; |
416 | dst->b = (float)db; |
417 | dc = -sc * det; |
418 | dst->c = (float)dc; |
419 | dd = sa * det; |
420 | dst->d = (float)dd; |
421 | da = -src.e * da - src.f * dc; |
422 | dst->f = (float)(-src.e * db - src.f * dd); |
423 | dst->e = (float)da; |
424 | return 0; |
425 | } |
426 | |
427 | /* |
428 | Check if a transformation is rectilinear. |
429 | |
430 | Rectilinear means that no shearing is present and that any |
431 | rotations present are a multiple of 90 degrees. Usually this |
432 | is used to make sure that axis-aligned rectangles before the |
433 | transformation are still axis-aligned rectangles afterwards. |
434 | */ |
435 | int |
436 | fz_is_rectilinear(fz_matrix m) |
437 | { |
438 | return (fabsf(m.b) < FLT_EPSILON && fabsf(m.c) < FLT_EPSILON) || |
439 | (fabsf(m.a) < FLT_EPSILON && fabsf(m.d) < FLT_EPSILON); |
440 | } |
441 | |
442 | /* |
443 | Calculate average scaling factor of matrix. |
444 | */ |
445 | float |
446 | fz_matrix_expansion(fz_matrix m) |
447 | { |
448 | return sqrtf(fabsf(m.a * m.d - m.b * m.c)); |
449 | } |
450 | |
451 | float |
452 | fz_matrix_max_expansion(fz_matrix m) |
453 | { |
454 | float max = fabsf(m.a); |
455 | float x = fabsf(m.b); |
456 | if (max < x) |
457 | max = x; |
458 | x = fabsf(m.c); |
459 | if (max < x) |
460 | max = x; |
461 | x = fabsf(m.d); |
462 | if (max < x) |
463 | max = x; |
464 | return max; |
465 | } |
466 | |
467 | /* |
468 | Apply a transformation to a point. |
469 | |
470 | transform: Transformation matrix to apply. See fz_concat, |
471 | fz_scale, fz_rotate and fz_translate for how to create a |
472 | matrix. |
473 | |
474 | point: Pointer to point to update. |
475 | |
476 | Returns transform (unchanged). |
477 | */ |
478 | fz_point |
479 | fz_transform_point(fz_point p, fz_matrix m) |
480 | { |
481 | float x = p.x; |
482 | p.x = x * m.a + p.y * m.c + m.e; |
483 | p.y = x * m.b + p.y * m.d + m.f; |
484 | return p; |
485 | } |
486 | |
487 | fz_point |
488 | fz_transform_point_xy(float x, float y, fz_matrix m) |
489 | { |
490 | fz_point p; |
491 | p.x = x * m.a + y * m.c + m.e; |
492 | p.y = x * m.b + y * m.d + m.f; |
493 | return p; |
494 | } |
495 | |
496 | /* |
497 | Apply a transformation to a vector. |
498 | |
499 | transform: Transformation matrix to apply. See fz_concat, |
500 | fz_scale and fz_rotate for how to create a matrix. Any |
501 | translation will be ignored. |
502 | |
503 | vector: Pointer to vector to update. |
504 | */ |
505 | fz_point |
506 | fz_transform_vector(fz_point p, fz_matrix m) |
507 | { |
508 | float x = p.x; |
509 | p.x = x * m.a + p.y * m.c; |
510 | p.y = x * m.b + p.y * m.d; |
511 | return p; |
512 | } |
513 | |
514 | /* |
515 | Normalize a vector to length one. |
516 | */ |
517 | fz_point |
518 | fz_normalize_vector(fz_point p) |
519 | { |
520 | float len = p.x * p.x + p.y * p.y; |
521 | if (len != 0) |
522 | { |
523 | len = sqrtf(len); |
524 | p.x /= len; |
525 | p.y /= len; |
526 | } |
527 | return p; |
528 | } |
529 | |
530 | /* Rectangles and bounding boxes */ |
531 | |
532 | /* biggest and smallest integers that a float can represent perfectly (i.e. 24 bits) */ |
533 | #define MAX_SAFE_INT 16777216 |
534 | #define MIN_SAFE_INT -16777216 |
535 | |
536 | const fz_rect fz_infinite_rect = { 1, 1, -1, -1 }; |
537 | const fz_rect fz_empty_rect = { 0, 0, 0, 0 }; |
538 | const fz_rect fz_unit_rect = { 0, 0, 1, 1 }; |
539 | |
540 | const fz_irect fz_infinite_irect = { 1, 1, -1, -1 }; |
541 | const fz_irect fz_empty_irect = { 0, 0, 0, 0 }; |
542 | const fz_irect fz_unit_bbox = { 0, 0, 1, 1 }; |
543 | |
544 | /* |
545 | Convert a rect into the minimal bounding box |
546 | that covers the rectangle. |
547 | |
548 | Coordinates in a bounding box are integers, so rounding of the |
549 | rects coordinates takes place. The top left corner is rounded |
550 | upwards and left while the bottom right corner is rounded |
551 | downwards and to the right. |
552 | */ |
553 | fz_irect |
554 | fz_irect_from_rect(fz_rect r) |
555 | { |
556 | fz_irect b; |
557 | if (fz_is_empty_rect(r)) |
558 | { |
559 | b.x0 = 0; |
560 | b.y0 = 0; |
561 | b.x1 = 0; |
562 | b.y1 = 0; |
563 | } |
564 | else |
565 | { |
566 | b.x0 = fz_clamp(floorf(r.x0), MIN_SAFE_INT, MAX_SAFE_INT); |
567 | b.y0 = fz_clamp(floorf(r.y0), MIN_SAFE_INT, MAX_SAFE_INT); |
568 | b.x1 = fz_clamp(ceilf(r.x1), MIN_SAFE_INT, MAX_SAFE_INT); |
569 | b.y1 = fz_clamp(ceilf(r.y1), MIN_SAFE_INT, MAX_SAFE_INT); |
570 | } |
571 | return b; |
572 | } |
573 | |
574 | /* |
575 | Convert a bbox into a rect. |
576 | |
577 | For our purposes, a rect can represent all the values we meet in |
578 | a bbox, so nothing can go wrong. |
579 | |
580 | rect: A place to store the generated rectangle. |
581 | |
582 | bbox: The bbox to convert. |
583 | |
584 | Returns rect (updated). |
585 | */ |
586 | fz_rect |
587 | fz_rect_from_irect(fz_irect a) |
588 | { |
589 | fz_rect r; |
590 | r.x0 = a.x0; |
591 | r.y0 = a.y0; |
592 | r.x1 = a.x1; |
593 | r.y1 = a.y1; |
594 | return r; |
595 | } |
596 | |
597 | /* |
598 | Round rectangle coordinates. |
599 | |
600 | Coordinates in a bounding box are integers, so rounding of the |
601 | rects coordinates takes place. The top left corner is rounded |
602 | upwards and left while the bottom right corner is rounded |
603 | downwards and to the right. |
604 | |
605 | This differs from fz_irect_from_rect, in that fz_irect_from_rect |
606 | slavishly follows the numbers (i.e any slight over/under calculations |
607 | can cause whole extra pixels to be added). fz_round_rect |
608 | allows for a small amount of rounding error when calculating |
609 | the bbox. |
610 | */ |
611 | fz_irect |
612 | fz_round_rect(fz_rect r) |
613 | { |
614 | fz_irect b; |
615 | int i; |
616 | |
617 | i = floorf(r.x0 + 0.001f); |
618 | b.x0 = fz_clamp(i, MIN_SAFE_INT, MAX_SAFE_INT); |
619 | i = floorf(r.y0 + 0.001f); |
620 | b.y0 = fz_clamp(i, MIN_SAFE_INT, MAX_SAFE_INT); |
621 | i = ceilf(r.x1 - 0.001f); |
622 | b.x1 = fz_clamp(i, MIN_SAFE_INT, MAX_SAFE_INT); |
623 | i = ceilf(r.y1 - 0.001f); |
624 | b.y1 = fz_clamp(i, MIN_SAFE_INT, MAX_SAFE_INT); |
625 | |
626 | return b; |
627 | } |
628 | |
629 | /* |
630 | Compute intersection of two rectangles. |
631 | |
632 | Given two rectangles, update the first to be the smallest |
633 | axis-aligned rectangle that covers the area covered by both |
634 | given rectangles. If either rectangle is empty then the |
635 | intersection is also empty. If either rectangle is infinite |
636 | then the intersection is simply the non-infinite rectangle. |
637 | Should both rectangles be infinite, then the intersection is |
638 | also infinite. |
639 | */ |
640 | fz_rect |
641 | fz_intersect_rect(fz_rect a, fz_rect b) |
642 | { |
643 | /* Check for empty box before infinite box */ |
644 | if (fz_is_empty_rect(a)) return fz_empty_rect; |
645 | if (fz_is_empty_rect(b)) return fz_empty_rect; |
646 | if (fz_is_infinite_rect(b)) return a; |
647 | if (fz_is_infinite_rect(a)) return b; |
648 | if (a.x0 < b.x0) |
649 | a.x0 = b.x0; |
650 | if (a.y0 < b.y0) |
651 | a.y0 = b.y0; |
652 | if (a.x1 > b.x1) |
653 | a.x1 = b.x1; |
654 | if (a.y1 > b.y1) |
655 | a.y1 = b.y1; |
656 | if (a.x1 < a.x0 || a.y1 < a.y0) |
657 | return fz_empty_rect; |
658 | return a; |
659 | } |
660 | |
661 | /* |
662 | Compute intersection of two bounding boxes. |
663 | |
664 | Similar to fz_intersect_rect but operates on two bounding |
665 | boxes instead of two rectangles. |
666 | */ |
667 | fz_irect |
668 | fz_intersect_irect(fz_irect a, fz_irect b) |
669 | { |
670 | /* Check for empty box before infinite box */ |
671 | if (fz_is_empty_irect(a)) return fz_empty_irect; |
672 | if (fz_is_empty_irect(b)) return fz_empty_irect; |
673 | if (fz_is_infinite_irect(b)) return a; |
674 | if (fz_is_infinite_irect(a)) return b; |
675 | if (a.x0 < b.x0) |
676 | a.x0 = b.x0; |
677 | if (a.y0 < b.y0) |
678 | a.y0 = b.y0; |
679 | if (a.x1 > b.x1) |
680 | a.x1 = b.x1; |
681 | if (a.y1 > b.y1) |
682 | a.y1 = b.y1; |
683 | if (a.x1 < a.x0 || a.y1 < a.y0) |
684 | return fz_empty_irect; |
685 | return a; |
686 | } |
687 | |
688 | /* |
689 | Compute union of two rectangles. |
690 | |
691 | Given two rectangles, update the first to be the smallest |
692 | axis-aligned rectangle that encompasses both given rectangles. |
693 | If either rectangle is infinite then the union is also infinite. |
694 | If either rectangle is empty then the union is simply the |
695 | non-empty rectangle. Should both rectangles be empty, then the |
696 | union is also empty. |
697 | */ |
698 | fz_rect |
699 | fz_union_rect(fz_rect a, fz_rect b) |
700 | { |
701 | /* Check for empty box before infinite box */ |
702 | if (fz_is_empty_rect(b)) return a; |
703 | if (fz_is_empty_rect(a)) return b; |
704 | if (fz_is_infinite_rect(a)) return a; |
705 | if (fz_is_infinite_rect(b)) return b; |
706 | if (a.x0 > b.x0) |
707 | a.x0 = b.x0; |
708 | if (a.y0 > b.y0) |
709 | a.y0 = b.y0; |
710 | if (a.x1 < b.x1) |
711 | a.x1 = b.x1; |
712 | if (a.y1 < b.y1) |
713 | a.y1 = b.y1; |
714 | return a; |
715 | } |
716 | |
717 | /* |
718 | Translate bounding box. |
719 | |
720 | Translate a bbox by a given x and y offset. Allows for overflow. |
721 | */ |
722 | fz_rect |
723 | fz_translate_rect(fz_rect a, float xoff, float yoff) |
724 | { |
725 | if (fz_is_empty_rect(a)) return a; |
726 | if (fz_is_infinite_rect(a)) return a; |
727 | a.x0 += xoff; |
728 | a.y0 += yoff; |
729 | a.x1 += xoff; |
730 | a.y1 += yoff; |
731 | return a; |
732 | } |
733 | |
734 | fz_irect |
735 | fz_translate_irect(fz_irect a, int xoff, int yoff) |
736 | { |
737 | int t; |
738 | |
739 | if (fz_is_empty_irect(a)) return a; |
740 | if (fz_is_infinite_irect(a)) return a; |
741 | a.x0 = ADD_WITH_SAT(t, a.x0, xoff); |
742 | a.y0 = ADD_WITH_SAT(t, a.y0, yoff); |
743 | a.x1 = ADD_WITH_SAT(t, a.x1, xoff); |
744 | a.y1 = ADD_WITH_SAT(t, a.y1, yoff); |
745 | return a; |
746 | } |
747 | |
748 | /* |
749 | Apply a transform to a rectangle. |
750 | |
751 | After the four corner points of the axis-aligned rectangle |
752 | have been transformed it may not longer be axis-aligned. So a |
753 | new axis-aligned rectangle is created covering at least the |
754 | area of the transformed rectangle. |
755 | |
756 | transform: Transformation matrix to apply. See fz_concat, |
757 | fz_scale and fz_rotate for how to create a matrix. |
758 | |
759 | rect: Rectangle to be transformed. The two special cases |
760 | fz_empty_rect and fz_infinite_rect, may be used but are |
761 | returned unchanged as expected. |
762 | */ |
763 | fz_rect |
764 | fz_transform_rect(fz_rect r, fz_matrix m) |
765 | { |
766 | fz_point s, t, u, v; |
767 | |
768 | if (fz_is_infinite_rect(r)) |
769 | return r; |
770 | |
771 | if (fabsf(m.b) < FLT_EPSILON && fabsf(m.c) < FLT_EPSILON) |
772 | { |
773 | if (m.a < 0) |
774 | { |
775 | float f = r.x0; |
776 | r.x0 = r.x1; |
777 | r.x1 = f; |
778 | } |
779 | if (m.d < 0) |
780 | { |
781 | float f = r.y0; |
782 | r.y0 = r.y1; |
783 | r.y1 = f; |
784 | } |
785 | s = fz_transform_point_xy(r.x0, r.y0, m); |
786 | t = fz_transform_point_xy(r.x1, r.y1, m); |
787 | r.x0 = s.x; r.y0 = s.y; |
788 | r.x1 = t.x; r.y1 = t.y; |
789 | return r; |
790 | } |
791 | |
792 | s.x = r.x0; s.y = r.y0; |
793 | t.x = r.x0; t.y = r.y1; |
794 | u.x = r.x1; u.y = r.y1; |
795 | v.x = r.x1; v.y = r.y0; |
796 | s = fz_transform_point(s, m); |
797 | t = fz_transform_point(t, m); |
798 | u = fz_transform_point(u, m); |
799 | v = fz_transform_point(v, m); |
800 | r.x0 = MIN4(s.x, t.x, u.x, v.x); |
801 | r.y0 = MIN4(s.y, t.y, u.y, v.y); |
802 | r.x1 = MAX4(s.x, t.x, u.x, v.x); |
803 | r.y1 = MAX4(s.y, t.y, u.y, v.y); |
804 | return r; |
805 | } |
806 | |
807 | fz_irect |
808 | fz_expand_irect(fz_irect a, int expand) |
809 | { |
810 | if (fz_is_infinite_irect(a)) return a; |
811 | a.x0 -= expand; |
812 | a.y0 -= expand; |
813 | a.x1 += expand; |
814 | a.y1 += expand; |
815 | return a; |
816 | } |
817 | |
818 | /* |
819 | Expand a bbox by a given amount in all directions. |
820 | */ |
821 | fz_rect |
822 | fz_expand_rect(fz_rect a, float expand) |
823 | { |
824 | if (fz_is_infinite_rect(a)) return a; |
825 | a.x0 -= expand; |
826 | a.y0 -= expand; |
827 | a.x1 += expand; |
828 | a.y1 += expand; |
829 | return a; |
830 | } |
831 | |
832 | /* |
833 | Expand a bbox to include a given point. |
834 | To create a rectangle that encompasses a sequence of points, the |
835 | rectangle must first be set to be the empty rectangle at one of |
836 | the points before including the others. |
837 | */ |
838 | fz_rect fz_include_point_in_rect(fz_rect r, fz_point p) |
839 | { |
840 | if (fz_is_infinite_rect(r)) return r; |
841 | if (p.x < r.x0) r.x0 = p.x; |
842 | if (p.x > r.x1) r.x1 = p.x; |
843 | if (p.y < r.y0) r.y0 = p.y; |
844 | if (p.y > r.y1) r.y1 = p.y; |
845 | return r; |
846 | } |
847 | |
848 | /* |
849 | Test rectangle inclusion. |
850 | |
851 | Return true if a entirely contains b. |
852 | */ |
853 | int fz_contains_rect(fz_rect a, fz_rect b) |
854 | { |
855 | if (fz_is_empty_rect(b)) |
856 | return 1; |
857 | if (fz_is_empty_rect(a)) |
858 | return 0; |
859 | return ((a.x0 <= b.x0) && |
860 | (a.y0 <= b.y0) && |
861 | (a.x1 >= b.x1) && |
862 | (a.y1 >= b.y1)); |
863 | } |
864 | |
865 | fz_rect |
866 | fz_rect_from_quad(fz_quad q) |
867 | { |
868 | fz_rect r; |
869 | r.x0 = MIN4(q.ll.x, q.lr.x, q.ul.x, q.ur.x); |
870 | r.y0 = MIN4(q.ll.y, q.lr.y, q.ul.y, q.ur.y); |
871 | r.x1 = MAX4(q.ll.x, q.lr.x, q.ul.x, q.ur.x); |
872 | r.y1 = MAX4(q.ll.y, q.lr.y, q.ul.y, q.ur.y); |
873 | return r; |
874 | } |
875 | |
876 | fz_quad |
877 | fz_transform_quad(fz_quad q, fz_matrix m) |
878 | { |
879 | q.ul = fz_transform_point(q.ul, m); |
880 | q.ur = fz_transform_point(q.ur, m); |
881 | q.ll = fz_transform_point(q.ll, m); |
882 | q.lr = fz_transform_point(q.lr, m); |
883 | return q; |
884 | } |
885 | |
886 | int fz_is_point_inside_rect(fz_point p, fz_rect r) |
887 | { |
888 | return (p.x >= r.x0 && p.x < r.x1 && p.y >= r.y0 && p.y < r.y1); |
889 | } |
890 | |
891 | int fz_is_point_inside_irect(int x, int y, fz_irect r) |
892 | { |
893 | return (x >= r.x0 && x < r.x1 && y >= r.y0 && y < r.y1); |
894 | } |
895 | |
896 | int fz_is_point_inside_quad(fz_point p, fz_quad q) |
897 | { |
898 | // TODO: non-rectilinear quads |
899 | return fz_is_point_inside_rect(p, fz_rect_from_quad(q)); |
900 | } |
901 | |