comparison mupdf-source/source/fitz/geometry.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2025 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #include "mupdf/fitz.h"
24
25 #include <math.h>
26 #include <float.h>
27 #include <limits.h>
28
29 #define MAX4(a,b,c,d) fz_max(fz_max(a,b), fz_max(c,d))
30 #define MIN4(a,b,c,d) fz_min(fz_min(a,b), fz_min(c,d))
31
32 /* A useful macro to add with overflow detection and clamping.
33
34 We want to do "b = a + x", but to allow for overflow. Consider the
35 top bits, and the cases in which overflow occurs:
36
37 overflow a x b ~a^x a^b (~a^x)&(a^b)
38 no 0 0 0 1 0 0
39 yes 0 0 1 1 1 1
40 no 0 1 0 0 0 0
41 no 0 1 1 0 1 0
42 no 1 0 0 0 1 0
43 no 1 0 1 0 0 0
44 yes 1 1 0 1 1 1
45 no 1 1 1 1 0 0
46 */
47 #define ADD_WITH_SAT(b,a,x) \
48 ((b) = (a) + (x), (b) = (((~(a)^(x))&((a)^(b))) < 0 ? ((x) < 0 ? INT_MIN : INT_MAX) : (b)))
49
50 /* Matrices, points and affine transformations */
51
52 const fz_matrix fz_identity = { 1, 0, 0, 1, 0, 0 };
53
54 fz_matrix
55 fz_concat(fz_matrix one, fz_matrix two)
56 {
57 fz_matrix dst;
58 dst.a = one.a * two.a + one.b * two.c;
59 dst.b = one.a * two.b + one.b * two.d;
60 dst.c = one.c * two.a + one.d * two.c;
61 dst.d = one.c * two.b + one.d * two.d;
62 dst.e = one.e * two.a + one.f * two.c + two.e;
63 dst.f = one.e * two.b + one.f * two.d + two.f;
64 return dst;
65 }
66
67 fz_matrix
68 fz_scale(float sx, float sy)
69 {
70 fz_matrix m;
71 m.a = sx; m.b = 0;
72 m.c = 0; m.d = sy;
73 m.e = 0; m.f = 0;
74 return m;
75 }
76
77 fz_matrix
78 fz_pre_scale(fz_matrix m, float sx, float sy)
79 {
80 m.a *= sx;
81 m.b *= sx;
82 m.c *= sy;
83 m.d *= sy;
84 return m;
85 }
86
87 fz_matrix
88 fz_post_scale(fz_matrix m, float sx, float sy)
89 {
90 m.a *= sx;
91 m.b *= sy;
92 m.c *= sx;
93 m.d *= sy;
94 m.e *= sx;
95 m.f *= sy;
96 return m;
97 }
98
99 fz_matrix
100 fz_shear(float h, float v)
101 {
102 fz_matrix m;
103 m.a = 1; m.b = v;
104 m.c = h; m.d = 1;
105 m.e = 0; m.f = 0;
106 return m;
107 }
108
109 fz_matrix
110 fz_pre_shear(fz_matrix m, float h, float v)
111 {
112 float a = m.a;
113 float b = m.b;
114 m.a += v * m.c;
115 m.b += v * m.d;
116 m.c += h * a;
117 m.d += h * b;
118 return m;
119 }
120
121 fz_matrix
122 fz_rotate(float theta)
123 {
124 fz_matrix m;
125 float s;
126 float c;
127
128 while (theta < 0)
129 theta += 360;
130 while (theta >= 360)
131 theta -= 360;
132
133 if (fabsf(0 - theta) < FLT_EPSILON)
134 {
135 s = 0;
136 c = 1;
137 }
138 else if (fabsf(90.0f - theta) < FLT_EPSILON)
139 {
140 s = 1;
141 c = 0;
142 }
143 else if (fabsf(180.0f - theta) < FLT_EPSILON)
144 {
145 s = 0;
146 c = -1;
147 }
148 else if (fabsf(270.0f - theta) < FLT_EPSILON)
149 {
150 s = -1;
151 c = 0;
152 }
153 else
154 {
155 s = sinf(theta * FZ_PI / 180);
156 c = cosf(theta * FZ_PI / 180);
157 }
158
159 m.a = c; m.b = s;
160 m.c = -s; m.d = c;
161 m.e = 0; m.f = 0;
162 return m;
163 }
164
165 fz_matrix
166 fz_pre_rotate(fz_matrix m, float theta)
167 {
168 while (theta < 0)
169 theta += 360;
170 while (theta >= 360)
171 theta -= 360;
172
173 if (fabsf(0 - theta) < FLT_EPSILON)
174 {
175 /* Nothing to do */
176 }
177 else if (fabsf(90.0f - theta) < FLT_EPSILON)
178 {
179 float a = m.a;
180 float b = m.b;
181 m.a = m.c;
182 m.b = m.d;
183 m.c = -a;
184 m.d = -b;
185 }
186 else if (fabsf(180.0f - theta) < FLT_EPSILON)
187 {
188 m.a = -m.a;
189 m.b = -m.b;
190 m.c = -m.c;
191 m.d = -m.d;
192 }
193 else if (fabsf(270.0f - theta) < FLT_EPSILON)
194 {
195 float a = m.a;
196 float b = m.b;
197 m.a = -m.c;
198 m.b = -m.d;
199 m.c = a;
200 m.d = b;
201 }
202 else
203 {
204 float s = sinf(theta * FZ_PI / 180);
205 float c = cosf(theta * FZ_PI / 180);
206 float a = m.a;
207 float b = m.b;
208 m.a = c * a + s * m.c;
209 m.b = c * b + s * m.d;
210 m.c =-s * a + c * m.c;
211 m.d =-s * b + c * m.d;
212 }
213
214 return m;
215 }
216
217 fz_matrix
218 fz_translate(float tx, float ty)
219 {
220 fz_matrix m;
221 m.a = 1; m.b = 0;
222 m.c = 0; m.d = 1;
223 m.e = tx; m.f = ty;
224 return m;
225 }
226
227 fz_matrix
228 fz_pre_translate(fz_matrix m, float tx, float ty)
229 {
230 m.e += tx * m.a + ty * m.c;
231 m.f += tx * m.b + ty * m.d;
232 return m;
233 }
234
235 fz_matrix
236 fz_transform_page(fz_rect mediabox, float resolution, float rotate)
237 {
238 float user_w, user_h, pixel_w, pixel_h;
239 fz_rect pixel_box;
240 fz_matrix matrix;
241
242 /* Adjust scaling factors to cover whole pixels */
243 user_w = mediabox.x1 - mediabox.x0;
244 user_h = mediabox.y1 - mediabox.y0;
245 pixel_w = floorf(user_w * resolution / 72 + 0.5f);
246 pixel_h = floorf(user_h * resolution / 72 + 0.5f);
247
248 matrix = fz_pre_rotate(fz_scale(pixel_w / user_w, pixel_h / user_h), rotate);
249
250 /* Adjust the page origin to sit at 0,0 after rotation */
251 pixel_box = fz_transform_rect(mediabox, matrix);
252 matrix.e -= pixel_box.x0;
253 matrix.f -= pixel_box.y0;
254
255 return matrix;
256 }
257
258 fz_matrix
259 fz_invert_matrix(fz_matrix src)
260 {
261 float a = src.a;
262 float det = a * src.d - src.b * src.c;
263 if (det < -FLT_EPSILON || det > FLT_EPSILON)
264 {
265 fz_matrix dst;
266 float rdet = 1 / det;
267 dst.a = src.d * rdet;
268 dst.b = -src.b * rdet;
269 dst.c = -src.c * rdet;
270 dst.d = a * rdet;
271 a = -src.e * dst.a - src.f * dst.c;
272 dst.f = -src.e * dst.b - src.f * dst.d;
273 dst.e = a;
274 return dst;
275 }
276 return src;
277 }
278
279 int
280 fz_try_invert_matrix(fz_matrix *dst, fz_matrix src)
281 {
282 double sa = (double)src.a;
283 double sb = (double)src.b;
284 double sc = (double)src.c;
285 double sd = (double)src.d;
286 double da, db, dc, dd;
287 double det = sa * sd - sb * sc;
288 if (det >= -DBL_EPSILON && det <= DBL_EPSILON)
289 return 1;
290 det = 1 / det;
291 da = sd * det;
292 dst->a = (float)da;
293 db = -sb * det;
294 dst->b = (float)db;
295 dc = -sc * det;
296 dst->c = (float)dc;
297 dd = sa * det;
298 dst->d = (float)dd;
299 da = -src.e * da - src.f * dc;
300 dst->f = (float)(-src.e * db - src.f * dd);
301 dst->e = (float)da;
302 return 0;
303 }
304
305 int
306 fz_is_rectilinear(fz_matrix m)
307 {
308 return (fabsf(m.b) < FLT_EPSILON && fabsf(m.c) < FLT_EPSILON) ||
309 (fabsf(m.a) < FLT_EPSILON && fabsf(m.d) < FLT_EPSILON);
310 }
311
312 float
313 fz_matrix_expansion(fz_matrix m)
314 {
315 return sqrtf(fabsf(m.a * m.d - m.b * m.c));
316 }
317
318 float
319 fz_matrix_max_expansion(fz_matrix m)
320 {
321 float max = fabsf(m.a);
322 float x = fabsf(m.b);
323 if (max < x)
324 max = x;
325 x = fabsf(m.c);
326 if (max < x)
327 max = x;
328 x = fabsf(m.d);
329 if (max < x)
330 max = x;
331 return max;
332 }
333
334 fz_point
335 fz_transform_point(fz_point p, fz_matrix m)
336 {
337 float x = p.x;
338 p.x = x * m.a + p.y * m.c + m.e;
339 p.y = x * m.b + p.y * m.d + m.f;
340 return p;
341 }
342
343 fz_point
344 fz_transform_point_xy(float x, float y, fz_matrix m)
345 {
346 fz_point p;
347 p.x = x * m.a + y * m.c + m.e;
348 p.y = x * m.b + y * m.d + m.f;
349 return p;
350 }
351
352 fz_point
353 fz_transform_vector(fz_point p, fz_matrix m)
354 {
355 float x = p.x;
356 p.x = x * m.a + p.y * m.c;
357 p.y = x * m.b + p.y * m.d;
358 return p;
359 }
360
361 fz_point
362 fz_normalize_vector(fz_point p)
363 {
364 float len = p.x * p.x + p.y * p.y;
365 if (len != 0)
366 {
367 len = sqrtf(len);
368 p.x /= len;
369 p.y /= len;
370 }
371 return p;
372 }
373
374 /* Rectangles and bounding boxes */
375
376 /* biggest and smallest integers that a float can represent perfectly (i.e. 24 bits) */
377 #define MAX_SAFE_INT 16777216
378 #define MIN_SAFE_INT -16777216
379
380 const fz_rect fz_infinite_rect = { FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT };
381 const fz_rect fz_empty_rect = { FZ_MAX_INF_RECT, FZ_MAX_INF_RECT, FZ_MIN_INF_RECT, FZ_MIN_INF_RECT };
382 const fz_rect fz_invalid_rect = { 0, 0, -1, -1 };
383 const fz_rect fz_unit_rect = { 0, 0, 1, 1 };
384
385 const fz_irect fz_infinite_irect = { FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT };
386 const fz_irect fz_empty_irect = { FZ_MAX_INF_RECT, FZ_MAX_INF_RECT, FZ_MIN_INF_RECT, FZ_MIN_INF_RECT };
387 const fz_irect fz_invalid_irect = { 0, 0, -1, -1 };
388 const fz_irect fz_unit_bbox = { 0, 0, 1, 1 };
389
390 const fz_quad fz_infinite_quad = { { -INFINITY, INFINITY}, {INFINITY, INFINITY}, {-INFINITY, -INFINITY}, {INFINITY, -INFINITY} };
391 const fz_quad fz_invalid_quad = { {NAN, NAN}, {NAN, NAN}, {NAN, NAN}, {NAN, NAN} };
392
393 fz_irect
394 fz_irect_from_rect(fz_rect r)
395 {
396 fz_irect b;
397 if (fz_is_infinite_rect(r))
398 return fz_infinite_irect;
399 if (!fz_is_valid_rect(r))
400 return fz_invalid_irect;
401
402 b.x0 = fz_clamp(floorf(r.x0), MIN_SAFE_INT, MAX_SAFE_INT);
403 b.y0 = fz_clamp(floorf(r.y0), MIN_SAFE_INT, MAX_SAFE_INT);
404 b.x1 = fz_clamp(ceilf(r.x1), MIN_SAFE_INT, MAX_SAFE_INT);
405 b.y1 = fz_clamp(ceilf(r.y1), MIN_SAFE_INT, MAX_SAFE_INT);
406
407 return b;
408 }
409
410 fz_rect
411 fz_rect_from_irect(fz_irect a)
412 {
413 fz_rect r;
414
415 if (fz_is_infinite_irect(a))
416 return fz_infinite_rect;
417
418 r.x0 = a.x0;
419 r.y0 = a.y0;
420 r.x1 = a.x1;
421 r.y1 = a.y1;
422 return r;
423 }
424
425 fz_irect
426 fz_round_rect(fz_rect r)
427 {
428 fz_irect b;
429 float f;
430
431 f = floorf(r.x0 + 0.001f);
432 b.x0 = fz_clamp(f, MIN_SAFE_INT, MAX_SAFE_INT);
433 f = floorf(r.y0 + 0.001f);
434 b.y0 = fz_clamp(f, MIN_SAFE_INT, MAX_SAFE_INT);
435 f = ceilf(r.x1 - 0.001f);
436 b.x1 = fz_clamp(f, MIN_SAFE_INT, MAX_SAFE_INT);
437 f = ceilf(r.y1 - 0.001f);
438 b.y1 = fz_clamp(f, MIN_SAFE_INT, MAX_SAFE_INT);
439
440 return b;
441 }
442
443 fz_rect
444 fz_intersect_rect(fz_rect a, fz_rect b)
445 {
446 if (fz_is_infinite_rect(b)) return a;
447 if (fz_is_infinite_rect(a)) return b;
448 if (a.x0 < b.x0)
449 a.x0 = b.x0;
450 if (a.y0 < b.y0)
451 a.y0 = b.y0;
452 if (a.x1 > b.x1)
453 a.x1 = b.x1;
454 if (a.y1 > b.y1)
455 a.y1 = b.y1;
456 return a;
457 }
458
459 fz_irect
460 fz_intersect_irect(fz_irect a, fz_irect b)
461 {
462 if (fz_is_infinite_irect(b)) return a;
463 if (fz_is_infinite_irect(a)) return b;
464 if (a.x0 < b.x0)
465 a.x0 = b.x0;
466 if (a.y0 < b.y0)
467 a.y0 = b.y0;
468 if (a.x1 > b.x1)
469 a.x1 = b.x1;
470 if (a.y1 > b.y1)
471 a.y1 = b.y1;
472 return a;
473 }
474
475 fz_rect
476 fz_union_rect(fz_rect a, fz_rect b)
477 {
478 /* Check for empty box before infinite box */
479 if (!fz_is_valid_rect(b)) return a;
480 if (!fz_is_valid_rect(a)) return b;
481 if (fz_is_infinite_rect(a)) return a;
482 if (fz_is_infinite_rect(b)) return b;
483 if (a.x0 > b.x0)
484 a.x0 = b.x0;
485 if (a.y0 > b.y0)
486 a.y0 = b.y0;
487 if (a.x1 < b.x1)
488 a.x1 = b.x1;
489 if (a.y1 < b.y1)
490 a.y1 = b.y1;
491 return a;
492 }
493
494 fz_rect
495 fz_translate_rect(fz_rect a, float xoff, float yoff)
496 {
497 if (fz_is_infinite_rect(a)) return a;
498 a.x0 += xoff;
499 a.y0 += yoff;
500 a.x1 += xoff;
501 a.y1 += yoff;
502 return a;
503 }
504
505 fz_irect
506 fz_translate_irect(fz_irect a, int xoff, int yoff)
507 {
508 int t;
509
510 if (fz_is_empty_irect(a)) return a;
511 if (fz_is_infinite_irect(a)) return a;
512 a.x0 = ADD_WITH_SAT(t, a.x0, xoff);
513 a.y0 = ADD_WITH_SAT(t, a.y0, yoff);
514 a.x1 = ADD_WITH_SAT(t, a.x1, xoff);
515 a.y1 = ADD_WITH_SAT(t, a.y1, yoff);
516 return a;
517 }
518
519 fz_rect
520 fz_transform_rect(fz_rect r, fz_matrix m)
521 {
522 fz_point s, t, u, v;
523 int invalid;
524
525 if (fz_is_infinite_rect(r))
526 return r;
527
528 if (fabsf(m.b) < FLT_EPSILON && fabsf(m.c) < FLT_EPSILON)
529 {
530 if (m.a < 0)
531 {
532 float f = r.x0;
533 r.x0 = r.x1;
534 r.x1 = f;
535 }
536 if (m.d < 0)
537 {
538 float f = r.y0;
539 r.y0 = r.y1;
540 r.y1 = f;
541 }
542 s = fz_transform_point_xy(r.x0, r.y0, m);
543 t = fz_transform_point_xy(r.x1, r.y1, m);
544 r.x0 = s.x; r.y0 = s.y;
545 r.x1 = t.x; r.y1 = t.y;
546 /* If r was invalid coming in, it'll still be invalid now. */
547 return r;
548 }
549 else if (fabsf(m.a) < FLT_EPSILON && fabsf(m.d) < FLT_EPSILON)
550 {
551 if (m.b < 0)
552 {
553 float f = r.x0;
554 r.x0 = r.x1;
555 r.x1 = f;
556 }
557 if (m.c < 0)
558 {
559 float f = r.y0;
560 r.y0 = r.y1;
561 r.y1 = f;
562 }
563 s = fz_transform_point_xy(r.x0, r.y0, m);
564 t = fz_transform_point_xy(r.x1, r.y1, m);
565 r.x0 = s.x; r.y0 = s.y;
566 r.x1 = t.x; r.y1 = t.y;
567 /* If r was invalid coming in, it'll still be invalid now. */
568 return r;
569 }
570
571 invalid = (r.x0 > r.x1) || (r.y0 > r.y1);
572 s.x = r.x0; s.y = r.y0;
573 t.x = r.x0; t.y = r.y1;
574 u.x = r.x1; u.y = r.y1;
575 v.x = r.x1; v.y = r.y0;
576 s = fz_transform_point(s, m);
577 t = fz_transform_point(t, m);
578 u = fz_transform_point(u, m);
579 v = fz_transform_point(v, m);
580 r.x0 = MIN4(s.x, t.x, u.x, v.x);
581 r.y0 = MIN4(s.y, t.y, u.y, v.y);
582 r.x1 = MAX4(s.x, t.x, u.x, v.x);
583 r.y1 = MAX4(s.y, t.y, u.y, v.y);
584
585 /* If we were called with an invalid rectangle, return an
586 * invalid rectangle after transformation. */
587 if (invalid)
588 {
589 float f;
590 f = r.x0; r.x0 = r.x1; r.x1 = f;
591 f = r.y0; r.y0 = r.y1; r.y1 = f;
592 }
593 return r;
594 }
595
596 fz_irect
597 fz_expand_irect(fz_irect a, int expand)
598 {
599 if (fz_is_infinite_irect(a)) return a;
600 if (!fz_is_valid_irect(a)) return a;
601 a.x0 -= expand;
602 a.y0 -= expand;
603 a.x1 += expand;
604 a.y1 += expand;
605 return a;
606 }
607
608 fz_rect
609 fz_expand_rect(fz_rect a, float expand)
610 {
611 if (fz_is_infinite_rect(a)) return a;
612 if (!fz_is_valid_rect(a)) return a;
613 a.x0 -= expand;
614 a.y0 -= expand;
615 a.x1 += expand;
616 a.y1 += expand;
617 return a;
618 }
619
620 /* Adding a point to an invalid rectangle makes the zero area rectangle
621 * that contains just that point. */
622 fz_rect fz_include_point_in_rect(fz_rect r, fz_point p)
623 {
624 if (fz_is_infinite_rect(r)) return r;
625 if (p.x < r.x0) r.x0 = p.x;
626 if (p.x > r.x1) r.x1 = p.x;
627 if (p.y < r.y0) r.y0 = p.y;
628 if (p.y > r.y1) r.y1 = p.y;
629 return r;
630 }
631
632 int fz_contains_rect(fz_rect a, fz_rect b)
633 {
634 /* An invalid rect can't contain anything */
635 if (!fz_is_valid_rect(a))
636 return 0;
637 /* Any valid rect contains all invalid rects */
638 if (!fz_is_valid_rect(b))
639 return 1;
640 return ((a.x0 <= b.x0) &&
641 (a.y0 <= b.y0) &&
642 (a.x1 >= b.x1) &&
643 (a.y1 >= b.y1));
644 }
645
646 int
647 fz_is_valid_quad(fz_quad q)
648 {
649 return (!isnan(q.ll.x) &&
650 !isnan(q.ll.y) &&
651 !isnan(q.ul.x) &&
652 !isnan(q.ul.y) &&
653 !isnan(q.lr.x) &&
654 !isnan(q.lr.y) &&
655 !isnan(q.ur.x) &&
656 !isnan(q.ur.y));
657 }
658
659 int
660 fz_is_infinite_quad(fz_quad q)
661 {
662 /* For a quad to be infinite, all the ordinates need to be infinite. */
663 if (!isinf(q.ll.x) ||
664 !isinf(q.ll.y) ||
665 !isinf(q.ul.x) ||
666 !isinf(q.ul.y) ||
667 !isinf(q.lr.x) ||
668 !isinf(q.lr.y) ||
669 !isinf(q.ur.x) ||
670 !isinf(q.ur.y))
671 return 0;
672
673 /* Just because all the ordinates are infinite, we don't necessarily have an infinite quad. */
674 /* The quad points in order are: ll, ul, ur, lr OR reversed: ll, lr, ur, ul */
675 /* The required points are: (-inf, -inf) (-inf, inf) (inf, inf) (inf, -inf) */
676
677 /* Not the fastest way to code it, but easy to understand! */
678 #define INF_QUAD_TEST(A,B,C,D) \
679 if (q.A.x < 0 && q.A.y < 0 && q.B.x < 0 && q.B.y > 0 && q.C.x > 0 && q.C.y > 0 && q.D.x > 0 && q.D.y < 0) return 1
680
681 INF_QUAD_TEST(ll, ul, ur, lr);
682 INF_QUAD_TEST(ul, ur, lr, ll);
683 INF_QUAD_TEST(ur, lr, ll, ul);
684 INF_QUAD_TEST(lr, ll, ul, ur);
685 INF_QUAD_TEST(ll, lr, ur, ul);
686 INF_QUAD_TEST(lr, ur, ul, ll);
687 INF_QUAD_TEST(ur, ul, ll, lr);
688 INF_QUAD_TEST(ul, ll, lr, ur);
689 #undef INF_QUAD_TEST
690
691 return 0;
692 }
693
694 int fz_is_empty_quad(fz_quad q)
695 {
696 /* Using "Shoelace" formula */
697 float area;
698
699 if (fz_is_infinite_quad(q))
700 return 0;
701 if (!fz_is_valid_quad(q))
702 return 1; /* All invalid quads are empty */
703
704 area = q.ll.x * q.lr.y +
705 q.lr.x * q.ur.y +
706 q.ur.x * q.ul.y +
707 q.ul.x * q.ll.y -
708 q.lr.x * q.ll.y -
709 q.ur.x * q.lr.y -
710 q.ul.x * q.ur.y -
711 q.ll.x * q.ul.y;
712
713 return area == 0;
714 }
715
716 fz_rect
717 fz_rect_from_quad(fz_quad q)
718 {
719 fz_rect r;
720
721 if (!fz_is_valid_quad(q))
722 return fz_invalid_rect;
723 if (fz_is_infinite_quad(q))
724 return fz_infinite_rect;
725
726 r.x0 = MIN4(q.ll.x, q.lr.x, q.ul.x, q.ur.x);
727 r.y0 = MIN4(q.ll.y, q.lr.y, q.ul.y, q.ur.y);
728 r.x1 = MAX4(q.ll.x, q.lr.x, q.ul.x, q.ur.x);
729 r.y1 = MAX4(q.ll.y, q.lr.y, q.ul.y, q.ur.y);
730 return r;
731 }
732
733 fz_quad
734 fz_transform_quad(fz_quad q, fz_matrix m)
735 {
736 if (!fz_is_valid_quad(q))
737 return q;
738 if (fz_is_infinite_quad(q))
739 return q;
740
741 q.ul = fz_transform_point(q.ul, m);
742 q.ur = fz_transform_point(q.ur, m);
743 q.ll = fz_transform_point(q.ll, m);
744 q.lr = fz_transform_point(q.lr, m);
745 return q;
746 }
747
748 fz_quad
749 fz_quad_from_rect(fz_rect r)
750 {
751 fz_quad q;
752
753 if (!fz_is_valid_rect(r))
754 return fz_invalid_quad;
755 if (fz_is_infinite_rect(r))
756 return fz_infinite_quad;
757
758 q.ul = fz_make_point(r.x0, r.y0);
759 q.ur = fz_make_point(r.x1, r.y0);
760 q.ll = fz_make_point(r.x0, r.y1);
761 q.lr = fz_make_point(r.x1, r.y1);
762 return q;
763 }
764
765
766 int fz_is_point_inside_rect(fz_point p, fz_rect r)
767 {
768 return (p.x >= r.x0 && p.x < r.x1 && p.y >= r.y0 && p.y < r.y1);
769 }
770
771 int fz_is_point_inside_irect(int x, int y, fz_irect r)
772 {
773 return (x >= r.x0 && x < r.x1 && y >= r.y0 && y < r.y1);
774 }
775
776 int fz_is_rect_inside_rect(fz_rect inner, fz_rect outer)
777 {
778 if (!fz_is_valid_rect(outer))
779 return 0;
780 if (!fz_is_valid_rect(inner))
781 return 0;
782 if (inner.x0 >= outer.x0 && inner.x1 <= outer.x1 && inner.y0 >= outer.y0 && inner.y1 <= outer.y1)
783 return 1;
784 return 0;
785 }
786
787 int fz_is_irect_inside_irect(fz_irect inner, fz_irect outer)
788 {
789 if (!fz_is_valid_irect(outer))
790 return 0;
791 if (!fz_is_valid_irect(inner))
792 return 0;
793 if (inner.x0 >= outer.x0 && inner.x1 <= outer.x1 && inner.y0 >= outer.y0 && inner.y1 <= outer.y1)
794 return 1;
795 return 0;
796 }
797
798 /* cross (b-a) with (p-a) */
799 static float
800 cross(fz_point a, fz_point b, fz_point p)
801 {
802 b.x -= a.x;
803 b.y -= a.y;
804 p.x -= a.x;
805 p.y -= a.y;
806 return b.x * p.y - b.y * p.x;
807 }
808
809 static int fz_is_point_inside_triangle(fz_point p, fz_point a, fz_point b, fz_point c)
810 {
811 /* Consider the following:
812 *
813 * P
814 * /|
815 * / |
816 * / |
817 * A +---+-------+ B
818 * M
819 *
820 * The cross product of vector AB and vector AP is the distance PM.
821 * The sign of this distance depends on what side of the line AB, P lies on.
822 *
823 * So, for a triangle ABC, if we take cross products of:
824 *
825 * AB and AP
826 * BC and BP
827 * CA and CP
828 *
829 * P can only be inside the triangle if the signs are all identical.
830 *
831 * One of the cross products being 0 indicates that the point is on a line.
832 * Two of the cross products being 0 indicates that the point is on a vertex.
833 *
834 * If 2 of the vertices are the same, the algorithm still works.
835 * Iff all 3 of the vertices are the same, the cross products are all zero. The
836 * value of p is irrelevant.
837 */
838 float crossa = cross(a, b, p);
839 float crossb = cross(b, c, p);
840 float crossc = cross(c, a, p);
841
842 /* Check for degenerate case. All vertices the same. */
843 if (crossa == 0 && crossb == 0 && crossc == 0)
844 return a.x == p.x && a.y == p.y;
845
846 if (crossa >= 0 && crossb >= 0 && crossc >= 0)
847 return 1;
848 if (crossa <= 0 && crossb <= 0 && crossc <= 0)
849 return 1;
850
851 return 0;
852 }
853
854 int fz_is_point_inside_quad(fz_point p, fz_quad q)
855 {
856 if (!fz_is_valid_quad(q))
857 return 0;
858 if (fz_is_infinite_quad(q))
859 return 1;
860
861 return
862 fz_is_point_inside_triangle(p, q.ul, q.ur, q.lr) ||
863 fz_is_point_inside_triangle(p, q.ul, q.lr, q.ll);
864 }
865
866 int fz_is_quad_inside_quad(fz_quad needle, fz_quad haystack)
867 {
868 if (!fz_is_valid_quad(needle) || !fz_is_valid_quad(haystack))
869 return 0;
870 if (fz_is_infinite_quad(haystack))
871 return 1;
872
873 return
874 fz_is_point_inside_quad(needle.ul, haystack) &&
875 fz_is_point_inside_quad(needle.ur, haystack) &&
876 fz_is_point_inside_quad(needle.ll, haystack) &&
877 fz_is_point_inside_quad(needle.lr, haystack);
878 }
879
880 int fz_is_quad_intersecting_quad(fz_quad a, fz_quad b)
881 {
882 fz_rect ar = fz_rect_from_quad(a);
883 fz_rect br = fz_rect_from_quad(b);
884 return !fz_is_empty_rect(fz_intersect_rect(ar, br));
885 }