Skip to content

Commit

Permalink
Fix shape outline normal computation
Browse files Browse the repository at this point in the history
The previous implementation could fail to determine if normals had to be
flipped or not: it assumed the first vertex position was strictly inside
the shape. This position being set to the bounding box's center, it is
possible for it be on an edge of the shape (consider a right triangle).
  • Loading branch information
kimci86 committed Oct 26, 2023
1 parent e45628e commit fa4dfb6
Showing 1 changed file with 15 additions and 11 deletions.
26 changes: 15 additions & 11 deletions src/SFML/Graphics/Shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@
namespace
{
// Compute the normal of a segment
sf::Vector2f computeNormal(const sf::Vector2f& p1, const sf::Vector2f& p2)
sf::Vector2f computeNormal(const sf::Vector2f& p1, const sf::Vector2f& p2, bool flipped)
{
sf::Vector2f normal = (p2 - p1).perpendicular();
const float length = normal.length();
if (length != 0.f)
normal /= length;
if (flipped)
normal = -normal;
return normal;
}
} // namespace
Expand Down Expand Up @@ -296,6 +298,15 @@ void Shape::updateOutline()
const std::size_t count = m_vertices.getVertexCount() - 2;
m_outlineVertices.resize((count + 1) * 2);

// Determine if points are defined clockwise or counterclockwise. This will impact normals computation.
const bool flipNormals = [this, count]()
{
float twiceArea = 0.f;
for (std::size_t i = 0; i < count; ++i)
twiceArea += m_vertices[i + 1].position.cross(m_vertices[i + 2].position);
return twiceArea >= 0.f;
}();

for (std::size_t i = 0; i < count; ++i)
{
const std::size_t index = i + 1;
Expand All @@ -305,16 +316,9 @@ void Shape::updateOutline()
const Vector2f p1 = m_vertices[index].position;
const Vector2f p2 = m_vertices[index + 1].position;

// Compute their normal
Vector2f n1 = computeNormal(p0, p1);
Vector2f n2 = computeNormal(p1, p2);

// Make sure that the normals point towards the outside of the shape
// (this depends on the order in which the points were defined)
if (n1.dot(m_vertices[0].position - p1) > 0)
n1 = -n1;
if (n2.dot(m_vertices[0].position - p1) > 0)
n2 = -n2;
// Compute their normal pointing towards the outside of the shape
const Vector2f n1 = computeNormal(p0, p1, flipNormals);
const Vector2f n2 = computeNormal(p1, p2, flipNormals);

// Combine them to get the extrusion direction
const float factor = 1.f + (n1.x * n2.x + n1.y * n2.y);
Expand Down

0 comments on commit fa4dfb6

Please sign in to comment.