Skip to content

Commit

Permalink
Updates to GetMaxSeparation functions.
Browse files Browse the repository at this point in the history
The latest related benchmark data shows the following:

Run on (8 X 2600 MHz CPU s)
2017-08-08 14:48:46
-------------------------------------------------------------------------
Benchmark                                  Time           CPU Iterations
-------------------------------------------------------------------------
MaxSepBetweenAbsRectangles                68 ns         67 ns   10098387
MaxSepBetweenRel4x4                       74 ns         74 ns    8566778
MaxSepBetweenRel2_4x4                     80 ns         80 ns    9227768
MaxSepBetweenRelRectanglesNoStop          93 ns         93 ns    7494085
MaxSepBetweenRelRectangles2NoStop         91 ns         91 ns    7573545
MaxSepBetweenRelRectangles                98 ns         98 ns    7125335
MaxSepBetweenRelRectangles2               97 ns         97 ns    7122869
Program ended with exit code: 0
  • Loading branch information
louis-langholtz committed Aug 8, 2017
1 parent ee74290 commit 0b7b64a
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 53 deletions.
65 changes: 65 additions & 0 deletions Benchmark/BenchmarkMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,47 @@ static void CrossProductFourRand(benchmark::State& state)
}
}

static void MaxSepBetweenRelRectanglesNoStop(benchmark::State& state)
{
const auto rot0 = playrho::Angle{playrho::Real{45.0f} * playrho::Degree};
const auto xfm0 = playrho::Transformation{playrho::Vec2{0, -2} * (playrho::Real(1) * playrho::Meter), playrho::UnitVec2::Get(rot0)}; // bottom
const auto xfm1 = playrho::Transformation{playrho::Vec2{0, +2} * (playrho::Real(1) * playrho::Meter), playrho::UnitVec2::GetRight()}; // top

const auto dim = playrho::Real(2) * playrho::Meter;
const auto shape0 = playrho::PolygonShape(dim, dim);
const auto shape1 = playrho::PolygonShape(dim, dim);

// Rotate square A and put it below square B.
// In ASCII art terms:
//
// +---4---+
// | | |
// | B 3 |
// | | |
// | 2 |
// | | |
// | 1 |
// | /+\ |
// 2-1-*-1-2
// / 1 \
// / A | \
// + 2 +
// \ | /
// \ 3 /
// \ | /
// \4/
// +

const auto child0 = shape0.GetChild(0);
const auto child1 = shape1.GetChild(0);

while (state.KeepRunning())
{
benchmark::DoNotOptimize(playrho::GetMaxSeparation(child0, xfm0, child1, xfm1));
benchmark::DoNotOptimize(playrho::GetMaxSeparation(child1, xfm1, child0, xfm0));
}
}

static void MaxSepBetweenRelRectangles(benchmark::State& state)
{
const auto rot0 = playrho::Angle{playrho::Real{45.0f} * playrho::Degree};
Expand Down Expand Up @@ -489,6 +530,28 @@ static void MaxSepBetweenRelRectangles(benchmark::State& state)
}
}

static void MaxSepBetweenRelRectangles2NoStop(benchmark::State& state)
{
const auto dim = playrho::Real(2) * playrho::Meter;
const auto shape = playrho::PolygonShape(dim, dim);

const auto xfm0 = playrho::Transformation{
playrho::Vec2{0, -1} * (playrho::Real(1) * playrho::Meter),
playrho::UnitVec2::GetRight()
}; // bottom
const auto xfm1 = playrho::Transformation{
playrho::Vec2{0, +1} * (playrho::Real(1) * playrho::Meter),
playrho::UnitVec2::GetRight()
}; // top

const auto child0 = shape.GetChild(0);
while (state.KeepRunning())
{
benchmark::DoNotOptimize(playrho::GetMaxSeparation(child0, xfm0, child0, xfm1));
benchmark::DoNotOptimize(playrho::GetMaxSeparation(child0, xfm1, child0, xfm0));
}
}

static void MaxSepBetweenRelRectangles2(benchmark::State& state)
{
const auto dim = playrho::Real(2) * playrho::Meter;
Expand Down Expand Up @@ -928,6 +991,8 @@ BENCHMARK(SolveVC);
BENCHMARK(MaxSepBetweenAbsRectangles);
BENCHMARK(MaxSepBetweenRel4x4);
BENCHMARK(MaxSepBetweenRel2_4x4);
BENCHMARK(MaxSepBetweenRelRectanglesNoStop);
BENCHMARK(MaxSepBetweenRelRectangles2NoStop);
BENCHMARK(MaxSepBetweenRelRectangles);
BENCHMARK(MaxSepBetweenRelRectangles2);

Expand Down
117 changes: 68 additions & 49 deletions PlayRho/Collision/ShapeSeparation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,37 @@

using namespace playrho;

namespace
{

inline IndexSeparation GetMinIndexSeparation(const DistanceProxy& proxy,
UnitVec2 normal, Length2D offset)
{
// Search for the vector that's most anti-parallel to the normal.
// See: https://en.wikipedia.org/wiki/Antiparallel_(mathematics)#Antiparallel_vectors

auto ap = IndexSeparation{
std::numeric_limits<Real>::infinity() * Meter,
IndexSeparation::InvalidIndex
};

const auto count = proxy.GetVertexCount();
for (auto j = decltype(count){0}; j < count; ++j)
{
// Get distance from offset to proxy2.GetVertex(j) in direction of normal.
const auto s = Dot(normal, proxy.GetVertex(j) - offset);
if (ap.separation > s)
{
ap.separation = s;
ap.index = j;
}
}

return ap;
}

} // anonymous namespace

IndexPairSeparation playrho::GetMaxSeparation4x4(const DistanceProxy& proxy1,
const Transformation xf1,
const DistanceProxy& proxy2,
Expand Down Expand Up @@ -75,99 +106,87 @@ IndexPairSeparation playrho::GetMaxSeparation4x4(const DistanceProxy& proxy1,
}

IndexPairSeparation playrho::GetMaxSeparation(const DistanceProxy& proxy1, const Transformation xf1,
const DistanceProxy& proxy2, const Transformation xf2,
Length stop)
const DistanceProxy& proxy2, const Transformation xf2)
{
// Find the max separation between proxy1 and proxy2 using edge normals from proxy1.
using CounterType = IndexSeparation::index_type;

auto indexPairSep = IndexPairSeparation{
-std::numeric_limits<Real>::infinity() * Meter,
IndexPairSeparation::InvalidIndex,
IndexPairSeparation::InvalidIndex
};

const auto count1 = proxy1.GetVertexCount();
const auto count2 = proxy2.GetVertexCount();

const auto xf = MulT(xf2, xf1);
for (auto i = decltype(count1){0}; i < count1; ++i)
for (auto i = CounterType{0}; i < count1; ++i)
{
// Get proxy1 normal and vertex relative to proxy2.
const auto normal = Rotate(proxy1.GetNormal(i), xf.q);
const auto offset = Transform(proxy1.GetVertex(i), xf);

// Search for the vector that's most anti-parallel to the normal.
// See: https://en.wikipedia.org/wiki/Antiparallel_(mathematics)#Antiparallel_vectors
auto ap = IndexSeparation{
std::numeric_limits<Real>::infinity() * Meter,
IndexSeparation::InvalidIndex
};
for (auto j = decltype(count2){0}; j < count2; ++j)
const auto ap = GetMinIndexSeparation(proxy2, normal, offset);
if (indexPairSep.separation < ap.separation)
{
// Get distance from offset to proxy2.GetVertex(j) in direction of normal.
const auto s = Dot(normal, proxy2.GetVertex(j) - offset);
if (ap.separation > s)
{
ap.separation = s;
ap.index = static_cast<IndexSeparation::index_type>(j);
}
indexPairSep.separation = ap.separation;
indexPairSep.index1 = i;
indexPairSep.index2 = ap.index;
}
}
return indexPairSep;
}

IndexPairSeparation playrho::GetMaxSeparation(const DistanceProxy& proxy1, const Transformation xf1,
const DistanceProxy& proxy2, const Transformation xf2,
Length stop)
{
// Find the max separation between proxy1 and proxy2 using edge normals from proxy1.
using CounterType = IndexSeparation::index_type;

auto indexPairSep = IndexPairSeparation{
-std::numeric_limits<Real>::infinity() * Meter,
IndexPairSeparation::InvalidIndex,
IndexPairSeparation::InvalidIndex
};
const auto xf = MulT(xf2, xf1);
const auto count1 = proxy1.GetVertexCount();
for (auto i = CounterType{0}; i < count1; ++i)
{
// Get proxy1 normal and vertex relative to proxy2.
const auto normal = Rotate(proxy1.GetNormal(i), xf.q);
const auto offset = Transform(proxy1.GetVertex(i), xf);
const auto ap = GetMinIndexSeparation(proxy2, normal, offset);
if (ap.separation > stop)
{
return IndexPairSeparation{
ap.separation, static_cast<IndexSeparation::index_type>(i), ap.index
};
return IndexPairSeparation{ap.separation, i, ap.index};
}
if (indexPairSep.separation < ap.separation)
{
indexPairSep.separation = ap.separation;
indexPairSep.index1 = static_cast<IndexSeparation::index_type>(i);
indexPairSep.index1 = i;
indexPairSep.index2 = ap.index;
}
}

return indexPairSep;
}

IndexPairSeparation playrho::GetMaxSeparation(const DistanceProxy& proxy1,
const DistanceProxy& proxy2,
Length stop)
const DistanceProxy& proxy2,
Length stop)
{
// Find the max separation between proxy1 and proxy2 using edge normals from proxy1.

auto indexPairSep = IndexPairSeparation{
-MaxFloat * Meter, IndexPairSeparation::InvalidIndex, IndexPairSeparation::InvalidIndex
};

const auto count1 = proxy1.GetVertexCount();
const auto count2 = proxy2.GetVertexCount();

for (auto i = decltype(count1){0}; i < count1; ++i)
{
// Get proxy1 normal and vertex relative to proxy2.
const auto normal = proxy1.GetNormal(i);
const auto offset = proxy1.GetVertex(i);

// Search for the vector that's most anti-parallel to the normal.
// See: https://en.wikipedia.org/wiki/Antiparallel_(mathematics)#Antiparallel_vectors
auto ap = IndexSeparation{};
for (auto j = decltype(count2){0}; j < count2; ++j)
{
// Get distance from offset to proxy2.GetVertex(j) in direction of normal.
const auto s = Dot(normal, proxy2.GetVertex(j) - offset);
if (ap.separation > s)
{
ap.separation = s;
ap.index = static_cast<IndexSeparation::index_type>(j);
}
}

const auto ap = GetMinIndexSeparation(proxy2, normal, offset);
if (ap.separation > stop)
{
return IndexPairSeparation{
ap.separation, static_cast<IndexSeparation::index_type>(i), ap.index
};
return IndexPairSeparation{ap.separation, i, ap.index};
}
if (indexPairSep.separation < ap.separation)
{
Expand Down
9 changes: 8 additions & 1 deletion PlayRho/Collision/ShapeSeparation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,21 @@ namespace playrho
index_type index1 = InvalidIndex;
index_type index2 = InvalidIndex;
};

/// @brief Gets the max separation information.
/// @return Index of the vertex and normal from <code>proxy1</code>,
/// index of the vertex from <code>proxy2</code> (that had the maximum separation
/// distance from each other in the direction of that normal), and the maximal distance.
IndexPairSeparation GetMaxSeparation(const DistanceProxy& proxy1, const Transformation xf1,
const DistanceProxy& proxy2, const Transformation xf2);

/// @brief Gets the max separation information.
/// @return Index of the vertex and normal from <code>proxy1</code>,
/// index of the vertex from <code>proxy2</code> (that had the maximum separation
/// distance from each other in the direction of that normal), and the maximal distance.
IndexPairSeparation GetMaxSeparation(const DistanceProxy& proxy1, const Transformation xf1,
const DistanceProxy& proxy2, const Transformation xf2,
Length stop = MaxFloat * Meter);
Length stop);

/// @brief Gets the max separation information for the first four vertices of the two
/// given shapes.
Expand Down
13 changes: 10 additions & 3 deletions PlayRho/Common/Math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,10 @@ constexpr inline Vec2 Transform(const Vec2 v, const Mat33& A) noexcept
};
}

/// Rotates a vector by a given angle.
/// @brief Rotates a vector by a given angle.
/// @details This rotates a vector by the angle expressed by the angle parameter.
/// @param vector Vector to forward rotate.
/// @param angle Expresses the angle to forward rotate the given vector by.
/// @sa InverseRotate.
template <class T>
constexpr inline auto Rotate(const Vector2D<T> vector, const UnitVec2& angle) noexcept
Expand All @@ -595,8 +598,12 @@ constexpr inline auto Rotate(const Vector2D<T> vector, const UnitVec2& angle) no
return Vector2D<T>{newX, newY};
}

/// Inverse rotate a vector.
/// @details This is the inverse of rotating a vector - it undoes what rotate does.
/// @brief Inverse rotates a vector.
/// @details This is the inverse of rotating a vector - it undoes what rotate does. I.e.
/// this effectively subtracts from the angle of the given vector the angle that's
/// expressed by the angle parameter.
/// @param vector Vector to reverse rotate.
/// @param angle Expresses the angle to reverse rotate the given vector by.
/// @sa Rotate.
template <class T>
constexpr inline auto InverseRotate(const Vector2D<T> vector, const UnitVec2& angle) noexcept
Expand Down

0 comments on commit 0b7b64a

Please sign in to comment.