1 #include "tickit.h"
2
minint(int a,int b)3 static inline int minint(int a, int b) { return a < b ? a : b; }
maxint(int a,int b)4 static inline int maxint(int a, int b) { return a > b ? a : b; }
5
tickit_rect_init_sized(TickitRect * rect,int top,int left,int lines,int cols)6 void tickit_rect_init_sized(TickitRect *rect, int top, int left, int lines, int cols)
7 {
8 rect->top = top;
9 rect->left = left;
10 rect->lines = lines;
11 rect->cols = cols;
12 }
13
tickit_rect_init_bounded(TickitRect * rect,int top,int left,int bottom,int right)14 void tickit_rect_init_bounded(TickitRect *rect, int top, int left, int bottom, int right)
15 {
16 rect->top = top;
17 rect->left = left;
18 rect->lines = bottom - top;
19 rect->cols = right - left;
20 }
21
tickit_rect_translate(TickitRect * rect,int downward,int rightward)22 void tickit_rect_translate(TickitRect *rect, int downward, int rightward)
23 {
24 rect->top += downward;
25 rect->left += rightward;
26 }
27
tickit_rect_intersect(TickitRect * dst,const TickitRect * a,const TickitRect * b)28 bool tickit_rect_intersect(TickitRect *dst, const TickitRect *a, const TickitRect *b)
29 {
30 int top = maxint(a->top, b->top);
31 int bottom = minint(tickit_rect_bottom(a), tickit_rect_bottom(b));
32
33 if(top >= bottom)
34 return false;
35
36 int left = maxint(a->left, b->left);
37 int right = minint(tickit_rect_right(a), tickit_rect_right(b));
38
39 if(left >= right)
40 return false;
41
42 tickit_rect_init_bounded(dst, top, left, bottom, right);
43 return true;
44 }
45
tickit_rect_intersects(const TickitRect * a,const TickitRect * b)46 bool tickit_rect_intersects(const TickitRect *a, const TickitRect *b)
47 {
48 return a->top < tickit_rect_bottom(b) &&
49 b->top < tickit_rect_bottom(a) &&
50 a->left < tickit_rect_right(b) &&
51 b->left < tickit_rect_right(a);
52 }
53
tickit_rect_contains(const TickitRect * large,const TickitRect * small)54 bool tickit_rect_contains(const TickitRect *large, const TickitRect *small)
55 {
56 return (small->top >= large->top ) &&
57 (tickit_rect_bottom(small) <= tickit_rect_bottom(large)) &&
58 (small->left >= large->left ) &&
59 (tickit_rect_right(small) <= tickit_rect_right(large) );
60 }
61
tickit_rect_add(TickitRect ret[3],const TickitRect * a,const TickitRect * b)62 int tickit_rect_add(TickitRect ret[3], const TickitRect *a, const TickitRect *b)
63 {
64 int a_bottom = tickit_rect_bottom(a);
65 int a_right = tickit_rect_right(a);
66 int b_bottom = tickit_rect_bottom(b);
67 int b_right = tickit_rect_right(b);
68
69 if(a->left > b_right || b->left > a_right ||
70 a->top > b_bottom || b->top > a_bottom) {
71 ret[0] = *a;
72 ret[1] = *b;
73 return 2;
74 }
75
76 int rows[4];
77 rows[0] = a->top;
78 rows[1] = b->top;
79 rows[2] = a_bottom;
80 rows[3] = b_bottom;
81
82 /* Since we know top < bottom for each rect individually we can do this
83 * better than a plain sort
84 */
85 if(rows[0] > rows[1]) { int tmp = rows[0]; rows[0] = rows[1]; rows[1] = tmp; } // tops now in order
86 if(rows[2] > rows[3]) { int tmp = rows[2]; rows[2] = rows[3]; rows[3] = tmp; } // bottoms now in order
87 if(rows[1] > rows[2]) { int tmp = rows[1]; rows[1] = rows[2]; rows[2] = tmp; } // all now in order
88
89 int rects = 0;
90 for(int i = 0; i < 3; i++ ) {
91 int this_top = rows[i];
92 int this_bottom = rows[i+1];
93
94 // Skip non-unique
95 if(this_top == this_bottom)
96 continue;
97
98 int has_a = this_top >= a->top && this_bottom <= a_bottom;
99 int has_b = this_top >= b->top && this_bottom <= b_bottom;
100
101 int this_left = (has_a && has_b) ? minint(a->left, b->left) :
102 (has_a) ? a->left :
103 b->left;
104
105 int this_right = (has_a && has_b) ? maxint(a_right, b_right) :
106 (has_a) ? a_right :
107 b_right;
108
109 if(rects && ret[rects-1].left == this_left && ret[rects-1].cols == this_right - this_left) {
110 ret[rects-1].lines = this_bottom - ret[rects-1].top;
111 }
112 else {
113 tickit_rect_init_bounded(ret + rects, this_top, this_left, this_bottom, this_right);
114 rects++;
115 }
116 }
117
118 return rects;
119 }
120
tickit_rect_subtract(TickitRect ret[5],const TickitRect * orig,const TickitRect * hole)121 int tickit_rect_subtract(TickitRect ret[5], const TickitRect *orig, const TickitRect *hole)
122 {
123 if(tickit_rect_contains(hole, orig))
124 return 0;
125
126 if(!tickit_rect_intersects(hole, orig)) {
127 ret[0] = *orig;
128 return 1;
129 }
130
131 int rects = 0;
132
133 int orig_right = tickit_rect_right(orig);
134 int hole_right = tickit_rect_right(hole);
135
136 if(orig->top < hole->top) {
137 tickit_rect_init_bounded(ret + rects, orig->top, orig->left, hole->top, orig_right);
138 rects++;
139 }
140
141 int orig_bottom = tickit_rect_bottom(orig);
142 int hole_bottom = tickit_rect_bottom(hole);
143
144 int mid_top = maxint(orig->top, hole->top);
145 int mid_bottom = minint(orig_bottom, hole_bottom);
146
147 if(orig->left < hole->left) {
148 tickit_rect_init_bounded(ret + rects, mid_top, orig->left, mid_bottom, hole->left);
149 rects++;
150 }
151
152 if(orig_right > hole_right) {
153 tickit_rect_init_bounded(ret + rects, mid_top, hole_right, mid_bottom, orig_right);
154 rects++;
155 }
156
157 if(orig_bottom > hole_bottom) {
158 tickit_rect_init_bounded(ret + rects, hole_bottom, orig->left, orig_bottom, orig_right);
159 rects++;
160 }
161
162 return rects;
163 }
164