egra: don't use ENTER/LEAVE (because intel sux, and they are slower than the correspo...
[iv.d.git] / _obsolete_dont_use / rect.d
blob940f914030c3d471f46f0cc0e4aa638672a979d5
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/>.
17 // severely outdated
18 module iv.rect /*is aliced*/;
19 import iv.alice;
22 ////////////////////////////////////////////////////////////////////////////////
23 struct Rect {
24 import std.traits : isIntegral, isUnsigned;
26 int x = 0, y = 0;
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);
38 @safe:
39 nothrow:
40 @nogc:
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;
57 alias left = x0;
58 alias top = y0;
59 alias right = x1;
60 alias bottom = y1;
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 {
67 return
68 !empty && !r.empty &&
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 {
75 return
76 !empty && !r.empty &&
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) {
83 if (!r.empty) {
84 if (empty) {
85 x = r.x;
86 y = r.y;
87 width = r.width;
88 height = r.height;
89 } else {
90 if (r.x < x) x = r.x;
91 if (r.y < y) y = r.y;
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) {
99 x = ax;
100 y = ay;
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) {
108 x += dx;
109 y += dy;
110 width -= dx;
111 height -= dy;
114 void moveX1Y1By (int dx, int dy) {
115 width += dx;
116 height += dy;
119 void moveBy (int dx, int dy) {
120 x += dx;
121 y += dy;
125 * clip (x,y,len) stripe to this rect
127 * Params:
128 * x = stripe start (not relative to rect)
129 * y = stripe start (not relative to rect)
130 * len = stripe length
132 * Returns:
133 * x = fixed x
134 * len = fixed length
135 * leftSkip = how much cells skipped at the left side
136 * result = false if stripe is completely clipped out
138 * TODO:
139 * overflows
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;
144 if (x < this.x) {
145 // left clip
146 if (x+len <= this.x) return false;
147 len -= (leftSkip = this.x-x);
148 x = this.x;
150 if (x+len >= this.x+width) {
151 // right clip
152 len = this.x+width-x;
153 assert(len > 0); // yeah, always
155 return true;
158 bool clipStripe(LT) (ref int x, int y, ref LT len) if (isIntegral!LT) {
159 int dummy = void;
160 return clipStripe(x, y, len, dummy);
164 * clip another rect to this rect. both rects has same origin.
166 * Params:
167 * rc = rect to clip against this
169 * Returns:
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
181 return true;
187 unittest {
188 auto rc = Rect(0, 0, 10, 10);
189 import iv.writer;
190 writefln!"rect=%s"(rc);