551 RectI(
const RectI& that) =
default;
552 RectI& operator=(
const RectI& that) =
default;
554 RectI(
int left_,
int top_,
int right_,
int bottom_) {
561 explicit RectI(
const SizeI& size) {
565 bottom = size.height;
571 right = origin.x + size.width;
572 bottom = origin.y + size.height;
575 RectI(
const PointI& leftTop,
const PointI& rightBottom) {
578 right = rightBottom.x;
579 bottom = rightBottom.y;
586 bottom = that.bottom;
589 void SortForPageSpace() {
591 std::swap(left, right);
593 std::swap(top, bottom);
595 static RectI MakeSortedForPageSpace(
const RectI& rect) {
597 result.SortForPageSpace();
601 void SortForDeviceSpace() {
603 std::swap(left, right);
605 std::swap(top, bottom);
607 static RectI MakeSortedForDeviceSpace(
const RectI& rect) {
609 result.SortForDeviceSpace();
614 int& MinX() {
return (left <= right ? left : right); }
615 int& MaxX() {
return (left > right ? left : right); }
616 int& MinY() {
return (top <= bottom ? top : bottom); }
617 int& MaxY() {
return (top > bottom ? top : bottom); }
620 int MinX()
const {
return (std::min)(left, right); }
621 int MaxX()
const {
return (std::max)(left, right); }
622 int MinY()
const {
return (std::min)(top, bottom); }
623 int MaxY()
const {
return (std::max)(top, bottom); }
625 bool Equals(
const RectI& that)
const {
628 return MinX() == that.MinX() &&
629 MaxX() == that.MaxX() &&
630 MinY() == that.MinY() &&
631 MaxY() == that.MaxY();
634 bool operator==(
const RectI& that)
const {
return Equals(that); }
635 bool operator!=(
const RectI& that)
const {
return !Equals(that); }
637 int GetWidth()
const {
return std::abs(right - left); }
638 int GetHeight()
const {
return std::abs(top - bottom); }
640 int GetArea()
const {
return GetWidth() * GetHeight(); }
641 bool IsAreaEmpty()
const {
return left == right || top == bottom; }
643 PointI GetOrigin()
const {
return PointI(MinX(), MinY()); }
644 SizeI GetSize()
const {
return SizeI(GetWidth(), GetHeight()); }
647 PointI GetLeftCenter()
const {
return PointI(left, MinY() + GetHeight() / 2); }
648 PointI GetLeftBottom()
const {
return PointI(left, bottom); }
650 PointI GetCenterTop()
const {
return PointI(MinX() + GetWidth() / 2, top); }
651 PointI GetCenter()
const {
return PointI(MinX() + GetWidth() / 2, MinY() + GetHeight() / 2); }
652 PointI GetCenterBottom()
const {
return PointI(MinX() + GetWidth() / 2, bottom); }
654 PointI GetRightTop()
const {
return PointI(right, top); }
655 PointI GetRightCenter()
const {
return PointI(right, MinY() + GetHeight() / 2); }
656 PointI GetRightBottom()
const {
return PointI(right, bottom); }
658 void Offset(
int dx,
int dy) {
664 void Offset(
const PointI& delta) { Offset(delta.x, delta.y); }
665 static RectI MakeOffset(
const RectI& rect,
int dx,
int dy) {
667 result.Offset(dx, dy);
670 static RectI MakeOffset(
const RectI& rect,
const PointI& delta) {
return MakeOffset(rect, delta.x, delta.y); }
672 RectI& operator+=(
const PointI& point) {
676 RectI& operator-=(
const PointI& point) {
680 RectI operator+(
const PointI& point)
const {
return MakeOffset(*
this, point); }
681 RectI operator-(
const PointI& point)
const {
return MakeOffset(*
this, -point); }
683 void Inflate(
int dx,
int dy) {
693 void Inflate(
int delta) {
return Inflate(delta, delta); }
694 static RectI MakeInflated(
const RectI& rect,
int dx,
int dy) {
696 result.Inflate(dx, dy);
699 static RectI MakeInflated(
const RectI& rect,
int delta) {
return MakeInflated(rect, delta, delta); }
701 void Extend(
const PointI& point) {
702 MinX() = (std::min)(MinX(), point.x);
703 MinY() = (std::min)(MinY(), point.y);
704 MaxX() = (std::max)(MaxX(), point.x);
705 MaxY() = (std::max)(MaxY(), point.y);
707 static RectI MakeExtended(
const RectI& rect,
const PointI& point) {
709 result.Extend(point);
713 bool Contains(
const PointI& point)
const {
714 return point.x >= MinX() && point.x < MaxX() && point.y >= MinY() && point.y < MaxY();
716 bool Contains(
const RectI& rect)
const {
717 return MinX() <= rect.MinX() && MaxX() >= rect.MaxX() && MinY() <= rect.MinY() && MaxY() >= rect.MaxY();
720 bool HasIntersection(
const RectI& rect)
const {
721 return MinX() < rect.MaxX() && MinY() < rect.MaxY() && MaxX() > rect.MinX() && MaxY() > rect.MinY();
723 static RectI MakeIntersection(
const RectI& a,
const RectI& b) {
724 if (!a.HasIntersection(b))
728 i.MinX() = (std::max)(a.MinX(), b.MinX());
729 i.MinY() = (std::max)(a.MinY(), b.MinY());
730 i.MaxX() = (std::min)(a.MaxX(), b.MaxX());
731 i.MaxY() = (std::min)(a.MaxY(), b.MaxY());
735 static RectI MakeUnion(
const RectI& a,
const RectI& b) {
737 u.MinX() = (std::min)(a.MinX(), b.MinX());
738 u.MinY() = (std::min)(a.MinY(), b.MinY());
739 u.MaxX() = (std::max)(a.MaxX(), b.MaxX());
740 u.MaxY() = (std::max)(a.MaxY(), b.MaxY());
743 static RectI MakeUnionIgnoringEmpty(
const RectI& a,
const RectI& b) {
748 return MakeUnion(a, b);
760 RectF(
const RectF& that) =
default;
761 RectF& operator=(
const RectF& that) =
default;
763 RectF(
float left_,
float top_,
float right_,
float bottom_) {
774 bottom = rect.bottom;
777 explicit RectF(
const SizeF& size) {
786 top = origin.y + size.height;
787 right = origin.x + size.width;
791 RectF(
const PointF& leftTop,
const PointF& rightBottom) {
794 right = rightBottom.x;
795 bottom = rightBottom.y;
798 RectF(
const RectI& recti) {
799 left =
static_cast<float>(recti.left);
800 top =
static_cast<float>(recti.top);
801 right =
static_cast<float>(recti.right);
802 bottom =
static_cast<float>(recti.bottom);
806 template<
class Po
intsIter>
807 static RectF EnclosingPoints(
const PointsIter& pointsBegin,
const PointsIter& pointsEnd) {
809 auto it = pointsBegin;
810 if (it != pointsEnd) {
811 rect = RectF(*it, *it);
812 while (++it != pointsEnd)
818 template<
class Po
intsContainer>
819 static RectF EnclosingPoints(
const PointsContainer& points) {
820 return EnclosingPoints(std::begin(points), std::end(points));
823 static RectF EnclosingPoints(
const std::initializer_list<PointF>& points) {
824 return EnclosingPoints(std::begin(points), std::end(points));
828 RectI Round()
const {
829 return RectI(
static_cast<int>(std::round(MinX())),
830 static_cast<int>(std::round(MinY())),
831 static_cast<int>(std::round(MaxX())),
832 static_cast<int>(std::round(MaxY())));
834 RectI Floor()
const {
835 return RectI(
static_cast<int>(std::ceil(MinX())),
836 static_cast<int>(std::ceil(MinY())),
837 static_cast<int>(std::floor(MaxX())),
838 static_cast<int>(std::floor(MaxY())));
841 return RectI(
static_cast<int>(std::floor(MinX())),
842 static_cast<int>(std::floor(MinY())),
843 static_cast<int>(std::ceil(MaxX())),
844 static_cast<int>(std::ceil(MaxY())));
847 void SortForPageSpace() {
849 std::swap(left, right);
851 std::swap(top, bottom);
853 static RectF MakeSortedForPageSpace(
const RectF& rect) {
855 result.SortForPageSpace();
859 void SortForDeviceSpace() {
861 std::swap(left, right);
863 std::swap(top, bottom);
865 static RectF MakeSortedForDeviceSpace(
const RectF& rect) {
867 result.SortForDeviceSpace();
872 float& MinX() {
return (left <= right ? left : right); }
873 float& MaxX() {
return (left > right ? left : right); }
874 float& MinY() {
return (top <= bottom ? top : bottom); }
875 float& MaxY() {
return (top > bottom ? top : bottom); }
878 float MinX()
const {
return (std::min)(left, right); }
879 float MaxX()
const {
return (std::max)(left, right); }
880 float MinY()
const {
return (std::min)(top, bottom); }
881 float MaxY()
const {
return (std::max)(top, bottom); }
883 bool Equals(
const RectF& that,
const float eps = Math::EPSILON)
const {
886 return Math::FloatEq(MinX(), that.MinX(), eps) &&
887 Math::FloatEq(MaxX(), that.MaxX(), eps) &&
888 Math::FloatEq(MinY(), that.MinY(), eps) &&
889 Math::FloatEq(MaxY(), that.MaxY(), eps);
892 bool operator==(
const RectF& that)
const {
return Equals(that); }
893 bool operator!=(
const RectF& that)
const {
return !Equals(that); }
895 float GetWidth()
const {
return std::abs(right - left); }
896 float GetHeight()
const {
return std::abs(top - bottom); }
898 float GetArea()
const {
return GetWidth() * GetHeight(); }
899 bool IsAreaEmpty()
const {
return Math::FloatEq(left, right) || Math::FloatEq(top, bottom); }
901 PointF GetOrigin()
const {
return PointF(MinX(), MinY()); }
902 SizeF GetSize()
const {
return SizeF(GetWidth(), GetHeight()); }
906 PointF GetLeftBottom()
const {
return PointF(left, bottom); }
909 PointF GetCenter()
const {
return PointF(MinX() + GetWidth() / 2.f, MinY() + GetHeight() / 2.f); }
912 PointF GetRightTop()
const {
return PointF(right, top); }
914 PointF GetRightBottom()
const {
return PointF(right, bottom); }
916 void Offset(
float dx,
float dy) {
922 void Offset(
const PointF& delta) { Offset(delta.x, delta.y); }
923 static RectF MakeOffset(
const RectF& rect,
float dx,
float dy) {
925 result.Offset(dx, dy);
928 static RectF MakeOffset(
const RectF& rect,
const PointF& delta) {
return MakeOffset(rect, delta.x, delta.y); }
930 void MoveTo(
float x,
float y) { Offset(x - MinX(), y - MinY()); }
931 void MoveTo(
const PointF& point) { MoveTo(point.x, point.y); }
932 static RectF MakeMoved(
const RectF& rect,
float x,
float y) {
937 static RectF MakeMoved(
const RectF& rect,
const PointF& point) {
return MakeMoved(rect, point.x, point.y); }
939 RectF& operator+=(
const PointF& point) {
943 RectF& operator-=(
const PointF& point) {
947 RectF operator+(
const PointF& point)
const {
return (RectF(*
this) += point); }
948 RectF operator-(
const PointF& point)
const {
return (RectF(*
this) -= point); }
950 void Inflate(
float dx,
float dy) {
960 void Inflate(
float delta) { Inflate(delta, delta); }
961 static RectF MakeInflated(
const RectF& rect,
float dx,
float dy) {
963 result.Inflate(dx, dy);
966 static RectF MakeInflated(
const RectF& rect,
float delta) {
return MakeInflated(rect, delta, delta); }
968 void Extend(
const PointF& point) {
969 float& minX = MinX();
970 float& minY = MinY();
971 float& maxX = MaxX();
972 float& maxY = MaxY();
973 minX = (std::min)(minX, point.x);
974 minY = (std::min)(minY, point.y);
975 maxX = (std::max)(maxX, point.x);
976 maxY = (std::max)(maxY, point.y);
978 static RectF MakeExtended(
const RectF& rect,
const PointF& point) {
980 result.Extend(point);
984 bool Contains(
const PointF& point)
const {
985 return point.x >= MinX() && point.x <= MaxX() && point.y >= MinY() && point.y <= MaxY();
987 bool Contains(
const RectF& rect)
const {
988 return MinX() <= rect.MinX() && MaxX() >= rect.MaxX() && MinY() <= rect.MinY() && MaxY() >= rect.MaxY();
991 bool HasIntersectionWithEdge(
const PointF& a,
const PointF& b)
const {
992 return (Contains(a) ||
994 Math::EdgeIntersectsEdge(GetLeftTop(), GetRightTop(), a, b) ||
995 Math::EdgeIntersectsEdge(GetRightTop(), GetRightBottom(), a, b) ||
996 Math::EdgeIntersectsEdge(GetRightBottom(), GetLeftBottom(), a, b) ||
997 Math::EdgeIntersectsEdge(GetLeftBottom(), GetLeftTop(), a, b));
999 bool HasIntersection(
const RectF& rect)
const {
1000 return MinX() < rect.MaxX() && MinY() < rect.MaxY() && MaxX() > rect.MinX() && MaxY() > rect.MinY();
1003 static RectF MakeIntersection(
const RectF& a,
const RectF& b) {
1004 if (!a.HasIntersection(b))
1008 i.MinX() = (std::max)(a.MinX(), b.MinX());
1009 i.MinY() = (std::max)(a.MinY(), b.MinY());
1010 i.MaxX() = (std::min)(a.MaxX(), b.MaxX());
1011 i.MaxY() = (std::min)(a.MaxY(), b.MaxY());
1015 static RectF MakeUnion(
const RectF& a,
const RectF& b) {
1017 u.MinX() = (std::min)(a.MinX(), b.MinX());
1018 u.MinY() = (std::min)(a.MinY(), b.MinY());
1019 u.MaxX() = (std::max)(a.MaxX(), b.MaxX());
1020 u.MaxY() = (std::max)(a.MaxY(), b.MaxY());
1024 static RectF MakeUnionIgnoringEmpty(
const RectF& a,
const RectF& b) {
1025 if (a.IsAreaEmpty())
1027 if (b.IsAreaEmpty())
1029 return MakeUnion(a, b);
1041 Quad(
const Quad& that) =
default;
1042 Quad& operator=(
const Quad& that) =
default;
1044 Quad(
const PDQuad& that) {
1045 topleft = that.topleft;
1046 topright = that.topright;
1047 botleft = that.botleft;
1048 botright = that.botright;
1053 topright = rightTop_;
1054 botleft = leftBottom_;
1055 botright = rightBottom_;
1058 explicit Quad(
const PDRectF& rect) {
1059 topleft =
PointF(rect.left, rect.top);
1060 topright =
PointF(rect.right, rect.top);
1061 botleft =
PointF(rect.left, rect.bottom);
1062 botright =
PointF(rect.right, rect.bottom);
1065 explicit Quad(
const RectF& rect) {
1066 topleft =
PointF(rect.left, rect.top);
1067 topright =
PointF(rect.right, rect.top);
1068 botleft =
PointF(rect.left, rect.bottom);
1069 botright =
PointF(rect.right, rect.bottom);
1072 PointF GetLeftTop()
const {
return topleft; }
1074 PointF GetLeftBottom()
const {
return botleft; }
1080 PointF GetRightTop()
const {
return topright; }
1081 PointF GetRightBottom()
const {
return botright; }
1084 RectF GetBound()
const {
1085 auto [minx, maxx] = std::minmax({topleft.x, topright.x, botleft.x, botright.x});
1086 auto [miny, maxy] = std::minmax({topleft.y, topright.y, botleft.y, botright.y});
1087 return RectF(minx, maxy, maxx, miny);
1090 float GetRotationAngle()
const {
return std::atan2(topright.y - topleft.y, topright.x - topleft.x); }
1092 bool IsRectangle()
const {
1093 return (std::min)(topleft.x, botright.x) == (std::min)(botleft.x, topright.x) &&
1094 (std::max)(topleft.x, botright.x) == (std::max)(botleft.x, topright.x) &&
1095 (std::min)(topleft.y, botright.y) == (std::min)(botleft.y, topright.y) &&
1096 (std::max)(topleft.y, botright.y) == (std::max)(botleft.y, topright.y);
1099 bool Equals(
const Quad& that,
const float eps = Math::EPSILON)
const {
1102 return GetLeftTop().Equals(that.GetLeftTop(), eps) &&
1103 GetRightTop().Equals(that.GetRightTop(), eps) &&
1104 GetLeftBottom().Equals(that.GetLeftBottom(), eps) &&
1105 GetRightBottom().Equals(that.GetRightBottom(), eps);
1108 bool operator==(
const Quad& that)
const {
return Equals(that); }
1109 bool operator!=(
const Quad& that)
const {
return !Equals(that); }
1111 void Offset(
float dx,
float dy) {
1121 void Offset(
const PointF& point) { Offset(point.x, point.y); }
1123 static Quad MakeOffset(
const Quad& quad,
float dx,
float dy) {
1125 result.Offset(dx, dy);
1128 static Quad MakeOffset(
const Quad& quad,
const PointF& delta) {
return MakeOffset(quad, delta.x, delta.y); }
1130 Quad& operator+=(
const PointF& point) {
1134 Quad& operator-=(
const PointF& point) {
1139 Quad operator+(
const PointF& point)
const {
return (Quad(*
this) += point); }
1140 Quad operator-(
const PointF& point)
const {
return (Quad(*
this) -= point); }
1142 bool Contains(
const PointF& point)
const {
1143 RectF bound = GetBound();
1144 if (!bound.Contains(point))
1147 if (point == topleft || point == topright || point == botleft || point == botright)
1150 if (Math::FloatEq(0.f, point.
DistanceToEdge(topleft, topright)) ||
1157 winding += (point.
TestSide(topleft, topright) > 0) ? 1 : -1;
1158 winding += (point.
TestSide(topright, botright) > 0) ? 1 : -1;
1159 winding += (point.
TestSide(botright, botleft) > 0) ? 1 : -1;
1160 winding += (point.
TestSide(botleft, topleft) > 0) ? 1 : -1;
1161 return winding != 0;
1164 bool Contains(
const Quad& that)
const {
1165 return Contains(that.GetLeftTop()) &&
1166 Contains(that.GetRightTop()) &&
1167 Contains(that.GetLeftBottom()) &&
1168 Contains(that.GetRightBottom());
1171 bool HasIntersectionWithEdge(
const PointF& a,
const PointF& b)
const {
1172 return (Contains(a) ||
1174 Math::EdgeIntersectsEdge(GetLeftTop(), GetRightTop(), a, b) ||
1175 Math::EdgeIntersectsEdge(GetRightTop(), GetRightBottom(), a, b) ||
1176 Math::EdgeIntersectsEdge(GetRightBottom(), GetLeftBottom(), a, b) ||
1177 Math::EdgeIntersectsEdge(GetLeftBottom(), GetLeftTop(), a, b));
1180 bool HasIntersection(
const RectF& rect)
const {
1181 return HasIntersection(Quad{rect});
1184 bool HasIntersection(
const Quad& quad)
const {
1185 return (Contains(quad.GetLeftTop()) ||
1186 Contains(quad.GetRightTop()) ||
1187 Contains(quad.GetRightBottom()) ||
1188 Contains(quad.GetLeftBottom()) ||
1189 quad.Contains(GetLeftTop()) ||
1190 quad.Contains(GetRightTop()) ||
1191 quad.Contains(GetRightBottom()) ||
1192 quad.Contains(GetLeftBottom()) ||
1193 HasIntersectionWithEdge(quad.GetLeftTop(), quad.GetRightTop()) ||
1194 HasIntersectionWithEdge(quad.GetRightTop(), quad.GetRightBottom()) ||
1195 HasIntersectionWithEdge(quad.GetRightBottom(), quad.GetLeftBottom()) ||
1196 HasIntersectionWithEdge(quad.GetLeftBottom(), quad.GetLeftTop()));
1201 QuadPoints() =
default;
1203 explicit QuadPoints(std::vector<Quad> Quads_)
1204 : quads(std::move(Quads_)) {
1207 RectF GetBound()
const {
1209 if (!quads.empty()) {
1210 rect = quads[0].GetBound();
1211 for (
const auto& quad : quads)
1212 rect = RectF::MakeUnion(rect, quad.GetBound());
1217 bool Equals(
const QuadPoints& that,
const float eps = Math::EPSILON)
const {
1220 if (quads.size() != that.quads.size())
1222 for (
size_t i = 0; i < quads.size(); ++i) {
1223 if (!(quads[i].Equals(that.quads[i], eps)))
1229 bool operator==(
const QuadPoints& that)
const {
return Equals(that); }
1230 bool operator!=(
const QuadPoints& that)
const {
return !Equals(that); }
1232 QuadPoints Optimize()
const {
1234 return QuadPoints();
1236 std::vector<Quad> merged;
1238 static constexpr auto areLinesCollinear = [](
const PointF& p0,
const PointF& p1,
const PointF& p2) {
1243 bool initialized =
false;
1244 for (
size_t i = 0; i <= quads.size(); ++i) {
1245 if (i == quads.size()) {
1246 merged.emplace_back(quad);
1250 auto& newQuad = quads[i];
1255 if (areLinesCollinear(quad.GetLeftBottom(), quad.GetRightBottom(), newQuad.GetLeftBottom()) &&
1256 areLinesCollinear(quad.GetLeftTop(), quad.GetRightTop(), newQuad.GetLeftTop()) &&
1257 quad.HasIntersection(newQuad)) {
1258 quad.topright = newQuad.GetRightTop();
1259 quad.botright = newQuad.GetRightBottom();
1261 merged.emplace_back(quad);
1267 return QuadPoints(std::move(merged));
1270 std::vector<Quad> quads;
1286 Matrix(
const Matrix& that) =
default;
1287 Matrix& operator=(
const Matrix& that) =
default;
1289 Matrix(
float a_,
float b_,
float c_,
float d_,
float e_,
float f_) {
1307 bool Equals(
const Matrix& that,
const float eps = Math::EPSILON)
const {
1310 return Math::FloatEq(a, that.a, eps) &&
1311 Math::FloatEq(b, that.b, eps) &&
1312 Math::FloatEq(c, that.c, eps) &&
1313 Math::FloatEq(d, that.d, eps) &&
1314 Math::FloatEq(e, that.e, eps) &&
1315 Math::FloatEq(f, that.f, eps);
1318 bool operator==(
const Matrix& that)
const {
return Equals(that); }
1319 bool operator!=(
const Matrix& that)
const {
return !Equals(that); }
1321 bool IsIdentity()
const {
return *
this == Matrix{}; }
1323 static Matrix Concat(
const Matrix& lhs,
const Matrix& rhs) {
1324 return Matrix(lhs.a * rhs.a + lhs.b * rhs.c,
1325 lhs.a * rhs.b + lhs.b * rhs.d,
1326 lhs.c * rhs.a + lhs.d * rhs.c,
1327 lhs.c * rhs.b + lhs.d * rhs.d,
1328 lhs.e * rhs.a + lhs.f * rhs.c + rhs.e,
1329 lhs.e * rhs.b + lhs.f * rhs.d + rhs.f);
1332 Matrix operator*(
const Matrix& that)
const {
return Concat(*
this, that); }
1333 Matrix& operator*=(
const Matrix& that) {
return (*
this = *
this * that); }
1336 return PointF(a * point.x + c * point.y + e, b * point.x + d * point.y + f);
1340 return SizeF(a * size.width + c * size.height, b * size.width + d * size.height);
1344 return MapQuad(
Quad{rect}).GetBound();
1347 Quad MapQuad(
const Quad& quad)
const {
1348 return Quad(MapPoint(quad.GetLeftTop()),
1349 MapPoint(quad.GetRightTop()),
1350 MapPoint(quad.GetLeftBottom()),
1351 MapPoint(quad.GetRightBottom()));
1354 float GetScalingX()
const {
1355 return std::sqrt(a * a + c * c);
1358 float GetScalingY()
const {
1359 return std::sqrt(b * b + d * d);
1362 bool HasRotation()
const {
1363 return !Math::FloatEq(b, 0.f) || !Math::FloatEq(c, 0.f);
1366 float GetRotation()
const {
1367 return std::atan2(b, a);
1370 float GetRotationDegrees()
const {
1371 return Math::RadianToDegree(GetRotation());
1374 double Determinant()
const {
return static_cast<double>(a) * d -
static_cast<double>(b) * c; }
1376 static Matrix Scaling(
float value) {
return Scaling(value, value); }
1377 static Matrix Scaling(
float x,
float y) {
return Matrix(x, 0.f, 0.f, y, 0.f, 0.f); }
1378 static Matrix Scaling(
const SizeF& scaling) {
return Scaling(scaling.width, scaling.height); }
1379 static Matrix Scaling(
float value,
const PointF& origin) {
return Scaling(value, value, origin); }
1380 static Matrix Scaling(
float x,
float y,
const PointF& origin) {
return Matrix(x, 0.f, 0.f, y, (1.f - x) * origin.x, (1.f - y) * origin.y); }
1381 static Matrix Scaling(
const SizeF& scaling,
const PointF& origin) {
return Scaling(scaling.width, scaling.height, origin); }
1383 void Scale(
float value) { *
this = Scaling(value) * *
this; }
1384 void Scale(
float x,
float y) { *
this = Scaling(x, y) * *
this; }
1385 void Scale(
const SizeF& scaling) { *
this = Scaling(scaling) * *
this; }
1386 void Scale(
float value,
const PointF& origin) { *
this = Scaling(value, origin) * *
this; }
1387 void Scale(
float x,
float y,
const PointF& origin) { *
this = Scaling(x, y, origin) * *
this; }
1388 void Scale(
const SizeF& scaling,
const PointF& origin) { *
this = Scaling(scaling, origin) * *
this; }
1390 static Matrix Rotation(
double radians) {
1391 float sina =
static_cast<float>(std::sin(radians));
1392 float cosa =
static_cast<float>(std::cos(radians));
1393 return Matrix(cosa, sina, -sina, cosa, 0.f, 0.f);
1395 static Matrix Rotation(
double radians,
const PointF& origin) {
1396 float sina =
static_cast<float>(std::sin(radians));
1397 float cosa =
static_cast<float>(std::cos(radians));
1398 float dx = origin.x * (1.f - cosa) + origin.y * sina;
1399 float dy = origin.y * (1.f - cosa) - origin.x * sina;
1400 return Matrix(cosa, sina, -sina, cosa, dx, dy);
1403 void Rotate(
double radians) { *
this = Rotation(radians) * *
this; }
1404 void Rotate(
double radians,
const PointF& origin) { *
this = Rotation(radians, origin) * *
this; }
1406 static Matrix RotationDegree(
double degree) {
1408 return RotationDegree(degree, zero);
1410 static Matrix RotationDegree(
double degree,
const PointF& origin) {
1413 if (degree == 0.0) {
1416 }
else if (degree == 90.0) {
1419 }
else if (degree == 180.0) {
1422 }
else if (degree == 270.0) {
1426 double radians = Math::DegreeToRadian(degree);
1427 sina =
static_cast<float>(std::sin(radians));
1428 cosa =
static_cast<float>(std::cos(radians));
1431 float dx = origin.x * (1.f - cosa) + origin.y * sina;
1432 float dy = origin.y * (1.f - cosa) - origin.x * sina;
1433 return Matrix(cosa, sina, -sina, cosa, dx, dy);
1436 void RotateDegree(
double degree) { *
this = RotationDegree(degree) * *
this; }
1437 void RotateDegree(
double degree,
const PointF& origin) { *
this = RotationDegree(degree, origin) * *
this; }
1439 static Matrix ReflectionX(
float width = 0.f) {
return Matrix(-1.f, 0.f, 0.f, 1.f, 0.f, width); }
1440 static Matrix ReflectionY(
float height = 0.f) {
return Matrix(1.f, 0.f, 0.f, -1.f, 0.f, height); }
1442 void ReflectX(
float width = 0.f) { *
this = ReflectionX(width) * *
this; }
1443 void ReflectY(
float height = 0.f) { *
this = ReflectionY(height) * *
this; }
1445 bool IsReflected()
const {
1446 return a * d < b * c;
1449 static Matrix Translation(
float x,
float y) {
return Matrix(1.f, 0.f, 0.f, 1.f, x, y); }
1450 static Matrix Translation(
const PointF& v) {
return Translation(v.x, v.y); }
1452 void Translate(
float x,
float y) { *
this = Translation(x, y) * *
this; }
1453 void Translate(
const PointF& v) { *
this = Translation(v) * *
this; }
1455 bool IsInvertible()
const {
1456 double det = Determinant();
1457 static constexpr double EPS = std::numeric_limits<double>::epsilon();
1458 return (det < -EPS || det > EPS);
1462 std::optional<Matrix> Inverse()
const {
1463 double det = Determinant();
1465 static constexpr double EPS = std::numeric_limits<double>::epsilon();
1466 if (det >= -EPS && det <= EPS)
1467 return std::nullopt;
1469 double invdet = 1.0 / det;
1470 float A =
static_cast<float>(d * invdet);
1471 float B =
static_cast<float>(-b * invdet);
1472 float C =
static_cast<float>(-c * invdet);
1473 float D =
static_cast<float>(a * invdet);
1474 float E =
static_cast<float>((f * c - e * d) * invdet);
1475 float F =
static_cast<float>((e * b - f * a) * invdet);
1476 return Matrix(A, B, C, D, E, F);
1480 Matrix InverseOrIdentity()
const {
1481 return Inverse().value_or(Matrix{});
1484 static Matrix RectToRect(
const RectF& source,
const RectF& dest) {
1485 float sx = dest.GetWidth() / source.GetWidth();
1486 float sy = dest.GetHeight() / source.GetHeight();
1487 float dx = dest.MinX() - sx * source.MinX();
1488 float dy = dest.MinY() - sy * source.MinY();
1489 return Matrix(sx, 0.f, 0.f, sy, dx, dy);
1492 static Matrix RectToRectProportional(
const RectF& source,
const RectF& dest) {
1493 float sx = dest.GetWidth() / source.GetWidth();
1494 float sy = dest.GetHeight() / source.GetHeight();
1495 float scale = (std::min)(sx, sy);
1496 float dx = dest.MinX() - scale * source.MinX() + (dest.GetWidth() - scale * source.GetWidth()) / 2.0f;
1497 float dy = dest.MinY() - scale * source.MinY() + (dest.GetHeight() - scale * source.GetHeight()) / 2.0f;
1498 return Matrix(scale, 0.f, 0.f, scale, dx, dy);
1501 bool DoesPreserveRects()
const {
1502 bool A = !Math::FloatEq(a, 0.0f);
1503 bool B = !Math::FloatEq(b, 0.0f);
1504 bool C = !Math::FloatEq(c, 0.0f);
1505 bool D = !Math::FloatEq(d, 0.0f);
1506 return (A == D && B == C && A != B && C != D);