1 /* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3 of the License ONLY.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 module iv
.gxx
.geom
/*is aliced*/;
20 // ////////////////////////////////////////////////////////////////////////// //
21 public struct GxSize
{
23 int width
, height
; ///
26 string
toString () const @trusted nothrow {
28 import core
.stdc
.stdio
: snprintf
;
30 return buf
[0..snprintf(buf
.ptr
, buf
.length
, "(%dx%d)", width
, height
)].idup
;
32 return "(invalid-size)";
36 pure nothrow @safe @nogc:
37 this() (in auto ref GxSize p
) { /*pragma(inline, true);*/ width
= p
.width
; height
= p
.height
; } ///
38 this (int ax
, int ay
) { /*pragma(inline, true);*/ width
= ax
; height
= ay
; } ///
39 @property bool valid () const { pragma(inline
, true); return (width
>= 0 && height
>= 0); } ///
40 @property bool invalid () const { pragma(inline
, true); return (width
< 0 || height
< 0); } ///
41 @property bool empty () const { pragma(inline
, true); return (width
<= 0 || height
<= 0); } /// invalid rects are empty
42 void opAssign() (in auto ref GxSize p
) { pragma(inline
, true); width
= p
.width
; height
= p
.height
; } ///
43 bool opEquals() (in auto ref GxSize p
) const { pragma(inline
, true); return (p
.width
== width
&& p
.height
== height
); } ///
45 int opCmp() (in auto ref GxSize p
) const {
47 if (auto d0
= height
-p
.height
) return (d0
< 0 ?
-1 : 1);
48 else if (auto d1
= width
-p
.width
) return (d1
< 0 ?
-1 : 1);
54 // ////////////////////////////////////////////////////////////////////////// //
55 public struct GxPoint
{
60 string
toString () const @trusted nothrow {
61 import core
.stdc
.stdio
: snprintf
;
63 return buf
[0..snprintf(buf
.ptr
, buf
.length
, "(%d,%d)", x
, y
)].idup
;
66 pure nothrow @safe @nogc:
67 this() (in auto ref GxPoint p
) { pragma(inline
, true); x
= p
.x
; y
= p
.y
; } ///
68 this (int ax
, int ay
) { pragma(inline
, true); x
= ax
; y
= ay
; } ///
69 void opAssign() (in auto ref GxPoint p
) { pragma(inline
, true); x
= p
.x
; y
= p
.y
; } ///
70 bool opEquals() (in auto ref GxPoint p
) const { pragma(inline
, true); return (p
.x
== x
&& p
.y
== y
); } ///
72 int opCmp() (in auto ref GxPoint p
) const {
74 if (auto d0
= y
-p
.y
) return (d0
< 0 ?
-1 : 1);
75 else if (auto d1
= x
-p
.x
) return (d1
< 0 ?
-1 : 1);
81 // ////////////////////////////////////////////////////////////////////////// //
82 public struct GxRect
{
85 int width
= -1; // <0: invalid rect
86 int height
= -1; // <0: invalid rect
91 alias bottom
= y1
; ///
96 string
toString () const @trusted nothrow {
98 import core
.stdc
.stdio
: snprintf
;
100 return buf
[0..snprintf(buf
.ptr
, buf
.length
, "(%d,%d)-(%d,%d)", x0
, y0
, x0
+width
-1, y0
+height
-1)].idup
;
102 return "(invalid-rect)";
106 pure nothrow @safe @nogc:
108 this() (in auto ref GxRect rc
) { /*pragma(inline, true);*/ x0
= rc
.x0
; y0
= rc
.y0
; width
= rc
.width
; height
= rc
.height
; }
111 this() (in auto ref GxSize sz
) { /*pragma(inline, true);*/ x0
= 0; y0
= 0; width
= sz
.width
; height
= sz
.height
; }
114 this (int ax0
, int ay0
, int awidth
, int aheight
) {
115 //pragma(inline, true);
123 this() (in auto ref GxPoint xy0
, int awidth
, int aheight
) {
124 //pragma(inline, true);
132 this() (in auto ref GxPoint xy0
, in auto ref GxPoint xy1
) {
133 //pragma(inline, true);
136 width
= xy1
.x
-xy0
.x
+1;
137 height
= xy1
.y
-xy0
.y
+1;
140 void opAssign() (in auto ref GxRect rc
) { /*pragma(inline, true);*/ x0
= rc
.x0
; y0
= rc
.y0
; width
= rc
.width
; height
= rc
.height
; } ///
141 bool opEquals() (in auto ref GxRect rc
) const { pragma(inline
, true); return (rc
.x0
== x0
&& rc
.y0
== y0
&& rc
.width
== width
&& rc
.height
== height
); } ///
143 int opCmp() (in auto ref GxRect p
) const {
144 if (auto d0
= y0
-rc
.y0
) return (d0
< 0 ?
-1 : 1);
145 if (auto d1
= x0
-rc
.x0
) return (d1
< 0 ?
-1 : 1);
146 if (auto d2
= width
*height
-rc
.width
*rc
.height
) return (d2
< 0 ?
-1 : 1);
150 @property bool valid () const { pragma(inline
, true); return (width
>= 0 && height
>= 0); } ///
151 @property bool invalid () const { pragma(inline
, true); return (width
< 0 || height
< 0); } ///
152 @property bool empty () const { pragma(inline
, true); return (width
<= 0 || height
<= 0); } /// invalid rects are empty
154 void invalidate () { pragma(inline
, true); width
= height
= -1; } ///
156 @property GxPoint
lefttop () const { pragma(inline
, true); return GxPoint(x0
, y0
); } ///
157 @property GxPoint
righttop () const { pragma(inline
, true); return GxPoint(x0
+width
-1, y0
); } ///
158 @property GxPoint
leftbottom () const { pragma(inline
, true); return GxPoint(x0
, y0
+height
-1); } ///
159 @property GxPoint
rightbottom () const { pragma(inline
, true); return GxPoint(x0
+width
-1, y0
+height
-1); } ///
161 @property void lefttop() (in auto ref GxPoint v
) { pragma(inline
, true); x0
= v
.x
; y0
= v
.y
; } ///
162 @property void righttop() (in auto ref GxPoint v
) { pragma(inline
, true); x1
= v
.x
; y0
= v
.y
; } ///
163 @property void leftbottom() (in auto ref GxPoint v
) { pragma(inline
, true); x0
= v
.x
; y1
= v
.y
; } ///
164 @property void rightbottom() (in auto ref GxPoint v
) { pragma(inline
, true); x1
= v
.x
; y1
= v
.y
; } ///
166 alias topleft
= lefttop
; ///
167 alias topright
= righttop
; ///
168 alias bottomleft
= leftbottom
; ///
169 alias bottomright
= rightbottom
; ///
171 @property GxSize
size () const { pragma(inline
, true); return GxSize(width
, height
); } ///
172 @property void size() (in auto ref GxSize sz
) { pragma(inline
, true); width
= sz
.width
; height
= sz
.height
; } ///
174 @property int x1 () const { pragma(inline
, true); return (width
> 0 ? x0
+width
-1 : x0
-1); } ///
175 @property int y1 () const { pragma(inline
, true); return (height
> 0 ? y0
+height
-1 : y0
-1); } ///
177 @property void x1 (in int val
) { pragma(inline
, true); width
= val
-x0
+1; } ///
178 @property void y1 (in int val
) { pragma(inline
, true); height
= val
-y0
+1; } ///
180 GxPoint
translateToGlobal() (in auto ref GxPoint lpt
) const {
181 pragma(inline
, true);
182 return GxPoint(lpt
.x
+x0
, lpt
.y
+y0
);
185 GxRect
translateToGlobal() (in auto ref GxRect lrc
) const {
186 pragma(inline
, true);
187 return GxRect(lrc
.x0
+x0
, lrc
.y0
+y0
, lrc
.width
, lrc
.height
);
191 bool inside() (in auto ref GxPoint p
) const {
192 pragma(inline
, true);
193 return (width
> 0 && height
> 0 ?
(p
.x
>= x0
&& p
.y
>= y0
&& p
.x
< x0
+width
&& p
.y
< y0
+height
) : false);
197 bool inside (in int ax
, in int ay
) const {
198 pragma(inline
, true);
199 return (width
> 0 && height
> 0 ?
(ax
>= x0
&& ay
>= y0
&& ax
< x0
+width
&& ay
< y0
+height
) : false);
202 /// is `r` inside `this`?
203 bool contains() (in auto ref GxRect r
) const {
204 pragma(inline
, true);
206 width
> 0 && height
> 0 &&
207 r
.width
> 0 && r
.height
> 0 &&
208 r
.x0
>= x0
&& r
.y0
>= y0
&&
209 r
.x0
+r
.width
<= x0
+width
&& r
.y0
+r
.height
<= y0
+height
;
212 /// is `r` and `this` overlaps?
213 bool overlaps() (in auto ref GxRect r
) const {
214 pragma(inline
, true);
216 width
> 0 && height
> 0 &&
217 r
.width
> 0 && r
.height
> 0 &&
218 x0
< r
.x0
+r
.width
&& r
.x0
< x0
+width
&&
219 y0
< r
.y0
+r
.height
&& r
.y0
< y0
+height
;
222 /// extend `this` so it will include `r`
223 void include() (in auto ref GxRect r
) {
224 pragma(inline
, true);
232 if (r
.x
< x0
) x0
= r
.x0
;
233 if (r
.y
< y0
) y0
= r
.y0
;
234 if (r
.x1
> x1
) x1
= r
.x1
;
235 if (r
.y1
> y1
) y1
= r
.y1
;
240 /// clip `this` so it will not be larger than `r`
241 bool intersect() (in auto ref GxRect r
) {
242 if (r
.invalid || invalid
) { width
= height
= -1; return false; }
243 if (r
.empty || empty
) { width
= height
= 0; return false; }
244 if (r
.y1
< y0 || r
.x1
< x0 || r
.x0
> x1 || r
.y0
> y1
) { width
= height
= 0; return false; }
245 // rc is at least partially inside this rect
246 if (x0
< r
.x0
) x0
= r
.x0
;
247 if (y0
< r
.y0
) y0
= r
.y0
;
248 if (x1
> r
.x1
) x1
= r
.x1
;
249 if (y1
> r
.y1
) y1
= r
.y1
;
250 assert(!empty
); // yeah, always
255 void shrinkBy (int dx
, int dy
) {
256 pragma(inline
, true);
257 if ((dx || dy
) && valid
) {
266 void shrinkBy() (in auto ref GxSize sz
) { pragma(inline
, true); shrinkBy(sz
.width
, sz
.height
); }
269 void growBy (int dx
, int dy
) {
270 pragma(inline
, true);
271 if ((dx || dy
) && valid
) {
280 void growBy() (in auto ref GxSize sz
) { pragma(inline
, true); growBy(sz
.width
, sz
.height
); }
283 void set (int ax0
, int ay0
, int awidth
, int aheight
) {
284 pragma(inline
, true);
292 void moveLeftTopBy (int dx
, int dy
) {
293 pragma(inline
, true);
301 void moveLeftTopBy() (in auto ref GxPoint p
) { pragma(inline
, true); moveLeftTopBy(p
.x
, p
.y
); }
303 alias moveTopLeftBy
= moveLeftTopBy
; /// ditto
306 void moveRightBottomBy (int dx
, int dy
) {
307 pragma(inline
, true);
313 void moveRightBottomBy() (in auto ref GxPoint p
) { pragma(inline
, true); moveRightBottomBy(p
.x
, p
.y
); }
315 alias moveBottomRightBy
= moveRightBottomBy
; /// ditto
318 void moveBy (int dx
, int dy
) {
319 pragma(inline
, true);
325 void moveBy() (in auto ref GxPoint p
) { pragma(inline
, true); moveBy(p
.x
, p
.y
); }
328 void moveTo (int nx
, int ny
) {
329 pragma(inline
, true);
335 void moveTo() (in auto ref GxPoint p
) { pragma(inline
, true); moveTo(p
.x
, p
.y
); }
338 * clip (x,y,len) stripe to this rect
341 * x = stripe start (not relative to rect)
342 * y = stripe start (not relative to rect)
343 * len = stripe length
346 * x = fixed x (invalid if result is false)
347 * len = fixed length (invalid if result is false)
348 * leftSkip = how much cells skipped at the left side (invalid if result is false)
349 * result = false if stripe is completely clipped out
354 bool clipHStripe (ref int x
, int y
, ref int len
, int* leftSkip
=null) const @trusted {
355 if (empty
) return false;
356 if (len
<= 0 || y
< y0 || y
>= y0
+height || x
>= x0
+width
) return false;
359 if (x
+len
<= x0
) return false;
360 immutable int dx
= x0
-x
;
361 if (leftSkip
!is null) *leftSkip
= dx
;
364 assert(len
> 0); // yeah, always
366 if (x
+len
> x0
+width
) {
369 assert(len
> 0); // yeah, always
375 * clip (x,y,hgt) stripe to this rect
378 * x = stripe start (not relative to rect)
379 * y = stripe start (not relative to rect)
380 * hgt = stripe length
383 * y = fixed y (invalid if result is false)
384 * hgt = fixed length (invalid if result is false)
385 * topSkip = how much cells skipped at the top side (invalid if result is false)
386 * result = false if stripe is completely clipped out
391 bool clipVStripe (int x
, ref int y
, ref int hgt
, int* topSkip
=null) const @trusted {
392 if (empty
) return false;
393 if (hgt
<= 0 || x
< x0 || x
>= x0
+width || y
>= y0
+height
) return false;
396 if (y
+hgt
<= y0
) return false;
397 immutable int dy
= y0
-y
;
398 if (topSkip
!is null) *topSkip
= dy
;
401 assert(hgt
> 0); // yeah, always
403 if (y
+hgt
> y0
+height
) {
406 assert(hgt
> 0); // yeah, always
412 bool clipHVStripes (ref int x
, ref int y
, ref int wdt
, ref int hgt
, int* leftSkip
=null, int* topSkip
=null) const @trusted {
413 if (empty || wdt
<= 0 || hgt
<= 0) return false;
414 if (y
>= y0
+height || x
>= x0
+width
) return false;
417 if (x
+wdt
<= x0
) return false;
418 immutable int dx
= x0
-x
;
419 if (leftSkip
!is null) *leftSkip
= dx
;
422 assert(wdt
> 0); // yeah, always
424 if (x
+wdt
> x0
+width
) {
427 assert(wdt
> 0); // yeah, always
432 if (y
+hgt
<= y0
) return false;
433 immutable int dy
= y0
-y
;
434 if (topSkip
!is null) *topSkip
= dy
;
437 assert(hgt
> 0); // yeah, always
439 if (y
+hgt
> y0
+height
) {
442 assert(hgt
> 0); // yeah, always