verify: implement P_Array_Append_One
[ajla.git] / stdlib / ui / rect.ajla
blob35a8af95dc52ad0d38a2ff09890bf8210d17c22b
1 {*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
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
9  * version.
10  *
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.
14  *
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/>.
17  *}
19 unit ui.rect;
21 record rect [
22         x1 x2 y1 y2 : int;
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);
41 implementation
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
56                 return r2;
57         if not rect_is_valid(r2) then
58                 return r1;
59         return rect.[
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),
64         ];
67 fn rect_intersection~inline(r1 r2 : rect) : rect
69         return 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),
74         ];
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 [
85                 var rr := rs[i];
86                 if rect_test_point(rr, x, y) then
87                         return true;
88         ]
89         return false;
92 fn rect_set_add(rs : rect_set, r : rect) : rect_set
94         if rect_is_valid(r) then
95                 rs +<= r;
96         return rs;
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 [
103                 var rr := rs[i];
104                 if not rect_test_intersect(r, rr) then [
105                         result := rect_set_add(result, rr);
106                         continue;
107                 ]
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);
118         ]
119         return result;
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 [
126                 var rr := rs[i];
127                 rr := rect_intersection(rr, r);
128                 result := rect_set_add(result, rr);
129         ]
130         return result;
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;
140         ]
141         return rs;
144 fn rect_set_to_rect(rs : rect_set) : rect
146         if len(rs) = 0 then
147                 return rect.[ x1 : 0, x2 : 0, y1 : 0, y2 : 0 ];
148         var r := rs[0];
149         for i := 1 to len(rs) do
150                 r := rect_unite(r, rs[i]);
151         return r;
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) :=
158         class_eq(rect).[
159                 equal : rect_equal,
160         ];