#pragma once
#include <vector>
#include "point.h"
#include <cmath>
#include <algorithm>
#include <limits>
#include "geocompute.h"
#include <cstdint>
using namespace std;

struct Point2D {
	//double x, y;
	double x;	// x坐标
	double y;	// y坐标
	double z;	// z坐标(默认为0,如果需要三维点则给z赋值)

	Point2D(double a = 0, double b = 0, double c = 0) { x = a; y = b; z = c; } // 构造函数
};

struct Line2D {
	//Point2D p1, p2;
	Point2D p1;	// 起点
	Point2D p2;	// 终点
	bool is_seg; // 是否是线段

	Line2D() {};	// 默认构造函数
	Line2D(Point2D a, Point2D b, bool _is_seg = true) { p1 = a; p2 = b; is_seg = _is_seg; }	// 构造函数(默认是线段)
};

struct Rectangle2D {
	Point2D vertices[4];
	double area() const {
		double width = std::sqrt(std::pow(vertices[1].x - vertices[0].x, 2) + std::pow(vertices[1].y - vertices[0].y, 2));
		double height = std::sqrt(std::pow(vertices[2].x - vertices[1].x, 2) + std::pow(vertices[2].y - vertices[1].y, 2));
		return width * height;
	}
};

class TopologicalAnalysis
{
public:
	TopologicalAnalysis(void);
	~TopologicalAnalysis(void);

	bool isPointInLine(double* point, double* startPoint, double* endPoint,float tolerance=0.001);

	// 判断点是否在线上
	int isPointInPolyLine(double* point, vector<double>& lineX,vector<double>& lineY,float tolerance=0.001);
	bool isPointInLine(CPoint1 point, CPoint1 startPoint, CPoint1 endPoint);

	//根据两点求出垂线过第三点的直线的交点
	bool GetPointToLineVerticalCross(double* linePt1,double* linePt2,double* pt,double* crossPt);

	//判断点是否在多边形内,交点法
	bool isPointInPolygon(CPoint1 point, vector<CPoint1> polygon);
	
	//判断两条直线段是否相交
	bool isLineIntersect(CPoint1 line1Start, CPoint1 line1End, CPoint1 line2Start, CPoint1 line2End);

	// 计算两点的欧式距离, 未实现
	double getDistance(CPoint1 point1, CPoint1 point2);

	//计算一组CPoint1的最大X
	double getMaxX(vector<CPoint1> points);

	//获取多边形外包矩形
	bool GetBoundingBoxVertices(const vector<double>& polygonX,const vector<double>& polygonY,vector<double>& rectangleX,vector<double>& rectangleY);

	//计算直线与多边形的交点
	int linePolygonIntersections(const Point2D& linePt1,const Point2D& linePt2,const vector<double>& polygonX,const std::vector<double>& polygonY,std::vector<Point2D>& result);

	/** 计算多边形最小宽度对应的边
	 * param: polygonX,polygonY,多边形顶点坐标(首尾坐标相同)
	 * return: 返回线段起始点ID号
	 */
	int getLineWithPolygonMinWidth(const vector<double>& polygonX,const vector<double>& polygonY);

	//判断点与直线的位置关系
	int pointPosition(const Point2D& pt,const Line2D& line);

	// 判断点P是否在多边形polygon内
	bool isPointInPolygon(const Point2D& P, vector<double>& regionLons,vector<double>& regionLats);
private:
	// 判断两条线段是否相交   
	int isLineIntersecting(const Line2D& l1, const Line2D& l2, Point2D& intersection);

	//数学计算
private:
	//计算两点(向量)的点积
	double dotProduct(const Point2D& p1, const Point2D& p2) {
		return p1.x * p2.x + p1.y * p2.y;
	}
	//计算两个点(向量)之间的差向量
	Point2D subtract(const Point2D& p1, const Point2D& p2) {
		Point2D point;
		point.x = p1.x - p2.x;
		point.y = p1.y - p2.y;
		return point;
	}

	//计算向量叉积
	double crossProduct(const Point2D& A, const Point2D& B, const Point2D& P) {
		return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x);
	}

/*
	double length(const Point2D& p) {
		return std::sqrt(p.x * p.x + p.y * p.y);
	}*/

/*
	Point2D normalize(const Point2D& p) {
		double len = length(p);
		Point2D pt;
		pt.x = p.x / len;
		pt.y = p.y / len;
		return pt;
	}*/

private:
	// 点的加法
	Point2D add(const Point2D& lhs, const Point2D& rhs)
	{
		Point2D res;

		res.x = lhs.x + rhs.x;
		res.y = lhs.y + rhs.y;
		res.z = lhs.z + rhs.z;

		return res;
	}
	// 点的减法
	Point2D sub(const Point2D& lhs, const Point2D& rhs)
	{
		Point2D res;

		res.x = lhs.x - rhs.x;
		res.y = lhs.y - rhs.y;
		res.z = lhs.z - rhs.z;

		return res;
	}
	// 向量的乘法
	Point2D mul(const Point2D& p, double ratio)
	{
		Point2D res;

		res.x = p.x * ratio;
		res.y = p.y * ratio;
		res.z = p.z * ratio;

		return res;
	}
	// 向量的除法
	Point2D div(const Point2D& p, double ratio)
	{
		Point2D res;

		res.x = p.x / ratio;
		res.y = p.y / ratio;
		res.z = p.z / ratio;

		return res;
	}

	// 点判断相等
	bool equal(const Point2D& lhs, const Point2D& rhs)
	{
		return(lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z);
	}

	// 1.3、矢量标准化(矢量的长度规约到1)
	//
	// 参数: vec : 矢量
	//
	Point2D normalize(const Point2D& vec)
	{
		Point2D res;

		res = div(vec, length(vec));

		return res;
	}

	// 1.9、点是否在线上
	// 线分为直线和线段,直线表示的是直线是否经过点
	//
	// 参数:p : 点  l : 线段或者线
	// 
	bool isponl(const Point2D& p, const Line2D& l)
	{
		Point2D line_vec = sub(l.p2, l.p1);
		Point2D point_vec1 = sub(p, l.p1);
		Point2D point_vec2 = sub(p, l.p2);

		Point2D mul_vec = multiply(line_vec, point_vec1);
		double dot = dotMultiply(point_vec1, point_vec2);
		// 点是否在线段上
		if (l.is_seg)
		{
			if (equal(p, l.p1) || equal(p, l.p2))
				return true;
			return (0.0 == length(mul_vec) && dot < 0.0);

		}
		// 点是否在直线上
		else
		{
			return (0.0 == length(mul_vec));
		}
	}

	// 1.4、矢量点乘
	//
	// 参数:(p1-op)为矢量1,(p2-op)为矢量2
	//
	double dotMultiply(const Point2D& op, const Point2D& p1, const Point2D& p2)
	{
		return ((p1.x - op.x) * (p2.x - op.x) + (p1.y - op.y) * (p2.y - op.y) + (p1.z - op.z) * (p2.z - op.z));
	}
	// 参数:vec1为矢量1,vec2为矢量2
	//
	double dotMultiply(const Point2D& vec1, const Point2D& vec2)
	{
		return(vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z);
	}

	// 1.5、矢量叉乘
	//
	// 参数:(p1-op)为矢量1,(p2-op)为矢量2
	// 
	Point2D multiply(const Point2D& op, const Point2D& p1, const Point2D& p2)
	{
		Point2D result;

		result.x = (p1.y - op.y) * (p2.z - op.z) - (p2.y - op.y) * (p1.z - op.z);
		result.y = (p1.z - op.z) * (p2.x - op.x) - (p2.z - op.z) * (p1.x - op.x);
		result.z = (p1.x - op.x) * (p2.y - op.y) - (p2.x - op.x) * (p1.y - op.y);

		return result;
	}

	// 参数: vec1为矢量1,vec2为矢量2
	//
	Point2D multiply(const Point2D& vec1, const Point2D& vec2)
	{
		Point2D result;

		result.x = vec1.y * vec2.z - vec2.y * vec1.z;
		result.y = vec1.z * vec2.x - vec2.z * vec1.x;
		result.z = vec1.x * vec2.y - vec2.x * vec1.y;

		return result;
	}

	// 参数: vec1 矢量1  vec2 矢量2
	// 
	double Cos(const Point2D& vec1, const Point2D& vec2)
	{
		Point2D unit_vec1 = normalize(vec1);
		Point2D unit_vec2 = normalize(vec2);

		return dotMultiply(unit_vec1, unit_vec2);
	}

	// 1.2、矢量的长度
	//
	// 参数: vec 矢量
	//
	double length(const Point2D& vec)
	{
		return (sqrt(pow(vec.x, 2) + pow(vec.y, 2) + pow(vec.z, 2)));
	}




	// 计算两点之间的向量
	Point2D mathVector(const Point2D& p1, const Point2D& p2) {
		Point2D pt;
		pt.x = p2.x - p1.x;
		pt.y = p2.y - p1.y;
		return pt;
	}
	// 计算两点之间的叉积
	double crossProduct(const Point2D& p1, const Point2D& p2) {
		return p1.x * p2.y - p1.y * p2.x;
	}

	//直线与线段的交点
	bool findIntersection(double x1, double y1, double x2, double y2, // 直线1的两个点
		double x3, double y3, double x4, double y4,Point2D& intersection);

};