1 #pragma once
2
3 /** @file the_Foundation/rect.h 2D integer rectangle.
4
5 @authors Copyright (c) 2019 Jaakko Keränen <jaakko.keranen@iki.fi>
6
7 @par License
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
11
12 1. Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright notice,
15 this list of conditions and the following disclaimer in the documentation
16 and/or other materials provided with the distribution.
17
18 <small>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</small>
28 */
29
30 #include "range.h"
31 #include "vec2.h"
32
33 iDeclareType(Rect)
34
35 iBeginPublic
36
37 struct Impl_Rect {
38 iInt2 pos;
39 iInt2 size;
40 };
41
42 iDeclareType(Stream)
iDeclareTypeSerialization(Rect)43 iDeclareTypeSerialization(Rect)
44
45 iLocalDef iRect zero_Rect(void) { return (iRect){ zero_I2(), zero_I2() }; }
46
init_Rect(int x,int y,int width,int height)47 iLocalDef iRect init_Rect(int x, int y, int width, int height) {
48 return (iRect){ init_I2(x, y), init_I2(width, height) };
49 }
50
initv_Rect(const int * v)51 iLocalDef iRect initv_Rect(const int *v) {
52 return (iRect){ initv_I2(v), initv_I2(v + 2) };
53 }
54
initCorners_Rect(const iInt2 topLeft,const iInt2 bottomRight)55 iLocalDef iRect initCorners_Rect(const iInt2 topLeft, const iInt2 bottomRight) {
56 return (iRect){ topLeft, sub_I2(bottomRight, topLeft) };
57 }
58
initCentered_Rect(const iInt2 center,const iInt2 size)59 iLocalDef iRect initCentered_Rect(const iInt2 center, const iInt2 size) {
60 return (iRect){ sub_I2(center, divi_I2(size, 2)), size };
61 }
62
initSize_Rect(int width,int height)63 iLocalDef iRect initSize_Rect(int width, int height) {
64 return init_Rect(0, 0, width, height);
65 }
66
left_Rect(const iRect d)67 iLocalDef int left_Rect (const iRect d) { return d.pos.x; }
right_Rect(const iRect d)68 iLocalDef int right_Rect (const iRect d) { return d.pos.x + d.size.x; }
top_Rect(const iRect d)69 iLocalDef int top_Rect (const iRect d) { return d.pos.y; }
bottom_Rect(const iRect d)70 iLocalDef int bottom_Rect (const iRect d) { return d.pos.y + d.size.y; }
width_Rect(const iRect d)71 iLocalDef int width_Rect (const iRect d) { return d.size.x; }
height_Rect(const iRect d)72 iLocalDef int height_Rect (const iRect d) { return d.size.y; }
area_Rect(const iRect d)73 iLocalDef int area_Rect (const iRect d) { return d.size.x * d.size.y; }
mid_Rect(const iRect d)74 iLocalDef iInt2 mid_Rect (const iRect d) { return add_I2(d.pos, divi_I2(d.size, 2)); }
75
topLeft_Rect(const iRect d)76 iLocalDef iInt2 topLeft_Rect(const iRect d) { return d.pos; }
77
topMid_Rect(const iRect d)78 iLocalDef iInt2 topMid_Rect(const iRect d) {
79 return init_I2(d.pos.x + d.size.x / 2, d.pos.y);
80 }
81
topRight_Rect(const iRect d)82 iLocalDef iInt2 topRight_Rect(const iRect d) {
83 return init_I2(right_Rect(d), d.pos.y);
84 }
85
bottomLeft_Rect(const iRect d)86 iLocalDef iInt2 bottomLeft_Rect(const iRect d) {
87 return init_I2(d.pos.x, bottom_Rect(d));
88 }
89
bottomMid_Rect(const iRect d)90 iLocalDef iInt2 bottomMid_Rect(const iRect d) {
91 return init_I2(d.pos.x + d.size.x / 2, bottom_Rect(d));
92 }
93
bottomRight_Rect(const iRect d)94 iLocalDef iInt2 bottomRight_Rect(const iRect d) {
95 return add_I2(d.pos, d.size);
96 }
97
xSpan_Rect(const iRect d)98 iLocalDef iRangei xSpan_Rect(const iRect d) {
99 return (iRangei){ left_Rect(d), right_Rect(d) };
100 }
101
ySpan_Rect(const iRect d)102 iLocalDef iRangei ySpan_Rect(const iRect d) {
103 return (iRangei){ top_Rect(d), bottom_Rect(d) };
104 }
105
contains_Rect(const iRect d,const iInt2 pos)106 iLocalDef iBool contains_Rect(const iRect d, const iInt2 pos) {
107 const iInt2 br = bottomRight_Rect(d);
108 return pos.x >= d.pos.x && pos.y >= d.pos.y && pos.x < br.x && pos.y < br.y;
109 }
110
containsRect_Rect(const iRect d,const iRect other)111 iLocalDef iBool containsRect_Rect(const iRect d, const iRect other) {
112 const iInt2 br = sub_I2(bottomRight_Rect(other), one_I2());
113 return contains_Rect(d, topLeft_Rect(other)) &&
114 contains_Rect(d, init_I2(br.x, top_Rect(other))) && contains_Rect(d, br) &&
115 contains_Rect(d, init_I2(left_Rect(other), br.y));
116 }
117
isOverlapping_Rect(const iRect d,const iRect other)118 iLocalDef iBool isOverlapping_Rect(const iRect d, const iRect other) {
119 /* Overlaps unless any one of the edges makes it impossible. */
120 return !(other.pos.x >= right_Rect(d) || other.pos.y >= bottom_Rect(d) ||
121 right_Rect(other) <= d.pos.x || bottom_Rect(other) <= d.pos.y);
122 }
123
isEmpty_Rect(const iRect d)124 iLocalDef iBool isEmpty_Rect(const iRect d) {
125 return prod_I2(d.size) == 0;
126 }
127
equal_Rect(const iRect d,const iRect other)128 iLocalDef iBool equal_Rect(const iRect d, const iRect other) {
129 return isEqual_I2(d.pos, other.pos) && isEqual_I2(d.size, other.size);
130 }
131
union_Rect(const iRect d,const iRect other)132 iLocalDef iRect union_Rect(const iRect d, const iRect other) {
133 if (isEmpty_Rect(d)) {
134 return other;
135 }
136 if (isEmpty_Rect(other)) {
137 return d;
138 }
139 const iInt2 tl = min_I2(d.pos, other.pos);
140 const iInt2 br = max_I2(bottomRight_Rect(d), bottomRight_Rect(other));
141 return (iRect){ tl, sub_I2(br, tl) };
142 }
143
intersect_Rect(const iRect d,const iRect other)144 iLocalDef iRect intersect_Rect(const iRect d, const iRect other) {
145 if (!isOverlapping_Rect(d, other)) {
146 return zero_Rect();
147 }
148 const iInt2 tl = max_I2(d.pos, other.pos);
149 const iInt2 br = min_I2(bottomRight_Rect(d), bottomRight_Rect(other));
150 return (iRect){ tl, sub_I2(br, tl) };
151 }
152
153 void expand_Rect (iRect *, iInt2 value);
154 void adjustEdges_Rect (iRect *, int top, int right, int bottom, int left);
155 iInt2 random_Rect (iRect);
156 iInt2 edgePos_Rect (iRect, int pos);
157 iInt2 randomEdgePos_Rect (iRect); // not a corner
158
shrink_Rect(iRect * d,iInt2 value)159 iLocalDef void shrink_Rect (iRect *d, iInt2 value) { expand_Rect(d, neg_I2(value)); }
160
expanded_Rect(iRect d,iInt2 value)161 iLocalDef iRect expanded_Rect(iRect d, iInt2 value) {
162 expand_Rect(&d, value);
163 return d;
164 }
165
shrunk_Rect(iRect d,iInt2 value)166 iLocalDef iRect shrunk_Rect(iRect d, iInt2 value) {
167 expand_Rect(&d, neg_I2(value));
168 return d;
169 }
170
adjusted_Rect(const iRect d,iInt2 topLeft,iInt2 bottomRight)171 iLocalDef iRect adjusted_Rect(const iRect d, iInt2 topLeft, iInt2 bottomRight) {
172 return initCorners_Rect(add_I2(d.pos, topLeft), add_I2(bottomRight_Rect(d), bottomRight));
173 }
174
moved_Rect(const iRect d,iInt2 offset)175 iLocalDef iRect moved_Rect(const iRect d, iInt2 offset) {
176 return (iRect){ add_I2(d.pos, offset), d.size };
177 }
178
179 iDeclareConstIterator(Rect, iRect)
180
181 struct ConstIteratorImpl_Rect {
182 iBool value; // position is valid
183 iInt2 pos;
184 iRect rect;
185 };
186
187 #define iForRectRadius(iter, center, radius, body) { \
188 const iInt2 center_ForRadius_ = (center); \
189 const int radius_ForRadius_ = (radius); \
190 const iRect rect_ForRadius_ = initCentered_Rect(center_ForRadius_, init1_I2(2 * radius_ForRadius_ + 1)); \
191 iConstForEach(Rect, iter, rect_ForRadius_) { \
192 if (dist_I2(center_ForRadius_, iter.pos) + .5f <= radius_ForRadius_) { body } \
193 } \
194 }
195
196 iEndPublic
197