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

时间:2014-02-11 11:01:40

标签: c++ algorithm

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

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

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

我的细分结构是:

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

如何更新集合中的x值?

2 个答案:

答案 0 :(得分:2)

std::set通常实现为红黑树。通过将元素对传递给存储在set中的比较函数来控制树中元素的排序;在插入过程中检查元素在排序顺序中的位置,并假设此后不再更改。 (你可能已经知道了所有这些......只是给出了一些背景知识。)

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

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

答案 1 :(得分:0)

我已经找到了问题的解决方案。 刚刚使用orientation来构造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 Segments\n");   
scanf("%d",&n);
segment segArray[n];




point p;
printf("Enter the co-ordinates of End points with top point first and then low  point\n");
  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("%d\t",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 %lf\n",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;
}