1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module iv
.rect
/*is aliced*/;
22 ////////////////////////////////////////////////////////////////////////////////
24 import std
.traits
: isIntegral
, isUnsigned
;
27 int width
= -1; // <0: invalid rect
28 int height
= -1; // <0: invalid rect
30 string
toString () const @safe pure {
31 import std
.string
: format
; // should be std.format, but gdc...
32 return (valid ?
"(%s,%s)-(%s,%s)".format(x
, y
, x
+width
-1, y
+height
-1) : "(invalid-rect)");
35 // default constructor: (x, y, w, h)
36 this(CW
, CH
) (int ax
, int ay
, CW awidth
, CH aheight
) if (isIntegral
!CW
&& isIntegral
!CH
) => set(ax
, ay
, awidth
, aheight
);
42 @property bool valid () const pure => (width
>= 0 && height
>= 0);
43 @property bool empty () const pure => (width
<= 0 || height
<= 0); /// invalid rects are empty
45 void invalidate () => width
= height
= -1;
47 @property int x0 () const pure => x
;
48 @property int y0 () const pure => y
;
49 @property int x1 () const pure => (width
> 0 ? x
+width
-1 : x
-1);
50 @property int y1 () const pure => (height
> 0 ? y
+height
-1 : y
-1);
52 @property void x0 (in int val
) { width
= x
+width
-val
; x
= val
; }
53 @property void y0 (in int val
) { height
= y
+height
-val
; y
= val
; }
54 @property void x1 (in int val
) => width
= val
-x
+1;
55 @property void y1 (in int val
) => height
= val
-y
+1;
62 bool inside (in int ax
, in int ay
) const pure =>
63 empty ?
false : (ax
>= x
&& ay
>= y
&& ax
< x
+width
&& ay
< y
+height
);
65 // is `r` inside `this`?
66 bool inside (in Rect r
) const pure {
69 r
.x
>= x
&& r
.y
>= y
&&
70 r
.x1
<= x1
&& r
.y1
<= y1
;
73 // is `r` and `this` overlaps?
74 bool overlap (in Rect r
) const pure {
77 x
<= r
.x1
&& r
.x
<= x1
&& y
<= r
.y1
&& r
.y
<= y1
;
78 //!(x > r.x1 || r.x > x1 || y > r.y1 || r.y > y1);
81 // extend `this` so it will include `r`
82 void include (in Rect r
) {
92 if (r
.x1
> x1
) x1
= r
.x1
;
93 if (r
.y1
> y1
) y1
= r
.y1
;
98 void set(CW
, CH
) (int ax
, int ay
, CW awidth
, CH aheight
) if (isIntegral
!CW
&& isIntegral
!CH
) {
101 static if (isUnsigned
!CW
&& CW
.sizeof
>= width
.sizeof
) if (awidth
>= width
.max
) awidth
= width
.max
;
102 static if (isUnsigned
!CH
&& CH
.sizeof
>= height
.sizeof
) if (aheight
>= height
.max
) aheight
= height
.max
;
103 width
= cast(int)awidth
;
104 height
= cast(int)aheight
;
107 void moveX0Y0By (int dx
, int dy
) {
114 void moveX1Y1By (int dx
, int dy
) {
119 void moveBy (int dx
, int dy
) {
125 * clip (x,y,len) stripe to this rect
128 * x = stripe start (not relative to rect)
129 * y = stripe start (not relative to rect)
130 * len = stripe length
135 * leftSkip = how much cells skipped at the left side
136 * result = false if stripe is completely clipped out
141 bool clipStripe(LT
) (ref int x
, int y
, ref LT len
, out int leftSkip
) if (isIntegral
!LT
) {
142 if (empty
) return false;
143 if (len
<= 0 || y
< this.y || y
>= this.y
+height || x
>= this.x
+width
) return false;
146 if (x
+len
<= this.x
) return false;
147 len
-= (leftSkip
= this.x
-x
);
150 if (x
+len
>= this.x
+width
) {
152 len
= this.x
+width
-x
;
153 assert(len
> 0); // yeah, always
158 bool clipStripe(LT
) (ref int x
, int y
, ref LT len
) if (isIntegral
!LT
) {
160 return clipStripe(x
, y
, len
, dummy
);
164 * clip another rect to this rect. both rects has same origin.
167 * rc = rect to clip against this
170 * result = false if rect is completely clipped out (and rc is invalidated)
172 bool clipRect (ref Rect rc
) {
173 if (rc
.empty ||
this.empty
) { rc
.invalidate(); return false; }
174 if (rc
.y1
< this.y0 || rc
.x1
< this.x0 || rc
.x0
> this.x1 || rc
.y0
> this.y1
) { rc
.invalidate(); return false; }
175 // rc is at least partially inside this rect
176 if (rc
.x0
< this.x0
) rc
.x0
= this.x0
; // clip left
177 if (rc
.y0
< this.y0
) rc
.y0
= this.y0
; // clip top
178 if (rc
.x1
> this.x1
) rc
.x1
= this.x1
; // clip right
179 if (rc
.y1
> this.y1
) rc
.y1
= this.y1
; // clip bottom
180 assert(!rc
.empty
); // yeah, always
188 auto rc = Rect(0, 0, 10, 10);
190 writefln!"rect=%s"(rc);