1 module skia.MathTypes;
2 
3 import skia.Definitions;
4 
5 import std.algorithm;
6 import std.format;
7 import std.math;
8 
9 struct SKPoint {
10 	enum SKPoint Empty = SKPoint(0,0);
11 
12 	// float x
13 	private float x;
14 	float X() {
15 		return x;
16 	}
17 
18 	void X(float value) {
19 		x = value;
20 	}
21 
22 	// float y
23 	private float y;
24 	float Y() {
25 		return y;
26 	}
27 
28 	void Y(float value) {
29 		y = value;
30 	}
31 
32 	// bool Equals (SKPoint obj) {
33 	// 	return x == obj.x && y == obj.y
34 	// }
35 
36 	// override bool Equals (object obj) {
37 	// 	return obj is SKPoint f && Equals (f)
38 	// }
39 
40 	// static bool operator == (SKPoint left, SKPoint right) {
41 	// 	return left.Equals (right)
42 	// }
43 
44 	// static bool operator != (SKPoint left, SKPoint right) {
45 	// 	return !left.Equals (right)
46 	// }
47 
48 	// override int GetHashCode ()
49 	// {
50 	// 	var hash = new HashCode ();
51 	// 	hash.Add (x);
52 	// 	hash.Add (y);
53 	// 	return hash.ToHashCode ();
54 	// }
55 
56 	this(float x, float y) {
57 		this.x = x;
58 		this.y = y;
59 	}
60 
61 	bool IsEmpty() {
62 		return this == Empty;
63 	}
64 
65 	float Length() {
66 		return cast(float) sqrt(x * x + y * y);
67 	}
68 
69 	float LengthSquared() {
70 		return x * x + y * y;
71 	}
72 
73 	void Offset(SKPoint p) {
74 		x += p.x;
75 		y += p.y;
76 	}
77 
78 	void Offset(float dx, float dy) {
79 		x += dx;
80 		y += dy;
81 	}
82 
83 	string ToString() {
84 		return format("{{X=%s, Y=%s}}", x, y);
85 	}
86 
87 	static SKPoint Normalize(SKPoint point) {
88 		auto ls = point.x * point.x + point.y * point.y;
89 		auto invNorm = 1.0 / sqrt(ls);
90 		return SKPoint(cast(float)(point.x * invNorm), cast(float)(point.y * invNorm));
91 	}
92 
93 	static float Distance(SKPoint point, SKPoint other) {
94 		auto dx = point.x - other.x;
95 		auto dy = point.y - other.y;
96 		auto ls = dx * dx + dy * dy;
97 		return cast(float) sqrt(ls);
98 	}
99 
100 	static float DistanceSquared(SKPoint point, SKPoint other) {
101 		auto dx = point.x - other.x;
102 		auto dy = point.y - other.y;
103 		return dx * dx + dy * dy;
104 	}
105 
106 	static SKPoint Reflect(SKPoint point, SKPoint normal) {
107 		auto dot = point.x * point.x + point.y * point.y;
108 		return SKPoint(point.x - 2.0f * dot * normal.x, point.y - 2.0f * dot * normal.y);
109 	}
110 
111 	static SKPoint Add(SKPoint pt, SKSizeI sz) {
112 		return pt + sz;
113 	}
114 
115 	static SKPoint Add(SKPoint pt, SKSize sz) {
116 		return pt + sz;
117 	}
118 
119 	static SKPoint Add(SKPoint pt, SKPointI sz) {
120 		return pt + sz;
121 	}
122 
123 	static SKPoint Add(SKPoint pt, SKPoint sz) {
124 		return pt + sz;
125 	}
126 
127 	static SKPoint Subtract(SKPoint pt, SKSizeI sz) {
128 		return pt - sz;
129 	}
130 
131 	static SKPoint Subtract(SKPoint pt, SKSize sz) {
132 		return pt - sz;
133 	}
134 
135 	static SKPoint Subtract(SKPoint pt, SKPointI sz) {
136 		return pt - sz;
137 	}
138 
139 	static SKPoint Subtract(SKPoint pt, SKPoint sz) {
140 		return pt - sz;
141 	}
142 
143 	SKPoint opBinary(string op, T)(T sz) if (is(T == SKSizeI) || is(T == SKSize)) {
144 		static if (op == "+") {
145 			return SKPoint(this.X + sz.Width, this.Y + sz.Height);
146 		} else static if (op == "-") {
147 			return SKPoint(this.X - sz.Width, this.Y - sz.Height);
148 		} else {
149 			static assert(false, op ~ " is not suuuported");
150 		}
151 	}
152 
153 	SKPoint opBinary(string op, T)(T sz) if (is(T == SKPointI) || is(T == SKPoint)) {
154 		static if (op == "+") {
155 			return SKPoint(this.X + sz.X, this.Y + sz.Y);
156 		} else static if (op == "-") {
157 			return SKPoint(this.X - sz.X, this.Y - sz.Y);
158 		} else {
159 			static assert(false, op ~ " is not suuuported");
160 		}
161 	}
162 
163 	// static SKPoint operator + (SKPoint pt, SKSizeI sz)
164 	// {
165 	//   return SKPoint (pt.x + sz.Width, pt.y + sz.Height);
166 	// }
167 
168 	// static SKPoint operator + (SKPoint pt, SKSize sz)
169 	// {
170 	//   return 	SKPoint (pt.x + sz.Width, pt.y + sz.Height);
171 	// }
172 
173 	// static SKPoint operator + (SKPoint pt, SKPointI sz)
174 	// {
175 	//   return 	SKPoint (pt.x + sz.X, pt.y + sz.Y);
176 	// }
177 
178 	// static SKPoint operator + (SKPoint pt, SKPoint sz)
179 	// {
180 	//   return SKPoint (pt.x + sz.X, pt.y + sz.Y);
181 	// }
182 
183 	// static SKPoint operator - (SKPoint pt, SKSizeI sz)
184 	// {
185 	//   return SKPoint (pt.X - sz.Width, pt.Y - sz.Height);
186 	// }
187 
188 	// static SKPoint operator - (SKPoint pt, SKSize sz)
189 	// {
190 	//   return SKPoint (pt.X - sz.Width, pt.Y - sz.Height);
191 	// }
192 
193 	// static SKPoint operator - (SKPoint pt, SKPointI sz)
194 	// {
195 	//   return SKPoint (pt.X - sz.X, pt.Y - sz.Y);
196 	// }
197 
198 	// static SKPoint operator - (SKPoint pt, SKPoint sz)
199 	// {
200 	//   return 	SKPoint (pt.X - sz.X, pt.Y - sz.Y);
201 	// }
202 
203 }
204 
205 struct SKPointI {
206 	enum SKPointI Empty = SKPointI();
207 
208 	// int32_t x
209 	private int x;
210 	int X() {
211 		return x;
212 	}
213 
214 	void X(int value) {
215 		x = value;
216 	}
217 
218 	// int32_t y
219 	private int y;
220 	int Y() {
221 		return y;
222 	}
223 
224 	void Y(int value) {
225 		y = value;
226 	}
227 
228 	// bool Equals (SKPointI obj) {
229 	// 	return x == obj.x && y == obj.y
230 	// }
231 
232 	// override bool Equals (object obj) {
233 	// 	return obj is SKPointI f && Equals (f)
234 	// }
235 
236 	// static bool operator == (SKPointI left, SKPointI right) {
237 	// 	return left.Equals (right)
238 	// }
239 
240 	// static bool operator != (SKPointI left, SKPointI right) {
241 	// 	return !left.Equals (right)
242 	// }
243 
244 	// override int GetHashCode ()
245 	// {
246 	// 	var hash = new HashCode ();
247 	// 	hash.Add (x);
248 	// 	hash.Add (y);
249 	// 	return hash.ToHashCode ();
250 	// }
251 
252 	this(SKSizeI sz) {
253 		x = sz.Width;
254 		y = sz.Height;
255 	}
256 
257 	this(int x, int y) {
258 		this.x = x;
259 		this.y = y;
260 	}
261 
262 	bool IsEmpty() {
263 		return this == Empty;
264 	}
265 
266 	int Length() {
267 		return cast(int) sqrt(cast(float) x * x + y * y);
268 	}
269 
270 	int LengthSquared() {
271 		return x * x + y * y;
272 	}
273 
274 	void Offset(SKPointI p) {
275 		x += p.X;
276 		y += p.Y;
277 	}
278 
279 	void Offset(int dx, int dy) {
280 		x += dx;
281 		y += dy;
282 	}
283 
284 	string ToString() {
285 		return "{{X={x},Y={y}}}";
286 	}
287 
288 	static SKPointI Normalize(SKPointI point) {
289 		auto ls = point.x * point.x + point.y * point.y;
290 		auto invNorm = 1.0 / sqrt(cast(float) ls);
291 		return SKPointI(cast(int)(point.x * invNorm), cast(int)(point.y * invNorm));
292 	}
293 
294 	static float Distance(SKPointI point, SKPointI other) {
295 		auto dx = point.x - other.x;
296 		auto dy = point.y - other.y;
297 		auto ls = dx * dx + dy * dy;
298 		return cast(float) sqrt(cast(float) ls);
299 	}
300 
301 	static float DistanceSquared(SKPointI point, SKPointI other) {
302 		auto dx = point.x - other.x;
303 		auto dy = point.y - other.y;
304 		return dx * dx + dy * dy;
305 	}
306 
307 	static SKPointI Reflect(SKPointI point, SKPointI normal) {
308 		auto dot = point.x * point.x + point.y * point.y;
309 		return SKPointI(cast(int)(point.x - 2.0f * dot * normal.x),
310 				cast(int)(point.y - 2.0f * dot * normal.y));
311 	}
312 
313 	static SKPointI Ceiling(SKPoint value) {
314 		int x, y;
315 		// checked {
316 		x = cast(int) ceil(value.X);
317 		y = cast(int) ceil(value.Y);
318 		// }
319 
320 		return SKPointI(x, y);
321 	}
322 
323 	static SKPointI Round(SKPoint value) {
324 		int x, y;
325 		// checked {
326 		x = cast(int) round(value.X);
327 		y = cast(int) round(value.Y);
328 		// }
329 
330 		return SKPointI(x, y);
331 	}
332 
333 	static SKPointI Truncate(SKPoint value) {
334 		int x, y;
335 		// checked {
336 		x = cast(int) value.X;
337 		y = cast(int) value.Y;
338 		// }
339 
340 		return SKPointI(x, y);
341 	}
342 
343 	static SKPointI Add(SKPointI pt, SKSizeI sz) {
344 		return pt + sz;
345 	}
346 
347 	static SKPointI Add(SKPointI pt, SKPointI sz) {
348 		return pt + sz;
349 	}
350 
351 	static SKPointI Subtract(SKPointI pt, SKSizeI sz) {
352 		return pt - sz;
353 	}
354 
355 	static SKPointI Subtract(SKPointI pt, SKPointI sz) {
356 		return pt - sz;
357 	}
358 
359 	SKPointI opBinary(string op, T)(T sz) if (is(T == SKSizeI)) {
360 		static if (op == "+") {
361 			return SKPointI(this.X + sz.Width, this.Y + sz.Height);
362 		} else static if (op == "-") {
363 			return SKPointI(this.X - sz.Width, this.Y - sz.Height);
364 		} else {
365 			static assert(false, op ~ " is not suuuported");
366 		}
367 	}
368 
369 	SKPointI opBinary(string op, T)(T sz) if (is(T == SKPointI)) {
370 		static if (op == "+") {
371 			return SKPointI(this.X + sz.X, this.Y + sz.Y);
372 		} else static if (op == "-") {
373 			return SKPointI(this.X - sz.X, this.Y - sz.Y);
374 		} else {
375 			static assert(false, op ~ " is not suuuported");
376 		}
377 	}
378 
379 	// static SKPointI operator + (SKPointI pt, SKSizeI sz)
380 	// {
381 	//   return SKPointI (pt.X + sz.Width, pt.Y + sz.Height);
382 	// }
383 
384 	// static SKPointI operator + (SKPointI pt, SKPointI sz)
385 	// {
386 	//   return SKPointI (pt.X + sz.X, pt.Y + sz.Y);
387 	// }
388 
389 	// static SKPointI operator - (SKPointI pt, SKSizeI sz)
390 	// {
391 	//   return SKPointI (pt.X - sz.Width, pt.Y - sz.Height);
392 	// }
393 
394 	// static SKPointI operator - (SKPointI pt, SKPointI sz)
395 	// {
396 	//   return SKPointI (pt.X - sz.X, pt.Y - sz.Y);
397 	// }
398 
399 	// static explicit operator SKSizeI (SKPointI p)
400 	// {
401 	//   return 	SKSizeI (p.X, p.Y);
402 	// }
403 
404 	// static implicit operator SKPoint (SKPointI p)
405 	// {
406 	//   return SKPoint (p.X, p.Y);
407 	// }
408 
409 }
410 
411 struct SKPoint3 {
412 	enum SKPoint3 Empty = SKPoint3(0, 0, 0);
413 
414 	// float x
415 
416 	// bool Equals (SKPoint3 obj) {
417 	// 	return x == obj.x && y == obj.y && z == obj.z
418 	// }
419 
420 	// override bool Equals (object obj) {
421 	// 	return obj is SKPoint3 f && Equals (f)
422 	// }
423 
424 	// static bool operator == (SKPoint3 left, SKPoint3 right) {
425 	// 	return left.Equals (right)
426 	// }
427 
428 	// static bool operator != (SKPoint3 left, SKPoint3 right) {
429 	// 	return !left.Equals (right)
430 	// }
431 
432 	// override int GetHashCode ()
433 	// {
434 	// 	var hash = new HashCode ();
435 	// 	hash.Add (x);
436 	// 	hash.Add (y);
437 	// 	hash.Add (z);
438 	// 	return hash.ToHashCode ();
439 	// }
440 
441 	this(float x, float y, float z) {
442 		this.x = x;
443 		this.y = y;
444 		this.z = z;
445 	}
446 
447 	bool IsEmpty() {
448 		return this == Empty;
449 	}
450 
451 	string ToString() {
452 		return format("{{X=%s, Y=%s, Z=%s}}", x, y, z);
453 	}
454 
455 	static SKPoint3 Add(SKPoint3 pt, SKPoint3 sz) {
456 		return pt + sz;
457 	}
458 
459 	static SKPoint3 Subtract(SKPoint3 pt, SKPoint3 sz) {
460 		return pt - sz;
461 	}
462 
463 	SKPoint3 opBinary(string op)(SKPoint3 sz) {
464 		static if (op == "+") {
465 			return SKPoint3(this.X + sz.X, this.Y + sz.Y, this.Z + sz.Z);
466 		} else static if (op == "-") {
467 			return SKPoint3(this.X - sz.X, this.Y - sz.Y, this.Z - sz.Z);
468 		} else {
469 			static assert(false, op ~ " is not suuuported");
470 		}
471 	}
472 
473 	// static SKPoint3 operator + (SKPoint3 pt, SKPoint3 sz)
474 	// {
475 	//   return 	new SKPoint3 (pt.X + sz.X, pt.Y + sz.Y, pt.Z + sz.Z);
476 	// }
477 
478 	// static SKPoint3 operator - (SKPoint3 pt, SKPoint3 sz)
479 	// {
480 	//   return new SKPoint3 (pt.X - sz.X, pt.Y - sz.Y, pt.Z - sz.Z);
481 	// }
482 
483 	private float x;
484 	float X() {
485 		return x;
486 	}
487 
488 	void X(float value) {
489 		x = value;
490 	}
491 
492 	// float y
493 	private float y;
494 	float Y() {
495 		return y;
496 	}
497 
498 	void Y(float value) {
499 		y = value;
500 	}
501 
502 	// float z
503 	private float z;
504 	float Z() {
505 		return z;
506 	}
507 
508 	void Z(float value) {
509 		z = value;
510 	}
511 
512 }
513 
514 struct SKSize {
515 	enum SKSize Empty = SKSize(0, 0);
516 
517 	// float w
518 	private float w;
519 	float Width() {
520 		return w;
521 	}
522 
523 	void Width(float value) {
524 		w = value;
525 	}
526 
527 	// float h
528 	private float h;
529 	float Height() {
530 		return h;
531 	}
532 
533 	void Height(float value) {
534 		h = value;
535 	}
536 
537 	// bool Equals (SKSize obj) {
538 	// 	return w == obj.w && h == obj.h
539 	// }
540 
541 	// override bool Equals (object obj) {
542 	// 	return obj is SKSize f && Equals (f)
543 	// }
544 
545 	// static bool operator == (SKSize left, SKSize right) {
546 	// 	return left.Equals (right)
547 	// }
548 
549 	// static bool operator != (SKSize left, SKSize right) {
550 	// 	return !left.Equals (right)
551 	// }
552 
553 	// override int GetHashCode ()
554 	// {
555 	// 	var hash = new HashCode ();
556 	// 	hash.Add (w);
557 	// 	hash.Add (h);
558 	// 	return hash.ToHashCode ();
559 	// }
560 
561 	this(float width, float height) {
562 		w = width;
563 		h = height;
564 	}
565 
566 	this(SKPoint pt) {
567 		w = pt.X;
568 		h = pt.Y;
569 	}
570 
571 	bool IsEmpty() {
572 		return this == Empty;
573 	}
574 
575 	SKPoint ToPoint() {
576 		return SKPoint(w, h);
577 	}
578 
579 	SKSizeI ToSizeI() {
580 		int w, h;
581 		// checked {
582 		w = cast(int) this.w;
583 		h = cast(int) this.h;
584 		// }
585 
586 		return SKSizeI(w, h);
587 	}
588 
589 	string ToString() {
590 		return "{{Width={w}, Height={h}}}";
591 	}
592 
593 	static SKSize Add(SKSize sz1, SKSize sz2) {
594 		return sz1 + sz2;
595 	}
596 
597 	static SKSize Subtract(SKSize sz1, SKSize sz2) {
598 		return sz1 - sz2;
599 	}
600 
601 	SKSize opBinary(string op)(SKSize sz) {
602 		static if (op == "+") {
603 			return SKSize(this.Width + sz.Width, this.Height + sz.Height);
604 		} else static if (op == "-") {
605 			return SKSize(this.Width - sz.Width, this.Height - sz.Height);
606 		} else {
607 			static assert(false, op ~ " is not suuuported");
608 		}
609 	}
610 
611 	SKPoint opCast(SKPoint)() {
612 		return SKPoint(this.Width, this.Height);
613 	}
614 
615 	SKSize opCast(SKSize)() {
616 		return SKSize(this.Width, this.Height);
617 	}
618 
619 	// static SKSize operator + (SKSize sz1, SKSize sz2)
620 	// {
621 	//   return SKSize (sz1.Width + sz2.Width, sz1.Height + sz2.Height);
622 	// }
623 
624 	// static SKSize operator - (SKSize sz1, SKSize sz2)
625 	// {
626 	//   return 	SKSize (sz1.Width - sz2.Width, sz1.Height - sz2.Height);
627 
628 	// }
629 
630 	// static explicit operator SKPoint (SKSize size)
631 	// {
632 	//   return SKPoint (size.Width, size.Height);
633 	// }
634 
635 	// static implicit operator SKSize (SKSizeI size)
636 	// {
637 	//   return SKSize (size.Width, size.Height);
638 	// }
639 
640 }
641 
642 struct SKSizeI {
643 	enum SKSizeI Empty = SKSizeI(0, 0);
644 
645 	// int32_t w
646 	private int w;
647 	int Width() {
648 		return w;
649 	}
650 
651 	void Width(int value) {
652 		w = value;
653 	}
654 
655 	// int32_t h
656 	private int h;
657 	int Height() {
658 		return h;
659 	}
660 
661 	void Height(int value) {
662 		h = value;
663 	}
664 
665 	// bool Equals (SKSizeI obj) {
666 	// 	return w == obj.w && h == obj.h
667 	// }
668 
669 	// override bool Equals (object obj) {
670 	// 	return obj is SKSizeI f && Equals (f)
671 	// }
672 
673 	// static bool operator == (SKSizeI left, SKSizeI right) {
674 	// 	return left.Equals (right)
675 	// }
676 
677 	// static bool operator != (SKSizeI left, SKSizeI right) {
678 	// 	return !left.Equals (right)
679 	// }
680 
681 	// override int GetHashCode ()
682 	// {
683 	// 	var hash = new HashCode ();
684 	// 	hash.Add (w);
685 	// 	hash.Add (h);
686 	// 	return hash.ToHashCode ();
687 	// }
688 
689 	this(int width, int height) {
690 		w = width;
691 		h = height;
692 	}
693 
694 	this(SKPointI pt) {
695 		w = pt.X;
696 		h = pt.Y;
697 	}
698 
699 	bool IsEmpty() {
700 		return this == Empty;
701 	}
702 
703 	SKPointI ToPointI() {
704 		return SKPointI(w, h);
705 	}
706 
707 	string ToString() {
708 		return "{{Width={w}, Height={h}}}";
709 	}
710 
711 	static SKSizeI Add(SKSizeI sz1, SKSizeI sz2) {
712 		return sz1 + sz2;
713 	}
714 
715 	static SKSizeI Subtract(SKSizeI sz1, SKSizeI sz2) {
716 		return sz1 - sz2;
717 	}
718 
719 	SKSizeI opBinary(string op)(SKSizeI sz) {
720 		static if (op == "+") {
721 			return SKSizeI(this.Width + sz.Width, this.Height + sz.Height);
722 		} else static if (op == "-") {
723 			return SKSizeI(this.Width - sz.Width, this.Height - sz.Height);
724 		} else {
725 			static assert(false, op ~ " is not suuuported");
726 		}
727 	}
728 
729 	// static SKSizeI operator + (SKSizeI sz1, SKSizeI sz2)
730 	// {
731 	//   return SKSizeI (sz1.Width + sz2.Width, sz1.Height + sz2.Height);
732 	// }
733 
734 	// static SKSizeI operator - (SKSizeI sz1, SKSizeI sz2)
735 	// {
736 	//   return SKSizeI (sz1.Width - sz2.Width, sz1.Height - sz2.Height);
737 	// }
738 
739 	// static explicit operator SKPointI (SKSizeI size)
740 	// {
741 	//   return 	SKPointI (size.Width, size.Height);
742 	// }
743 
744 }
745 
746 struct SKRect {
747 	enum SKRect Empty = SKRect(0, 0, 0, 0);
748 
749 	// float left
750 	private float left;
751 	float Left() {
752 		return left;
753 	}
754 
755 	void Left(float value) {
756 		left = value;
757 	}
758 
759 	// float top
760 	private float top;
761 	float Top() {
762 		return top;
763 	}
764 
765 	void Top(float value) {
766 		top = value;
767 	}
768 
769 	// float right
770 	private float right;
771 	float Right() {
772 		return right;
773 	}
774 
775 	void Right(float value) {
776 		right = value;
777 	}
778 
779 	// float bottom
780 	private float bottom;
781 	float Bottom() {
782 		return bottom;
783 	}
784 
785 	void Bottom(float value) {
786 		bottom = value;
787 	}
788 
789 	// bool Equals (SKRect obj) {
790 	// 	return left == obj.left && top == obj.top && right == obj.right && bottom == obj.bottom
791 	// }
792 
793 	// override bool Equals (object obj) {
794 	// 	return obj is SKRect f && Equals (f)
795 	// }
796 
797 	// static bool operator == (SKRect left, SKRect right) {
798 	// 	return left.Equals (right)
799 	// }
800 
801 	// static bool operator != (SKRect left, SKRect right) {
802 	// 	return !left.Equals (right)
803 	// }
804 
805 	// override int GetHashCode ()
806 	// {
807 	// 	var hash = new HashCode ();
808 	// 	hash.Add (left);
809 	// 	hash.Add (top);
810 	// 	hash.Add (right);
811 	// 	hash.Add (bottom);
812 	// 	return hash.ToHashCode ();
813 	// }
814 
815 	this(float left, float top, float right, float bottom) {
816 		this.left = left;
817 		this.right = right;
818 		this.top = top;
819 		this.bottom = bottom;
820 	}
821 
822 	float MidX() {
823 		return left + (Width / 2f);
824 	}
825 
826 	float MidY() {
827 		return top + (Height / 2f);
828 	}
829 
830 	float Width() {
831 		return right - left;
832 	}
833 
834 	float Height() {
835 		return bottom - top;
836 	}
837 
838 	bool IsEmpty() {
839 		return this == Empty;
840 	}
841 
842 	SKSize Size() {
843 		return SKSize(Width, Height);
844 	}
845 
846 	void Size(SKSize value) {
847 		right = left + value.Width;
848 		bottom = top + value.Height;
849 	}
850 
851 	SKPoint Location() {
852 		return SKPoint(left, top);
853 	}
854 
855 	void Location(SKPoint value) {
856 		this = SKRect.Create(value, Size);
857 	}
858 
859 	SKRect Standardized() {
860 
861 		if (left > right) {
862 			if (top > bottom) {
863 				return SKRect(right, bottom, left, top);
864 			} else {
865 				return SKRect(right, top, left, bottom);
866 			}
867 		} else {
868 			if (top > bottom) {
869 				return SKRect(left, bottom, right, top);
870 			} else {
871 				return SKRect(left, top, right, bottom);
872 			}
873 		}
874 
875 	}
876 
877 	SKRect AspectFit(SKSize size) {
878 		return AspectResize(size, true);
879 	}
880 
881 	SKRect AspectFill(SKSize size) {
882 		return AspectResize(size, false);
883 	}
884 
885 	private SKRect AspectResize(SKSize size, bool fit) {
886 		if (size.Width == 0 || size.Height == 0 || Width == 0 || Height == 0)
887 			return Create(MidX, MidY, 0, 0);
888 
889 		auto aspectWidth = size.Width;
890 		auto aspectHeight = size.Height;
891 		auto imgAspect = aspectWidth / aspectHeight;
892 		auto fullRectAspect = Width / Height;
893 
894 		auto compare = fit ? (fullRectAspect > imgAspect) : (fullRectAspect < imgAspect);
895 		if (compare) {
896 			aspectHeight = Height;
897 			aspectWidth = aspectHeight * imgAspect;
898 		} else {
899 			aspectWidth = Width;
900 			aspectHeight = aspectWidth / imgAspect;
901 		}
902 		auto aspectLeft = MidX - (aspectWidth / 2f);
903 		auto aspectTop = MidY - (aspectHeight / 2f);
904 
905 		return Create(aspectLeft, aspectTop, aspectWidth, aspectHeight);
906 	}
907 
908 	static SKRect Inflate(SKRect rect, float x, float y) {
909 		auto r = SKRect(rect.left, rect.top, rect.right, rect.bottom);
910 		r.Inflate(x, y);
911 		return r;
912 	}
913 
914 	void Inflate(SKSize size) {
915 		Inflate(size.Width, size.Height);
916 	}
917 
918 	void Inflate(float x, float y) {
919 		left -= x;
920 		top -= y;
921 		right += x;
922 		bottom += y;
923 	}
924 
925 	static SKRect Intersect(SKRect a, SKRect b) {
926 		if (!a.IntersectsWithInclusive(b)) {
927 			return Empty;
928 		}
929 		return SKRect(max(a.left, b.left), max(a.top, b.top), min(a.right,
930 				b.right), min(a.bottom, b.bottom));
931 	}
932 
933 	void Intersect(SKRect rect) {
934 		SKRect.Intersect(this, rect);
935 	}
936 
937 	static SKRect Union(SKRect a, SKRect b) {
938 		return SKRect(min(a.left, b.left), min(a.top, b.top), max(a.right,
939 				b.right), max(a.bottom, b.bottom));
940 	}
941 
942 	void Union(SKRect rect) {
943 		Union(this, rect);
944 	}
945 
946 	SKRect opCast(SKRect)() {
947 		return SKRect(this.Left, this.Top, this.Right, this.Bottom);
948 	}
949 
950 	// static implicit operator SKRect (SKRectI r)
951 	// {
952 	//   return 	SKRect (r.Left, r.Top, r.Right, r.Bottom);
953 	// }
954 
955 	bool Contains(float x, float y) {
956 		return (x >= left) && (x < right) && (y >= top) && (y < bottom);
957 	}
958 
959 	bool Contains(SKPoint pt) {
960 		return Contains(pt.X, pt.Y);
961 	}
962 
963 	bool Contains(SKRect rect) {
964 		return (left <= rect.left) && (right >= rect.right) && (top <= rect.top)
965 			&& (bottom >= rect.bottom);
966 	}
967 
968 	bool IntersectsWith(SKRect rect) {
969 		return (left < rect.right) && (right > rect.left) && (top < rect.bottom)
970 			&& (bottom > rect.top);
971 	}
972 
973 	bool IntersectsWithInclusive(SKRect rect) {
974 		return (left <= rect.right) && (right >= rect.left)
975 			&& (top <= rect.bottom) && (bottom >= rect.top);
976 	}
977 
978 	void Offset(float x, float y) {
979 		left += x;
980 		top += y;
981 		right += x;
982 		bottom += y;
983 	}
984 
985 	void Offset(SKPoint pos) {
986 		return Offset(pos.X, pos.Y);
987 	}
988 
989 	string ToString() {
990 		return format("{{Left=%s,Top=%s,Width=%s,Height=%s}}", Left, Top, Width, Height);
991 	}
992 
993 	static SKRect Create(int width, int height) {
994 		return SKRect(SKPoint.Empty.X, SKPoint.Empty.Y, width, height);
995 	}
996 
997 	static SKRect Create(SKPoint location, SKSize size) {
998 		return Create(location.X, location.Y, size.Width, size.Height);
999 	}
1000 
1001 	static SKRect Create(SKSize size) {
1002 		return Create(SKPoint.Empty, size);
1003 	}
1004 
1005 	static SKRect Create(float width, float height) {
1006 		return SKRect(SKPoint.Empty.X, SKPoint.Empty.Y, width, height);
1007 	}
1008 
1009 	static SKRect Create(float x, float y, float width, float height) {
1010 		return SKRect(x, y, x + width, y + height);
1011 	}
1012 
1013 }
1014 
1015 struct SKRectI {
1016 	static SKRectI Empty;
1017 
1018 	// int32_t left
1019 	private int left;
1020 	int Left() {
1021 		return left;
1022 	}
1023 
1024 	void Left(int value) {
1025 		left = value;
1026 	}
1027 
1028 	// int32_t top
1029 	private int top;
1030 	int Top() {
1031 		return top;
1032 	}
1033 
1034 	void Top(int value) {
1035 		top = value;
1036 	}
1037 
1038 	// int32_t right
1039 	private int right;
1040 	int Right() {
1041 		return right;
1042 	}
1043 
1044 	void Right(int value) {
1045 		right = value;
1046 	}
1047 
1048 	// int32_t bottom
1049 	private int bottom;
1050 	int Bottom() {
1051 		return bottom;
1052 	}
1053 
1054 	void Bottom(int value) {
1055 		bottom = value;
1056 	}
1057 
1058 	// bool Equals (SKRectI obj) {
1059 	// 	return left == obj.left && top == obj.top && right == obj.right && bottom == obj.bottom
1060 	// }
1061 
1062 	// override bool Equals (object obj) {
1063 	// 	return obj is SKRectI f && Equals (f)
1064 	// }
1065 
1066 	// static bool operator == (SKRectI left, SKRectI right) {
1067 	// 	return left.Equals (right)
1068 	// }
1069 
1070 	// static bool operator != (SKRectI left, SKRectI right) {
1071 	// 	return !left.Equals (right)
1072 	// }
1073 
1074 	// override int GetHashCode ()
1075 	// {
1076 	// 	var hash = new HashCode ();
1077 	// 	hash.Add (left);
1078 	// 	hash.Add (top);
1079 	// 	hash.Add (right);
1080 	// 	hash.Add (bottom);
1081 	// 	return hash.ToHashCode ();
1082 	// }
1083 
1084 	this(int left, int top, int right, int bottom) {
1085 		this.left = left;
1086 		this.right = right;
1087 		this.top = top;
1088 		this.bottom = bottom;
1089 	}
1090 
1091 	int MidX() {
1092 		return left + (Width / 2);
1093 	}
1094 
1095 	int MidY() {
1096 		return top + (Height / 2);
1097 	}
1098 
1099 	int Width() {
1100 		return right - left;
1101 	}
1102 
1103 	int Height() {
1104 		return bottom - top;
1105 
1106 	}
1107 
1108 	bool IsEmpty() {
1109 		return this == Empty;
1110 	}
1111 
1112 	SKSizeI Size() {
1113 		return SKSizeI(Width, Height);
1114 	}
1115 
1116 	void Size(SKSizeI value) {
1117 		right = left + value.Width;
1118 		bottom = top + value.Height;
1119 	}
1120 
1121 	SKPointI Location() {
1122 		return SKPointI(left, top);
1123 	}
1124 
1125 	void Location(SKPointI value) {
1126 
1127 		this = SKRectI.Create(value, Size);
1128 	}
1129 
1130 	SKRectI Standardized() {
1131 
1132 		if (left > right) {
1133 			if (top > bottom) {
1134 				return SKRectI(right, bottom, left, top);
1135 			} else {
1136 				return SKRectI(right, top, left, bottom);
1137 			}
1138 		} else {
1139 			if (top > bottom) {
1140 				return SKRectI(left, bottom, right, top);
1141 			} else {
1142 				return SKRectI(left, top, right, bottom);
1143 			}
1144 		}
1145 
1146 	}
1147 
1148 	SKRectI AspectFit(SKSizeI size) {
1149 		return Truncate((cast(SKRect) this).AspectFit(cast(SKSize) size));
1150 	}
1151 
1152 	SKRectI AspectFill(SKSizeI size) {
1153 		return Truncate((cast(SKRect) this).AspectFill(cast(SKSize) size));
1154 	}
1155 
1156 	static SKRectI Ceiling(SKRect value) {
1157 		return Ceiling(value, false);
1158 	}
1159 
1160 	static SKRectI Ceiling(SKRect value, bool outwards) {
1161 		int x, y, r, b;
1162 		// checked {
1163 		x = cast(int)(outwards && value.Width > 0 ? floor(value.Left) : ceil(value.Left));
1164 		y = cast(int)(outwards && value.Height > 0 ? floor(value.Top) : ceil(value.Top));
1165 		r = cast(int)(outwards && value.Width < 0 ? floor(value.Right) : ceil(value.Right));
1166 		b = cast(int)(outwards && value.Height < 0 ? floor(value.Bottom) : ceil(value.Bottom));
1167 		// }
1168 
1169 		return SKRectI(x, y, r, b);
1170 	}
1171 
1172 	static SKRectI Inflate(SKRectI rect, int x, int y) {
1173 		auto r = SKRectI(rect.left, rect.top, rect.right, rect.bottom);
1174 		r.Inflate(x, y);
1175 		return r;
1176 	}
1177 
1178 	void Inflate(SKSizeI size) {
1179 		return Inflate(size.Width, size.Height);
1180 	}
1181 
1182 	void Inflate(int width, int height) {
1183 		left -= width;
1184 		top -= height;
1185 		right += width;
1186 		bottom += height;
1187 	}
1188 
1189 	static SKRectI Intersect(SKRectI a, SKRectI b) {
1190 		if (!a.IntersectsWithInclusive(b))
1191 			return Empty;
1192 
1193 		return SKRectI(max(a.left, b.left), max(a.top, b.top), min(a.right,
1194 				b.right), min(a.bottom, b.bottom));
1195 	}
1196 
1197 	// 	void Intersect (SKRectI rect)
1198 	//   {
1199 	//     return this = Intersect (this, rect);
1200 	//   }
1201 
1202 	static SKRectI Round(SKRect value) {
1203 		int x, y, r, b;
1204 		// checked {
1205 		x = cast(int) round(value.Left);
1206 		y = cast(int) round(value.Top);
1207 		r = cast(int) round(value.Right);
1208 		b = cast(int) round(value.Bottom);
1209 		// }
1210 
1211 		return SKRectI(x, y, r, b);
1212 	}
1213 
1214 	static SKRectI Floor(SKRect value) {
1215 		return Floor(value, false);
1216 	}
1217 
1218 	static SKRectI Floor(SKRect value, bool inwards) {
1219 		int x, y, r, b;
1220 		// checked {
1221 		x = cast(int)(inwards && value.Width > 0 ? ceil(value.Left) : floor(value.Left));
1222 		y = cast(int)(inwards && value.Height > 0 ? ceil(value.Top) : floor(value.Top));
1223 		r = cast(int)(inwards && value.Width < 0 ? ceil(value.Right) : floor(value.Right));
1224 		b = cast(int)(inwards && value.Height < 0 ? ceil(value.Bottom) : floor(value.Bottom));
1225 		// }
1226 
1227 		return SKRectI(x, y, r, b);
1228 	}
1229 
1230 	static SKRectI Truncate(SKRect value) {
1231 		int x, y, r, b;
1232 		// checked {
1233 		x = cast(int) value.Left;
1234 		y = cast(int) value.Top;
1235 		r = cast(int) value.Right;
1236 		b = cast(int) value.Bottom;
1237 		// }
1238 
1239 		return SKRectI(x, y, r, b);
1240 	}
1241 
1242 	static SKRectI Union(SKRectI a, SKRectI b) {
1243 		return SKRectI(min(a.Left, b.Left), min(a.Top, b.Top), max(a.Right,
1244 				b.Right), max(a.Bottom, b.Bottom));
1245 	}
1246 
1247 	void Union(SKRectI rect) {
1248 		Union(this, rect);
1249 	}
1250 
1251 	bool Contains(int x, int y) {
1252 		return (x >= left) && (x < right) && (y >= top) && (y < bottom);
1253 	}
1254 
1255 	bool Contains(SKPointI pt) {
1256 		return Contains(pt.X, pt.Y);
1257 	}
1258 
1259 	bool Contains(SKRectI rect) {
1260 		return (left <= rect.left) && (right >= rect.right) && (top <= rect.top)
1261 			&& (bottom >= rect.bottom);
1262 
1263 	}
1264 
1265 	bool IntersectsWith(SKRectI rect) {
1266 		return (left < rect.right) && (right > rect.left) && (top < rect.bottom)
1267 			&& (bottom > rect.top);
1268 	}
1269 
1270 	bool IntersectsWithInclusive(SKRectI rect) {
1271 		return (left <= rect.right) && (right >= rect.left)
1272 			&& (top <= rect.bottom) && (bottom >= rect.top);
1273 	}
1274 
1275 	void Offset(int x, int y) {
1276 		left += x;
1277 		top += y;
1278 		right += x;
1279 		bottom += y;
1280 	}
1281 
1282 	void Offset(SKPointI pos) {
1283 		return Offset(pos.X, pos.Y);
1284 	}
1285 
1286 	string ToString() {
1287 		return "{{Left={Left},Top={Top},Width={Width},Height={Height}}}";
1288 	}
1289 
1290 	static SKRectI Create(SKSizeI size) {
1291 		return Create(SKPointI.Empty.X, SKPointI.Empty.Y, size.Width, size.Height);
1292 	}
1293 
1294 	static SKRectI Create(SKPointI location, SKSizeI size) {
1295 		return Create(location.X, location.Y, size.Width, size.Height);
1296 	}
1297 
1298 	static SKRectI Create(int width, int height) {
1299 		return SKRectI(SKPointI.Empty.X, SKPointI.Empty.X, width, height);
1300 
1301 	}
1302 
1303 	static SKRectI Create(int x, int y, int width, int height) {
1304 		return SKRectI(x, y, x + width, y + height);
1305 	}
1306 
1307 }