# coding=utf-8
#author:        4N
#createtime:    2022/3/8
#email:         nheweijun@sina.com


from osgeo import ogr
from osgeo.ogr import *
import math
import os
import copy
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"

from test.zonghe.ShapeData import ShapeData
from test.zonghe.ConcaveHull import concaveHull
import numpy as np

class Zonghe:

    data:ShapeData
    area_threshold = 100.0
    buffer_threshold = 100.0
    distance_buffer_threshold = 2.114691025217302e-04

    def __init__(self,data):
        self.data = data


    def creat_point(self,tuple):
        p: Geometry = ogr.Geometry(ogr.wkbPoint)
        p.AddPoint(tuple[0], tuple[1])
        return p



    def merge2(self,p1,p2):

        polygons = []
        points = []

        for p in [p1,p2]:

            if p.GetGeometryCount() == 1:
                polygon_line: Geometry = ogr.ForceToLineString(p)
            # 有孔Polygon
            else:
                polygon_line: Geometry = ogr.ForceToLineString(p.GetGeometryRef(0))

            points.extend(polygon_line.GetPoints()[:-1])

        multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint)


        for p in  points:
            poi = ogr.Geometry(ogr.wkbPoint)
            poi.AddPoint(p[0],p[1])
            multipoint.AddGeometry(poi)

        delauney: Geometry = multipoint.DelaunayTriangulation()
        merge_polygon = None

        for p in delauney:

            p_c = p.Centroid()

            # print("\"" + p_c.ExportToWkt() + "\",")
            if p1.Contains(p) or p2.Contains(p):
                continue
            print("\"" + p.ExportToWkt() + "\",")


        return polygons


    def merge(self,p1,p2):



        if p1.GetGeometryCount() == 1:
            polygon_line1: Geometry = ogr.ForceToLineString(p1)
        # 有孔Polygon
        else:
            polygon_line1: Geometry = ogr.ForceToLineString(p1.GetGeometryRef(0))


        p1_points =   polygon_line1.GetPoints()[:-1]

        if p2.GetGeometryCount() == 1:
            polygon_line2: Geometry = ogr.ForceToLineString(p2)
        # 有孔Polygon
        else:
            polygon_line2: Geometry = ogr.ForceToLineString(p2.GetGeometryRef(0))

        p2_points = polygon_line2.GetPoints()[:-1]


        multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint)




        for p in p1_points:

            p_t = False
            for pp in p2_points:
                line = ogr.Geometry(ogr.wkbLineString)
                line.AddPoint(p[0], p[1])
                line.AddPoint(pp[0], pp[1])

                ggg:Geometry = line.Intersection(p1)


                if ggg.GetGeometryType() in [1,-2147483647,3001]:
                    p_t = True
                    break
            if p_t:
                pppp = ogr.Geometry(ogr.wkbPoint)
                pppp.AddPoint(p[0],p[1])

                multipoint.AddGeometry(pppp)

        for p in p2_points:

            p_t = False
            for pp in p1_points:
                line = ogr.Geometry(ogr.wkbLineString)
                line.AddPoint(p[0], p[1])
                line.AddPoint(pp[0], pp[1])

                ggg:Geometry = line.Intersection(p2)


                if ggg.GetGeometryType() in [1,-2147483647,3001]:
                    p_t = True
                    break
            if p_t:
                pppp = ogr.Geometry(ogr.wkbPoint)
                pppp.AddPoint(p[0],p[1])
                multipoint.AddGeometry(pppp)


        delauney: Geometry = multipoint.DelaunayTriangulation()
        merge_polygon = None

        for p in delauney:

            print("\"" + p.ExportToWkt() + "\",")



        return None

    def merge3(self,polygons,distance_threshold):

        merge_raw :Geometry = polygons[0]
        for p in polygons:
            merge_raw = merge_raw.Union(p)


        points = []

        for i in range(merge_raw.GetGeometryCount()):

            poly = merge_raw.GetGeometryRef(i)
            if poly.GetGeometryCount() == 1:
                poly_line: Geometry = ogr.ForceToLineString(poly)
            # 有孔Polygon
            else:
                poly_line: Geometry = ogr.ForceToLineString(poly.GetGeometryRef(0))


            for indx in range(poly_line.GetPointCount() -1) :
                poi = poly_line.GetPoint(indx)

                points.append(poi)

                poi_next = poly_line.GetPoint(indx+1)

                dis = math.sqrt(math.pow(poi[0] - poi_next[0],2) + math.pow(poi[1] - poi_next[1],2))
                # print(dis)
                if dis > distance_threshold:
                    times = int(dis/distance_threshold)
                    # print(times)
                    for time in range(1,times+1):
                        x,y = self.get_radline(poi[0],poi[1],poi_next[0],poi_next[1],(time*distance_threshold))
                        points.append([x,y])

        points = np.array([[p[0],p[1]] for p in points])


        for pp in points:
            poi = ogr.Geometry(ogr.wkbPoint)
            poi.AddPoint(pp[0],pp[1])
            print("\"" + poi.ExportToWkt() + "\",")


        merge_p_line = concaveHull(points, 3)


        ring = ogr.Geometry(ogr.wkbLinearRing)

        merge_p = ogr.Geometry(ogr.wkbPolygon)


        for l in merge_p_line:
            ring.AddPoint(l[0], l[1])

        ring.AddPoint(merge_p_line[0][0], merge_p_line[0][1])

        merge_p.AddGeometry(ring)


        # for p in polygons:
        #
        #     merge_p = merge_p.Union(p)
        #
        #
        #
        # print(merge_p)

        return [merge_p.ExportToWkt()]


    def get_radline(self,x0,y0,x1,y1,len_size):

        len_size = len_size
        tanx = abs(y1-y0) / abs(x1-x0)
        cosx = 1 / math.sqrt(1 + tanx *tanx)
        dx = cosx* len_size
        dy = tanx * dx

        if x1 == x0:
            x2 = x0
            if y1 > y0 :
                y2 = y0 + abs(dy)
            else:
                y2 = y0 - abs(dy)
        else:
            if x1 < x0:
                x2 = x0 - dx
            else:
                x2 = x0 + dx

            if y1 < y0:
                y2 = y0 - dy
            else:
                y2 = y0 + dy

        return x2,y2

    def merge4(self,polygons):


        mp: Geometry = ogr.Geometry(ogr.wkbMultiPolygon)
        for p in polygons:
            mp.AddGeometry(p)



        delauney: Geometry = mp.DelaunayTriangulation()


        return [p.ExportToWkt() for p in delauney]

    def merge5(self,p1:Geometry,p2):



        ext = p1.GetEnvelope()

        tor = min(ext[1]-ext[0],ext[3]-ext[2])

        pp = p1.Simplify(tor/20)

        pp2 = p2.Simplify(tor / 20)

        return [pp.ExportToWkt(),pp2.ExportToWkt() ]


    def process(self):
        polygons = self.data.get_polygons()

        # return self.merge3(polygons,0.00007)

        return self.merge4(polygons)


if __name__ == '__main__':


    # print(sd.get_polygons()[0])
    # sd.close()

    # create = True
    # create = False
    #
    # if create:
    #
    #     sd = ShapeData(r"J:\Data\制图综合\me.shp")
    #
    #     ext =  sd.layer.GetExtent()
    #     threshold = (ext[1]-ext[0])/20
    #     print(threshold)
    #
    #
    #     zh = Zonghe(sd)
    #     zh.process()
    # else:
    #     wkts = ["POLYGON ((113.371086251 22.5101043861001,113.371311338 22.5099257505,113.371611445 22.5098560668001,113.371450698 22.5095291511,113.370775465 22.5096884259,113.371086251 22.5101043861001))"
    #             ]
    #     result = r"J:\Data\制图综合\mes.shp"
    #     ShapeData.create_shp_fromwkts(result,"zh",wkts)
    #


    sd = ShapeData(r"J:\Data\制图综合\concave5.shp")

    ext =  sd.layer.GetExtent()
    threshold = (ext[1]-ext[0])/20
    print(threshold)


    zh = Zonghe(sd)
    wkts = zh.process()

    result = r"J:\Data\制图综合\concave5_merge.shp"
    ShapeData.create_shp_fromwkts(result,"zh",wkts)