From dc772d42e192f17cbd7e9ae77b7c0c1d92401412 Mon Sep 17 00:00:00 2001 From: Ryo Suzuki Date: Wed, 2 Oct 2024 21:06:18 +0900 Subject: [PATCH] =?UTF-8?q?[=E5=85=B1=E9=80=9A]=20Rect::chamfered()=20#126?= =?UTF-8?q?8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Siv3D/include/Siv3D/Rect.hpp | 17 ++- Siv3D/include/Siv3D/RectF.hpp | 19 ++- Siv3D/src/Siv3D/Rect/SivRect.cpp | 12 +- Siv3D/src/Siv3D/RectF/SivRectF.cpp | 190 ++++++++++++++++++++++++++++- 4 files changed, 233 insertions(+), 5 deletions(-) diff --git a/Siv3D/include/Siv3D/Rect.hpp b/Siv3D/include/Siv3D/Rect.hpp index 949e6a2ab..1a54ab015 100644 --- a/Siv3D/include/Siv3D/Rect.hpp +++ b/Siv3D/include/Siv3D/Rect.hpp @@ -724,7 +724,22 @@ namespace s3d constexpr RoundRect rounded(double r) const noexcept; [[nodiscard]] - Polygon rounded(double tl, double tr, double br, double bl) const noexcept; + Polygon rounded(double tl, double tr, double br, double bl) const; + + /// @brief 長方形を面取りした Polygon を返します。 + /// @param size 面取りの大きさ + /// @return 面取りした Polygon + [[nodiscard]] + Polygon chamfered(double size) const; + + /// @brief 長方形を面取りした Polygon を返します。 + /// @param tl 左上の面取りの大きさ + /// @param tr 右上の面取りの大きさ + /// @param br 右下の面取りの大きさ + /// @param bl 左下の面取りの大きさ + /// @return 面取りした Polygon + [[nodiscard]] + Polygon chamfered(double tl, double tr, double br, double bl) const; /// @brief 長方形を Quad として返します。 /// @return 長方形の Quad diff --git a/Siv3D/include/Siv3D/RectF.hpp b/Siv3D/include/Siv3D/RectF.hpp index ae7702fe2..18721b5d2 100644 --- a/Siv3D/include/Siv3D/RectF.hpp +++ b/Siv3D/include/Siv3D/RectF.hpp @@ -783,8 +783,23 @@ namespace s3d constexpr RoundRect rounded(double r) const noexcept; [[nodiscard]] - Polygon rounded(double tl, double tr, double br, double bl) const noexcept; - + Polygon rounded(double tl, double tr, double br, double bl) const; + + /// @brief 長方形を面取りした Polygon を返します。 + /// @param size 面取りの大きさ + /// @return 面取りした Polygon + [[nodiscard]] + Polygon chamfered(double size) const; + + /// @brief 長方形を面取りした Polygon を返します。 + /// @param tl 左上の面取りの大きさ + /// @param tr 右上の面取りの大きさ + /// @param br 右下の面取りの大きさ + /// @param bl 左下の面取りの大きさ + /// @return 面取りした Polygon + [[nodiscard]] + Polygon chamfered(double tl, double tr, double br, double bl) const; + /// @brief 長方形を Rect として返します。 /// @return 長方形の Rect [[nodiscard]] diff --git a/Siv3D/src/Siv3D/Rect/SivRect.cpp b/Siv3D/src/Siv3D/Rect/SivRect.cpp index 0d92395bd..5ae897379 100644 --- a/Siv3D/src/Siv3D/Rect/SivRect.cpp +++ b/Siv3D/src/Siv3D/Rect/SivRect.cpp @@ -89,7 +89,7 @@ namespace s3d return quad; } - Polygon Rect::rounded(double tl, double tr, double br, double bl) const noexcept + Polygon Rect::rounded(double tl, double tr, double br, double bl) const { constexpr double epsilon = 0.001; @@ -224,6 +224,16 @@ namespace s3d return Polygon{ vertices }; } + Polygon Rect::chamfered(const double size) const + { + return RectF{ *this }.chamfered(size); + } + + Polygon Rect::chamfered(const double tl, const double tr, const double br, const double bl) const + { + return RectF{ *this }.chamfered(tl, tr, br, bl); + } + LineString Rect::outline(const CloseRing closeRing) const { if (closeRing) diff --git a/Siv3D/src/Siv3D/RectF/SivRectF.cpp b/Siv3D/src/Siv3D/RectF/SivRectF.cpp index fe8cbc21f..9ba001d95 100644 --- a/Siv3D/src/Siv3D/RectF/SivRectF.cpp +++ b/Siv3D/src/Siv3D/RectF/SivRectF.cpp @@ -89,7 +89,7 @@ namespace s3d return quad; } - Polygon RectF::rounded(double tl, double tr, double br, double bl) const noexcept + Polygon RectF::rounded(double tl, double tr, double br, double bl) const { constexpr double epsilon = 0.001; @@ -224,6 +224,194 @@ namespace s3d return Polygon{ vertices }; } + Polygon RectF::chamfered(double s) const + { + if (s <= 0.0) + { + return asPolygon(); + } + + s = Min(s, (Min(w, h) * 0.5)); + + Array points; + + // 上辺 + if ((s * 2.0) < w) + { + points.emplace_back((x + s), y); + points.emplace_back((x + w - s), y); + } + else + { + points.emplace_back((x + w * 0.5), y); + } + + // 右辺 + if ((s * 2.0) < h) + { + points.emplace_back((x + w), (y + s)); + points.emplace_back((x + w), (y + h - s)); + } + else + { + points.emplace_back((x + w), (y + h * 0.5)); + } + + // 下辺 + if ((s * 2.0) < w) + { + points.emplace_back((x + w - s), (y + h)); + points.emplace_back((x + s), (y + h)); + } + else + { + points.emplace_back((x + w * 0.5), (y + h)); + } + + // 左辺 + if ((s * 2.0) < h) + { + points.emplace_back(x, (y + h - s)); + points.emplace_back(x, (y + s)); + } + else + { + points.emplace_back(x, (y + h * 0.5)); + } + + Array indices(points.size() - 2); + + for (Vertex2D::IndexType i = 0; i < indices.size(); ++i) + { + indices[i] = { 0, static_cast(i + 1), static_cast(i + 2) }; + } + + return Polygon{ points, indices, *this }; + } + + Polygon RectF::chamfered(double tl, double tr, double br, double bl) const + { + tl = Max(tl, 0.0); + tr = Max(tr, 0.0); + br = Max(br, 0.0); + bl = Max(bl, 0.0); + + if (double top = (tl + tr); + w < top) + { + tl *= (w / top); + tr *= (w / top); + } + + if (double right = (tr + br); + h < right) + { + tr *= (h / right); + br *= (h / right); + } + + if (double bottom = (br + bl); + w < bottom) + { + br *= (w / bottom); + bl *= (w / bottom); + } + + if (double left = (bl + tl); + h < left) + { + bl *= (h / left); + tl *= (h / left); + } + + Array points; + + // 左上 + if (tl) + { + const Vec2 p0{ x, (y + tl) }; + const Vec2 p1{ (x + tl), y }; + points << p0; + points << p1; + } + else + { + points << this->tl(); + } + + // 右上 + if (tr) + { + const Vec2 p0{ (x + w - tr), y }; + const Vec2 p1{ (x + w), (y + tr) }; + + if (points.back() != p0) + { + points << p0; + } + + points << p1; + } + else + { + points << this->tr(); + } + + // 右下 + if (br) + { + const Vec2 p0{ (x + w), (y + h - br) }; + const Vec2 p1{ (x + w - br), (y + h) }; + + if (points.back() != p0) + { + points << p0; + } + + points << p1; + } + else + { + points << this->br(); + } + + // 左下 + if (bl) + { + const Vec2 p0{ (x + bl), (y + h) }; + const Vec2 p1{ x, (y + h - bl) }; + + if (points.back() != p0) + { + points << p0; + } + + if (points.front() != p1) + { + points << p1; + } + } + else + { + const Vec2 p0 = this->bl(); + + if ((points.back() != p0) + && (points.front() != p0)) + { + points << p0; + } + } + + Array indices(points.size() - 2); + + for (Vertex2D::IndexType i = 0; i < indices.size(); ++i) + { + indices[i] = { 0, static_cast(i + 1), static_cast(i + 2) }; + } + + return Polygon{ points, indices, *this }; + } + LineString RectF::outline(const CloseRing closeRing) const { if (closeRing)