BLI_convexhull_2d: adjust order of edge iteration

Begin testing the edge edge between indices [0, 1] indices,
instead of [last, 0]. This only ever makes a difference as a tie breaker,
where [0, 1] is now prioritized.

This minor change simplifies further optimizations.
This commit is contained in:
Campbell Barton 2024-03-31 22:39:14 +11:00
parent c76eed6717
commit 7c4b2ec722
2 changed files with 24 additions and 19 deletions

View File

@ -233,17 +233,18 @@ int BLI_convexhull_2d(const float (*points)[2], const int points_num, int r_poin
* \{ */
#if defined(USE_BRUTE_FORCE_ASSERT) && !defined(NDEBUG)
static float convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[2],
int points_hull_num)
static float2 convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[2],
int points_hull_num)
{
float area_best = FLT_MAX;
float2 sincos_best = {0.0f, 1.0f}; /* Track the best angle as a unit vector, delaying `atan2`. */
for (int i = 0, i_prev = points_hull_num - 1; i < points_hull_num; i_prev = i++) {
for (int i = 0; i < points_hull_num; i++) {
const int i_next = (i + 1) % points_hull_num;
/* 2D rotation matrix. */
float dvec_length = 0.0f;
const float2 sincos = math::normalize_and_get_length(
float2(points_hull[i]) - float2(points_hull[i_prev]), dvec_length);
float2(points_hull[i_next]) - float2(points_hull[i]), dvec_length);
if (UNLIKELY(dvec_length == 0.0f)) {
continue;
}
@ -274,7 +275,7 @@ static float convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[
}
}
return (area_best != FLT_MAX) ? float(atan2(sincos_best[0], sincos_best[1])) : 0.0f;
return sincos_best;
}
#endif
@ -337,11 +338,12 @@ static float convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], int poin
/* Initialize to zero because the first pass uses the first index to set the bounds. */
blender::Bounds<int> bounds_index[2] = {{0, 0}, {0, 0}};
for (int i = 0, i_prev = points_hull_num - 1; i < points_hull_num; i_prev = i++) {
for (int i = 0; i < points_hull_num; i++) {
const int i_next = (i + 1) % points_hull_num;
/* 2D rotation matrix. */
float dvec_length = 0.0f;
const float2 sincos = math::normalize_and_get_length(
float2(points_hull[i]) - float2(points_hull[i_prev]), dvec_length);
float2(points_hull[i_next]) - float2(points_hull[i]), dvec_length);
if (UNLIKELY(dvec_length == 0.0f)) {
continue;
}
@ -406,8 +408,11 @@ static float convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], int poin
#if defined(USE_BRUTE_FORCE_ASSERT) && !defined(NDEBUG)
{
/* Ensure the optimized result matches the brute-force version. */
const float angle_test = convexhull_aabb_fit_hull_2d_brute_force(points_hull, points_hull_num);
BLI_assert(angle == angle_test);
const float2 sincos_test = convexhull_aabb_fit_hull_2d_brute_force(points_hull,
points_hull_num);
if (sincos_best != sincos_test) {
BLI_assert(sincos_best == sincos_test);
}
}
#endif

View File

@ -146,7 +146,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
for (int sign_x = -1; sign_x <= 2; sign_x += 2) {
blender::Array<float2> points = {{0.0f, 0.0f}, {1.0f * sign_x, 0.0}};
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
float(math::AngleRadian::from_degree(-90.0f)),
float(math::AngleRadian::from_degree(90.0f)),
ROTATION_EPS);
}
}
@ -154,7 +154,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
for (int sign_x = -1; sign_x <= 2; sign_x += 2) {
blender::Array<float2> points = {{0.0f, 0.0f}, {1.0f * sign_x, 0.0}, {2.0f * sign_x, 0.0}};
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
float(math::AngleRadian::from_degree(-90.0f)),
float(math::AngleRadian::from_degree(90.0f)),
ROTATION_EPS);
}
}
@ -163,7 +163,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
for (int sign_y = -1; sign_y <= 2; sign_y += 2) {
blender::Array<float2> points = {{0.0f, 0.0f}, {0.0f, 1.0f * sign_y}};
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
float(math::AngleRadian::from_degree(180.0f)),
float(math::AngleRadian::from_degree(0.0f)),
ROTATION_EPS);
}
}
@ -171,7 +171,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
for (int sign_y = -1; sign_y <= 2; sign_y += 2) {
blender::Array<float2> points = {{0.0f, 0.0f}, {0.0f, 1.0f * sign_y}, {0.0f, 2.0f * sign_y}};
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
float(math::AngleRadian::from_degree(180.0f)),
float(math::AngleRadian::from_degree(0.0f)),
ROTATION_EPS);
}
}
@ -186,7 +186,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
p[0] = 0.0;
}
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points), M_PI, ROTATION_EPS);
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points), 0.0f, ROTATION_EPS);
}
}
@ -201,7 +201,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
}
blender::Array<float2> points_hull = convexhull_2d_as_array(points);
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points_hull), M_PI, ROTATION_EPS);
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points_hull), 0.0f, ROTATION_EPS);
}
}
}
@ -209,7 +209,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
TEST(convexhull_2d, Lines_Diagonal)
{
{ /* Diagonal line (2 points). */
const float expected[4] = {-135, 135, 135, -135};
const float expected[4] = {45, -45, -45, 45};
int index = 0;
for (int sign_x = -1; sign_x <= 2; sign_x += 2) {
for (int sign_y = -1; sign_y <= 2; sign_y += 2) {
@ -223,7 +223,7 @@ TEST(convexhull_2d, Lines_Diagonal)
}
{ /* Diagonal line (3 points). */
const float expected[4] = {-135, 135, 135, -135};
const float expected[4] = {45, -45, -45, 45};
int index = 0;
for (int sign_x = -1; sign_x <= 2; sign_x += 2) {
for (int sign_y = -1; sign_y <= 2; sign_y += 2) {
@ -251,7 +251,7 @@ TEST(convexhull_2d, Simple)
{1.0f, 0.0f},
};
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
float(math::AngleRadian::from_degree(135.0f)),
float(math::AngleRadian::from_degree(45.0f)),
ROTATION_EPS);
}
@ -263,7 +263,7 @@ TEST(convexhull_2d, Simple)
{1.0f, -1.0f},
};
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
float(math::AngleRadian::from_degree(180.0f)),
float(math::AngleRadian::from_degree(90.0f)),
ROTATION_EPS);
}
}