sweep intersection

/*#####################################################################################################################
#####################################################################################################################
#####################################################################################################################*/
#include<algorithm>
#include<set>
#include<string>
#include<vector>
#include <stack>
#include <iostream>
#include <unordered_map>
#include <fstream>

#include<vector>
#include<fstream>
#include<sstream>
//#include <bits/stdc++.h>
using namespace std;

// A point in 2D plane
struct Point
{
    double x, y;
};

// A line segment with left as Point
// with smaller x value and right with
// larger x value.
struct Segment
{
    Point left, right;
   /* Segment add(Point left, Point right) {

    }*/

};


// An event for sweep line algorithm
// An event has a point, the position
// of point (whether left or right) and
// index of point in the original input
// array of segments.
struct Event {
    double x, y;
    bool isLeft;
    int index;
    Event(double x, double y, bool l, int i) : x(x), y(y), isLeft(l), index(i) {}

    // This is for maintaining the order in set.
    bool operator<(const Event& e) const {
        if (y == e.y)return x < e.x;
        return y < e.y;
    }
};


// Given three collinear points p, q, r, the function checks if
// point q lies on line segment 'pr'
bool onSegment(Point p, Point q, Point r)
{
    if (q.x <= max(p.x, r.x) && q.x >= min(p.x, r.x) &&
        q.y <= max(p.y, r.y) && q.y >= min(p.y, r.y))
        return true;

    return false;
}

// To find orientation of ordered triplet (p, q, r).
// The function returns following values
// 0 --> p, q and r are collinear
// 1 --> Clockwise
// 2 --> Counterclockwise
int orientation(Point p, Point q, Point r)
{
    // See https://www.geeksforgeeks.org/orientation-3-ordered-points/
    // for details of below formula.
    double val = (q.y - p.y) * (r.x - q.x) -
        (q.x - p.x) * (r.y - q.y);

    if (val == 0) return 0;  // collinear

    return (val > 0) ? 1 : 2; // clock or counterclock wise
}

// The main function that returns true if line segment 'p1q1'
// and 'p2q2' intersect.
bool doIntersect(Segment s1, Segment s2)
{
    Point p1 = s1.left, q1 = s1.right, p2 = s2.left, q2 = s2.right;

    // Find the four orientations needed for general and
    // special cases
    int o1 = orientation(p1, q1, p2);
    int o2 = orientation(p1, q1, q2);
    int o3 = orientation(p2, q2, p1);
    int o4 = orientation(p2, q2, q1);

    // General case
    if (o1 != o2 && o3 != o4)
        return true;

    // Special Cases
    // p1, q1 and p2 are collinear and p2 lies on segment p1q1
    if (o1 == 0 && onSegment(p1, p2, q1)) return true;

    // p1, q1 and q2 are collinear and q2 lies on segment p1q1
    if (o2 == 0 && onSegment(p1, q2, q1)) return true;

    // p2, q2 and p1 are collinear and p1 lies on segment p2q2
    if (o3 == 0 && onSegment(p2, p1, q2)) return true;

    // p2, q2 and q1 are collinear and q1 lies on segment p2q2
    if (o4 == 0 && onSegment(p2, q1, q2)) return true;

    return false; // Doesn't fall in any of the above cases
}


// Find predecessor of iterator in s.
set<Event>::iterator pred(set<Event>& s, set<Event>::iterator it) {
    return it == s.begin() ? s.end() : --it;
}

// Find successor of iterator in s.
set<Event>::iterator succ(set<Event>& s, set<Event>::iterator it) {
    return ++it;
}



double determinant(double v1, double v2, double  v3, double v4) {
    return  (v1 * v4 - v2 * v3);

}

Point intersectionaxis(Point p1, Point q1, Point p2, Point q2) {
    Point respoint;
    double delta = determinant( q1.x- p1.x, p2.x - q2.x, q1.y - p1.y, p2.y - q2.y);
    if (delta <= (1e-6) && delta >= -(1e-6)) {
        respoint.x= p1.x;
        respoint.y = p1.y;
    }
   double namenda = determinant(p2.x - p1.x, p2.x - q2.x, p2.y - p1.y, p2.y - q2.y) / delta;
   if (namenda > 1 || namenda < 0){
       respoint.x = p1.x;
       respoint.y = p1.y;
   }
  
   double miu = determinant(q1.x - p1.x, p2.x - p1.x, q1.y - p1.y, p2.y - p1.y) / delta;
   if (miu > 1 || miu < 0) {
       respoint.x = p1.x;
       respoint.y = p1.y;
   }
     
   respoint.x = p1.x + namenda * (q1.x - p1.x);
   respoint.y = p1.y + namenda * (q1.y - p1.y);

   return respoint;
}





// Returns true if any two lines intersect.
int isIntersect(Segment arr[], int n)
{
    unordered_map<string, int> mp;  // to note the pair for which intersection is checked already
    // Pushing all points to a vector of events
    vector<Event> e;
    for (int i = 0; i < n; ++i) {
        e.push_back(Event(arr[i].left.x, arr[i].left.y, true, i));
        e.push_back(Event(arr[i].right.x, arr[i].right.y, false, i));
    }

    // Sorting all events according to x coordinate.
    sort(e.begin(), e.end(), [](Event& e1, Event& e2) {return e1.x < e2.x; });

    // For storing active segments.
    set<Event> s;
    int ans = 0;
    // Traversing through sorted points
    for (int i = 0; i < 2 * n; i++)
    {
        Event curr = e[i];
        int index = curr.index;

        // If current point is left of its segment
        if (curr.isLeft)
        {
            // Get above and below points
            auto next = s.lower_bound(curr);
            auto prev = pred(s, next);
            // Check if current point intersects with
            // any of its adjacent
            bool flag = false;
            if (next != s.end() && doIntersect(arr[next->index], arr[index])) {
                string s = to_string(next->index + 1) + " " + to_string(index + 1);
                if (mp.count(s) == 0) { mp[s]++; ans++; } //if not already checked we can increase count in map
            }
            if (prev != s.end() && doIntersect(arr[prev->index], arr[index])) {
                string s = to_string(prev->index + 1) + " " + to_string(index + 1);
                if (mp.count(s) == 0) { mp[s]++; ans++; } //if not already checked we can increase count in map
            }
            // if same line segment is there then decrease answer as it got increased twice
            if (prev != s.end() && next != s.end() && next->index == prev->index)ans--;


            // Insert current point (or event)
            s.insert(curr);
        }

        // If current point is right of its segment
        else
        {
            // Find the iterator
            auto it = s.find(Event(arr[index].left.x, arr[index].left.y, true, index));
            // Find above and below points
            auto next = succ(s, it);
            auto prev = pred(s, it);

            // If above and below point intersect
            if (next != s.end() && prev != s.end())
            {
                string s = to_string(next->index + 1) + " " + to_string(prev->index + 1);
                string s1 = to_string(prev->index + 1) + " " + to_string(next->index + 1);
                if (mp.count(s) == 0 && mp.count(s1) == 0 && doIntersect(arr[prev->index], arr[next->index]))
                    ans++;
                mp[s]++;
            }

            // Remove current segment
            s.erase(it);

        }
    }
    //print pair of lines having intersection

    ofstream outfile("test.txt", std::ios::app);
    for (auto& pr : mp) {
        //cout << pr.first[0] <<" "<< pr.first[1] << "\n";
        //cout << pr.first << "\n";
        
        outfile << pr.first[0]<< " "<<pr.first[2] << std::endl;

    /*    cout << pr.first[0]<< "\n";
        cout << pr.first[2] << "\n";
        cout << arr[pr.first[2]].left.x << "\n";*/


        /*struct Point respoint = intersectionaxis(arr[pr.first[0]].left, arr[pr.first[0]].right, arr[pr.first[2]].left, arr[pr.first[2]].right);
         cout << respoint.x << " " << respoint.y;*/

    }
    outfile.close();
    return ans;
}



// Driver code
int main() {
    //Segment arr[] = { {{1, 5}, {4, 5}}, {{2, 5}, {10, 1}},{{3, 2}, {10, 3}},{{6, 4}, {9, 4}},{{7, 1}, {8, 1}} };
    //Segment arr[] = { {{1, 0}, {1, 1}}, {{1,0}, {5,5}}};
    

    Segment arr[2];
    arr[0].left.x = 1;
    arr[0].left.y = 0;
    arr[0].right.x =5;
    arr[0].right.y = 5;
    arr[1].left.x = 1;
    arr[1].left.y = 1;
    arr[1].right.x =3;
    arr[1].right.y = 0;
    /*arr[2].left.x = 0;
    arr[2].left.y = 0;
    arr[2].right.x = 3;
    arr[2].right.y = 2;*/


    /*cout << sizeof(arr)<<"\n";*/
    int n = sizeof(arr) / sizeof(arr[0]);
    //cout << n;
    isIntersect(arr, n);
    /*cout << isIntersect(arr, n);*/
    

    /*读取保存那些线相交的txt文件,并将有哪些线相交记录下来,比如 第一行是3 2 表示第二条和第三条线段相交*/
    ifstream f;
    f.open("test.txt");
    string str;
    vector<vector<int> > num;
    while (getline(f, str))
    {
        istringstream input(str);
        vector<int> tmp;
        int a;
        while (input >> a)
            tmp.push_back(a);
        num.push_back(tmp);
    }
    //cout << num[1][1];

    /*END   读取保存那些线相交的txt文件*/


    for (int i = 0; i < num.size(); ++i)
    {
        //cout << num[i][1]<<"\n";
        /*比如 第一行是3 2 表示第二条和第三条线段相交,则arr[num[i][0]-1] 表示相交的第一条线段*/
        Point p1 = arr[num[i][0]-1].left;
        Point q1 = arr[num[i][0]-1].right;
        Point p2 = arr[num[i][1]-1].left;
        Point q2 = arr[num[i][1]-1].right;
        /*cout <<p1.x << " " << p1.y << "\n";
        cout << q1.x << " " << q1.y << "\n";
        cout << p2.x << " " << p2.y << "\n";
        cout << q2.x << " " << q2.y << "\n";*/

        //cout << typeid(arr[num[i][0]].left.x).name();
        struct Point respoint = intersectionaxis( p1,  q1,  p2,  q2);
            cout << respoint.x << " " << respoint.y<<"\n";
        
    }


    //cout << (arr[1].right.x);
    system("pause");
    return 0;
}
/*#####################################################################################################################
#####################################################################################################################
#####################################################################################################################*/




 方法二:

```cpp
#include <iostream>
#include <cmath>
#include <cassert>
using namespace std;

/** Calculate determinant of matrix:
	[a b]
	[c d]
*/

struct Point
{
	double x, y;
};
inline double Det(double a, double b, double c, double d)
{
	return a * d - b * c;
}

/// Calculate intersection of two lines.
Point LineLineIntersect(Point p1, // Line 1 start
		Point q1, // Line 1 end
		Point p2, // Line 2 start
		Point q2, // Line 2 end
	double& ixOut, double& iyOut) // Output 
{
	Point respoint;
	double x1 = p1.x;
	double y1= q1.y;
	double x2 = q1.x;
	double y2 = q1.y;
	double x3 = p2.x;
	double y3 = p2.y;
	double x4 = q2.x;
	double y4 = q2.y;

	double detL1 = Det(x1, y1, x2, y2);
	double detL2 = Det(x3, y3, x4, y4);
	double x1mx2 = x1 - x2;
	double x3mx4 = x3 - x4;
	double y1my2 = y1 - y2;
	double y3my4 = y3 - y4;

	double denom = Det(x1mx2, y1my2, x3mx4, y3my4);
	if (denom == 0.0) // Lines don't seem to cross
	{
		ixOut = NAN;
		iyOut = NAN;
		respoint.x= ixOut;
		respoint.y = iyOut;
		//return false;
	}
	double xnom = Det(detL1, x1mx2, detL2, x3mx4);
	double ynom = Det(detL1, y1my2, detL2, y3my4);
	ixOut = xnom / denom;
	iyOut = ynom / denom;
	if (!isfinite(ixOut) || !isfinite(iyOut)) { // Probably a numerical issue
		//return false;
		respoint.x = NAN;
		respoint.y = NAN;
	}
	//return true; //All OK
	respoint.x = ixOut;
	respoint.y = iyOut;
 return respoint;
}

int main()
{
	// **Simple crossing diagonal lines**

	// Line 1
	Point p1;
	Point q1; 
	Point p2;
	Point q2;
	double x1 = 0.0, y1 = 1.0;
	double x2 = 5.0, y2 = 1.0;

	// Line 2
	double x3 = 1.0, y3 = 0.0;
	double x4 = 1.0, y4 = 5.0;
	double ix = -1.0, iy = -1.0;

	 p1.x= x1;
     q1.y= y1;
	 q1.x= x2;
	 q1.y=y2;
	 p2.x= x3 ;
	 p2.y= y3;
	 q2.x= x4;
	 q2.y= y4;

	
	Point respoint = LineLineIntersect(p1,q1,p2,q2, ix, iy);
	cout << respoint.x << "," << respoint.y << endl;

	//double eps = 1e-6;
	/*assert(result == true);
	assert(fabs(ix - 5.0) < eps);
	assert(fabs(iy - 5.0) < eps);*/
	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值