Skip to content

Commit

Permalink
update Polygon to v1.3
Browse files Browse the repository at this point in the history
update Polygon to v1.3, adding some extra functionality.

adds ability to manually set triangle limit: maximum amount of triangles that can be created before the update is halted. the default is 10000 (this limit was previously hard-coded as 100).

adds ability to add a "wireframe" mesh over the top of the polygon. this is drawn using separate lines and is rebuilt (updated) whenever the polygon is updated. it's based on the final triangles after triangulation so will continue to work when other methods are added.

the wireframe can be set to be shown or not and its colour can also be set. if it's set to not be shown, it will clear it (as well as not build it or draw it) during the update. note that this means that update will need to be called if this is modified.

in addition, casts have been corrected: now casts to the long double it should be. also added const where a parameter is not expected to change, and removed some unused (commented-out) code.
  • Loading branch information
Hapaxia committed Feb 12, 2024
1 parent 5ffd546 commit a688724
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 27 deletions.
102 changes: 76 additions & 26 deletions src/SelbaWard/Polygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,22 @@ inline bool isSecondVectorAntiClockwiseOfFirstVector(const sf::Vector2f& first,
return (first.x * second.y) < (first.y * second.x);
}

inline bool pointIsInsideTriangle(const std::vector<sf::Vector2f>& points, sf::Vector2f point)
inline bool pointIsInsideTriangle(const std::vector<sf::Vector2f>& points, const sf::Vector2f point)
{
long double point1X{ static_cast<double>(points[0].x) };
long double point1Y{ static_cast<double>(points[0].y) };
long double point2X{ static_cast<double>(points[1].x) };
long double point2Y{ static_cast<double>(points[1].y) };
long double point3X{ static_cast<double>(points[2].x) };
long double point3Y{ static_cast<double>(points[2].y) };
long double pointX{ static_cast<double>(point.x) };
long double pointY{ static_cast<double>(point.y) };
long double point1X{ static_cast<long double>(points[0].x) };
long double point1Y{ static_cast<long double>(points[0].y) };
long double point2X{ static_cast<long double>(points[1].x) };
long double point2Y{ static_cast<long double>(points[1].y) };
long double point3X{ static_cast<long double>(points[2].x) };
long double point3Y{ static_cast<long double>(points[2].y) };
long double pointX{ static_cast<long double>(point.x) };
long double pointY{ static_cast<long double>(point.y) };

long double denominatorMultiplier{ 1.l / ((point2Y - point3Y) * (point1X - point3X) + (point3X - point2X) * (point1Y - point3Y)) };
long double a{ ((point2Y - point3Y) * (pointX - point3X) + (point3X - point2X) * (pointY - point3Y)) * denominatorMultiplier };
long double b{ ((point3Y - point1Y) * (pointX - point3X) + (point1X - point3X) * (pointY - point3Y)) * denominatorMultiplier };
long double c{ 1.l - a - b };
return a >= 0.l && a <= 1.l && b >= 0.l && b <= 1.l && c >= 0.l && c <= 1.l;

/*
float denominatorMultiplier{ 1.f / ((points[1u].y - points[2u].y) * (points[0u].x - points[2u].x) + (points[2u].x - points[1u].x) * (points[0u].y - points[2u].y)) };
float a{ ((points[1u].y - points[2u].y) * (point.x - points[2u].x) + (points[2u].x - points[1u].x) * (point.y - points[2u].y)) * denominatorMultiplier };
float b{ ((points[2u].y - points[0u].y) * (point.x - points[2u].x) + (points[0u].x - points[2u].x) * (point.y - points[2u].y)) * denominatorMultiplier };
float c{ 1.f - a - b };
return a >= 0.f && a <= 1.f && b >= 0.f && b <= 1.f && c >= 0.f && c <= 1.f;
*/
}

inline float crossProduct(const sf::Vector2f& a, const sf::Vector2f& b)
Expand All @@ -92,8 +84,12 @@ Polygon::Polygon()
, m_vertices()
, m_holeStartIndices()
, m_color{ sf::Color::White }
, m_showWireframe{ false }
, m_wireframeVertices{}
, m_wireframeColor{ sf::Color::White }
, m_triangulationMethod{ TriangulationMethod::BasicEarClip }
, m_meshRefinementMethod{ MeshRefinementMethod::None }
, m_triangleLimit{ 10000u }
, m_throwExceptions{ true }
{

Expand Down Expand Up @@ -169,6 +165,36 @@ sf::Vector2f Polygon::getVertexPosition(const std::size_t index) const
return m_vertices[index].position;
}

void Polygon::setTriangleLimit(const std::size_t triangleLimit)
{
m_triangleLimit = triangleLimit;
}

std::size_t Polygon::getTriangleLimit() const
{
return m_triangleLimit;
}

void Polygon::setShowWireframe(bool showWireframe)
{
m_showWireframe = showWireframe;
}

bool Polygon::getShowWireframe() const
{
return m_showWireframe;
}

void Polygon::setWireframeColor(sf::Color wireframeColor)
{
m_wireframeColor = wireframeColor;
}

sf::Color Polygon::getWireframeColor() const
{
return m_wireframeColor;
}

void Polygon::addHoleStartIndex(const std::size_t index)
{
m_holeStartIndices.push_back(index);
Expand Down Expand Up @@ -219,8 +245,10 @@ void Polygon::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.texture = nullptr;
states.transform *= getTransform();
if (m_outputVertices.size() > 0)
if (!m_outputVertices.empty())
target.draw(m_outputVertices.data(), m_outputVertices.size(), sf::Triangles, states);
if (m_showWireframe && !m_wireframeVertices.empty())
target.draw(m_wireframeVertices.data(), m_wireframeVertices.size(), sf::Lines, states);
}

void Polygon::priv_update()
Expand All @@ -241,6 +269,8 @@ void Polygon::priv_updateOutputVertices()
m_outputVertices[baseIndex + v].color = m_color;
}
}

priv_buildWireframe();
}

void Polygon::priv_triangulate()
Expand All @@ -260,8 +290,6 @@ void Polygon::priv_triangulate()

void Polygon::priv_triangulateEarClip()
{
constexpr std::size_t stopAfterThisNumberOfTrianglesHaveBeenCreated{ 100u };

// ear clipping method
// polygon points must be anti-clockwise
// hole points must be clockwise
Expand Down Expand Up @@ -580,12 +608,12 @@ void Polygon::priv_triangulateEarClip()
ear.erase(std::find(ear.begin(), ear.end(), indices[current]));
indices.erase(currentIt);

if (m_triangles.size() == stopAfterThisNumberOfTrianglesHaveBeenCreated)
if (m_triangles.size() == m_triangleLimit)
break;
}

// 3 vertices remaining; add final triangle
if (m_triangles.size() < stopAfterThisNumberOfTrianglesHaveBeenCreated)
if (m_triangles.size() < m_triangleLimit)
{
TriangleIndices triangle{ vertexNumbers[indices[0u]], vertexNumbers[indices[1u]], vertexNumbers[indices[2u]] };
m_triangles.push_back(triangle);
Expand All @@ -594,8 +622,6 @@ void Polygon::priv_triangulateEarClip()

void Polygon::priv_triangulateBasicEarClip()
{
constexpr std::size_t stopAfterThisNumberOfTrianglesHaveBeenCreated{ 100u };

// ear clipping method
// polygon points must be anti-clockwise
// number of triangles will always be (number of points - 2)
Expand Down Expand Up @@ -711,11 +737,11 @@ void Polygon::priv_triangulateBasicEarClip()
ear.erase(std::find(ear.begin(), ear.end(), indices[current]));
indices.erase(currentIt);

if (m_triangles.size() == stopAfterThisNumberOfTrianglesHaveBeenCreated)
if (m_triangles.size() == m_triangleLimit)
break;
}

if (m_triangles.size() < stopAfterThisNumberOfTrianglesHaveBeenCreated)
if (m_triangles.size() < m_triangleLimit)
{
TriangleIndices triangle{ indices[0u], indices[1u], indices[2u] };
m_triangles.push_back(triangle);
Expand All @@ -738,4 +764,28 @@ bool Polygon::priv_testVertexIndex(const std::size_t vertexIndex, const std::str
return true;
}

void Polygon::priv_buildWireframe()
{
if (!m_showWireframe)
{
m_wireframeVertices.clear();
return;
}

m_wireframeVertices.resize(m_triangles.size() * 6u);

for (std::size_t t{ 0u }; t < m_triangles.size(); ++t)
{
const std::size_t baseTriangleIndex{ t * 6u };
for (std::size_t l{ 0u }; l < 3u; ++l)
{
const std::size_t baseLineIndex{ l * 2u };
m_wireframeVertices[baseTriangleIndex + baseLineIndex + 0u].position = m_vertices[m_triangles[t][l]].position;
m_wireframeVertices[baseTriangleIndex + baseLineIndex + 1u].position = m_vertices[m_triangles[t][(l < 2u) ? l + 1u : 0u]].position;
m_wireframeVertices[baseTriangleIndex + baseLineIndex + 0u].color = m_wireframeColor;
m_wireframeVertices[baseTriangleIndex + baseLineIndex + 1u].color = m_wireframeColor;
}
}
}

} // namespace selbaward
18 changes: 17 additions & 1 deletion src/SelbaWard/Polygon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
namespace selbaward
{

// SW Polygon v1.2.3
// SW Polygon v1.3.0
class Polygon : public sf::Drawable, public sf::Transformable
{
public:
Expand Down Expand Up @@ -72,6 +72,15 @@ class Polygon : public sf::Drawable, public sf::Transformable
void setVertexPosition(std::size_t index, sf::Vector2f position);
sf::Vector2f getVertexPosition(std::size_t index) const;

void setTriangleLimit(std::size_t triangleLimit);
std::size_t getTriangleLimit() const;

void setShowWireframe(bool showWireframe);
bool getShowWireframe() const;

void setWireframeColor(sf::Color wireframeColor);
sf::Color getWireframeColor() const;

void reverseVertices();

void importVertexPositions(const std::vector<sf::Vector2f>& position);
Expand All @@ -97,9 +106,15 @@ class Polygon : public sf::Drawable, public sf::Transformable
std::vector<std::size_t> m_holeStartIndices;
sf::Color m_color;

bool m_showWireframe;
std::vector<sf::Vertex> m_wireframeVertices;
sf::Color m_wireframeColor;

TriangulationMethod m_triangulationMethod;
MeshRefinementMethod m_meshRefinementMethod;

std::size_t m_triangleLimit;

const bool m_throwExceptions;

virtual void draw(sf::RenderTarget&, sf::RenderStates) const;
Expand All @@ -110,6 +125,7 @@ class Polygon : public sf::Drawable, public sf::Transformable
void priv_triangulateBasicEarClip();
bool priv_isValidVertexIndex(std::size_t vertexIndex) const;
bool priv_testVertexIndex(std::size_t vertexIndex, const std::string& exceptionMessage) const;
void priv_buildWireframe();
};

} // namespace selbaward
Expand Down

0 comments on commit a688724

Please sign in to comment.