#include "stdafx.h"
#include "topologicalanalysis.h"


TopologicalAnalysis::TopologicalAnalysis(void)
{
}


TopologicalAnalysis::~TopologicalAnalysis(void)
{
}


bool TopologicalAnalysis::isPointInLine(double* point, double* startPoint, double* endPoint,float tolerance)
{
	double AX = startPoint[0];
	double AY = startPoint[1];
	double BX = endPoint[0];
	double BY = endPoint[1];
	double PX = point[0];
	double PY = point[1];

	double dx_AB = AX - BX;
	double dy_AB = AY - BY;
	double dx_PA = PX - AX;
	double dy_PA = PY - AY;
	double dx_PB = PX - BX;
	double dy_PB = PY - BY;

	double AB = sqrt(dx_AB*dx_AB + dy_AB*dy_AB);
	double PA = sqrt(dx_PA*dx_PA + dy_PA*dy_PA);
	double PB = sqrt(dx_PB*dx_PB + dy_PB*dy_PB);
	double rate = abs(PA + PB - AB) / AB;
	if (rate < tolerance)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//ÅжÏÏßÊÇ·ñÔÚÕÛÏßÉÏ
int TopologicalAnalysis::isPointInPolyLine(double* point, vector<double>& lineX,vector<double>& lineY,float tolerance)
{
	int lineNum = lineX.size();
	double startPoint[2],endPoint[2];
	for (int i=0;i<lineNum-1;i++)
	{
		startPoint[0] = lineX.at(i);
		startPoint[1] = lineY.at(i);
		endPoint[0] = lineX.at(i+1);
		endPoint[1] = lineY.at(i+1);
		bool b_in = isPointInLine(point,startPoint,endPoint,tolerance);
		if(b_in)
		{
			return (i+1);
		}
	}
	//ÅжÏÊÕβµãÏß¶Î
	startPoint[0] = lineX.at(lineNum-1);
	startPoint[1] = lineY.at(lineNum-1);
	endPoint[0] = lineX.at(0);
	endPoint[1] = lineY.at(0);
	bool b_end = isPointInLine(point,startPoint,endPoint,tolerance);
	if (b_end)
	{
		return lineNum;
	}
	else
	{
		return 0;
	}
}

//¸ù¾ÝÁ½µãÇó³ö´¹Ïß¹ýµÚÈýµãµÄÖ±ÏߵĽ»µã
bool TopologicalAnalysis::GetPointToLineVerticalCross(double* linePt1,double* linePt2,double* pt,double* crossPt)
{
	//´¹Ö±Ïß
	if (linePt1[0] == linePt2[0])
	{
		crossPt[0] = linePt1[0];
		crossPt[1] = pt[1];
		return true;
	}
	//ˮƽÏß
	if (linePt1[1] == linePt2[1])
	{
		crossPt[0] = pt[0];
		crossPt[1] = linePt1[1];
		return true;
	}
	float A = (linePt1[1]- linePt2[1]) * 1.0 / (linePt1[0]- linePt2[0]);
	float B = (linePt1[1] - A * linePt1[0]);
	float m = pt[0] + A * pt[1];

	/// ÇóÁ½Ö±Ïß½»µã×ø±ê
	crossPt[0] = (m - A * B) * 1.0f / (A * A + 1);
	crossPt[1] = A * crossPt[0] + B;
	return true;
}

//ÅжϵãÊÇ·ñÔÚ(¼òµ¥)¶à±ßÐÎÄÚ
//polygon: Ê×βÏàͬµÄCpoint1Áбí
bool TopologicalAnalysis::isPointInPolygon(CPoint1 point, vector<CPoint1> polygon){
	if (polygon.size()<=3) return false;	// Ò»¸öÓÐЧ¶à±ßÐζ¥µãÊýÓ¦´óÓÚ3

	int LineNum = polygon.size();
	CPoint1 leftP = point;
	CPoint1 rightP;
	rightP.SetX(getMaxX(polygon) + 1);
	rightP.SetY(point.GetY());
	int count = 0, yPrev = polygon[LineNum - 2].GetY();
	CPoint1 v1, v2;
	v1 = polygon[LineNum - 1];
	for (int i = 0; i < LineNum; i++)
	{
		v2 = polygon[i];

		if (isPointInLine(leftP, v1, v2))
			return true;

		if (v1.GetY() != v2.GetY())
		{
			if (isLineIntersect(v1, v2, leftP, rightP))
			{
				if (isPointInLine(v1, leftP, rightP))
				{
					if (v1.GetY()<v2.GetY()) { if (v1.GetY()>yPrev)  count++; }
					else { if (v1.GetY() < yPrev) count++; }
				}
				else if (!isPointInLine(v2, leftP, rightP))
				{
					count++;
				}
			}
		}
		yPrev = v1.GetY();

		v1 = v2;
	}
	return   (count % 2 == 1);
}

double TopologicalAnalysis::getMaxX(vector<CPoint1> points){
	if (points.size()==0)
		return -1;
	else if(points.size()==1)
		return points[0].GetX();
	else{
		double maxx = points[0].GetX();
		for (unsigned i=1; i<points.size();i++)
		{
			if(points[i].GetX()>maxx){
				maxx = points[i].GetX();
			}
		}
		return maxx;
	}
}

bool  TopologicalAnalysis::isPointInLine(CPoint1 point, CPoint1 startPoint, CPoint1 endPoint)
{
	long AX = startPoint.GetX();
	long AY = startPoint.GetY();
	long BX = endPoint.GetX();
	long BY = endPoint.GetY();
	long PX = point.GetX();
	long PY = point.GetY();

	double dx_AB = AX - BX;
	double dy_AB = AY - BY;
	double dx_PA = PX - AX;
	double dy_PA = PY - AY;
	double dx_PB = PX - BX;
	double dy_PB = PY - BY;

	double AB = sqrt(dx_AB*dx_AB + dy_AB*dy_AB);
	double PA = sqrt(dx_PA*dx_PA + dy_PA*dy_PA);
	double PB = sqrt(dx_PB*dx_PB + dy_PB*dy_PB);
	double rate = abs(PA + PB - AB) / AB;
	if (rate < 0.001)
	{
		return true;
	}
	else
	{
		return false;
	}
}
// ²æ»ý
double mult(CPoint1 a, CPoint1 b, CPoint1 c)  
{  
	return (a.GetX()-c.GetX())*(b.GetY()-c.GetY())-(b.GetX()-c.GetX())*(a.GetY()-c.GetY());  
}

//ÅжÏÁ½ÌõÖ±Ïß¶ÎÊÇ·ñÏཻ
bool TopologicalAnalysis::isLineIntersect(CPoint1 line1Start, CPoint1 line1End, CPoint1 line2Start, CPoint1 line2End){
	double l1sx = line1Start.GetX();
	double l1sy = line1Start.GetY();
	double l1ex = line1End.GetX();
	double l1ey = line1End.GetY();
	double l2sx = line2Start.GetX();
	double l2sy = line2Start.GetY();
	double l2ex = line2End.GetX(); 
	double l2ey = line2End.GetY();
	if ( max(l1sx, l1ex)<min(l2sx, l2ex) )  
	{  
		return false;  
	}  
	if ( max(l1sy, l1ey)<min(l2sy,l2ey) )  
	{  
		return false;  
	}  
	if ( max(l2sx, l2ex)<min(l1sx, l1ex) )  
	{  
		return false;  
	}  
	if ( max(l2sy,l2ey)<min(l1sy, l1ey) )  
	{  
		return false;  
	}  
	if ( mult(line2Start, line1End, line1Start)*mult(line1End, line2End, line1Start)<0 )  
	{  
		return false;  
	}  
	if ( mult(line1Start, line2End, line2Start)*mult(line2End, line1End, line2Start)<0 )  
	{  
		return false;  
	}  
	return true;  
}


bool TopologicalAnalysis::GetBoundingBoxVertices(const vector<double>& polygonX,const vector<double>& polygonY,vector<double>& rectangleX,vector<double>& rectangleY)
{
	if (polygonX.size()<3 || polygonY.size()<3) return false;

	//¼ÆËã×î´ó×îСxºÍy
	double minX = polygonX[0];
	double minY = polygonY[0];
	double maxX = polygonX[0];
	double maxY = polygonY[0];

	for (int i=0;i<polygonY.size();++i) {
		if (polygonX[i] < minX) minX = polygonX[i];
		if (polygonY[i] < minY) minY = polygonY[i];
		if (polygonX[i] > maxX) maxX = polygonX[i];
		if (polygonY[i] > maxY) maxY = polygonY[i];
	}

	rectangleX.push_back(minX);
	rectangleX.push_back(maxX);
	rectangleX.push_back(maxX);
	rectangleX.push_back(minX);

	rectangleY.push_back(maxY);
	rectangleY.push_back(maxY);
	rectangleY.push_back(minY);
	rectangleY.push_back(minY);
}

//¼ÆËãÖ±ÏßÓë¶à±ßÐεĽ»µã
int TopologicalAnalysis::linePolygonIntersections(const Point2D& linePt1,const Point2D& linePt2,const vector<double>& polygonX,const vector<double>& polygonY, vector<Point2D>& result)
{

	Line2D line1;
	line1.p1 = linePt1;
	line1.p2 = linePt2;
	line1.is_seg = false;
	Point2D intersectionPt;
	vector<Point2D> resPoints;
	for (int i=0;i<polygonX.size()-1;++i)
	{
		Point2D pt1,pt2;
		pt1.x = polygonX[i];
		pt1.y = polygonY[i];
		pt2.x = polygonX[i+1];
		pt2.y = polygonY[i+1];
		Line2D line2;
		line2.p1 = pt1;
		line2.p2 = pt2;
		line2.is_seg = false;

/*
		int type = isLineIntersecting(line1,line2,intersectionPt);
		if (type == 1 || type == 2) //Ïཻ»òÖØºÏ
		{
			resPoints.push_back(intersectionPt);
		}*/

/*
		if (isSegIntersect(line1,line2,intersectionPt))
		{
			line2.is_seg = true;
			if (isponl(intersectionPt,line2))
			{
				resPoints.push_back(intersectionPt);
			}	
			//resPoints.push_back(intersectionPt);
		}*/

		
		if (findIntersection(linePt1.x,linePt1.y,linePt2.x,linePt2.y,pt1.x,pt1.y,pt2.x,pt2.y,intersectionPt))
		{
			resPoints.push_back(intersectionPt);
		}
	}

	if (resPoints.size()>1)
	{
		//»ñÈ¡×î×ó»òÕß×îÓÒµÄÁ½¸öµã,ºöÂÔ°¼¶à±ßÐÎÖм佻µã
		double minX = resPoints[0].x;
		double maxX = resPoints[0].x;
		int minIndex = 0;
		int maxIndex = 0;

		for (int i=0;i<resPoints.size();++i) {
			if (resPoints[i].x < minX) minIndex = i;
			if (resPoints[i].x > maxX) maxIndex = i;
		}
		result.push_back(resPoints[minIndex]);
		result.push_back(resPoints[maxIndex]);
	}

	return resPoints.size();

}

// ÅжÏÁ½ÌõÏß¶ÎÊÇ·ñÏཻ
int TopologicalAnalysis::isLineIntersecting(const Line2D& l1, const Line2D& l2, Point2D& intersection) {
	float  numera = (l2.p2.x-l2.p1.x) * (l1.p1.y-l2.p1.y) - (l2.p2.y-l2.p1.y) * (l1.p1.x-l2.p1.x);
	float  numerb = (l1.p2.x-l1.p1.x) * (l1.p1.y-l2.p1.y) - (l1.p2.y-l1.p1.y) * (l1.p1.x-l2.p1.x);

	float  denom  = (l2.p2.y-l2.p1.y) * (l1.p2.x-l1.p1.x) - (l2.p2.x-l2.p1.x) * (l1.p2.y-l1.p1.y);

	if(denom == 0.0f)
	{
		if(numera == 0.0f && numerb == 0.0f)
		{
			intersection.x = l2.p2.x;
			intersection.y = l2.p2.y;
			return 2; //ÖØºÏ
		}
		return 3; //ƽÐÐ
	}

	float ua = numera / denom;
	float ub = numerb / denom;

	if(ua >= 0.0f && ua <= 1.0f && ub >= 0.0f && ub <= 1.0f)
	{
		intersection.x = l1.p1.x + ua*(l1.p2.x - l1.p1.x);
		intersection.y = l1.p1.y + ua*(l1.p2.y - l1.p1.y);

/*
		double a1 = l1.p2.y - l1.p1.y;
		double b1 = l1.p1.x - l1.p2.x;
		double c1 = l1.p2.x * l1.p1.y - l1.p1.x * l1.p2.y;

		double a2 = l2.p2.y - l2.p1.y;
		double b2 = l2.p1.x - l2.p2.x;
		double c2 = l2.p2.x * l2.p1.y - l2.p1.x * l2.p2.y;
		double det = a1 * b2 - a2 * b1;

		intersection.x = (b2 * c1 - b1 * c2) / det;
		intersection.y = (a1 * c2 - a2 * c1) / det;*/

		return 1; //Ïཻ
	}

	return 0; //²»Ïཻ
}

//¼ÆËã¶à±ßÐÎ×îС¿í¶È
int TopologicalAnalysis::getLineWithPolygonMinWidth(const vector<double>& polygonX,const vector<double>& polygonY)
{
	int n = polygonX.size();
	double minWidth = INT64_MAX;
	int lineID = 0;

	for (int i=0;i<n-1;++i) //±éÀúÿһÌõ±ß
	{
		int startID = i;
		int endID = i + 1;
		double width = 0;
		for (int j=0;j<n-1;++j) //¼ÆËã³ý±ßÁ½¸ö¶¥µãÍâ¶à±ßÐÎÆäËû¶¥µãµ½Ö±ÏߵľàÀë
		{
			if(startID == j || endID == j || (endID== n-1 && j==0)) continue;
			//¼ÆËã´¹×ãµã
			double linePt1[2] = {polygonX[startID],polygonY[startID]};
			double linePt2[2] = {polygonX[endID],polygonY[endID]};
			double targetPt[2] = {0.0,0.0};
			double pt[2] = {polygonX[j],polygonY[j]};
			GetPointToLineVerticalCross(linePt1,linePt2,pt,targetPt);
			//¼ÆËã¾àÀë
			double dist;
			CalculateTwoPtsDistance(dist,pt[0],pt[1],targetPt[0],targetPt[1],3);
			if(dist > width) width = dist;
		}
		if(width < minWidth)
		{
			minWidth = width;
			lineID = startID;
		}
	}
	
	return lineID;
}

//ÅжϵãÓëÖ±ÏßµÄλÖùØÏµ
int TopologicalAnalysis::pointPosition(const Point2D& pt,const Line2D& line)
{
	double cross = crossProduct(line.p1, line.p2, pt);
	if (cross > 0) {
		return 1; //×ó²à
	} else if (cross < 0) {
		return -1; //ÓÒ²à
	} else {
		return 0; //ÏßÉÏ
	}
}


// ÅжϵãPÊÇ·ñÔÚ¶à±ßÐÎpolygonÄÚ
bool TopologicalAnalysis::isPointInPolygon(const Point2D& P, vector<double>& regionLons,vector<double>& regionLats) {
	int n =  regionLons.size();
	bool inside = false;
	double xints;
	for(int i=0, j=n-1; i<n; j=i++) {
		double xi =  regionLons[i], yi = regionLats[i];
		double xj =  regionLons[j], yj = regionLats[j];

		// µãÔÚ¶à±ßÐεĶ¥µãÉÏÒ²ÊÇÒ»ÖÖÌØÊâÇé¿ö£¬ÕâÀï¼ò»¯´¦Àíδ°üº¬
		// ¼ì²éÉäÏßÊÇ·ñÓ뵱ǰ±ßÏཻ
		if(((yi > P.y) != (yj > P.y)) && // ±ßµÄÁ½¶ËµãÔÚÉäÏßÁ½²à
			(P.x < (xj - xi) * (P.y - yi) / (yj - yi) + xi)) { // ÉäÏßÓë±ßÏཻµÄÌõ¼þ
				inside = !inside; // ½»µãÊý¼ÓÒ»£¬¸Ä±äinside״̬
		}
	}
	return inside;
}

//Ö±ÏßÓëÏ߶εĽ»µã
bool TopologicalAnalysis::findIntersection(double x1, double y1, double x2, double y2, // Ö±Ïß1µÄÁ½¸öµã
	double x3, double y3, double x4, double y4,Point2D& intersection) { // Ï߶εÄÁ½¸ö¶Ëµã
		// ¼ÆËãÖ±Ïß1µÄ·½ÏòÏòÁ¿
		double dx1 = x2 - x1;
		double dy1 = y2 - y1;

		// ¼ÆËãÏ߶εķ½ÏòÏòÁ¿
		double dx2 = x4 - x3;
		double dy2 = y4 - y3;

		// ¼ÆËãÏòÁ¿»ý£¬ÅжÏÊÇ·ñƽÐУ¨¼´ÎÞ½»µã£©
		double cross = -dx1 * dy2 + dy1 * dx2;
		if (cross == 0) return false;

		// ¼ÆËã²ÎÊýt1£¨Ö±Ïß1Éϵĵ㣩ºÍt2£¨Ïß¶ÎÉϵĵ㣩
		double t1 = (dx2 * (y3 - y1) - dy2 * (x3 - x1)) / cross;
		double t2 = (dx1 * (y3 - y1) - dy1 * (x3 - x1)) / cross;

		// ÅжÏt2ÊÇ·ñÔÚÏß¶ÎÉÏ
		if (t2 >= 0 && t2 <= 1) {
			// ¼ÆËã²¢·µ»Ø½»µã×ø±ê
			intersection.x = x1 + t1 * dx1;
			intersection.y = y1 + t1 * dy1;
			return true;
		} else {
			// Èç¹ût2²»ÔÚ[0, 1]Çø¼äÄÚ£¬ËµÃ÷²»ÏཻÓÚÏß¶ÎÉÏ
			return false;
		}
}