2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
25 type rect_set := list(rect);
27 fn rect_is_valid~inline(r : rect) : bool;
28 fn rect_test_point~inline(r : rect, x y : int) : bool;
29 fn rect_unite(r1 r2 : rect) : rect;
30 fn rect_intersection~inline(r1 r2 : rect) : rect;
31 fn rect_test_intersect(r1 r2 : rect) : bool;
32 fn rect_set_test_point(rs : rect_set, x y : int) : bool;
33 fn rect_set_add(rs : rect_set, r : rect) : rect_set;
34 fn rect_set_exclude(rs : rect_set, r : rect) : rect_set;
35 fn rect_set_intersect(rs : rect_set, r : rect) : rect_set;
36 fn rect_set_move(rs : rect_set, offset_x offset_y : int) : rect_set;
37 fn rect_set_to_rect(rs : rect_set) : rect;
39 implicit fn instance_eq_rect : class_eq(rect);
43 fn rect_is_valid~inline(r : rect) : bool
45 return r.x1 < r.x2 and r.y1 < r.y2;
48 fn rect_test_point~inline(r : rect, x y : int) : bool
50 return x >= r.x1 and x < r.x2 and y >= r.y1 and y < r.y2;
53 fn rect_unite(r1 r2 : rect) : rect
55 if not rect_is_valid(r1) then
57 if not rect_is_valid(r2) then
60 x1 : min(r1.x1, r2.x1),
61 x2 : max(r1.x2, r2.x2),
62 y1 : min(r1.y1, r2.y1),
63 y2 : max(r1.y2, r2.y2),
67 fn rect_intersection~inline(r1 r2 : rect) : rect
70 x1 : max(r1.x1, r2.x1),
71 x2 : min(r1.x2, r2.x2),
72 y1 : max(r1.y1, r2.y1),
73 y2 : min(r1.y2, r2.y2),
77 fn rect_test_intersect(r1 r2 : rect) : bool
79 return rect_is_valid(rect_intersection(r1, r2));
82 fn rect_set_test_point(rs : rect_set, x y : int) : bool
84 for i := 0 to len(rs) do [
86 if rect_test_point(rr, x, y) then
92 fn rect_set_add(rs : rect_set, r : rect) : rect_set
94 if rect_is_valid(r) then
99 fn rect_set_exclude(rs : rect_set, r : rect) : rect_set
101 var result := empty(rect);
102 for i := 0 to len(rs) do [
104 if not rect_test_intersect(r, rr) then [
105 result := rect_set_add(result, rr);
108 var r1 := rect.[ x1 : rr.x1, x2 : rr.x2, y1 : rr.y1, y2 : r.y1 ];
109 var r2 := rect.[ x1 : rr.x1, x2 : r.x1, y1 : r.y1, y2 : r.y2 ];
110 var r3 := rect.[ x1 : r.x2, x2 : rr.x2, y1 : r.y1, y2 : r.y2 ];
111 var r4 := rect.[ x1 : rr.x1, x2 : rr.x2, y1 : r.y2, y2 : rr.y2 ];
112 r2 := rect_intersection(r2, rr);
113 r3 := rect_intersection(r3, rr);
114 result := rect_set_add(result, r1);
115 result := rect_set_add(result, r2);
116 result := rect_set_add(result, r3);
117 result := rect_set_add(result, r4);
122 fn rect_set_intersect(rs : rect_set, r : rect) : rect_set
124 var result := empty(rect);
125 for i := 0 to len(rs) do [
127 rr := rect_intersection(rr, r);
128 result := rect_set_add(result, rr);
133 fn rect_set_move(rs : rect_set, offset_x offset_y : int) : rect_set
135 for i := 0 to len(rs) do [
136 rs[i].x1 += offset_x;
137 rs[i].x2 += offset_x;
138 rs[i].y1 += offset_y;
139 rs[i].y2 += offset_y;
144 fn rect_set_to_rect(rs : rect_set) : rect
147 return rect.[ x1 : 0, x2 : 0, y1 : 0, y2 : 0 ];
149 for i := 1 to len(rs) do
150 r := rect_unite(r, rs[i]);
154 fn rect_equal(r1 r2 : rect) : bool :=
155 r1.x1 = r2.x1 and r1.x2 = r2.x2 and r1.y1 = r2.y1 and r1.y2 = r2.y2;
157 implicit fn instance_eq_rect : class_eq(rect) :=