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 }