Skip to content

Commit

Permalink
Update convex utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
eliogovea committed Mar 9, 2024
1 parent 14a8a26 commit ae0e0b8
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 0 deletions.
4 changes: 4 additions & 0 deletions sources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ set(
geometry_polygon_convex.hpp
geometry_segment.hpp
geometry_segment_traits.hpp
geometry_value_sign.hpp
power.hpp
)

Expand Down Expand Up @@ -54,6 +55,7 @@ target_sources(
geometry_polygon_convex.cpp
geometry_segment.cpp
geometry_segment_traits.cpp
geometry_value_sign.cpp
)

target_link_libraries(
Expand All @@ -79,8 +81,10 @@ target_sources(
geometry_point_operations_test.cpp
geometry_point_test.cpp
geometry_point_traits_test.cpp
geometry_polygon_convex_test.cpp
geometry_segment_test.cpp
geometry_segment_traits_test.cpp
geometry_value_sign_test.cpp
power_test.cpp
)

Expand Down
43 changes: 43 additions & 0 deletions sources/geometry_polygon_convex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,53 @@
#include <span>

#include "geometry_point.hpp"
#include "geometry_point_operations.hpp"
#include "geometry_point_traits.hpp"
#include "geometry_value_sign.hpp"

namespace Geometry {

template <typename Point, std::size_t Size>
requires PointCheckValue<Point>
auto CheckConvex(std::span<Point const, Size> points) -> bool
{
if (points.size() <= 3) {
return true;
}

auto sign_cross_all = ValueSign::Zero;

for (std::size_t index = 0; index < points.size(); index++) {
auto const& point = points[index];

auto const& point_prev
= points[index != 0 ? index - 1 : points.size() - 1];

auto const& point_next
= points[index != points.size() - 1 ? index + 1 : 0];

auto const cross = PointCross(point_prev - point, point_next - point);

auto const sign_cross = GetValueSign(cross);

if (sign_cross == ValueSign::Zero) {
continue;
}

if (sign_cross == sign_cross_all) {
continue;
}

if (sign_cross_all != ValueSign::Zero) {
return false;
}

sign_cross_all = sign_cross;
}

return true;
}

template <typename Point>
requires PointCheckValue<Point>
auto NormalizeConvexPolygon(std::span<Point> points) -> std::span<Point>
Expand Down
62 changes: 62 additions & 0 deletions sources/geometry_polygon_convex_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include <gtest/gtest.h>

#include "geometry_polygon_convex.hpp"

TEST(GeometryPolygonConvex, CheckConvexTriangle)
{
Geometry::Point<int> const points[] = {
{0, 0},
{1, 0},
{1, 1},
};

EXPECT_TRUE(Geometry::CheckConvex(std::span{points}));
}

TEST(GeometryPolygonConvex, CheckConvexCCW)
{
Geometry::Point<int> const points[] = {
{0, 0},
{1, 0},
{1, 1},
{0, 1},
};

EXPECT_TRUE(Geometry::CheckConvex(std::span{points}));
}

TEST(GeometryPolygonConvex, CheckConvexCW)
{
Geometry::Point<int> const points[] = {
{0, 0},
{0, 1},
{1, 1},
{1, 0},
};

EXPECT_TRUE(Geometry::CheckConvex(std::span{points}));
}

TEST(GeometryPolygonConvex, CheckNoConvexCCW)
{
Geometry::Point<int> const points[] = {
{0, 0},
{3, 0},
{1, 1},
{0, 3},
};

EXPECT_FALSE(Geometry::CheckConvex(std::span{points}));
}

TEST(GeometryPolygonConvex, CheckNoConvexCW)
{
Geometry::Point<int> const points[] = {
{0, 0},
{0, 3},
{1, 1},
{3, 0},
};

EXPECT_FALSE(Geometry::CheckConvex(std::span{points}));
}
1 change: 1 addition & 0 deletions sources/geometry_value_sign.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "geometry_value_sign.hpp"
37 changes: 37 additions & 0 deletions sources/geometry_value_sign.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include <cstdint>
#include <type_traits>

namespace Geometry {

enum class ValueSign : std::int8_t
{
Negative = -1,
Zero = 0,
Positive = +1,
};

inline auto operator*(ValueSign lhs, ValueSign rhs) -> ValueSign
{
return static_cast<ValueSign>(static_cast<std::int8_t>(lhs)
* static_cast<std::int8_t>(rhs));
}

template <typename Value>
auto GetValueSign(Value&& value) -> ValueSign
{
constexpr auto ValueZero = std::remove_cvref_t<Value>{0};

if (value < ValueZero) {
return ValueSign::Negative;
}

if (ValueZero < value) {
return ValueSign::Positive;
}

return ValueSign::Zero;
}

} // namespace Geometry
12 changes: 12 additions & 0 deletions sources/geometry_value_sign_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <gtest/gtest.h>

#include "geometry_value_sign.hpp"

template auto Geometry::GetValueSign(int&& value) -> Geometry::ValueSign;

TEST(GeometryValue, CheckSign)
{
EXPECT_EQ(Geometry::GetValueSign(-1), Geometry::ValueSign::Negative);
EXPECT_EQ(Geometry::GetValueSign(0), Geometry::ValueSign::Zero);
EXPECT_EQ(Geometry::GetValueSign(+1), Geometry::ValueSign::Positive);
}

0 comments on commit ae0e0b8

Please sign in to comment.