我有一个矩形列表(它们无法旋转):
struct Rectangle {
double centerX;
double centerY;
double width;
double height;
Rectangle(double x, double y, double w, double h):centerx(x),centery(y),width(w),height(h){}
};
std::vector<Rectangle> rectangles;
rectangles.push_back(Rectangle(0 , 0 , 1 , 1 );
rectangles.push_back(Rectangle(0.5, 0.5, 1 , 1 );
rectangles.push_back(Rectangle(3 , 2 , 0.5, 0.6);
rectangles.push_back(Rectangle(0.2, 0.5, 0.5, 0.6);
rectangles.push_back(Rectangle(2 , -0.3, 0.4, 0.4);
rectangles.push_back(Rectangle(0.2, -0.4, 0.3, 0.4);
我想计算具有至少一个交叉点的矩形组,具有传递属性。即如果r1与r2相交且r2与r3相交,则r1,r2,r3属于同一组。
在此示例中,组将是
{{3}, {4, 1, 2}, {5, 6}}
组内的组顺序和元素顺序并不重要。
如何计算这些群组?如有必要,我可以更改数据结构。
例如,我可以将std::vector
更改为std::set
,并按左顶点X坐标对矩形进行排序。通过这种方式,我可以使用扫描线算法。但是我无法找到任何可以应用于我的问题的样本。
如何获得交叉组?
答案 0 :(得分:4)
我认为集合的向量可以完成任务。
像这样:
std::vector< std::set< int > > groups;
// loop over rectangles
for( int r1 = 0; r1 < rectangles.size(); r1++ )
{
// check if rectngle already in group
auto g_it = groups.end();
for( auto group = groups.begin();
group != groups.end(); group++ )
{
auto group_r1_it = group->find( r1 );
if( group_r1_it != group->end() )
{
g_it = group;
break;
}
}
if( g_it == groups.end() )
{
// not already in group, so create new group
set<int> s;
s.insert( r1 );
groups.push_back( s );
g_it = groups.end()-1;
}
// loop over remaining rectangles
for( int r2 = r1+1; r2 < rectangles.size(); r2++ )
{
// check for intersection
if( rectangles[r1].Intersect( rectangles[r2] ))
{
//report intersection
cout << r1+1 <<" " <<r2+1 << endl;
// add to group
g_it->insert( r2 );
}
}
}
// Display results
for ( auto group : groups )
{
cout << "{ ";
for( auto r : group )
{
cout << r+1 << " ";
}
cout << "} ";
}
cout << endl;
为了编写更干净的代码,我建议升级你的矩形,以便它与STL很好地搭配......
class Rectangle
{
public:
double centerX;
double centerY;
double width;
double height;
int myID;
static int lastID;
Rectangle(double x, double y, double w, double h)
:centerX(x),centerY(y),width(w),height(h),
myID( ++lastID )
{ }
bool Intersect( const Rectangle& other ) const
{
...
}
bool operator ==(const Rectangle& other ) const
{
return myID == other.myID;
}
bool operator <(const Rectangle& other ) const
{
return myID < other.myID;
}
};
int Rectangle::lastID = 0;
...添加一个类来处理集合的向量...
class RectangleGroups
{
public:
typedef std::set< Rectangle > group_t;
typedef std::vector< group_t >::iterator iter;
iter begin()
{
return groups.begin();
}
iter end()
{
return groups.end();
}
/** Build the groups of intersecting trinagles
@param[in] rectangles vector of rectangles
@param[in] intersections vector of pairs of intersecting rectangles
*/
void Make(
std::vector< Rectangle > rectangles,
std::vector< std::pair< Rectangle&, Rectangle& > >& intesections )
{
// loop over intersecting triangles
for( auto rp : intesections )
{
iter g_it = Find( rp.first );
if( g_it != groups.end() )
{
g_it->insert( rp.second );
continue;
}
g_it = Find( rp.second );
if( g_it != groups.end() )
{
g_it->insert( rp.first );
continue;
}
// neither rectangle is already in group, so add new group
g_it = Add( rp.first );
g_it->insert( rp.second );
}
// Add orphans
for( auto& r : rectangles )
{
if ( Find( r ) == groups.end() )
{
Add( r );
}
}
}
/// Display rectangle IDs in groups marked off with curly braces
void Display()
{
for ( auto group : groups )
{
cout << "{ ";
for( auto r : group )
{
cout << r.myID << " ";
}
cout << "} ";
}
cout << endl;
}
private:
std::vector< group_t > groups;
/// Add new group containing a copy of a rectangle, return iterator pointing to new group
iter Add( const Rectangle& r )
{
group_t s;
s.insert( r );
groups.push_back( s );
return groups.end()-1;
}
/// Find group containing rectangle, return iterator pointing to found group or to end
iter Find( const Rectangle& r )
{
for( iter it = groups.begin(); it != groups.end(); it++ )
{
auto group_it = it->find( r );
if( group_it != it->end() )
{
return it;
}
}
return groups.end();
}
};
...这样我们就可以写...
// vector of intesections
// you can build this using various algorithms, even a sweepline
// here I will use a simple pair of nested for loops
std::vector< std::pair< Rectangle&, Rectangle& > > intersections;
// loop over rectangles
for( auto& r1 : rectangles )
{
// loop over remaining rectangles
for( auto& r2 : rectangles )
{
if( r2 < r1 || r1 == r2 )
continue;
// check for intersection
if( r1.Intersect( r2 ))
{
intersections.push_back( std::pair<Rectangle&, Rectangle& >( r1, r2 ) );
}
}
}
// Construct a vector of rectangle groups
// The groups will contain interesecting rectangles.
RectangleGroups groups;
groups.Make(
rectangles,
intersections );
// Display results
groups.Display();
答案 1 :(得分:1)
我一直在研究OP的问题是中间解决方案的问题。给定矩形集(或任何矩形集)的过程如下:
制作与每个矩形相交的矩形列表。因此,对于样本中的6个矩形,我们将有6个列表。步骤1的结果如下所示:
[[1,2], [2,1,4], [4,2], [3], [5,6], [6,5]]
接下来,如果下一个列表中存在其中一个矩形,我们将遍历此列表列表并合并列表。例如。列表1的矩形1存在于列表2中。因此,由list1和list2形成的合并列表将是[1,2,4]。清空list1,这样我们就无法在下一次迭代中再次使用它。每次迭代的结果如下所示:
[[], [2,1,4], [4,2], [3], [5,6], [6,5]]
[[], [], [4,2,1], [3], [5,6], [6,5]]
[[], [], [4,2,1], [3], [5,6], [6,5]]
[[], [], [4,2,1], [3], [5,6], [6,5]]
[[], [], [4,2,1], [3], [], [6,5]]
从列表中删除空列表。结果是一组相交的行。
[[4,2,1], [3], [6,5]]
希望这会有所帮助。我不能流利地说C ++。但是,如果有帮助,我可以与您分享我编写的导演Lingo代码。我没有发布Lingo代码的原因是因为很少有人在Director中工作。