状态结构在线段相交平面扫描算法中的应用

Use of Status structure in Plane sweep Algorithm for line Segment Intersection

本文关键字:算法 应用 扫描 平面 结构 在线 段相交 状态      更新时间:2023-10-16

我想在平面扫描算法中实现状态结构。我的扫描线从上到下在y方向上移动。

目前,我使用set(c++中预定义的一个)根据x值存储段。

当扫描线向下移动时,每个段的x值都会改变,因此集合中的顺序应该改变,但集合中的搜索键一旦添加就不能修改,所以我的x值一旦分配就不会改变,所以每次我移动到下一个事件点时,我都必须删除完整的树,并用新的x值创建新的。

我的细分市场结构是:

struct Segment
{
double x1;
double x2;
double y1;
double y2;
int name;
double x;
double y;
};

如何更新集合中的x值?

std::set通常被实现为红黑树。通过将元素对传递给存储在set中的比较函数来控制树中元素的排序;元素在排序顺序中的位置在插入期间进行检查,并假定此后不会更改。(你可能已经知道这一切了……只是提供一些背景信息。)

平面扫描算法还通常使用自平衡树,例如红黑树作为其状态结构。然而,相似之处就到此为止了。状态结构中的元素(段)没有固有的整体排序;该顺序是在给定特定y坐标的情况下定义的,并且将随y坐标而变化。最重要的是,在交叉事件点,两个分段将交换排序中的位置,这一操作甚至对std::set都没有意义。

一句话:std::set和其他排序的容器类通常不适合实现平面扫描算法的扫描状态,即使底层数据结构是合适的。您应该使用一个较低级别的、直接公开的红黑树实现,它将允许您交换元素。

我已经找到了这个问题的解决方案。只是用方位代替x坐标构造了AVL树。

这是我的完整源代码。

#include <string>
#include <queue>
#include <iostream>
#include<stdlib.h>
#include<stdio.h>
#include <set>
using namespace std;  
struct Point {
double x;
double y;
int segment;
int segid1;
int segid2;
};
typedef struct Point point;
struct Segment{
double x1;
double x2;
double y1;
double y2;
int name;
double x;
double y;
};
typedef struct Segment segment;
struct classcomp {
bool operator() (const segment& lhs,const segment& rhs) 
{//return lhs.x>rhs.x;
if(rhs.x==lhs.x && rhs.y==lhs.y)
return ((rhs.x1 - lhs.x2) * (rhs.y2 - lhs.y2) - (rhs.y1 - lhs.y2) *     (rhs.x2 - lhs.x2))<0;
else
return ((rhs.x1 - lhs.x1) * (rhs.y2 - lhs.y1) - (rhs.y1 - lhs.y1) * (rhs.x2 - lhs.x1))<0;
}
};
class CompareEventPoint {
public:
bool operator()(point& t1, point& t2) // Returns true if t1 is earlier than t2
{
if(t1.y<t2.y)return true;
return false;
}
};

point checkIntersection(segment a,segment b)
{
point p;
p.segment=-1;
double num=(a.y1-b.y1)*(b.x2-b.x1)-(a.x1-b.x1)*(b.y2-b.y1);
double den=(a.y1-a.y2)*(b.x2-b.x1)-(a.x1-a.x2)*(b.y2-b.y1);
double s=num/den;
if(s>0 && s<1)
{
double t=((1-s)*a.x1+s*a.x2-b.x1)/(b.x2-b.x1);
if(t>0 && t<1)
{
p.segment=0;
if(a.x1>b.x1)
{
p.segid1=a.name;
p.segid2=b.name;
}
else
{
p.segid1=b.name;
p.segid2=a.name;    
}
p.x=(1-s)*a.x1+s*a.x2;
p.y=(1-s)*a.y1+s*a.y2;
return p;
}
}
return p;
}
int main()
{
int n,i;
FILE *fp,*f;
priority_queue<point, vector<point>, CompareEventPoint> pq; // Creates a priority queue pq to store strings, and initializes the queue to be empty.
printf("Enter the number of line Segmentsn");   
scanf("%d",&n);
segment segArray[n];


point p;
printf("Enter the co-ordinates of End points with top point first and then low  pointn");
for(i=0;i<n;i++)
{
scanf("%lf%lf",&p.x,&p.y);
p.segment=i+1;
pq.push(p);
segArray[i].name=i+1;
segArray[i].x1=p.x;
segArray[i].y1=p.y;
scanf("%lf%lf",&p.x,&p.y);
p.segment=-(i+1);
pq.push(p);
segArray[i].x2=p.x;
segArray[i].y2=p.y;
}

set<segment,classcomp> tree;
set<segment,classcomp>::iterator itlow,itup;
int segid;
point ptemp;
double lineY;
int iteration=0;
while (!pq.empty()) {
ptemp=pq.top();
pq.pop(); 
iteration++; 
segid=ptemp.segment;
lineY=ptemp.y;
// Case of starting Point
for (itlow=tree.begin(); itlow!=tree.end();++itlow)
printf("%dt",itlow->name);
printf("n");

if(segid>0)
{
tree.insert(segArray[segid-1]);
itlow=tree.lower_bound (segArray[segid-1]);   
if(itlow!=tree.begin())                                                  //       ^
{    itlow--;
p=checkIntersection(segArray[segid-1],segArray[itlow->name-1]);
if(p.segment==0 && ptemp.y>p.y)
{
pq.push(p);
}
}
itup=tree.upper_bound (segArray[segid-1]); 
if(itup!=tree.end())
{
p=checkIntersection(segArray[segid-1],segArray[itup->name-1]);
if(p.segment==0 && ptemp.y>p.y)
{
pq.push(p);
}
}
}

// Case of intersection Point
if(segid==0)
{
int t1=ptemp.segid1;
int t2=ptemp.segid2;

segment s1=segArray[t1-1];
segment s2=segArray[t2-1];

tree.erase(s1); 
tree.erase(s2); 

segArray[t1-1].x=ptemp.x;
segArray[t1-1].x1=ptemp.x;
segArray[t2-1].x=ptemp.x;
segArray[t2-1].x1=ptemp.x;
segArray[t1-1].y=ptemp.y;
segArray[t1-1].y1=ptemp.y;
segArray[t2-1].y=ptemp.y;
segArray[t2-1].y1=ptemp.y;
s1=segArray[t1-1];
s2=segArray[t2-1];
tree.insert(s1);
tree.insert(s2);

itlow=tree.lower_bound (s1);
if(itlow!=tree.begin())
{       itlow--;
p=checkIntersection(s1,segArray[itlow->name-1]);
if(p.segment==0 && ptemp.y>p.y)
{
pq.push(p);
}
}
itup=tree.upper_bound (s2); 
if(itup!=tree.end())
{
p=checkIntersection(s2,segArray[itup->name-1]);
if(p.segment==0 && ptemp.y>p.y)
{
pq.push(p);
} 
}

printf("Intersection point=%lf %lfn",ptemp.x,ptemp.y);
}
// Case of End point
if(segid<0)
{

segid=-segid;
if(itlow!=tree.begin() && itup!=tree.end())
{
itlow=tree.lower_bound (segArray[segid-1]);
itlow--;
itup=tree.upper_bound (segArray[segid-1]); 
}
tree.erase(segArray[segid-1]); 
if(itlow!=tree.begin() && itup!=tree.end())
{
p=checkIntersection(segArray[itlow->name-1],segArray[itup->name-1]);
if(p.segment==0 && ptemp.y>p.y)
{
pq.push(p);
}
}
}
}
return 0;
}