///////////////////////////////////////////////////////
| 296 | |
| 297 | //////////////////////////////////////////////////////////// |
| 298 | void Shape::updateOutline() |
| 299 | { |
| 300 | // Return if there is no outline or no vertices |
| 301 | if (m_outlineThickness == 0.f || m_vertices.getVertexCount() < 2) |
| 302 | { |
| 303 | m_outlineVertices.clear(); |
| 304 | m_bounds = m_insideBounds; |
| 305 | return; |
| 306 | } |
| 307 | |
| 308 | const std::size_t count = m_vertices.getVertexCount() - 2; |
| 309 | m_outlineVertices.resize((count + 1) * 2); // We need at least that many vertices. |
| 310 | // We will add two more vertices each time we need a bevel. |
| 311 | |
| 312 | // Determine if points are defined clockwise or counterclockwise. This will impact normals computation. |
| 313 | const bool flipNormals = [this, count]() |
| 314 | { |
| 315 | // p0 is either strictly inside the shape, or on an edge. |
| 316 | const sf::Vector2f p0 = m_vertices[0].position; |
| 317 | for (std::size_t i = 0; i < count; ++i) |
| 318 | { |
| 319 | const sf::Vector2f p1 = m_vertices[i + 1].position; |
| 320 | const sf::Vector2f p2 = m_vertices[i + 2].position; |
| 321 | const float product = (p1 - p0).cross(p2 - p0); |
| 322 | if (product == 0.f) |
| 323 | { |
| 324 | // p0 is on the edge p1-p2. We cannot determine shape orientation yet, so continue. |
| 325 | continue; |
| 326 | } |
| 327 | return product > 0.f; |
| 328 | } |
| 329 | return true; |
| 330 | }(); |
| 331 | |
| 332 | std::size_t outlineIndex = 0; |
| 333 | for (std::size_t i = 0; i < count; ++i) |
| 334 | { |
| 335 | const std::size_t index = i + 1; |
| 336 | |
| 337 | // Get the two segments shared by the current point |
| 338 | const Vector2f p0 = (i == 0) ? m_vertices[count].position : m_vertices[index - 1].position; |
| 339 | const Vector2f p1 = m_vertices[index].position; |
| 340 | const Vector2f p2 = m_vertices[index + 1].position; |
| 341 | |
| 342 | // Compute their direction |
| 343 | const Vector2f d1 = computeDirection(p0, p1); |
| 344 | const Vector2f d2 = computeDirection(p1, p2); |
| 345 | |
| 346 | // Compute their normal pointing towards the outside of the shape |
| 347 | const Vector2f n1 = flipNormals ? -d1.perpendicular() : d1.perpendicular(); |
| 348 | const Vector2f n2 = flipNormals ? -d2.perpendicular() : d2.perpendicular(); |
| 349 | |
| 350 | // Decide whether to add a bevel or not |
| 351 | const float twoCos2 = 1.f + n1.dot(n2); |
| 352 | const float squaredLengthRatio = m_miterLimit * m_miterLimit * twoCos2 / 2.f; |
| 353 | const bool isConvexCorner = d1.dot(n2) * m_outlineThickness >= 0.f; |
| 354 | const bool needsBevel = twoCos2 == 0.f || (squaredLengthRatio < 1.f && isConvexCorner); |
| 355 |
nothing calls this directly
no test coverage detected