mirror of
https://github.com/SFML/SFML.git
synced 2024-11-24 20:31:05 +08:00
Add sf::Shape::getGeometricCenter()
This adds virtual Vector2f getGeometricCenter() const = 0; Signed-off-by: Ted Lyngmo <ted@lyncon.se>
This commit is contained in:
parent
f95d159711
commit
9855552f64
@ -105,6 +105,18 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f getPoint(std::size_t index) const override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the geometric center of the circle
|
||||
///
|
||||
/// The returned point is in local coordinates, that is,
|
||||
/// the shape's transforms (position, rotation, scale) are
|
||||
/// not taken into account.
|
||||
///
|
||||
/// \return The geometric center of the shape
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f getGeometricCenter() const override;
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
|
@ -93,6 +93,18 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f getPoint(std::size_t index) const override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the geometric center of the rectangle
|
||||
///
|
||||
/// The returned point is in local coordinates, that is,
|
||||
/// the shape's transforms (position, rotation, scale) are
|
||||
/// not taken into account.
|
||||
///
|
||||
/// \return The geometric center of the shape
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f getGeometricCenter() const override;
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
|
@ -208,6 +208,18 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Vector2f getPoint(std::size_t index) const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the geometric center of the shape
|
||||
///
|
||||
/// The returned point is in local coordinates, that is,
|
||||
/// the shape's transforms (position, rotation, scale) are
|
||||
/// not taken into account.
|
||||
///
|
||||
/// \return The geometric center of the shape
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Vector2f getGeometricCenter() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the local bounding rectangle of the entity
|
||||
///
|
||||
|
@ -75,4 +75,11 @@ Vector2f CircleShape::getPoint(std::size_t index) const
|
||||
return Vector2f(m_radius, m_radius) + Vector2f(m_radius, angle);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f CircleShape::getGeometricCenter() const
|
||||
{
|
||||
return Vector2f(m_radius, m_radius);
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
@ -78,4 +78,11 @@ Vector2f RectangleShape::getPoint(std::size_t index) const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f RectangleShape::getGeometricCenter() const
|
||||
{
|
||||
return m_size / 2.f;
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
@ -29,8 +29,7 @@
|
||||
#include <SFML/Graphics/Shape.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -130,6 +129,56 @@ float Shape::getOutlineThickness() const
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f Shape::getGeometricCenter() const
|
||||
{
|
||||
const auto count = getPointCount();
|
||||
|
||||
switch (count)
|
||||
{
|
||||
case 0:
|
||||
assert(false);
|
||||
return Vector2f{};
|
||||
case 1:
|
||||
return getPoint(0);
|
||||
case 2:
|
||||
return (getPoint(0) + getPoint(1)) / 2.f;
|
||||
default: // more than two points
|
||||
Vector2f centroid;
|
||||
float twiceArea = 0;
|
||||
|
||||
auto previousPoint = getPoint(count - 1);
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
const auto currentPoint = getPoint(i);
|
||||
const float product = previousPoint.cross(currentPoint);
|
||||
twiceArea += product;
|
||||
centroid += (currentPoint + previousPoint) * product;
|
||||
|
||||
previousPoint = currentPoint;
|
||||
}
|
||||
|
||||
if (twiceArea != 0.f)
|
||||
{
|
||||
return centroid / 3.f / twiceArea;
|
||||
}
|
||||
|
||||
// Fallback for no area - find the center of the bounding box
|
||||
auto minPoint = getPoint(0);
|
||||
auto maxPoint = minPoint;
|
||||
for (std::size_t i = 1; i < count; ++i)
|
||||
{
|
||||
const auto currentPoint = getPoint(i);
|
||||
minPoint.x = std::min(minPoint.x, currentPoint.x);
|
||||
maxPoint.x = std::max(maxPoint.x, currentPoint.x);
|
||||
minPoint.y = std::min(minPoint.y, currentPoint.y);
|
||||
maxPoint.y = std::max(maxPoint.y, currentPoint.y);
|
||||
}
|
||||
return (maxPoint + minPoint) / 2.f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
FloatRect Shape::getLocalBounds() const
|
||||
{
|
||||
|
@ -22,6 +22,7 @@ TEST_CASE("[Graphics] sf::CircleShape")
|
||||
CHECK(circle.getPointCount() == 30);
|
||||
for (std::size_t i = 0; i < circle.getPointCount(); ++i)
|
||||
CHECK(circle.getPoint(i) == sf::Vector2f(0, 0));
|
||||
CHECK(circle.getGeometricCenter() == sf::Vector2f(0, 0));
|
||||
}
|
||||
|
||||
SECTION("Radius constructor")
|
||||
@ -59,6 +60,7 @@ TEST_CASE("[Graphics] sf::CircleShape")
|
||||
CHECK(circle.getPoint(27) == Approx(sf::Vector2f(6.183218002f, 2.864748001f)));
|
||||
CHECK(circle.getPoint(28) == Approx(sf::Vector2f(8.898950577f, 1.296818733f)));
|
||||
CHECK(circle.getPoint(29) == Approx(sf::Vector2f(11.881320953f, 0.327786446f)));
|
||||
CHECK(circle.getGeometricCenter() == sf::Vector2f(15.f, 15.f));
|
||||
}
|
||||
|
||||
SECTION("Radius and point count constructor")
|
||||
@ -74,6 +76,7 @@ TEST_CASE("[Graphics] sf::CircleShape")
|
||||
CHECK(circle.getPoint(5) == Approx(sf::Vector2f(1.464466095f, 8.535533905f)));
|
||||
CHECK(circle.getPoint(6) == Approx(sf::Vector2f(0.000000000f, 4.999999523f)));
|
||||
CHECK(circle.getPoint(7) == Approx(sf::Vector2f(1.464465857f, 1.464466572f)));
|
||||
CHECK(circle.getGeometricCenter() == sf::Vector2f(5.f, 5.f));
|
||||
}
|
||||
|
||||
SECTION("Set radius")
|
||||
@ -88,6 +91,7 @@ TEST_CASE("[Graphics] sf::CircleShape")
|
||||
CHECK(circle.getPoint(3) == Approx(sf::Vector2f(10.000000000f, 20.000000000f)));
|
||||
CHECK(circle.getPoint(4) == Approx(sf::Vector2f(1.339746475f, 15.000000000f)));
|
||||
CHECK(circle.getPoint(5) == Approx(sf::Vector2f(1.339745522f, 5.000000000f)));
|
||||
CHECK(circle.getGeometricCenter() == sf::Vector2f(10.f, 10.f));
|
||||
}
|
||||
|
||||
SECTION("Set point count")
|
||||
@ -100,6 +104,7 @@ TEST_CASE("[Graphics] sf::CircleShape")
|
||||
CHECK(circle.getPoint(1) == Approx(sf::Vector2f(8.000000000f, 4.000000000f)));
|
||||
CHECK(circle.getPoint(2) == Approx(sf::Vector2f(3.999999762f, 8.000000000f)));
|
||||
CHECK(circle.getPoint(3) == Approx(sf::Vector2f(0.000000000f, 3.999999762f)));
|
||||
CHECK(circle.getGeometricCenter() == sf::Vector2f(4.f, 4.f));
|
||||
}
|
||||
|
||||
SECTION("Equilateral triangle")
|
||||
@ -110,5 +115,19 @@ TEST_CASE("[Graphics] sf::CircleShape")
|
||||
CHECK(triangle.getPoint(0) == Approx(sf::Vector2f(1.999999881f, 0.000000000f)));
|
||||
CHECK(triangle.getPoint(1) == Approx(sf::Vector2f(3.732050896f, 3.000000000f)));
|
||||
CHECK(triangle.getPoint(2) == Approx(sf::Vector2f(0.267949224f, 3.000000000f)));
|
||||
CHECK(triangle.getGeometricCenter() == sf::Vector2f(2.f, 2.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center")
|
||||
{
|
||||
SECTION("2 points")
|
||||
{
|
||||
CHECK(sf::CircleShape(2.f, 2).getGeometricCenter() == sf::Vector2f(2.f, 2.f));
|
||||
}
|
||||
|
||||
SECTION("3 points")
|
||||
{
|
||||
CHECK(sf::CircleShape(4.f, 3).getGeometricCenter() == sf::Vector2f(4.f, 4.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include <SFML/Graphics/ConvexShape.hpp>
|
||||
|
||||
// Other 1st party headers
|
||||
#include <SFML/Graphics/CircleShape.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <SystemUtil.hpp>
|
||||
@ -45,4 +48,146 @@ TEST_CASE("[Graphics] sf::ConvexShape")
|
||||
convex.setPoint(0, {3, 4});
|
||||
CHECK(convex.getPoint(0) == sf::Vector2f(3, 4));
|
||||
}
|
||||
|
||||
SECTION(
|
||||
"Construct clockwise ConvexShapes from CircleShapes to verify that they get approx. the same geometric center")
|
||||
{
|
||||
sf::ConvexShape convex;
|
||||
for (unsigned int i = 2; i < 10; ++i)
|
||||
{
|
||||
const sf::CircleShape circle(4.f, i);
|
||||
convex.setPointCount(i);
|
||||
for (unsigned int j = 0; j < i; ++j)
|
||||
{
|
||||
convex.setPoint(j, circle.getPoint(j));
|
||||
}
|
||||
CHECK(convex.getGeometricCenter() == Approx(circle.getGeometricCenter()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION(
|
||||
"Construct counterclockwise ConvexShapes from CircleShapes to verify that they get approx. the same geometric "
|
||||
"center")
|
||||
{
|
||||
sf::ConvexShape convex;
|
||||
for (unsigned int i = 2; i < 10; ++i)
|
||||
{
|
||||
const sf::CircleShape circle(4.f, i);
|
||||
convex.setPointCount(i);
|
||||
for (unsigned int j = 0; j < i; ++j)
|
||||
{
|
||||
convex.setPoint(i - 1 - j, circle.getPoint(j));
|
||||
}
|
||||
CHECK(convex.getGeometricCenter() == Approx(circle.getGeometricCenter()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Geometric center for one point")
|
||||
{
|
||||
sf::ConvexShape convex(1);
|
||||
convex.setPoint(0, {1.f, 1.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(1.f, 1.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for two points")
|
||||
{
|
||||
sf::ConvexShape convex(2);
|
||||
convex.setPoint(0, {0.f, 0.f});
|
||||
convex.setPoint(1, {4.f, 2.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(2.f, 1.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for three points with a small area")
|
||||
{
|
||||
sf::ConvexShape convex(3);
|
||||
convex.setPoint(0, {-100000.f, 0.f});
|
||||
convex.setPoint(1, {100000.f, 0.f});
|
||||
convex.setPoint(2, {100000.f, 0.000001f});
|
||||
CHECK(convex.getGeometricCenter() == Approx(sf::Vector2f(100000.f / 3.f, 0.f)));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for aligned points")
|
||||
{
|
||||
SECTION("Geometric center for partly aligned points")
|
||||
{
|
||||
sf::ConvexShape convex(3);
|
||||
convex.setPoint(0, {-100.f, 0.f});
|
||||
convex.setPoint(1, {0.f, 0.f});
|
||||
convex.setPoint(2, {100.f, 1.f});
|
||||
CHECK(convex.getGeometricCenter() == Approx(sf::Vector2f(0.f, 1.f / 3.f)));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for aligned points with the two furthest apart not first and last")
|
||||
{
|
||||
sf::ConvexShape convex(4);
|
||||
convex.setPoint(0, {-50.f, -50.f});
|
||||
convex.setPoint(1, {-150.f, -150.f});
|
||||
convex.setPoint(2, {150.f, 150.f});
|
||||
convex.setPoint(3, {50.f, 50.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(0.f, 0.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for aligned points increasing x and y")
|
||||
{
|
||||
sf::ConvexShape convex(3);
|
||||
convex.setPoint(0, {1.f, 1.f});
|
||||
convex.setPoint(1, {5.f, 3.f});
|
||||
convex.setPoint(2, {9.f, 5.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(5.f, 3.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for aligned points increasing x, decreasing y")
|
||||
{
|
||||
sf::ConvexShape convex(3);
|
||||
convex.setPoint(0, {1.f, 5.f});
|
||||
convex.setPoint(1, {5.f, 3.f});
|
||||
convex.setPoint(2, {9.f, 1.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(5.f, 3.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for aligned points decreasing x and y")
|
||||
{
|
||||
sf::ConvexShape convex(3);
|
||||
convex.setPoint(0, {9.f, 5.f});
|
||||
convex.setPoint(1, {5.f, 3.f});
|
||||
convex.setPoint(2, {1.f, 1.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(5.f, 3.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for aligned points decreasing x, increasing y")
|
||||
{
|
||||
sf::ConvexShape convex(3);
|
||||
convex.setPoint(0, {9.f, 1.f});
|
||||
convex.setPoint(1, {5.f, 3.f});
|
||||
convex.setPoint(2, {1.f, 5.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(5.f, 3.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for aligned points with the same x value")
|
||||
{
|
||||
sf::ConvexShape convex(3);
|
||||
convex.setPoint(0, {1.f, 2.f});
|
||||
convex.setPoint(1, {1.f, 3.f});
|
||||
convex.setPoint(2, {1.f, 1.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(1.f, 2.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for aligned points with the same y value")
|
||||
{
|
||||
sf::ConvexShape convex(3);
|
||||
convex.setPoint(0, {2.f, 5.f});
|
||||
convex.setPoint(1, {3.f, 5.f});
|
||||
convex.setPoint(2, {1.f, 5.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(2.f, 5.f));
|
||||
}
|
||||
|
||||
SECTION("Geometric center for aligned points out of order")
|
||||
{
|
||||
sf::ConvexShape convex(3);
|
||||
convex.setPoint(0, {5.f, 3.f});
|
||||
convex.setPoint(1, {1.f, 5.f});
|
||||
convex.setPoint(2, {9.f, 1.f});
|
||||
CHECK(convex.getGeometricCenter() == sf::Vector2f(5.f, 3.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ TEST_CASE("[Graphics] sf::RectangleShape")
|
||||
CHECK(rectangle.getPoint(1) == sf::Vector2f(0, 0));
|
||||
CHECK(rectangle.getPoint(2) == sf::Vector2f(0, 0));
|
||||
CHECK(rectangle.getPoint(3) == sf::Vector2f(0, 0));
|
||||
CHECK(rectangle.getGeometricCenter() == sf::Vector2f(0, 0));
|
||||
}
|
||||
|
||||
SECTION("Size constructor")
|
||||
@ -35,6 +36,7 @@ TEST_CASE("[Graphics] sf::RectangleShape")
|
||||
CHECK(rectangle.getPoint(1) == sf::Vector2f(9, 0));
|
||||
CHECK(rectangle.getPoint(2) == sf::Vector2f(9, 8));
|
||||
CHECK(rectangle.getPoint(3) == sf::Vector2f(0, 8));
|
||||
CHECK(rectangle.getGeometricCenter() == sf::Vector2f(9.f, 8.f) / 2.f);
|
||||
}
|
||||
|
||||
SECTION("Set size")
|
||||
@ -42,5 +44,6 @@ TEST_CASE("[Graphics] sf::RectangleShape")
|
||||
sf::RectangleShape rectangle({7, 6});
|
||||
rectangle.setSize({5, 4});
|
||||
CHECK(rectangle.getSize() == sf::Vector2f(5, 4));
|
||||
CHECK(rectangle.getGeometricCenter() == sf::Vector2f(5.f, 4.f) / 2.f);
|
||||
}
|
||||
}
|
||||
|
@ -88,13 +88,14 @@ TEST_CASE("[Graphics] sf::Shape")
|
||||
CHECK(triangleShape.getOutlineThickness() == 3.14f);
|
||||
}
|
||||
|
||||
SECTION("Virtual functions: getPoint, getPointCount")
|
||||
SECTION("Virtual functions: getPoint, getPointCount, getGeometricCenter")
|
||||
{
|
||||
const TriangleShape triangleShape({2, 2});
|
||||
CHECK(triangleShape.getPointCount() == 3);
|
||||
CHECK(triangleShape.getPoint(0) == sf::Vector2f(1, 0));
|
||||
CHECK(triangleShape.getPoint(1) == sf::Vector2f(0, 2));
|
||||
CHECK(triangleShape.getPoint(2) == sf::Vector2f(2, 2));
|
||||
CHECK(triangleShape.getGeometricCenter() == sf::Vector2f(1.f, 4.f / 3.f));
|
||||
}
|
||||
|
||||
SECTION("Get bounds")
|
||||
|
Loading…
Reference in New Issue
Block a user