/*
* 实现碰撞检测中一个经典的Sweep And Prune算法
* 参考文章:D. Baraff (Ph. D thesis), p 52.
* http://www.cs.cmu.edu/~baraff/papers/thesis-part1.ps.Z
*/
#include <iostream>
#include <vector>
#include <map>
#include <list>
#include <algorithm>
void sweepAndPrune(std::vector<std::tuple<bool, unsigned int, double>> values, std::map<unsigned int, std::list<unsigned int>> &collision)
{
// 根据区间端点位置对各个区间端点进行排序
std::sort(values.begin(), values.end(), [](std::tuple<bool, unsigned int, double> a, std::tuple<bool, unsigned int, double> b) { return std::get<2>(a) < std::get<2>(b); });
// 输出排序之后的结果
for (auto ite = values.begin(); ite != values.end(); ite++)
{
auto t = std::get<0>(*ite) ? "b" : "e";
auto idx = std::get<1>(*ite);
std::cout << idx << "," << t << ": " << std::get<2>(*ite) << std::endl;
}
std::list<unsigned int> activeList = {};
// 遍历区间端点,生成每个区间对应的重叠区间列表。如果区间端点为起始点,那么就activeList中的区间索引就是该区间的重叠区间,并将该区间添加到activeList中
// 否则就在activeList中删除该区间索引
for (auto ite = values.begin(); ite != values.end(); ite++)
{
auto idx = std::get<1>(*ite);
if (std::get<0>(*ite)) // b
{
collision[idx] = activeList;
activeList.push_back(idx);
}
else // e
{
activeList.remove(idx);
}
}
}
int main()
{
// 在一个坐标轴上的多个区间
std::vector<std::pair<double, double>> interal = { {3.0,5.0},{7.0,18.0},{0.0,8.0},{10.0,16.0},{6.0,12.0},{1.0,4.0} };
for (auto ite = interal.begin(); ite != interal.end(); ite++)
{
std::cout << "[" << ite->first << "," << ite->second << "]\n";
}
// 保存每个区间端点是否为起始点(b:true, e:false),索引值,位置
std::vector<std::tuple<bool,unsigned int, double>> values;
for (unsigned int i = 0; i < interal.size(); i++)
{
values.push_back({ true, i,interal[i].first });
values.push_back({ false,i,interal[i].second });
}
std::map<unsigned int, std::list<unsigned int>> collision;
sweepAndPrune(values, collision);
// 输出具有重叠的线段
for (auto ite = collision.begin(); ite != collision.end(); ite++)
{
std::cout << "the " << ite->first + 1<< "th segment is overlapping with segments: ";
for (auto i : ite->second)
{
std::cout << i + 1 <<",";
}
std::cout << "."<<std::endl;
}
return 0;
}