正在显示
28 个修改的文件
包含
3961 行增加
和
368 行删除
| @@ -205,7 +205,7 @@ class EntryDataVacuate: | @@ -205,7 +205,7 @@ class EntryDataVacuate: | ||
| 205 | 205 | ||
| 206 | # 复制原图层的属性 | 206 | # 复制原图层的属性 |
| 207 | # 去掉fid的属性 | 207 | # 去掉fid的属性 |
| 208 | - schema = [sche for sche in layer.schema if not sche.name.__eq__(fid)] | 208 | + schema = [sche for sche in layer.schema if not sche.name.lower().__eq__(fid)] |
| 209 | pg_layer.CreateFields(schema) | 209 | pg_layer.CreateFields(schema) |
| 210 | 210 | ||
| 211 | #创建抽稀过程 | 211 | #创建抽稀过程 |
| @@ -38,14 +38,7 @@ class Api(ApiTemplate): | @@ -38,14 +38,7 @@ class Api(ApiTemplate): | ||
| 38 | append_dict["sr_wkt"] = sr.ExportToWkt() | 38 | append_dict["sr_wkt"] = sr.ExportToWkt() |
| 39 | append_dict["sr_proj4"] = sr.ExportToProj4() | 39 | append_dict["sr_proj4"] = sr.ExportToProj4() |
| 40 | 40 | ||
| 41 | - srid_sql = '''select st_srid("{}") from public."{}" limit 1'''.format(layer.GetGeometryColumn(),layer.GetName()) | ||
| 42 | - srid_layer:Layer = pg_ds.ExecuteSQL(srid_sql) | ||
| 43 | - if srid_layer: | ||
| 44 | - srid_feature : Feature = srid_layer.GetNextFeature() | ||
| 45 | - if srid_feature: | ||
| 46 | - if srid_feature.GetField(0): | ||
| 47 | - append_dict["srid"] = str(srid_feature.GetField(0)) | ||
| 48 | - | 41 | + append_dict["srid"] = str(PGUtil.get_srid(pg_ds,layer.GetName())) |
| 49 | else: | 42 | else: |
| 50 | append_dict["exist"]=0 | 43 | append_dict["exist"]=0 |
| 51 | columns = table.relate_columns.order_by(Columns.name).all() | 44 | columns = table.relate_columns.order_by(Columns.name).all() |
| @@ -5,7 +5,6 @@ | @@ -5,7 +5,6 @@ | ||
| 5 | 5 | ||
| 6 | from app.models import db | 6 | from app.models import db |
| 7 | from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time,Float,Binary,Sequence | 7 | from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time,Float,Binary,Sequence |
| 8 | -from sqlalchemy import Sequence | ||
| 9 | from sqlalchemy.orm import relationship | 8 | from sqlalchemy.orm import relationship |
| 10 | import base64 | 9 | import base64 |
| 11 | from pyDes import * | 10 | from pyDes import * |
| @@ -38,7 +38,7 @@ class Api(ApiTemplate): | @@ -38,7 +38,7 @@ class Api(ApiTemplate): | ||
| 38 | map_service_update = {} | 38 | map_service_update = {} |
| 39 | 39 | ||
| 40 | for key in self.para.keys(): | 40 | for key in self.para.keys(): |
| 41 | - if key in ["name","title","state","description","overview","catalog_guid"]: | 41 | + if key in ["name","title","description","overview","catalog_guid"]: |
| 42 | service_update[key] = self.para.get(key) | 42 | service_update[key] = self.para.get(key) |
| 43 | if key in ["name","tile","project","capabilities"]: | 43 | if key in ["name","tile","project","capabilities"]: |
| 44 | map_service_update[key] = self.para.get(key) | 44 | map_service_update[key] = self.para.get(key) |
| @@ -47,7 +47,9 @@ class Api(ApiTemplate): | @@ -47,7 +47,9 @@ class Api(ApiTemplate): | ||
| 47 | "title":self.para.get("title"), | 47 | "title":self.para.get("title"), |
| 48 | "type":"mapserver", | 48 | "type":"mapserver", |
| 49 | "capabilities":2, | 49 | "capabilities":2, |
| 50 | - "project":self.para.get("project")} | 50 | + "project":self.para.get("project"), |
| 51 | + "state":service.state | ||
| 52 | + } | ||
| 51 | 53 | ||
| 52 | map_service_register_url = "{}/dmap/api/manager/regservice".format(configure.dmap_engine) | 54 | map_service_register_url = "{}/dmap/api/manager/regservice".format(configure.dmap_engine) |
| 53 | resp: requests.Response = requests.post(map_service_register_url,data=json.dumps(para), | 55 | resp: requests.Response = requests.post(map_service_register_url,data=json.dumps(para), |
| @@ -199,11 +199,16 @@ class Api(ApiTemplate): | @@ -199,11 +199,16 @@ class Api(ApiTemplate): | ||
| 199 | 199 | ||
| 200 | extent = [float(x) for x in table.extent.split(",")] | 200 | extent = [float(x) for x in table.extent.split(",")] |
| 201 | 201 | ||
| 202 | + minx = para.get("minx") | ||
| 203 | + miny = para.get("miny") | ||
| 204 | + maxx = para.get("maxx") | ||
| 205 | + maxy = para.get("maxy") | ||
| 206 | + | ||
| 202 | xml = xml_format.format(name = para.get("name"), | 207 | xml = xml_format.format(name = para.get("name"), |
| 203 | - xmin = extent[0], | ||
| 204 | - xmax = extent[1], | ||
| 205 | - ymin = extent[2], | ||
| 206 | - ymax = extent[3], | 208 | + xmin = minx if minx else extent[0], |
| 209 | + xmax = maxx if maxx else extent[1], | ||
| 210 | + ymin = miny if miny else extent[2], | ||
| 211 | + ymax = maxy if maxy else extent[3], | ||
| 207 | feature_count = table.feature_count, | 212 | feature_count = table.feature_count, |
| 208 | database_guid = table.database_guid, | 213 | database_guid = table.database_guid, |
| 209 | gemetry_type = gemetry_type, | 214 | gemetry_type = gemetry_type, |
| @@ -302,12 +307,23 @@ class Api(ApiTemplate): | @@ -302,12 +307,23 @@ class Api(ApiTemplate): | ||
| 302 | "type": "string", | 307 | "type": "string", |
| 303 | "description": "表名", | 308 | "description": "表名", |
| 304 | "required": "true"}, | 309 | "required": "true"}, |
| 305 | - | ||
| 306 | {"name": "token", | 310 | {"name": "token", |
| 307 | "in": "formData", | 311 | "in": "formData", |
| 308 | "type": "string", | 312 | "type": "string", |
| 309 | "description": "token", | 313 | "description": "token", |
| 310 | "required": "true"}, | 314 | "required": "true"}, |
| 315 | + {"name": "minx", | ||
| 316 | + "in": "formData", | ||
| 317 | + "type": "string"}, | ||
| 318 | + {"name": "miny", | ||
| 319 | + "in": "formData", | ||
| 320 | + "type": "string"}, | ||
| 321 | + {"name": "maxx", | ||
| 322 | + "in": "formData", | ||
| 323 | + "type": "string"}, | ||
| 324 | + {"name": "maxy", | ||
| 325 | + "in": "formData", | ||
| 326 | + "type": "string"}, | ||
| 311 | ], | 327 | ], |
| 312 | "responses": { | 328 | "responses": { |
| 313 | 200: { | 329 | 200: { |
| @@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
| 3 | #createtime: 2021/10/26 | 3 | #createtime: 2021/10/26 |
| 4 | #email: nheweijun@sina.com | 4 | #email: nheweijun@sina.com |
| 5 | 5 | ||
| 6 | -from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time,Float,Binary | 6 | +from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime |
| 7 | from sqlalchemy.orm import relationship | 7 | from sqlalchemy.orm import relationship |
| 8 | from app.models import db | 8 | from app.models import db |
| 9 | 9 |
| @@ -104,6 +104,7 @@ class Api(ApiTemplate): | @@ -104,6 +104,7 @@ class Api(ApiTemplate): | ||
| 104 | # 显示别名 | 104 | # 显示别名 |
| 105 | user_alias = UserAlias() | 105 | user_alias = UserAlias() |
| 106 | for service_json in res["data"]["list"]: | 106 | for service_json in res["data"]["list"]: |
| 107 | + | ||
| 107 | service_json["display_name"] = user_alias.get_alias(service_json["creator"]) | 108 | service_json["display_name"] = user_alias.get_alias(service_json["creator"]) |
| 108 | 109 | ||
| 109 | res["result"] = True | 110 | res["result"] = True |
| @@ -6,6 +6,8 @@ | @@ -6,6 +6,8 @@ | ||
| 6 | from app.util.component.ApiTemplate import ApiTemplate | 6 | from app.util.component.ApiTemplate import ApiTemplate |
| 7 | from .models import Service | 7 | from .models import Service |
| 8 | from .util.ServiceType import ServiceType | 8 | from .util.ServiceType import ServiceType |
| 9 | + | ||
| 10 | + | ||
| 9 | class Api(ApiTemplate): | 11 | class Api(ApiTemplate): |
| 10 | api_name = "注册服务" | 12 | api_name = "注册服务" |
| 11 | def process(self): | 13 | def process(self): |
| @@ -27,7 +27,6 @@ class Api(ApiTemplate): | @@ -27,7 +27,6 @@ class Api(ApiTemplate): | ||
| 27 | if service: | 27 | if service: |
| 28 | service.state = state | 28 | service.state = state |
| 29 | 29 | ||
| 30 | - | ||
| 31 | operate = "startService" if state == 1 else "stopService" | 30 | operate = "startService" if state == 1 else "stopService" |
| 32 | server_type = "tileserver" if s_type == "电子地图" else "mapserver" | 31 | server_type = "tileserver" if s_type == "电子地图" else "mapserver" |
| 33 | dmap_engine_url = "{}/dmap/api/manager/{}?servicename={}&servername={}".format(configure.dmap_engine, | 32 | dmap_engine_url = "{}/dmap/api/manager/{}?servicename={}&servername={}".format(configure.dmap_engine, |
| @@ -35,7 +35,7 @@ class Api(ApiTemplate): | @@ -35,7 +35,7 @@ class Api(ApiTemplate): | ||
| 35 | service_update = {"update_time":this_time} | 35 | service_update = {"update_time":this_time} |
| 36 | tile_update = {} | 36 | tile_update = {} |
| 37 | for key in self.para.keys(): | 37 | for key in self.para.keys(): |
| 38 | - if key in ["name","title","state","description","overview","catalog_guid"]: | 38 | + if key in ["name","title","description","overview","catalog_guid"]: |
| 39 | service_update[key] = self.para.get(key) | 39 | service_update[key] = self.para.get(key) |
| 40 | if key in ["name","tile_type","vendor","crs","datasource","description", | 40 | if key in ["name","tile_type","vendor","crs","datasource","description", |
| 41 | "layer_name","layer_alias","layer_title","layer_style","layer_format", | 41 | "layer_name","layer_alias","layer_title","layer_style","layer_format", |
| @@ -61,7 +61,8 @@ class Api(ApiTemplate): | @@ -61,7 +61,8 @@ class Api(ApiTemplate): | ||
| 61 | 61 | ||
| 62 | para = {"name":self.para.get("name") if self.para.get("name") else se.name, | 62 | para = {"name":self.para.get("name") if self.para.get("name") else se.name, |
| 63 | "title":self.para.get("title") if self.para.get("title") else se.title, | 63 | "title":self.para.get("title") if self.para.get("title") else se.title, |
| 64 | - "type":"tileserver","capabilities":1 if tile_type == "WMTS" else 16,"project":project_file} | 64 | + "type":"tileserver","capabilities":1 if tile_type == "WMTS" else 16,"project":project_file, |
| 65 | + "state": service.state} | ||
| 65 | 66 | ||
| 66 | 67 | ||
| 67 | tile_service_edit_url = "{}/dmap/api/manager/RegService".format(configure.dmap_engine) | 68 | tile_service_edit_url = "{}/dmap/api/manager/RegService".format(configure.dmap_engine) |
| @@ -7,7 +7,6 @@ from flask import current_app,request | @@ -7,7 +7,6 @@ from flask import current_app,request | ||
| 7 | import traceback | 7 | import traceback |
| 8 | import json | 8 | import json |
| 9 | from app.models import db | 9 | from app.models import db |
| 10 | -from app.modules.auth.models import OAuth2Token,User | ||
| 11 | import app | 10 | import app |
| 12 | 11 | ||
| 13 | class ApiTemplate: | 12 | class ApiTemplate: |
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | #createtime: 2021/5/24 | 3 | #createtime: 2021/5/24 |
| 4 | #email: nheweijun@sina.com | 4 | #email: nheweijun@sina.com |
| 5 | from osgeo import ogr | 5 | from osgeo import ogr |
| 6 | +from osgeo.ogr import Layer | ||
| 6 | from sqlalchemy import create_engine | 7 | from sqlalchemy import create_engine |
| 7 | from sqlalchemy.orm import sessionmaker,Session | 8 | from sqlalchemy.orm import sessionmaker,Session |
| 8 | from app.util.component.StructurePrint import StructurePrint | 9 | from app.util.component.StructurePrint import StructurePrint |
| @@ -126,16 +127,19 @@ class PGUtil: | @@ -126,16 +127,19 @@ class PGUtil: | ||
| 126 | 127 | ||
| 127 | @classmethod | 128 | @classmethod |
| 128 | def get_srid(cls,pg_ds,table_name): | 129 | def get_srid(cls,pg_ds,table_name): |
| 129 | - layer = pg_ds.GetLayerByName(table_name) | 130 | + layer:Layer = pg_ds.GetLayerByName(table_name) |
| 130 | if not layer: | 131 | if not layer: |
| 131 | return None | 132 | return None |
| 132 | - srid_sql = '''select st_srid("{}") from public."{}" limit 1'''.format(layer.GetGeometryColumn(), layer.GetName()) | 133 | + |
| 134 | + srid_sql ="SELECT srid FROM public.geometry_columns where f_table_name='{}'".format(table_name) | ||
| 135 | + | ||
| 133 | srid_layer = pg_ds.ExecuteSQL(srid_sql) | 136 | srid_layer = pg_ds.ExecuteSQL(srid_sql) |
| 134 | srid_feature = srid_layer.GetNextFeature() | 137 | srid_feature = srid_layer.GetNextFeature() |
| 135 | if srid_feature: | 138 | if srid_feature: |
| 136 | if srid_feature.GetField(0): | 139 | if srid_feature.GetField(0): |
| 137 | return int(srid_feature.GetField(0)) | 140 | return int(srid_feature.GetField(0)) |
| 138 | else: | 141 | else: |
| 142 | + | ||
| 139 | return None | 143 | return None |
| 140 | 144 | ||
| 141 | 145 |
test/MapSynthesize/Delauney.py
0 → 100644
| 1 | +# coding=utf-8 | ||
| 2 | +#author: 4N | ||
| 3 | +#createtime: 2022/3/15 | ||
| 4 | +#email: nheweijun@sina.com | ||
| 5 | + | ||
| 6 | +from osgeo import ogr | ||
| 7 | +from osgeo.ogr import * | ||
| 8 | +import math | ||
| 9 | +import os | ||
| 10 | +import copy | ||
| 11 | +from test.zonghe.RepresentPoint import RepresentPoint | ||
| 12 | +import time | ||
| 13 | + | ||
| 14 | +class DelauneyNode: | ||
| 15 | + | ||
| 16 | + def __init__(self, rp): | ||
| 17 | + self.rp = rp | ||
| 18 | + self.children_nodes = list() | ||
| 19 | + self.children_delauney_lines = list() | ||
| 20 | + | ||
| 21 | + def get_all_node(self): | ||
| 22 | + for node in self.children_nodes: | ||
| 23 | + yield node.get_all_node() | ||
| 24 | + yield self | ||
| 25 | + | ||
| 26 | + def get_rps(self): | ||
| 27 | + for node in self.children_nodes: | ||
| 28 | + for rp in node.get_rps(): | ||
| 29 | + yield rp | ||
| 30 | + yield self.rp | ||
| 31 | + | ||
| 32 | + def get_polygons(self): | ||
| 33 | + for node in self.children_nodes: | ||
| 34 | + for rp in node.get_rps(): | ||
| 35 | + yield rp.polygon | ||
| 36 | + yield self.rp.polygon | ||
| 37 | + | ||
| 38 | + def get_delauney_lines(self): | ||
| 39 | + for node in self.children_nodes: | ||
| 40 | + for ll in node.get_delauney_lines(): | ||
| 41 | + yield ll | ||
| 42 | + for l in self.children_delauney_lines: | ||
| 43 | + yield l | ||
| 44 | + | ||
| 45 | + def add_children(self,node,delauney_line): | ||
| 46 | + self.children_nodes.append(node) | ||
| 47 | + self.children_delauney_lines.append(delauney_line) | ||
| 48 | + | ||
| 49 | +class DelauneyLine: | ||
| 50 | + | ||
| 51 | + def __init__(self,rp1,rp2): | ||
| 52 | + | ||
| 53 | + self.rp1 = rp1 | ||
| 54 | + self.rp2 = rp2 | ||
| 55 | + self.distance = rp1.polygon.Distance(rp2.polygon) | ||
| 56 | + | ||
| 57 | + self.line = ogr.Geometry(ogr.wkbLineString) | ||
| 58 | + self.line.AddPoint(self.rp1.point.GetX(),self.rp1.point.GetY()) | ||
| 59 | + self.line.AddPoint(self.rp2.point.GetX(),self.rp2.point.GetY()) | ||
| 60 | + | ||
| 61 | + | ||
| 62 | +class DelauneyMinTree: | ||
| 63 | + | ||
| 64 | + def __init__(self): | ||
| 65 | + self.delauney_lines_list = list() | ||
| 66 | + self.rps = set() | ||
| 67 | + self.touch_delauney_lines = set() | ||
| 68 | + | ||
| 69 | + def append(self,delauney_line,other_delauney_lines_kv): | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + candicates = [] | ||
| 73 | + if not self.rps.__contains__(delauney_line.rp1): | ||
| 74 | + self.rps.add(delauney_line.rp1) | ||
| 75 | + | ||
| 76 | + candicates.extend(other_delauney_lines_kv.get(delauney_line.rp1)) | ||
| 77 | + | ||
| 78 | + if not self.rps.__contains__(delauney_line.rp2): | ||
| 79 | + self.rps.add(delauney_line.rp2) | ||
| 80 | + | ||
| 81 | + candicates.extend(other_delauney_lines_kv.get(delauney_line.rp2)) | ||
| 82 | + | ||
| 83 | + for candicate in candicates: | ||
| 84 | + if (candicate.rp1 in self.rps) and (candicate.rp2 in self.rps): | ||
| 85 | + #初始化 | ||
| 86 | + try: | ||
| 87 | + self.touch_delauney_lines.remove(candicate) | ||
| 88 | + except: | ||
| 89 | + print(111) | ||
| 90 | + | ||
| 91 | + else: | ||
| 92 | + self.touch_delauney_lines.add(candicate) | ||
| 93 | + | ||
| 94 | + self.delauney_lines_list.append(delauney_line) | ||
| 95 | + | ||
| 96 | + | ||
| 97 | + | ||
| 98 | + def get_rps(self): | ||
| 99 | + return self.rps | ||
| 100 | + | ||
| 101 | + | ||
| 102 | + def get_other_relate_delauney_lines(self,other_delauney_lines_kv,rps_set): | ||
| 103 | + | ||
| 104 | + other_relate_delauney_lines = [] | ||
| 105 | + | ||
| 106 | + for rp in self.rps: | ||
| 107 | + candicates = other_delauney_lines_kv.get(rp) | ||
| 108 | + candicates = [c for c in candicates if c.rp1 in rps_set or c.rp2 in rps_set] | ||
| 109 | + other_relate_delauney_lines.extend(candicates) | ||
| 110 | + | ||
| 111 | + # other_relate_delauney_lines.append() | ||
| 112 | + | ||
| 113 | + return other_relate_delauney_lines | ||
| 114 | + | ||
| 115 | + def get_other_rp(self,delauney_line): | ||
| 116 | + rp1 = delauney_line.rp1 | ||
| 117 | + rp2 = delauney_line.rp2 | ||
| 118 | + | ||
| 119 | + if not self.rps.__contains__(rp1): | ||
| 120 | + return rp1 | ||
| 121 | + if not self.rps.__contains__(rp2): | ||
| 122 | + return rp2 | ||
| 123 | + return None | ||
| 124 | + | ||
| 125 | + | ||
| 126 | + |
test/MapSynthesize/MapSynthesize.py
0 → 100644
| 1 | +# coding=utf-8 | ||
| 2 | +#author: 4N | ||
| 3 | +#createtime: 2022/3/31 | ||
| 4 | +#email: nheweijun@sina.com | ||
| 5 | + | ||
| 6 | +# coding=utf-8 | ||
| 7 | +#author: 4N | ||
| 8 | +#createtime: 2022/3/8 | ||
| 9 | +#email: nheweijun@sina.com | ||
| 10 | + | ||
| 11 | + | ||
| 12 | +from osgeo import ogr | ||
| 13 | +from osgeo.ogr import * | ||
| 14 | +import math | ||
| 15 | +import os | ||
| 16 | +import copy | ||
| 17 | +os.environ["CUDA_VISIBLE_DEVICES"] = "-1" | ||
| 18 | +from test.MapSynthesize.ShapeData import ShapeData | ||
| 19 | +from test.MapSynthesize.Delauney import DelauneyNode,DelauneyLine,DelauneyMinTree | ||
| 20 | +from test.MapSynthesize.RepresentPoint import RepresentPoint | ||
| 21 | +from test.MapSynthesize.PolygonMerge import PolygonMerge | ||
| 22 | +import cv2 | ||
| 23 | +import time | ||
| 24 | +import numpy as np | ||
| 25 | + | ||
| 26 | +class MapSynthesize: | ||
| 27 | + | ||
| 28 | + data:ShapeData | ||
| 29 | + area_threshold = 10.0 | ||
| 30 | + buffer_threshold = 100.0 | ||
| 31 | + distance_buffer_threshold = 1.114691025217302e-04 | ||
| 32 | + | ||
| 33 | + def __init__(self,data): | ||
| 34 | + self.data = data | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + #只处理Polygon,MultiPolygon要拆开 | ||
| 38 | + def get_polygon_reprecent_point(self,polygon:Geometry): | ||
| 39 | + | ||
| 40 | + polygon_env = polygon.GetEnvelope() | ||
| 41 | + | ||
| 42 | + area_thre = polygon.GetArea()/self.area_threshold | ||
| 43 | + | ||
| 44 | + line_length = math.sqrt(math.pow(polygon_env[1] - polygon_env[0],2) + math.pow(polygon_env[3] - polygon_env[2],2)) | ||
| 45 | + | ||
| 46 | + short_length = min(polygon_env[1]-polygon_env[0],polygon_env[3]-polygon_env[2]) | ||
| 47 | + | ||
| 48 | + center:Geometry = polygon.Centroid() | ||
| 49 | + # print(center) | ||
| 50 | + | ||
| 51 | + | ||
| 52 | + # 提前return | ||
| 53 | + if polygon.Contains(center): | ||
| 54 | + # print("\"" + center.ExportToWkt() + "\",") | ||
| 55 | + return RepresentPoint(center, polygon) | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + last_state = None | ||
| 59 | + line = None | ||
| 60 | + calculate_time = 0 | ||
| 61 | + | ||
| 62 | + direction = self.get_direction(polygon, center, line_length) | ||
| 63 | + | ||
| 64 | + | ||
| 65 | + in_hole = False | ||
| 66 | + in_hole_line = None | ||
| 67 | + | ||
| 68 | + | ||
| 69 | + #无孔Polygon | ||
| 70 | + if polygon.GetGeometryCount() == 1: | ||
| 71 | + polygon_line = ogr.ForceToLineString(polygon) | ||
| 72 | + | ||
| 73 | + # 有孔Polygon,要分2种情况 | ||
| 74 | + else: | ||
| 75 | + polygon_line = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 76 | + for i in range(1,polygon.GetGeometryCount()): | ||
| 77 | + hole_line = polygon.GetGeometryRef(i) | ||
| 78 | + hole_polygon : Geometry = ogr.ForceToPolygon(hole_line) | ||
| 79 | + if hole_polygon.Contains(center): | ||
| 80 | + in_hole = True | ||
| 81 | + direction = range(0,190,10) | ||
| 82 | + in_hole_line = ogr.ForceToLineString(hole_line) | ||
| 83 | + # print("in_hole") | ||
| 84 | + | ||
| 85 | + angle1,angle2=None,None | ||
| 86 | + line = None | ||
| 87 | + oneside_area, otherside_area = None,None | ||
| 88 | + for angle in direction: | ||
| 89 | + | ||
| 90 | + if in_hole: | ||
| 91 | + line = self.get_doubleline(center.GetX(),center.GetY(),angle,line_length) | ||
| 92 | + else: | ||
| 93 | + line = self.get_line(center.GetX(),center.GetY(),angle,line_length) | ||
| 94 | + | ||
| 95 | + oneside_area, otherside_area = self.jude(polygon, line, angle, line_length) | ||
| 96 | + | ||
| 97 | + | ||
| 98 | + if oneside_area > 0 and otherside_area >0: | ||
| 99 | + if abs(oneside_area-otherside_area) < area_thre: | ||
| 100 | + break | ||
| 101 | + | ||
| 102 | + if last_state is None: | ||
| 103 | + | ||
| 104 | + angle2 = angle | ||
| 105 | + | ||
| 106 | + if oneside_area == 0 and otherside_area==0: | ||
| 107 | + last_state = 0 | ||
| 108 | + else: | ||
| 109 | + last_state = 1 if oneside_area < otherside_area else -1 | ||
| 110 | + else: | ||
| 111 | + | ||
| 112 | + angle1 = angle2 | ||
| 113 | + angle2 = angle | ||
| 114 | + | ||
| 115 | + if oneside_area == 0 and otherside_area==0: | ||
| 116 | + now_state = 0 | ||
| 117 | + else: | ||
| 118 | + now_state = 1 if oneside_area < otherside_area else -1 | ||
| 119 | + | ||
| 120 | + if last_state* now_state < 0: | ||
| 121 | + # print(angle) | ||
| 122 | + break | ||
| 123 | + else: | ||
| 124 | + last_state = now_state | ||
| 125 | + | ||
| 126 | + #第一条线就是均分线 | ||
| 127 | + if angle1 is None or angle2 is None: | ||
| 128 | + pass | ||
| 129 | + else: | ||
| 130 | + #如果面积差大于阈值,二分法查找 | ||
| 131 | + if abs(oneside_area - otherside_area) > area_thre: | ||
| 132 | + line = self.division(polygon, center, in_hole, line_length, angle1, angle2, area_thre) | ||
| 133 | + | ||
| 134 | + | ||
| 135 | + # 提前return | ||
| 136 | + if in_hole: | ||
| 137 | + | ||
| 138 | + point_intersection: Geometry = line.Intersection(in_hole_line) | ||
| 139 | + plist = [] | ||
| 140 | + for i in range(point_intersection.GetGeometryCount()): | ||
| 141 | + pi = point_intersection.GetGeometryRef(i) | ||
| 142 | + plist.append(pi) | ||
| 143 | + plist_d = [(pi,center.Distance(pi)) for pi in plist] | ||
| 144 | + plist_d.sort(key=lambda x:x[1]) | ||
| 145 | + | ||
| 146 | + nearest_point= plist_d[0][0] | ||
| 147 | + firt_short_length = short_length/20.0 | ||
| 148 | + radline,other_point = self.get_radline(center.GetX(),center.GetY(),nearest_point.GetX(),nearest_point.GetY(),firt_short_length) | ||
| 149 | + # print("\"" + other_point.ExportToWkt() + "\",") | ||
| 150 | + | ||
| 151 | + | ||
| 152 | + while not polygon.Contains(other_point): | ||
| 153 | + | ||
| 154 | + firt_short_length = firt_short_length / 2 | ||
| 155 | + radline, other_point = self.get_radline(center.GetX(), center.GetY(), nearest_point.GetX(), | ||
| 156 | + nearest_point.GetY(), firt_short_length) | ||
| 157 | + | ||
| 158 | + | ||
| 159 | + | ||
| 160 | + return RepresentPoint(other_point,polygon) | ||
| 161 | + | ||
| 162 | + | ||
| 163 | + point_intersection:Geometry = line.Intersection(polygon_line) | ||
| 164 | + xlist = [] | ||
| 165 | + ylist = [] | ||
| 166 | + plist = [] | ||
| 167 | + | ||
| 168 | + for i in range(point_intersection.GetGeometryCount()): | ||
| 169 | + pi = point_intersection.GetGeometryRef(i) | ||
| 170 | + xlist.append(pi.GetX()) | ||
| 171 | + ylist.append(pi.GetY()) | ||
| 172 | + plist.append(pi) | ||
| 173 | + | ||
| 174 | + | ||
| 175 | + reprecent_point = [(min(xlist)+max(xlist))/2.0,(min(ylist)+max(ylist))/2.0] | ||
| 176 | + | ||
| 177 | + reprecent_point = self.creat_point(reprecent_point) | ||
| 178 | + | ||
| 179 | + if not polygon.Contains(reprecent_point): | ||
| 180 | + plist_d = [(pi,center.Distance(pi)) for pi in plist] | ||
| 181 | + plist_d.sort(key=lambda x:x[1]) | ||
| 182 | + reprecent_point = self.creat_point(((plist_d[0][0].GetX()+ plist_d[1][0].GetX())/2.0, (plist_d[0][0].GetY()+plist_d[1][0].GetY())/2.0)) | ||
| 183 | + | ||
| 184 | + # print("\""+reprecent_point.ExportToWkt() + "\",") | ||
| 185 | + | ||
| 186 | + rp = RepresentPoint(reprecent_point,polygon) | ||
| 187 | + | ||
| 188 | + return rp | ||
| 189 | + | ||
| 190 | + def get_line(self, x0, y0 , angle, r): | ||
| 191 | + | ||
| 192 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 193 | + line.AddPoint(x0, y0) | ||
| 194 | + hudu = angle/360.0 * 2 * math.pi | ||
| 195 | + dx = math.sin(hudu) * r | ||
| 196 | + dy = math.cos(hudu) * r | ||
| 197 | + line.AddPoint(x0+dx, y0+dy) | ||
| 198 | + | ||
| 199 | + return line | ||
| 200 | + | ||
| 201 | + def get_doubleline(self, x0, y0 , angle, r): | ||
| 202 | + | ||
| 203 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 204 | + | ||
| 205 | + hudu = angle/360.0 * 2 * math.pi | ||
| 206 | + dx = math.sin(hudu) * r | ||
| 207 | + dy = math.cos(hudu) * r | ||
| 208 | + | ||
| 209 | + hudu = (angle+180)/360.0 * 2 * math.pi | ||
| 210 | + dx2 = math.sin(hudu) * r | ||
| 211 | + dy2 = math.cos(hudu) * r | ||
| 212 | + | ||
| 213 | + line.AddPoint(x0 + dx2, y0 + dy2) | ||
| 214 | + line.AddPoint(x0+dx, y0+dy) | ||
| 215 | + | ||
| 216 | + return line | ||
| 217 | + | ||
| 218 | + def get_radline(self,x0,y0,x1,y1,len_size): | ||
| 219 | + a2 = math.pow((x1-x0),2) | ||
| 220 | + b2 = math.pow((y1-y0),2) | ||
| 221 | + len_size = len_size+ math.sqrt(a2+b2) | ||
| 222 | + | ||
| 223 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 224 | + line.AddPoint(x0, y0) | ||
| 225 | + tanx = abs(y1-y0) / abs(x1-x0) | ||
| 226 | + cosx = 1 / math.sqrt(1 + tanx *tanx) | ||
| 227 | + dx = cosx* len_size | ||
| 228 | + dy = tanx * dx | ||
| 229 | + | ||
| 230 | + if x1 == x0: | ||
| 231 | + x2 = x0 | ||
| 232 | + if y1 > y0 : | ||
| 233 | + y2 = y0 + abs(dy) | ||
| 234 | + else: | ||
| 235 | + y2 = y0 - abs(dy) | ||
| 236 | + else: | ||
| 237 | + if x1 < x0: | ||
| 238 | + x2 = x0 - dx | ||
| 239 | + else: | ||
| 240 | + x2 = x0 + dx | ||
| 241 | + | ||
| 242 | + if y1 < y0: | ||
| 243 | + y2 = y0 - dy | ||
| 244 | + else: | ||
| 245 | + y2 = y0 + dy | ||
| 246 | + | ||
| 247 | + line.AddPoint(x2, y2) | ||
| 248 | + | ||
| 249 | + other_point = ogr.Geometry(ogr.wkbPoint) | ||
| 250 | + other_point.AddPoint(x2, y2) | ||
| 251 | + | ||
| 252 | + return line , other_point | ||
| 253 | + | ||
| 254 | + def get_direction(self,polygon,center,line_length): | ||
| 255 | + ''' | ||
| 256 | + 判断旋转方向 | ||
| 257 | + :param polygon: | ||
| 258 | + :param center: | ||
| 259 | + :param line_length: | ||
| 260 | + :return: | ||
| 261 | + ''' | ||
| 262 | + | ||
| 263 | + line = self.get_line(center.GetX(),center.GetY(),0,line_length) | ||
| 264 | + | ||
| 265 | + oneside_area, otherside_area = self.jude(polygon,line,0,line_length) | ||
| 266 | + | ||
| 267 | + if oneside_area == 0 and otherside_area == 0 : | ||
| 268 | + return range(0, 390, 30) | ||
| 269 | + else: | ||
| 270 | + line = self.get_line(center.GetX(), center.GetY(), 10, line_length) | ||
| 271 | + oneside_area_contrast, otherside_area_contrast = self.jude(polygon, line, 30, line_length) | ||
| 272 | + | ||
| 273 | + if oneside_area_contrast == 0 and otherside_area_contrast == 0: | ||
| 274 | + return range(360, -30, -30) | ||
| 275 | + else: | ||
| 276 | + if abs(oneside_area - otherside_area) > abs(oneside_area_contrast - otherside_area_contrast): | ||
| 277 | + return range(0, 390, 30) | ||
| 278 | + else: | ||
| 279 | + return range(360, -30, -30) | ||
| 280 | + | ||
| 281 | + def jude(self,polygon,line,angle,line_length): | ||
| 282 | + | ||
| 283 | + line_buffer: Geometry = line.Buffer(line_length / self.buffer_threshold) | ||
| 284 | + clip_geom: Geometry = polygon.Difference(line_buffer) | ||
| 285 | + | ||
| 286 | + oneside_area = 0 | ||
| 287 | + otherside_area = 0 | ||
| 288 | + | ||
| 289 | + gc = clip_geom.GetGeometryCount() | ||
| 290 | + if gc <= 1: | ||
| 291 | + oneside_area = 0 | ||
| 292 | + otherside_area = 0 | ||
| 293 | + else: | ||
| 294 | + triangle1, triangle2 = self.get_side_triangle(line, angle) | ||
| 295 | + | ||
| 296 | + | ||
| 297 | + for gi in range(clip_geom.GetGeometryCount()): | ||
| 298 | + clip_geom_i: Geometry = clip_geom.GetGeometryRef(gi) | ||
| 299 | + it = clip_geom_i.Intersection(triangle1) | ||
| 300 | + | ||
| 301 | + if clip_geom_i.Intersect(triangle1) and it.Buffer(line_length / self.buffer_threshold).Intersect( | ||
| 302 | + line_buffer): | ||
| 303 | + oneside_area += clip_geom_i.GetArea() | ||
| 304 | + else: | ||
| 305 | + otherside_area += clip_geom_i.GetArea() | ||
| 306 | + return oneside_area, otherside_area | ||
| 307 | + | ||
| 308 | + def division(self,polygon,center,in_hole,line_length,angle1,angle2,area_thre): | ||
| 309 | + ''' | ||
| 310 | + 二分法查找 | ||
| 311 | + :param polygon: | ||
| 312 | + :param center: | ||
| 313 | + :param in_hole: | ||
| 314 | + :param line_length: | ||
| 315 | + :param angle1: | ||
| 316 | + :param angle2: | ||
| 317 | + :param area_thre: | ||
| 318 | + :return: | ||
| 319 | + ''' | ||
| 320 | + | ||
| 321 | + mid_angle = (angle1 + angle2)/2.0 | ||
| 322 | + | ||
| 323 | + | ||
| 324 | + if in_hole: | ||
| 325 | + line = self.get_doubleline(center.GetX(), center.GetY(), mid_angle, line_length) | ||
| 326 | + else: | ||
| 327 | + line = self.get_line(center.GetX(), center.GetY(), mid_angle, line_length) | ||
| 328 | + | ||
| 329 | + one,other = self.jude(polygon,line,mid_angle,line_length) | ||
| 330 | + | ||
| 331 | + while abs(one - other) > area_thre: | ||
| 332 | + if one > other: | ||
| 333 | + if angle1 > angle2: | ||
| 334 | + return self.division(polygon, center, in_hole, line_length, angle2, mid_angle, area_thre) | ||
| 335 | + else: | ||
| 336 | + return self.division(polygon, center, in_hole, line_length, mid_angle, angle1, area_thre) | ||
| 337 | + else: | ||
| 338 | + if angle1 > angle2: | ||
| 339 | + return self.division(polygon, center, in_hole, line_length, mid_angle, angle1, area_thre) | ||
| 340 | + else: | ||
| 341 | + return self.division(polygon, center, in_hole, line_length, angle2, mid_angle, area_thre) | ||
| 342 | + return line | ||
| 343 | + | ||
| 344 | + def get_side_triangle(self,line:Geometry,angle): | ||
| 345 | + ''' | ||
| 346 | + 获取方向三角形 | ||
| 347 | + :param line: | ||
| 348 | + :param angle: | ||
| 349 | + :return: | ||
| 350 | + ''' | ||
| 351 | + | ||
| 352 | + start = line.GetPoint(0) | ||
| 353 | + end = line.GetPoint(1) | ||
| 354 | + | ||
| 355 | + | ||
| 356 | + angle_t = angle-30 | ||
| 357 | + hudu = angle_t/360.0 * 2 * math.pi | ||
| 358 | + | ||
| 359 | + r = line.Length() / (2*math.cos( math.pi/6)) | ||
| 360 | + dx = math.sin(hudu) * r | ||
| 361 | + dy = math.cos(hudu) * r | ||
| 362 | + | ||
| 363 | + | ||
| 364 | + ring1 = ogr.Geometry(ogr.wkbLinearRing) | ||
| 365 | + ring1.AddPoint(start[0], start[1]) | ||
| 366 | + ring1.AddPoint(start[0] + dx, start[1] + dy) | ||
| 367 | + ring1.AddPoint(end[0], end[1]) | ||
| 368 | + ring1.AddPoint(start[0], start[1]) | ||
| 369 | + triangle1 = ogr.Geometry(ogr.wkbPolygon) | ||
| 370 | + triangle1.AddGeometry(ring1) | ||
| 371 | + | ||
| 372 | + | ||
| 373 | + angle_t = angle+30 | ||
| 374 | + hudu = angle_t/360.0 * 2 * math.pi | ||
| 375 | + | ||
| 376 | + r = line.Length() / (2*math.cos( math.pi/6)) | ||
| 377 | + | ||
| 378 | + dx = math.sin(hudu) * r | ||
| 379 | + dy = math.cos(hudu) * r | ||
| 380 | + | ||
| 381 | + ring2 = ogr.Geometry(ogr.wkbLinearRing) | ||
| 382 | + ring2.AddPoint(start[0], start[1]) | ||
| 383 | + ring2.AddPoint(start[0]+dx, start[1]+dy) | ||
| 384 | + ring2.AddPoint(end[0], end[1]) | ||
| 385 | + ring2.AddPoint(start[0], start[1]) | ||
| 386 | + triangle2 = ogr.Geometry(ogr.wkbPolygon) | ||
| 387 | + triangle2.AddGeometry(ring2) | ||
| 388 | + | ||
| 389 | + return triangle1,triangle2 | ||
| 390 | + | ||
| 391 | + def creat_point(self,tuple): | ||
| 392 | + p: Geometry = ogr.Geometry(ogr.wkbPoint) | ||
| 393 | + p.AddPoint(tuple[0], tuple[1]) | ||
| 394 | + return p | ||
| 395 | + | ||
| 396 | + def create_delauney(self,rps): | ||
| 397 | + multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) | ||
| 398 | + | ||
| 399 | + rp_dict = {} | ||
| 400 | + delauney_lines = [] | ||
| 401 | + | ||
| 402 | + rps_sub = set() | ||
| 403 | + for rp in rps: | ||
| 404 | + multipoint.AddGeometry(rp.point) | ||
| 405 | + # 多边形代表点相同,需要融合多边形 | ||
| 406 | + if rp_dict.get(rp.point.GetPoint(0).__str__()): | ||
| 407 | + rp_exist = rp_dict.get(rp.point.GetPoint(0).__str__()) | ||
| 408 | + rp_exist.polygon = rp_exist.polygon.Union(rp.polygon) | ||
| 409 | + else: | ||
| 410 | + rp_dict[rp.point.GetPoint(0).__str__()] = rp | ||
| 411 | + rps_sub.add(rp) | ||
| 412 | + | ||
| 413 | + delauney:Geometry = multipoint.DelaunayTriangulation(bOnlyEdges=True) | ||
| 414 | + | ||
| 415 | + for index in range(delauney.GetGeometryCount()): | ||
| 416 | + triangle_line:Geometry = delauney.GetGeometryRef(index) | ||
| 417 | + p = triangle_line.GetPoint(0) | ||
| 418 | + p_next = triangle_line.GetPoint(1) | ||
| 419 | + | ||
| 420 | + rp1 = rp_dict.get(p.__str__()) | ||
| 421 | + rp2 = rp_dict.get(p_next.__str__()) | ||
| 422 | + | ||
| 423 | + delauney_line = DelauneyLine(rp1,rp2) | ||
| 424 | + delauney_lines.append(delauney_line) | ||
| 425 | + | ||
| 426 | + return delauney_lines,rps_sub | ||
| 427 | + | ||
| 428 | + def create_min_delauney(self,delauney_lines,rps): | ||
| 429 | + ''' | ||
| 430 | + 使用prim算法计算最小生成树 | ||
| 431 | + :param delauney_lines: | ||
| 432 | + :param polygons: | ||
| 433 | + :return: | ||
| 434 | + ''' | ||
| 435 | + | ||
| 436 | + kv = dict() | ||
| 437 | + print(len(rps)) | ||
| 438 | + | ||
| 439 | + | ||
| 440 | + rps_set = set(rps) | ||
| 441 | + | ||
| 442 | + for delauney_line in delauney_lines: | ||
| 443 | + if kv.get(delauney_line.rp1): | ||
| 444 | + kv[delauney_line.rp1].add(delauney_line) | ||
| 445 | + else: | ||
| 446 | + kv[delauney_line.rp1] = set() | ||
| 447 | + kv[delauney_line.rp1].add(delauney_line) | ||
| 448 | + | ||
| 449 | + if kv.get(delauney_line.rp2): | ||
| 450 | + kv[delauney_line.rp2].add(delauney_line) | ||
| 451 | + else: | ||
| 452 | + kv[delauney_line.rp2] = set() | ||
| 453 | + kv[delauney_line.rp2].add(delauney_line) | ||
| 454 | + | ||
| 455 | + print(len(kv)) | ||
| 456 | + | ||
| 457 | + print("完成三角边倒排索引") | ||
| 458 | + | ||
| 459 | + #初始化树 | ||
| 460 | + delauney_lines = sorted(delauney_lines,key=lambda x:x.distance) | ||
| 461 | + delauney_min_tree = DelauneyMinTree() | ||
| 462 | + | ||
| 463 | + delauney_min_tree.append(delauney_lines[0],kv) | ||
| 464 | + | ||
| 465 | + rps_set.remove(delauney_lines[0].rp1) | ||
| 466 | + rps_set.remove(delauney_lines[0].rp2) | ||
| 467 | + | ||
| 468 | + kv[delauney_lines[0].rp1].remove(delauney_lines[0]) | ||
| 469 | + kv[delauney_lines[0].rp2].remove(delauney_lines[0]) | ||
| 470 | + | ||
| 471 | + print("完成最小生成树初始化") | ||
| 472 | + | ||
| 473 | + while rps_set.__len__()>0: | ||
| 474 | + | ||
| 475 | + print(rps_set.__len__()) | ||
| 476 | + t1 = time.time() | ||
| 477 | + # relate_delauney_line = delauney_min_tree.get_other_relate_delauney_lines(kv,rps_set) | ||
| 478 | + | ||
| 479 | + relate_delauney_line = delauney_min_tree.touch_delauney_lines | ||
| 480 | + | ||
| 481 | + | ||
| 482 | + relate_delauney_line_sort = sorted(relate_delauney_line,key=lambda x:x.distance) | ||
| 483 | + | ||
| 484 | + min_distance_line = relate_delauney_line_sort[0] | ||
| 485 | + #删除 | ||
| 486 | + other_rp = delauney_min_tree.get_other_rp(min_distance_line) | ||
| 487 | + | ||
| 488 | + if other_rp is None: | ||
| 489 | + kv[min_distance_line.rp1].remove(min_distance_line) | ||
| 490 | + kv[min_distance_line.rp2].remove(min_distance_line) | ||
| 491 | + continue | ||
| 492 | + | ||
| 493 | + delauney_min_tree.append(min_distance_line,kv) | ||
| 494 | + | ||
| 495 | + rps_set.remove(other_rp) | ||
| 496 | + | ||
| 497 | + kv[min_distance_line.rp1].remove(min_distance_line) | ||
| 498 | + kv[min_distance_line.rp2].remove(min_distance_line) | ||
| 499 | + | ||
| 500 | + # print(time.time() - t2) | ||
| 501 | + print("完成最小生成树") | ||
| 502 | + | ||
| 503 | + return delauney_min_tree | ||
| 504 | + | ||
| 505 | + def cut_delauney_min_tree(self,delauney_min_tree:DelauneyMinTree,threshold): | ||
| 506 | + | ||
| 507 | + trees = [] | ||
| 508 | + kv = {} | ||
| 509 | + | ||
| 510 | + count = 0 | ||
| 511 | + | ||
| 512 | + for delauney_line in delauney_min_tree.delauney_lines_list: | ||
| 513 | + | ||
| 514 | + dn1 = kv.get(delauney_line.rp1) | ||
| 515 | + dn2 = kv.get(delauney_line.rp2) | ||
| 516 | + | ||
| 517 | + | ||
| 518 | + if not dn1: | ||
| 519 | + dn1 = DelauneyNode(delauney_line.rp1) | ||
| 520 | + kv[delauney_line.rp1] = dn1 | ||
| 521 | + | ||
| 522 | + if not dn2: | ||
| 523 | + | ||
| 524 | + trees.append(dn1) | ||
| 525 | + | ||
| 526 | + dn2 = DelauneyNode(delauney_line.rp2) | ||
| 527 | + kv[delauney_line.rp2] = dn2 | ||
| 528 | + | ||
| 529 | + if delauney_line.distance < threshold: | ||
| 530 | + dn1.add_children(dn2,delauney_line) | ||
| 531 | + count +=1 | ||
| 532 | + | ||
| 533 | + else: | ||
| 534 | + #断开 | ||
| 535 | + trees.append(dn2) | ||
| 536 | + else: | ||
| 537 | + | ||
| 538 | + if delauney_line.distance < threshold: | ||
| 539 | + dn2.add_children(dn1,delauney_line) | ||
| 540 | + count += 1 | ||
| 541 | + else: | ||
| 542 | + trees.append(dn1) | ||
| 543 | + else: | ||
| 544 | + | ||
| 545 | + dn2 = DelauneyNode(delauney_line.rp2) | ||
| 546 | + kv[delauney_line.rp2] = dn2 | ||
| 547 | + | ||
| 548 | + if delauney_line.distance < threshold: | ||
| 549 | + dn1.add_children(dn2,delauney_line) | ||
| 550 | + count += 1 | ||
| 551 | + else: | ||
| 552 | + trees.append(dn2) | ||
| 553 | + | ||
| 554 | + | ||
| 555 | + return trees | ||
| 556 | + | ||
| 557 | + def create_polygon(self,p1,p2,p3,p4): | ||
| 558 | + | ||
| 559 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 560 | + ring.AddPoint(p1[0], p1[1]) | ||
| 561 | + ring.AddPoint(p2[0], p2[1]) | ||
| 562 | + ring.AddPoint(p3[0], p3[1]) | ||
| 563 | + ring.AddPoint(p4[0], p4[1]) | ||
| 564 | + ring.AddPoint(p1[0], p1[1]) | ||
| 565 | + | ||
| 566 | + poly = ogr.Geometry(ogr.wkbPolygon) | ||
| 567 | + poly.AddGeometry(ring) | ||
| 568 | + return poly | ||
| 569 | + | ||
| 570 | + def get_polygon_lines(self,polygon): | ||
| 571 | + #无孔Polygon | ||
| 572 | + if polygon.GetGeometryCount() in [0,1]: | ||
| 573 | + polygon_line : Geometry = ogr.ForceToLineString(polygon) | ||
| 574 | + # 有孔Polygon | ||
| 575 | + else: | ||
| 576 | + polygon_line : Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 577 | + | ||
| 578 | + return polygon_line | ||
| 579 | + | ||
| 580 | + def merge_concave(self, trees, distance_threshold): | ||
| 581 | + merge_polygons = [] | ||
| 582 | + count = 1 | ||
| 583 | + | ||
| 584 | + for tree in trees: | ||
| 585 | + print(count) | ||
| 586 | + count+=1 | ||
| 587 | + polygons = list(tree.get_polygons()) | ||
| 588 | + | ||
| 589 | + merge_raw: Geometry = polygons[0] | ||
| 590 | + for p in polygons: | ||
| 591 | + merge_raw = merge_raw.Union(p) | ||
| 592 | + | ||
| 593 | + points = [] | ||
| 594 | + | ||
| 595 | + | ||
| 596 | + for i in range(merge_raw.GetGeometryCount()): | ||
| 597 | + | ||
| 598 | + poly = merge_raw.GetGeometryRef(i) | ||
| 599 | + poly_line :Geometry = self.get_polygon_lines(poly) | ||
| 600 | + if poly_line: | ||
| 601 | + for indx in range(poly_line.GetPointCount() - 1): | ||
| 602 | + poi = poly_line.GetPoint(indx) | ||
| 603 | + | ||
| 604 | + points.append(poi) | ||
| 605 | + | ||
| 606 | + poi_next = poly_line.GetPoint(indx + 1) | ||
| 607 | + | ||
| 608 | + dis = math.sqrt(math.pow(poi[0] - poi_next[0], 2) + math.pow(poi[1] - poi_next[1], 2)) | ||
| 609 | + # print(dis) | ||
| 610 | + if dis > distance_threshold: | ||
| 611 | + times = int(dis / distance_threshold) | ||
| 612 | + # print(times) | ||
| 613 | + for time in range(1, times + 1): | ||
| 614 | + x, y = self.get_subpoint(poi[0], poi[1], poi_next[0], poi_next[1], (time * distance_threshold)) | ||
| 615 | + points.append([x, y]) | ||
| 616 | + | ||
| 617 | + points = np.array([[p[0], p[1]] for p in points]) | ||
| 618 | + | ||
| 619 | + | ||
| 620 | + cp = [] | ||
| 621 | + for pp in points: | ||
| 622 | + poi = ogr.Geometry(ogr.wkbPoint) | ||
| 623 | + poi.AddPoint(pp[0], pp[1]) | ||
| 624 | + cp.append(poi) | ||
| 625 | + | ||
| 626 | + merge_p_line = concaveHull(points, 3) | ||
| 627 | + | ||
| 628 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 629 | + | ||
| 630 | + merge_p = ogr.Geometry(ogr.wkbPolygon) | ||
| 631 | + | ||
| 632 | + for l in merge_p_line: | ||
| 633 | + ring.AddPoint(l[0], l[1]) | ||
| 634 | + | ||
| 635 | + ring.AddPoint(merge_p_line[0][0], merge_p_line[0][1]) | ||
| 636 | + | ||
| 637 | + merge_p.AddGeometry(ring) | ||
| 638 | + merge_p = merge_p.Simplify(self.distance_buffer_threshold/10) | ||
| 639 | + merge_polygons.append(merge_p) | ||
| 640 | + | ||
| 641 | + return merge_polygons | ||
| 642 | + | ||
| 643 | + def get_subpoint(self, x0, y0, x1, y1, len_size): | ||
| 644 | + | ||
| 645 | + len_size = len_size | ||
| 646 | + tanx = abs(y1 - y0) / abs(x1 - x0) | ||
| 647 | + cosx = 1 / math.sqrt(1 + tanx * tanx) | ||
| 648 | + dx = cosx * len_size | ||
| 649 | + dy = tanx * dx | ||
| 650 | + | ||
| 651 | + if x1 == x0: | ||
| 652 | + x2 = x0 | ||
| 653 | + if y1 > y0: | ||
| 654 | + y2 = y0 + abs(dy) | ||
| 655 | + else: | ||
| 656 | + y2 = y0 - abs(dy) | ||
| 657 | + else: | ||
| 658 | + if x1 < x0: | ||
| 659 | + x2 = x0 - dx | ||
| 660 | + else: | ||
| 661 | + x2 = x0 + dx | ||
| 662 | + | ||
| 663 | + if y1 < y0: | ||
| 664 | + y2 = y0 - dy | ||
| 665 | + else: | ||
| 666 | + y2 = y0 + dy | ||
| 667 | + | ||
| 668 | + return x2, y2 | ||
| 669 | + | ||
| 670 | + def process(self): | ||
| 671 | + polygons = self.data.get_polygons() | ||
| 672 | + rps = [] | ||
| 673 | + | ||
| 674 | + for poly in polygons: | ||
| 675 | + rp = self.get_polygon_reprecent_point(poly) | ||
| 676 | + rps.append(rp) | ||
| 677 | + print("完成代表点计算") | ||
| 678 | + | ||
| 679 | + #代表点要融合 | ||
| 680 | + delauney_lines,rps_sub = self.create_delauney(rps) | ||
| 681 | + | ||
| 682 | + print("完成树生成计算") | ||
| 683 | + min_delauney = self.create_min_delauney(delauney_lines,rps_sub) | ||
| 684 | + print("完成最小生成树计算") | ||
| 685 | + trees = self.cut_delauney_min_tree(min_delauney,self.distance_buffer_threshold) | ||
| 686 | + print("完成树裁剪") | ||
| 687 | + | ||
| 688 | + polygon_result = [] | ||
| 689 | + for index,tree in enumerate(trees): | ||
| 690 | + | ||
| 691 | + polygons = tree.get_polygons() | ||
| 692 | + print(index) | ||
| 693 | + polygons = list(polygons) | ||
| 694 | + print(len(polygons)) | ||
| 695 | + polygon_result.append(PolygonMerge.merge(polygons,self.distance_buffer_threshold)) | ||
| 696 | + | ||
| 697 | + # polygons = self.merge_concave(trees,self.distance_buffer_threshold) | ||
| 698 | + | ||
| 699 | + return [p.ExportToWkt() for p in polygon_result] | ||
| 700 | + | ||
| 701 | +if __name__ == '__main__': | ||
| 702 | + | ||
| 703 | + | ||
| 704 | + | ||
| 705 | + t1 = time.time() | ||
| 706 | + sd = ShapeData(r"J:\Data\制图综合result\zhongshansub.shp") | ||
| 707 | + | ||
| 708 | + mapsynthesize = MapSynthesize(sd) | ||
| 709 | + wkts = mapsynthesize.process() | ||
| 710 | + result = r"J:\Data\制图综合result\zhongshansub_merge22.shp" | ||
| 711 | + ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 712 | + | ||
| 713 | + print(time.time()-t1) |
test/MapSynthesize/PolygonMerge.py
0 → 100644
| 1 | +# coding=utf-8 | ||
| 2 | +#author: 4N | ||
| 3 | +#createtime: 2022/3/30 | ||
| 4 | +#email: nheweijun@sina.com | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +from osgeo import ogr,gdal | ||
| 8 | +from osgeo.ogr import * | ||
| 9 | + | ||
| 10 | +from test.zonghe.ShapeData import ShapeData | ||
| 11 | +import copy | ||
| 12 | + | ||
| 13 | +from rtreelib import RTree,Rect | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +class RTreeData: | ||
| 18 | + | ||
| 19 | + def __init__(self,triangle,state): | ||
| 20 | + self.state = state | ||
| 21 | + self.triangle = triangle | ||
| 22 | + | ||
| 23 | + def set_state(self,state): | ||
| 24 | + self.state = state | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +def env2rect(env): | ||
| 28 | + return Rect(env[0],env[2],env[1],env[3]) | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +class PolygonMerge: | ||
| 32 | + | ||
| 33 | + @classmethod | ||
| 34 | + def get_delauney(cls,polygon): | ||
| 35 | + | ||
| 36 | + polygon_line = cls.get_polygon_lines(polygon) | ||
| 37 | + polygon_line_points:list = polygon_line.GetPoints() | ||
| 38 | + | ||
| 39 | + if len(polygon_line_points)==4: | ||
| 40 | + tris = [polygon] | ||
| 41 | + else: | ||
| 42 | + d = 0 | ||
| 43 | + for ind in range(len(polygon_line_points) - 1): | ||
| 44 | + p = polygon_line_points[ind] | ||
| 45 | + p_n = polygon_line_points[ind + 1] | ||
| 46 | + | ||
| 47 | + d += -0.5 * (p_n[1] + p[1]) * (p_n[0] - p[0]) | ||
| 48 | + | ||
| 49 | + if d < 0: | ||
| 50 | + polygon_line_points.reverse() | ||
| 51 | + | ||
| 52 | + tris = list(cls.get_tri(polygon_line_points)) | ||
| 53 | + | ||
| 54 | + return tris | ||
| 55 | + | ||
| 56 | + @classmethod | ||
| 57 | + def get_tri(cls,polygon_line_points:list): | ||
| 58 | + | ||
| 59 | + if len(polygon_line_points) == 4 or len(polygon_line_points) == 3: | ||
| 60 | + yield cls.create_polygon(polygon_line_points) | ||
| 61 | + else: | ||
| 62 | + for index,point in enumerate(polygon_line_points): | ||
| 63 | + if index == 0: | ||
| 64 | + continue | ||
| 65 | + else: | ||
| 66 | + try: | ||
| 67 | + point_front = polygon_line_points[index-1] | ||
| 68 | + point_next = polygon_line_points[index+1] | ||
| 69 | + except Exception as e: | ||
| 70 | + print(e) | ||
| 71 | + kk=1 | ||
| 72 | + d=1 | ||
| 73 | + | ||
| 74 | + check = (point[0]-point_front[0]) * (point_next[1]-point[1]) - (point_next[0]-point[0])*(point[1]-point_front[1]) | ||
| 75 | + | ||
| 76 | + if check > 0: | ||
| 77 | + triangle = cls.create_polygon([point_front,point,point_next,point_front]) | ||
| 78 | + yield triangle | ||
| 79 | + | ||
| 80 | + polygon_line_points.pop(index) | ||
| 81 | + for tri in cls.get_tri(polygon_line_points): | ||
| 82 | + yield tri | ||
| 83 | + break | ||
| 84 | + | ||
| 85 | + @classmethod | ||
| 86 | + def merge(cls,polygons:list,distance_buffer_threshold): | ||
| 87 | + | ||
| 88 | + rtree = RTree() | ||
| 89 | + | ||
| 90 | + polygon:Geometry = polygons[0] | ||
| 91 | + # multipolygon = ogr.Geometry(ogr.wkbMultiPolygon) | ||
| 92 | + # for poly in polygons: | ||
| 93 | + # multipolygon.AddGeometry(poly) | ||
| 94 | + | ||
| 95 | + for poly in polygons: | ||
| 96 | + polygon = polygon.Union(poly) | ||
| 97 | + | ||
| 98 | + | ||
| 99 | + | ||
| 100 | + delauney: Geometry = polygon.DelaunayTriangulation() | ||
| 101 | + | ||
| 102 | + for index in range(delauney.GetGeometryCount()): | ||
| 103 | + de:Geometry = copy.deepcopy(delauney.GetGeometryRef(index)) | ||
| 104 | + de_extent = de.GetEnvelope() | ||
| 105 | + rtree.insert(RTreeData(de,1), env2rect(de_extent)) | ||
| 106 | + | ||
| 107 | + bians: list = cls.get_bian(polygon) | ||
| 108 | + | ||
| 109 | + | ||
| 110 | + for bian in bians: | ||
| 111 | + | ||
| 112 | + bian_ext = bian.GetEnvelope() | ||
| 113 | + | ||
| 114 | + query_result = rtree.query(env2rect(bian_ext)) | ||
| 115 | + | ||
| 116 | + intersection_data = [] | ||
| 117 | + | ||
| 118 | + | ||
| 119 | + for entry in query_result: | ||
| 120 | + | ||
| 121 | + # 已被抛弃的不要 | ||
| 122 | + if entry.data.state == 0: | ||
| 123 | + continue | ||
| 124 | + intersection_geom: Geometry = bian.Intersection(entry.data.triangle) | ||
| 125 | + | ||
| 126 | + if not intersection_geom.IsEmpty(): | ||
| 127 | + if not intersection_geom.Equals(bian): | ||
| 128 | + if intersection_geom.GetGeometryType() in [2, 5, -2147483643, -2147483646, 3002, 3005]: | ||
| 129 | + intersection_data.append(entry.data) | ||
| 130 | + | ||
| 131 | + | ||
| 132 | + for data in intersection_data: | ||
| 133 | + data.set_state(0) | ||
| 134 | + | ||
| 135 | + if intersection_data: | ||
| 136 | + | ||
| 137 | + inter_tri_merge:Geometry = intersection_data[0].triangle | ||
| 138 | + | ||
| 139 | + for ind in range(1,len(intersection_data)): | ||
| 140 | + inter_tri_merge = inter_tri_merge.Union(intersection_data[ind].triangle) | ||
| 141 | + | ||
| 142 | + | ||
| 143 | + inter_tri_merge_line:Geometry = cls.get_polygon_lines(inter_tri_merge) | ||
| 144 | + | ||
| 145 | + inter_tri_merge_line_points:list = inter_tri_merge_line.GetPoints() | ||
| 146 | + | ||
| 147 | + bian_ps = bian.GetPoints() | ||
| 148 | + | ||
| 149 | + if len(inter_tri_merge_line_points[0]) == 3: | ||
| 150 | + try: | ||
| 151 | + first_index = inter_tri_merge_line_points.index(bian_ps[0]) | ||
| 152 | + second_index = inter_tri_merge_line_points.index(bian_ps[1]) | ||
| 153 | + except: | ||
| 154 | + rtree.insert(RTreeData(inter_tri_merge, 1), env2rect(inter_tri_merge.GetEnvelope())) | ||
| 155 | + continue | ||
| 156 | + else: | ||
| 157 | + try: | ||
| 158 | + first_index = inter_tri_merge_line_points.index((bian_ps[0][0],bian_ps[0][1])) | ||
| 159 | + second_index = inter_tri_merge_line_points.index((bian_ps[1][0],bian_ps[1][1])) | ||
| 160 | + except: | ||
| 161 | + rtree.insert(RTreeData(inter_tri_merge, 1), env2rect(inter_tri_merge.GetEnvelope())) | ||
| 162 | + continue | ||
| 163 | + | ||
| 164 | + | ||
| 165 | + | ||
| 166 | + small_index = min(first_index,second_index) | ||
| 167 | + big_index = max(first_index,second_index) | ||
| 168 | + | ||
| 169 | + small_points:list = inter_tri_merge_line_points[:small_index+1] | ||
| 170 | + small_points.extend(inter_tri_merge_line_points[big_index:]) | ||
| 171 | + small_polygon:Geometry = cls.create_polygon(small_points) | ||
| 172 | + | ||
| 173 | + delauney = cls.get_delauney(small_polygon) | ||
| 174 | + for de in delauney: | ||
| 175 | + de_extent = de.GetEnvelope() | ||
| 176 | + rtree.insert(RTreeData(de, 1), env2rect(de_extent)) | ||
| 177 | + | ||
| 178 | + big_points = inter_tri_merge_line_points[small_index:big_index+1] | ||
| 179 | + big_points.append(inter_tri_merge_line_points[small_index]) | ||
| 180 | + | ||
| 181 | + big_polygon:Geometry = cls.create_polygon(big_points) | ||
| 182 | + | ||
| 183 | + delauney = cls.get_delauney(big_polygon) | ||
| 184 | + for de in delauney: | ||
| 185 | + de_extent = de.GetEnvelope() | ||
| 186 | + rtree.insert(RTreeData(de, 1), env2rect(de_extent)) | ||
| 187 | + | ||
| 188 | + for entry in rtree.get_leaf_entries(): | ||
| 189 | + triangle = entry.data.triangle | ||
| 190 | + if entry.data.state==0: | ||
| 191 | + continue | ||
| 192 | + if polygon.Contains(triangle): | ||
| 193 | + pass | ||
| 194 | + else: | ||
| 195 | + tri_center,tri_center2 = cls.get_center(triangle) | ||
| 196 | + distance = tri_center.Distance(polygon) | ||
| 197 | + distance2 = tri_center2.Distance(polygon) | ||
| 198 | + | ||
| 199 | + if distance > distance_buffer_threshold : | ||
| 200 | + continue | ||
| 201 | + # if distance2 > distance_buffer_threshold: | ||
| 202 | + # continue | ||
| 203 | + | ||
| 204 | + polygon = polygon.Union(triangle) | ||
| 205 | + # polygon.AddGeometry(triangle) | ||
| 206 | + | ||
| 207 | + result :Geometry = polygon | ||
| 208 | + | ||
| 209 | + return result | ||
| 210 | + | ||
| 211 | + | ||
| 212 | + @classmethod | ||
| 213 | + def get_center(cls,tri:Geometry): | ||
| 214 | + | ||
| 215 | + tri_line: Geometry = cls.get_polygon_lines(tri) | ||
| 216 | + tri_line_points = tri_line.GetPoints() | ||
| 217 | + | ||
| 218 | + lines = [] | ||
| 219 | + | ||
| 220 | + for index in range(len(tri_line_points)-1): | ||
| 221 | + first = tri_line_points[index] | ||
| 222 | + second = tri_line_points[index+1] | ||
| 223 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 224 | + line.AddPoint(first[0], first[1]) | ||
| 225 | + line.AddPoint(second[0], second[1]) | ||
| 226 | + lines.append(line) | ||
| 227 | + | ||
| 228 | + lines = sorted(lines,key=lambda l:l.Length()) | ||
| 229 | + | ||
| 230 | + return lines[-1].Centroid(),lines[-2].Centroid() | ||
| 231 | + | ||
| 232 | + @classmethod | ||
| 233 | + def get_polygon_lines(cls,polygon): | ||
| 234 | + #无孔Polygon | ||
| 235 | + if polygon.GetGeometryCount() in [0,1]: | ||
| 236 | + polygon_line : Geometry = ogr.ForceToLineString(polygon) | ||
| 237 | + # 有孔Polygon | ||
| 238 | + else: | ||
| 239 | + polygon_line : Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 240 | + | ||
| 241 | + return polygon_line | ||
| 242 | + | ||
| 243 | + @classmethod | ||
| 244 | + def get_bian(cls,polygon): | ||
| 245 | + | ||
| 246 | + bians = [] | ||
| 247 | + | ||
| 248 | + polygon_lines = [] | ||
| 249 | + | ||
| 250 | + if polygon.GetGeometryCount() in [0, 1]: | ||
| 251 | + polygon_line: Geometry = ogr.ForceToLineString(polygon) | ||
| 252 | + polygon_lines.append(polygon_line) | ||
| 253 | + # 有孔Polygon | ||
| 254 | + else: | ||
| 255 | + for index in range(polygon.GetGeometryCount()): | ||
| 256 | + polygon_line: Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(index)) | ||
| 257 | + polygon_lines.append(polygon_line) | ||
| 258 | + | ||
| 259 | + for polygon_line in polygon_lines: | ||
| 260 | + for index in range(polygon_line.GetPointCount()-1): | ||
| 261 | + p = polygon_line.GetPoint(index) | ||
| 262 | + p_next = polygon_line.GetPoint(index+1) | ||
| 263 | + | ||
| 264 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 265 | + | ||
| 266 | + if len(p) ==2: | ||
| 267 | + line.AddPoint(p[0], p[1],0) | ||
| 268 | + line.AddPoint(p_next[0], p_next[1],0) | ||
| 269 | + else: | ||
| 270 | + line.AddPoint(p[0], p[1]) | ||
| 271 | + line.AddPoint(p_next[0], p_next[1]) | ||
| 272 | + bians.append(line) | ||
| 273 | + | ||
| 274 | + return bians | ||
| 275 | + | ||
| 276 | + @classmethod | ||
| 277 | + def create_polygon(cls,ps): | ||
| 278 | + | ||
| 279 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 280 | + for p in ps: | ||
| 281 | + ring.AddPoint(p[0], p[1]) | ||
| 282 | + poly = ogr.Geometry(ogr.wkbPolygon) | ||
| 283 | + poly.AddGeometry(ring) | ||
| 284 | + return poly | ||
| 285 | + | ||
| 286 | + | ||
| 287 | +if __name__ == '__main__': | ||
| 288 | + import time | ||
| 289 | + t1 = time.time() | ||
| 290 | + | ||
| 291 | + | ||
| 292 | + # sd = ShapeData(r"J:\Data\制图综合result\t4.shp") | ||
| 293 | + # mp = ogr.Geometry(ogr.wkbMultiPolygon) | ||
| 294 | + # polygons = sd.get_polygons() | ||
| 295 | + # | ||
| 296 | + # wkts = PolygonMerge.merge(polygons) | ||
| 297 | + # | ||
| 298 | + # result = r"J:\Data\制图综合result\t4_merge.shp" | ||
| 299 | + # | ||
| 300 | + # ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 301 | + # | ||
| 302 | + # print(time.time()-t1) | ||
| 303 | + | ||
| 304 | + | ||
| 305 | + p = PolygonMerge.create_polygon([(113.37029204400005, 22.526576828100076, 0.0), (113.36972403800007, 22.526369320699985, 0.0), (113.36974547200009, 22.526379207800005, 0.0), (113.37025989200004, 22.52656695200011, 0.0), (113.37029204400005, 22.526576828100076, 0.0)]) | ||
| 306 | + | ||
| 307 | + pl:Geometry = ogr.ForceToLineString(p) | ||
| 308 | + | ||
| 309 | + ps:list = pl.GetPoints() | ||
| 310 | + ps.reverse() | ||
| 311 | + | ||
| 312 | + PolygonMerge.get_tri(ps) | ||
| 313 | + | ||
| 314 | + # wkts =[p.ExportToWkt()] | ||
| 315 | + # | ||
| 316 | + # result = r"J:\Data\制图综合result\error.shp" | ||
| 317 | + # | ||
| 318 | + # ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 319 | + # | ||
| 320 | + # print(time.time()-t1) |
test/MapSynthesize/RepresentPoint.py
0 → 100644
test/MapSynthesize/ShapeData.py
0 → 100644
| 1 | +# coding=utf-8 | ||
| 2 | +#author: 4N | ||
| 3 | +#createtime: 2022/3/15 | ||
| 4 | +#email: nheweijun@sina.com | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +from osgeo import ogr | ||
| 8 | +from osgeo.ogr import * | ||
| 9 | +import math | ||
| 10 | +import os | ||
| 11 | +import copy | ||
| 12 | + | ||
| 13 | +class ShapeData: | ||
| 14 | + | ||
| 15 | + driver = ogr.GetDriverByName("ESRI Shapefile") | ||
| 16 | + | ||
| 17 | + def __init__(self,path): | ||
| 18 | + | ||
| 19 | + self.ds: DataSource = self.driver.Open(path, 1) | ||
| 20 | + if not self.ds: | ||
| 21 | + raise Exception("打开数据失败!") | ||
| 22 | + self.layer: Layer = self.ds.GetLayer(0) | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + def get_polygons(self): | ||
| 26 | + | ||
| 27 | + polygons = [] | ||
| 28 | + for feature in self.layer: | ||
| 29 | + f:Feature = feature | ||
| 30 | + geom : Geometry = copy.deepcopy(f.GetGeometryRef()) | ||
| 31 | + if geom is None: | ||
| 32 | + continue | ||
| 33 | + if geom.GetGeometryType() in [3,-2147483645,3001]: | ||
| 34 | + polygons.append(ogr.ForceToPolygon(geom)) | ||
| 35 | + if geom.GetGeometryType() in [6 ,-2147483642 ,3006]: | ||
| 36 | + for i in range(geom.GetGeometryCount()): | ||
| 37 | + polygons.append(ogr.ForceToPolygon(geom.GetGeometryRef(i))) | ||
| 38 | + | ||
| 39 | + # p_cs = [] | ||
| 40 | + # for p in polygons: | ||
| 41 | + # polygon_line: Geometry = self.get_polygon_lines(p) | ||
| 42 | + # print(polygon_line) | ||
| 43 | + # p_cs.append(self.create_polygon(polygon_line.GetPoints())) | ||
| 44 | + # | ||
| 45 | + # return p_cs | ||
| 46 | + return polygons | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + def get_polygon_lines(self,polygon): | ||
| 50 | + #无孔Polygon | ||
| 51 | + if polygon.GetGeometryCount() in [0,1]: | ||
| 52 | + polygon_line : Geometry = ogr.ForceToLineString(polygon) | ||
| 53 | + # 有孔Polygon | ||
| 54 | + else: | ||
| 55 | + polygon_line : Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 56 | + | ||
| 57 | + return polygon_line | ||
| 58 | + | ||
| 59 | + | ||
| 60 | + def create_polygon(self,ps): | ||
| 61 | + | ||
| 62 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 63 | + for p in ps: | ||
| 64 | + ring.AddPoint(p[0], p[1],0) | ||
| 65 | + poly = ogr.Geometry(ogr.wkbPolygon) | ||
| 66 | + poly.AddGeometry(ring) | ||
| 67 | + return poly | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + | ||
| 71 | + def close(self): | ||
| 72 | + self.ds.Destroy() | ||
| 73 | + | ||
| 74 | + | ||
| 75 | + | ||
| 76 | + | ||
| 77 | + @classmethod | ||
| 78 | + def create_by_layer(cls,path,layer:Layer): | ||
| 79 | + data_source: DataSource = cls.driver.CreateDataSource(path) | ||
| 80 | + data_source.CopyLayer(layer,layer.GetName()) | ||
| 81 | + data_source.Destroy() | ||
| 82 | + | ||
| 83 | + @classmethod | ||
| 84 | + def create_by_scheme(cls,path,name,sr,geo_type,scheme,features): | ||
| 85 | + data_source: DataSource = cls.driver.CreateDataSource(path) | ||
| 86 | + layer :Layer = data_source.CreateLayer(name, sr, geo_type) | ||
| 87 | + if scheme: | ||
| 88 | + layer.CreateFields(scheme) | ||
| 89 | + for feature in features: | ||
| 90 | + layer.CreateFeature(feature) | ||
| 91 | + data_source.Destroy() | ||
| 92 | + | ||
| 93 | + @classmethod | ||
| 94 | + def create_point(cls,path,name,point): | ||
| 95 | + data_source: DataSource = cls.driver.CreateDataSource(path) | ||
| 96 | + layer :Layer = data_source.CreateLayer(name, None, ogr.wkbPoint) | ||
| 97 | + | ||
| 98 | + feat_new = ogr.Feature(layer.GetLayerDefn()) | ||
| 99 | + feat_new.SetGeometry(point) | ||
| 100 | + layer.CreateFeature(feat_new) | ||
| 101 | + data_source.Destroy() | ||
| 102 | + | ||
| 103 | + @classmethod | ||
| 104 | + def create_shp_fromwkts(cls,path,name,wkts): | ||
| 105 | + | ||
| 106 | + geo_type = None | ||
| 107 | + geoms = [] | ||
| 108 | + for wkt in wkts: | ||
| 109 | + geom : Geometry = ogr.CreateGeometryFromWkt(wkt) | ||
| 110 | + if geo_type is None: | ||
| 111 | + geo_type = geom.GetGeometryType() | ||
| 112 | + geoms.append(geom) | ||
| 113 | + | ||
| 114 | + if os.path.exists(path): | ||
| 115 | + | ||
| 116 | + pre_name = ".".join(path.split(".")[0:-1]) | ||
| 117 | + for bac in ["dbf","prj","cpg","shp","shx","sbn","sbx"]: | ||
| 118 | + try: | ||
| 119 | + os.remove(pre_name+"."+bac) | ||
| 120 | + except Exception as e: | ||
| 121 | + pass | ||
| 122 | + | ||
| 123 | + data_source: DataSource = cls.driver.CreateDataSource(path) | ||
| 124 | + layer :Layer = data_source.CreateLayer(name, None, geo_type) | ||
| 125 | + | ||
| 126 | + for geom in geoms: | ||
| 127 | + feat_new = ogr.Feature(layer.GetLayerDefn()) | ||
| 128 | + feat_new.SetGeometry(geom) | ||
| 129 | + layer.CreateFeature(feat_new) | ||
| 130 | + data_source.Destroy() | ||
| 131 | + | ||
| 132 | + | ||
| 133 | +if __name__ == '__main__': | ||
| 134 | + sd = ShapeData(r"J:\Data\制图综合result\test.shp") | ||
| 135 | + # polygons = sd.get_polygons() | ||
| 136 | + # wkts = [] | ||
| 137 | + # for p in polygons: | ||
| 138 | + # # print(p.ExportToWkt()) | ||
| 139 | + # wkts.append(p.ExportToWkt()) | ||
| 140 | + # result = r"J:\Data\制图综合result\zhongshan_ronghe.shp" | ||
| 141 | + # ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 142 | + | ||
| 143 | + layer = sd.layer | ||
| 144 | + | ||
| 145 | + fn = "PG: user=postgres password=chinadci host=172.26.60.101 port=5432 dbname=ceshi " | ||
| 146 | + driver = ogr.GetDriverByName("PostgreSQL") | ||
| 147 | + if driver is None: | ||
| 148 | + raise Exception("打开PostgreSQL驱动失败,可能是当前GDAL未支持PostgreSQL驱动!") | ||
| 149 | + ds:DataSource = driver.Open(fn, 1) | ||
| 150 | + | ||
| 151 | + | ||
| 152 | + pg_layer = ds.CreateLayer("test", layer.GetSpatialRef(), layer.GetGeomType(), ["overwrite=yes"]) | ||
| 153 | + schema = layer.schema | ||
| 154 | + pg_layer.CreateFields(schema) | ||
| 155 | + for feature in layer: | ||
| 156 | + out_feature: Feature = copy.copy(feature) | ||
| 157 | + out_feature.SetFID(out_feature.GetFID() + 1) | ||
| 158 | + pg_layer.CreateFeature(out_feature) | ||
| 159 | + | ||
| 160 | + | ||
| 161 | + ds.Destroy() |
test/MapSynthesize/__init__.py
0 → 100644
| @@ -10,7 +10,6 @@ | @@ -10,7 +10,6 @@ | ||
| 10 | 10 | ||
| 11 | import numpy as np | 11 | import numpy as np |
| 12 | import scipy.spatial as spt | 12 | import scipy.spatial as spt |
| 13 | -import matplotlib.pyplot as plt | ||
| 14 | from matplotlib.path import Path | 13 | from matplotlib.path import Path |
| 15 | from test.zonghe import lineintersect as li | 14 | from test.zonghe import lineintersect as li |
| 16 | 15 | ||
| @@ -47,27 +46,6 @@ def SortByAngle(kNearestPoints, currentPoint, prevPoint): | @@ -47,27 +46,6 @@ def SortByAngle(kNearestPoints, currentPoint, prevPoint): | ||
| 47 | i=i+1 | 46 | i=i+1 |
| 48 | return kNearestPoints[np.argsort(angles)] | 47 | return kNearestPoints[np.argsort(angles)] |
| 49 | 48 | ||
| 50 | -# def plotPoints(dataset): | ||
| 51 | -# plt.plot(dataset[:,0],dataset[:,1],'o',markersize=10,markerfacecolor='0.75', | ||
| 52 | -# markeredgewidth=1) | ||
| 53 | -# plt.axis('equal') | ||
| 54 | -# plt.axis([min(dataset[:,0])-0.5,max(dataset[:,0])+0.5,min(dataset[:,1])-0.5, | ||
| 55 | -# max(dataset[:,1])+0.5]) | ||
| 56 | -# plt.show() | ||
| 57 | -# | ||
| 58 | -# def plotPath(dataset, path): | ||
| 59 | -# plt.plot(dataset[:,0],dataset[:,1],'o',markersize=10,markerfacecolor='0.65', | ||
| 60 | -# markeredgewidth=0) | ||
| 61 | -# path = np.asarray(path) | ||
| 62 | -# plt.plot(path[:,0],path[:,1],'o',markersize=10,markerfacecolor='0.55', | ||
| 63 | -# markeredgewidth=0) | ||
| 64 | -# plt.plot(path[:,0],path[:,1],'-',lw=1.4,color='k') | ||
| 65 | -# plt.axis('equal') | ||
| 66 | -# plt.axis([min(dataset[:,0])-0.5,max(dataset[:,0])+0.5,min(dataset[:,1])-0.5, | ||
| 67 | -# max(dataset[:,1])+0.5]) | ||
| 68 | -# plt.axis('off') | ||
| 69 | -# plt.savefig('./doc/figure_1.png', bbox_inches='tight') | ||
| 70 | -# plt.show() | ||
| 71 | 49 | ||
| 72 | def removePoint(dataset, point): | 50 | def removePoint(dataset, point): |
| 73 | delmask = [np.logical_or(dataset[:,0]!=point[0],dataset[:,1]!=point[1])] | 51 | delmask = [np.logical_or(dataset[:,0]!=point[0],dataset[:,1]!=point[1])] |
| @@ -89,9 +67,13 @@ def concaveHull(dataset, k): | @@ -89,9 +67,13 @@ def concaveHull(dataset, k): | ||
| 89 | hull.append(firstpoint) | 67 | hull.append(firstpoint) |
| 90 | # and remove it from dataset | 68 | # and remove it from dataset |
| 91 | points = removePoint(points,firstpoint) | 69 | points = removePoint(points,firstpoint) |
| 70 | + | ||
| 92 | currentPoint = firstpoint | 71 | currentPoint = firstpoint |
| 93 | # set prevPoint to a Point righ of currentpoint (angle=0) | 72 | # set prevPoint to a Point righ of currentpoint (angle=0) |
| 73 | + | ||
| 94 | prevPoint = (currentPoint[0]+10, currentPoint[1]) | 74 | prevPoint = (currentPoint[0]+10, currentPoint[1]) |
| 75 | + | ||
| 76 | + | ||
| 95 | step = 2 | 77 | step = 2 |
| 96 | 78 | ||
| 97 | while ( (not np.array_equal(firstpoint, currentPoint) or (step==2)) and points.size > 0 ): | 79 | while ( (not np.array_equal(firstpoint, currentPoint) or (step==2)) and points.size > 0 ): |
| @@ -116,7 +98,7 @@ def concaveHull(dataset, k): | @@ -116,7 +98,7 @@ def concaveHull(dataset, k): | ||
| 116 | hull[step-1-j-1],hull[step-j-1]) | 98 | hull[step-1-j-1],hull[step-j-1]) |
| 117 | j=j+1 | 99 | j=j+1 |
| 118 | if ( its==True ): | 100 | if ( its==True ): |
| 119 | - print("all candidates intersect -- restarting with k = ",k+1) | 101 | + # print("all candidates intersect -- restarting with k = ",k+1) |
| 120 | return concaveHull(dataset,k+1) | 102 | return concaveHull(dataset,k+1) |
| 121 | prevPoint = currentPoint | 103 | prevPoint = currentPoint |
| 122 | currentPoint = cPoints[i-1] | 104 | currentPoint = cPoints[i-1] |
| @@ -127,11 +109,12 @@ def concaveHull(dataset, k): | @@ -127,11 +109,12 @@ def concaveHull(dataset, k): | ||
| 127 | # check if all points are inside the hull | 109 | # check if all points are inside the hull |
| 128 | p = Path(hull) | 110 | p = Path(hull) |
| 129 | pContained = p.contains_points(dataset, radius=0.0000000001) | 111 | pContained = p.contains_points(dataset, radius=0.0000000001) |
| 112 | + | ||
| 130 | if (not pContained.all()): | 113 | if (not pContained.all()): |
| 131 | - print("not all points of dataset contained in hull -- restarting with k = ",k+1) | 114 | + # print("not all points of dataset contained in hull -- restarting with k = ",k+1) |
| 132 | return concaveHull(dataset, k+1) | 115 | return concaveHull(dataset, k+1) |
| 133 | 116 | ||
| 134 | - print("finished with k = ",k) | 117 | + # print("finished with k = ",k) |
| 135 | return hull | 118 | return hull |
| 136 | 119 | ||
| 137 | 120 |
| @@ -9,8 +9,7 @@ import math | @@ -9,8 +9,7 @@ import math | ||
| 9 | import os | 9 | import os |
| 10 | import copy | 10 | import copy |
| 11 | from test.zonghe.RepresentPoint import RepresentPoint | 11 | from test.zonghe.RepresentPoint import RepresentPoint |
| 12 | - | ||
| 13 | - | 12 | +import time |
| 14 | 13 | ||
| 15 | class DelauneyNode: | 14 | class DelauneyNode: |
| 16 | 15 | ||
| @@ -65,22 +64,52 @@ class DelauneyMinTree: | @@ -65,22 +64,52 @@ class DelauneyMinTree: | ||
| 65 | def __init__(self): | 64 | def __init__(self): |
| 66 | self.delauney_lines_list = list() | 65 | self.delauney_lines_list = list() |
| 67 | self.rps = set() | 66 | self.rps = set() |
| 67 | + self.touch_delauney_lines = set() | ||
| 68 | + | ||
| 69 | + def append(self,delauney_line,other_delauney_lines_kv): | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + candicates = [] | ||
| 73 | + if not self.rps.__contains__(delauney_line.rp1): | ||
| 74 | + self.rps.add(delauney_line.rp1) | ||
| 75 | + | ||
| 76 | + candicates.extend(other_delauney_lines_kv.get(delauney_line.rp1)) | ||
| 77 | + | ||
| 78 | + if not self.rps.__contains__(delauney_line.rp2): | ||
| 79 | + self.rps.add(delauney_line.rp2) | ||
| 80 | + | ||
| 81 | + candicates.extend(other_delauney_lines_kv.get(delauney_line.rp2)) | ||
| 68 | 82 | ||
| 69 | - def append(self,delauney_line): | ||
| 70 | - # self.delauney_lines.add(delauney_line) | 83 | + for candicate in candicates: |
| 84 | + if (candicate.rp1 in self.rps) and (candicate.rp2 in self.rps): | ||
| 85 | + #初始化 | ||
| 86 | + try: | ||
| 87 | + self.touch_delauney_lines.remove(candicate) | ||
| 88 | + except: | ||
| 89 | + print(111) | ||
| 71 | 90 | ||
| 72 | - self.rps.add(delauney_line.rp1) | ||
| 73 | - self.rps.add(delauney_line.rp2) | 91 | + else: |
| 92 | + self.touch_delauney_lines.add(candicate) | ||
| 74 | 93 | ||
| 75 | self.delauney_lines_list.append(delauney_line) | 94 | self.delauney_lines_list.append(delauney_line) |
| 76 | 95 | ||
| 96 | + | ||
| 97 | + | ||
| 77 | def get_rps(self): | 98 | def get_rps(self): |
| 78 | return self.rps | 99 | return self.rps |
| 79 | 100 | ||
| 80 | - def get_other_relate_delauney_lines(self,other_delauney_lines_kv): | 101 | + |
| 102 | + def get_other_relate_delauney_lines(self,other_delauney_lines_kv,rps_set): | ||
| 103 | + | ||
| 81 | other_relate_delauney_lines = [] | 104 | other_relate_delauney_lines = [] |
| 105 | + | ||
| 82 | for rp in self.rps: | 106 | for rp in self.rps: |
| 83 | - other_relate_delauney_lines.extend(other_delauney_lines_kv.get(rp)) | 107 | + candicates = other_delauney_lines_kv.get(rp) |
| 108 | + candicates = [c for c in candicates if c.rp1 in rps_set or c.rp2 in rps_set] | ||
| 109 | + other_relate_delauney_lines.extend(candicates) | ||
| 110 | + | ||
| 111 | + # other_relate_delauney_lines.append() | ||
| 112 | + | ||
| 84 | return other_relate_delauney_lines | 113 | return other_relate_delauney_lines |
| 85 | 114 | ||
| 86 | def get_other_rp(self,delauney_line): | 115 | def get_other_rp(self,delauney_line): |
test/zonghe/PolygonDivision.py
0 → 100644
| 1 | +# coding=utf-8 | ||
| 2 | +#author: 4N | ||
| 3 | +#createtime: 2022/3/30 | ||
| 4 | +#email: nheweijun@sina.com | ||
| 5 | + | ||
| 6 | +import math | ||
| 7 | + | ||
| 8 | +from osgeo import ogr,gdal | ||
| 9 | +from osgeo.ogr import * | ||
| 10 | + | ||
| 11 | +from test.zonghe.ShapeData import ShapeData | ||
| 12 | +import copy | ||
| 13 | + | ||
| 14 | +from scipy import spatial | ||
| 15 | +from rtreelib import RTree,Rect | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +class RTreeData: | ||
| 20 | + | ||
| 21 | + def __init__(self,triangle,state): | ||
| 22 | + self.state = state | ||
| 23 | + self.triangle = triangle | ||
| 24 | + | ||
| 25 | + def set_state(self,state): | ||
| 26 | + self.state = state | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +def env2rect(env): | ||
| 30 | + return Rect(env[0],env[2],env[1],env[3]) | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +class PolygonDivision: | ||
| 34 | + | ||
| 35 | + @classmethod | ||
| 36 | + def get_delauney(cls,polygon): | ||
| 37 | + | ||
| 38 | + polygon_line = cls.get_polygon_lines(polygon) | ||
| 39 | + polygon_line_points:list = polygon_line.GetPoints() | ||
| 40 | + | ||
| 41 | + if len(polygon_line_points)==4: | ||
| 42 | + tris = [polygon] | ||
| 43 | + else: | ||
| 44 | + d = 0 | ||
| 45 | + for ind in range(len(polygon_line_points) - 1): | ||
| 46 | + p = polygon_line_points[ind] | ||
| 47 | + p_n = polygon_line_points[ind + 1] | ||
| 48 | + | ||
| 49 | + d += -0.5 * (p_n[1] + p[1]) * (p_n[0] - p[0]) | ||
| 50 | + | ||
| 51 | + if d < 0: | ||
| 52 | + polygon_line_points.reverse() | ||
| 53 | + | ||
| 54 | + tris = list(cls.get_tri(polygon_line_points)) | ||
| 55 | + | ||
| 56 | + return tris | ||
| 57 | + | ||
| 58 | + @classmethod | ||
| 59 | + def get_tri(cls,polygon_line_points:list): | ||
| 60 | + | ||
| 61 | + if len(polygon_line_points) == 4: | ||
| 62 | + yield cls.create_polygon(polygon_line_points) | ||
| 63 | + else: | ||
| 64 | + for index,point in enumerate(polygon_line_points): | ||
| 65 | + if index == 0: | ||
| 66 | + continue | ||
| 67 | + # elif index == len(polygon_line_points)-1 : | ||
| 68 | + # pass | ||
| 69 | + else: | ||
| 70 | + point_front = polygon_line_points[index-1] | ||
| 71 | + point_next = polygon_line_points[index+1] | ||
| 72 | + | ||
| 73 | + check = (point[0]-point_front[0]) * (point_next[1]-point[1]) - (point_next[0]-point[0])*(point[1]-point_front[1]) | ||
| 74 | + | ||
| 75 | + if check > 0: | ||
| 76 | + triangle = cls.create_polygon([point_front,point,point_next,point_front]) | ||
| 77 | + yield triangle | ||
| 78 | + polygon_line_points.pop(index) | ||
| 79 | + for tri in cls.get_tri(polygon_line_points): | ||
| 80 | + yield tri | ||
| 81 | + break | ||
| 82 | + | ||
| 83 | + @classmethod | ||
| 84 | + def triangle_division(cls,polygon:Geometry): | ||
| 85 | + | ||
| 86 | + rtree = RTree() | ||
| 87 | + polygon = polygon.UnionCascaded() | ||
| 88 | + delauney: Geometry = polygon.DelaunayTriangulation() | ||
| 89 | + | ||
| 90 | + for index in range(delauney.GetGeometryCount()): | ||
| 91 | + de:Geometry = copy.deepcopy(delauney.GetGeometryRef(index)) | ||
| 92 | + de_extent = de.GetEnvelope() | ||
| 93 | + rtree.insert(RTreeData(de,1), env2rect(de_extent)) | ||
| 94 | + | ||
| 95 | + | ||
| 96 | + # return [entry.data.triangle.ExportToWkt() for entry in rtree.get_leaf_entries()] | ||
| 97 | + bians: list = cls.get_bian(polygon) | ||
| 98 | + | ||
| 99 | + | ||
| 100 | + for bian in bians: | ||
| 101 | + | ||
| 102 | + bian_ext = bian.GetEnvelope() | ||
| 103 | + | ||
| 104 | + query_result = rtree.query(env2rect(bian_ext)) | ||
| 105 | + | ||
| 106 | + intersection_data = [] | ||
| 107 | + | ||
| 108 | + | ||
| 109 | + for entry in query_result: | ||
| 110 | + | ||
| 111 | + # 已被抛弃的不要 | ||
| 112 | + if entry.data.state == 0: | ||
| 113 | + continue | ||
| 114 | + intersection_geom: Geometry = bian.Intersection(entry.data.triangle) | ||
| 115 | + | ||
| 116 | + if not intersection_geom.IsEmpty(): | ||
| 117 | + if not intersection_geom.Equals(bian): | ||
| 118 | + if intersection_geom.GetGeometryType() in [2, 5, -2147483643, -2147483646, 3002, 3005]: | ||
| 119 | + intersection_data.append(entry.data) | ||
| 120 | + | ||
| 121 | + | ||
| 122 | + for data in intersection_data: | ||
| 123 | + data.set_state(0) | ||
| 124 | + | ||
| 125 | + if intersection_data: | ||
| 126 | + | ||
| 127 | + inter_tri_merge:Geometry = intersection_data[0].triangle | ||
| 128 | + | ||
| 129 | + for ind in range(1,len(intersection_data)): | ||
| 130 | + inter_tri_merge = inter_tri_merge.Union(intersection_data[ind].triangle) | ||
| 131 | + | ||
| 132 | + | ||
| 133 | + | ||
| 134 | + inter_tri_merge_line:Geometry = cls.get_polygon_lines(inter_tri_merge) | ||
| 135 | + | ||
| 136 | + inter_tri_merge_line_points:list = inter_tri_merge_line.GetPoints() | ||
| 137 | + | ||
| 138 | + bian_ps = bian.GetPoints() | ||
| 139 | + | ||
| 140 | + if len(inter_tri_merge_line_points[0]) == 3: | ||
| 141 | + try: | ||
| 142 | + first_index = inter_tri_merge_line_points.index(bian_ps[0]) | ||
| 143 | + second_index = inter_tri_merge_line_points.index(bian_ps[1]) | ||
| 144 | + except: | ||
| 145 | + print(11) | ||
| 146 | + print(bian) | ||
| 147 | + print(inter_tri_merge) | ||
| 148 | + | ||
| 149 | + rtree.insert(RTreeData(inter_tri_merge, 1), env2rect(inter_tri_merge.GetEnvelope())) | ||
| 150 | + | ||
| 151 | + continue | ||
| 152 | + else: | ||
| 153 | + try: | ||
| 154 | + first_index = inter_tri_merge_line_points.index((bian_ps[0][0],bian_ps[0][1])) | ||
| 155 | + second_index = inter_tri_merge_line_points.index((bian_ps[1][0],bian_ps[1][1])) | ||
| 156 | + except: | ||
| 157 | + print(11) | ||
| 158 | + print(bian) | ||
| 159 | + print(inter_tri_merge) | ||
| 160 | + | ||
| 161 | + rtree.insert(RTreeData(inter_tri_merge, 1), env2rect(inter_tri_merge.GetEnvelope())) | ||
| 162 | + continue | ||
| 163 | + | ||
| 164 | + | ||
| 165 | + | ||
| 166 | + small_index = min(first_index,second_index) | ||
| 167 | + big_index = max(first_index,second_index) | ||
| 168 | + | ||
| 169 | + small_points:list = inter_tri_merge_line_points[:small_index+1] | ||
| 170 | + small_points.extend(inter_tri_merge_line_points[big_index:]) | ||
| 171 | + small_polygon:Geometry = cls.create_polygon(small_points) | ||
| 172 | + | ||
| 173 | + | ||
| 174 | + | ||
| 175 | + # delauney: Geometry = small_polygon.DelaunayTriangulation() | ||
| 176 | + # | ||
| 177 | + # for index in range(delauney.GetGeometryCount()): | ||
| 178 | + # de: Geometry = copy.deepcopy(delauney.GetGeometryRef(index)) | ||
| 179 | + # | ||
| 180 | + # if small_polygon.Contains(de): | ||
| 181 | + # de_extent = de.GetEnvelope() | ||
| 182 | + # rtree.insert(RTreeData(de, 1), env2rect(de_extent)) | ||
| 183 | + | ||
| 184 | + delauney = cls.get_delauney(small_polygon) | ||
| 185 | + for de in delauney: | ||
| 186 | + de_extent = de.GetEnvelope() | ||
| 187 | + rtree.insert(RTreeData(de, 1), env2rect(de_extent)) | ||
| 188 | + | ||
| 189 | + | ||
| 190 | + big_points = inter_tri_merge_line_points[small_index:big_index+1] | ||
| 191 | + big_points.append(inter_tri_merge_line_points[small_index]) | ||
| 192 | + | ||
| 193 | + big_polygon:Geometry = cls.create_polygon(big_points) | ||
| 194 | + | ||
| 195 | + # delauney: Geometry = big_polygon.DelaunayTriangulation() | ||
| 196 | + # | ||
| 197 | + # for index in range(delauney.GetGeometryCount()): | ||
| 198 | + # de: Geometry = copy.deepcopy(delauney.GetGeometryRef(index)) | ||
| 199 | + # | ||
| 200 | + # if big_polygon.Contains(de): | ||
| 201 | + # | ||
| 202 | + # de_extent = de.GetEnvelope() | ||
| 203 | + # rtree.insert(RTreeData(de, 1), env2rect(de_extent)) | ||
| 204 | + | ||
| 205 | + delauney = cls.get_delauney(big_polygon) | ||
| 206 | + for de in delauney: | ||
| 207 | + de_extent = de.GetEnvelope() | ||
| 208 | + rtree.insert(RTreeData(de, 1), env2rect(de_extent)) | ||
| 209 | + | ||
| 210 | + tris = [] | ||
| 211 | + | ||
| 212 | + for entry in rtree.get_leaf_entries(): | ||
| 213 | + if entry.data.state==0: | ||
| 214 | + continue | ||
| 215 | + if polygon.Contains(entry.data.triangle): | ||
| 216 | + pass | ||
| 217 | + else: | ||
| 218 | + tris.append(entry.data.triangle) | ||
| 219 | + | ||
| 220 | + for tri in tris: | ||
| 221 | + | ||
| 222 | + tri_center,long_line = cls.get_center(tri) | ||
| 223 | + dd = tri_center.Distance(polygon) | ||
| 224 | + if dd > 1.114691025217302e-04: | ||
| 225 | + continue | ||
| 226 | + | ||
| 227 | + polygon.AddGeometry(tri) | ||
| 228 | + result :Geometry = polygon.UnionCascaded() | ||
| 229 | + return [result.ExportToWkt()] | ||
| 230 | + | ||
| 231 | + | ||
| 232 | + @classmethod | ||
| 233 | + def get_center(cls,tri:Geometry): | ||
| 234 | + tri_line: Geometry = ogr.ForceToLineString(tri) | ||
| 235 | + tri_line_points = tri_line.GetPoints() | ||
| 236 | + | ||
| 237 | + lines = [] | ||
| 238 | + | ||
| 239 | + for index in range(len(tri_line_points)-1): | ||
| 240 | + first = tri_line_points[index] | ||
| 241 | + second = tri_line_points[index+1] | ||
| 242 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 243 | + line.AddPoint(first[0], first[1]) | ||
| 244 | + line.AddPoint(second[0], second[1]) | ||
| 245 | + lines.append(line) | ||
| 246 | + | ||
| 247 | + lines = sorted(lines,key=lambda l:l.Length()) | ||
| 248 | + | ||
| 249 | + return lines[-1].Centroid(),lines[-1] | ||
| 250 | + | ||
| 251 | + @classmethod | ||
| 252 | + def get_polygon_lines(cls,polygon): | ||
| 253 | + #无孔Polygon | ||
| 254 | + if polygon.GetGeometryCount() in [0,1]: | ||
| 255 | + polygon_line : Geometry = ogr.ForceToLineString(polygon) | ||
| 256 | + # 有孔Polygon | ||
| 257 | + else: | ||
| 258 | + polygon_line : Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 259 | + | ||
| 260 | + return polygon_line | ||
| 261 | + | ||
| 262 | + @classmethod | ||
| 263 | + def get_bian(cls,polygon): | ||
| 264 | + | ||
| 265 | + bians = [] | ||
| 266 | + | ||
| 267 | + polygon_lines = [] | ||
| 268 | + | ||
| 269 | + if polygon.GetGeometryCount() in [0, 1]: | ||
| 270 | + polygon_line: Geometry = ogr.ForceToLineString(polygon) | ||
| 271 | + polygon_lines.append(polygon_line) | ||
| 272 | + # 有孔Polygon | ||
| 273 | + else: | ||
| 274 | + for index in range(polygon.GetGeometryCount()): | ||
| 275 | + polygon_line: Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(index)) | ||
| 276 | + polygon_lines.append(polygon_line) | ||
| 277 | + | ||
| 278 | + for polygon_line in polygon_lines: | ||
| 279 | + for index in range(polygon_line.GetPointCount()-1): | ||
| 280 | + p = polygon_line.GetPoint(index) | ||
| 281 | + p_next = polygon_line.GetPoint(index+1) | ||
| 282 | + | ||
| 283 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 284 | + | ||
| 285 | + if len(p) ==2: | ||
| 286 | + line.AddPoint(p[0], p[1],0) | ||
| 287 | + line.AddPoint(p_next[0], p_next[1],0) | ||
| 288 | + else: | ||
| 289 | + line.AddPoint(p[0], p[1]) | ||
| 290 | + line.AddPoint(p_next[0], p_next[1]) | ||
| 291 | + bians.append(line) | ||
| 292 | + | ||
| 293 | + return bians | ||
| 294 | + | ||
| 295 | + @classmethod | ||
| 296 | + def create_polygon(cls,ps): | ||
| 297 | + | ||
| 298 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 299 | + for p in ps: | ||
| 300 | + ring.AddPoint(p[0], p[1]) | ||
| 301 | + poly = ogr.Geometry(ogr.wkbPolygon) | ||
| 302 | + poly.AddGeometry(ring) | ||
| 303 | + return poly | ||
| 304 | + | ||
| 305 | + | ||
| 306 | +if __name__ == '__main__': | ||
| 307 | + import time | ||
| 308 | + t1 = time.time() | ||
| 309 | + gdal.UseExceptions() | ||
| 310 | + | ||
| 311 | + sd = ShapeData(r"J:\Data\制图综合result\t4.shp") | ||
| 312 | + mp = ogr.Geometry(ogr.wkbMultiPolygon) | ||
| 313 | + polygons = sd.get_polygons() | ||
| 314 | + for p in polygons: | ||
| 315 | + mp.AddGeometry(p) | ||
| 316 | + | ||
| 317 | + wkts = PolygonDivision.triangle_division(mp) | ||
| 318 | + | ||
| 319 | + result = r"J:\Data\制图综合result\t4_merge.shp" | ||
| 320 | + | ||
| 321 | + ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 322 | + | ||
| 323 | + print(time.time()-t1) | ||
| 324 | + | ||
| 325 | + |
| @@ -3,13 +3,10 @@ | @@ -3,13 +3,10 @@ | ||
| 3 | #createtime: 2022/3/15 | 3 | #createtime: 2022/3/15 |
| 4 | #email: nheweijun@sina.com | 4 | #email: nheweijun@sina.com |
| 5 | 5 | ||
| 6 | -from osgeo import ogr | ||
| 7 | -from osgeo.ogr import * | ||
| 8 | -import math | ||
| 9 | -import os | ||
| 10 | -import copy | 6 | +import uuid |
| 11 | class RepresentPoint: | 7 | class RepresentPoint: |
| 12 | 8 | ||
| 13 | def __init__(self,point,polygon): | 9 | def __init__(self,point,polygon): |
| 14 | self.point = point | 10 | self.point = point |
| 15 | self.polygon = polygon | 11 | self.polygon = polygon |
| 12 | + self.uuid = uuid.uuid1().__str__() |
| @@ -16,7 +16,7 @@ class ShapeData: | @@ -16,7 +16,7 @@ class ShapeData: | ||
| 16 | 16 | ||
| 17 | def __init__(self,path): | 17 | def __init__(self,path): |
| 18 | 18 | ||
| 19 | - self.ds: DataSource = self.driver.Open(path, 0) | 19 | + self.ds: DataSource = self.driver.Open(path, 1) |
| 20 | if not self.ds: | 20 | if not self.ds: |
| 21 | raise Exception("打开数据失败!") | 21 | raise Exception("打开数据失败!") |
| 22 | self.layer: Layer = self.ds.GetLayer(0) | 22 | self.layer: Layer = self.ds.GetLayer(0) |
| @@ -28,13 +28,46 @@ class ShapeData: | @@ -28,13 +28,46 @@ class ShapeData: | ||
| 28 | for feature in self.layer: | 28 | for feature in self.layer: |
| 29 | f:Feature = feature | 29 | f:Feature = feature |
| 30 | geom : Geometry = copy.deepcopy(f.GetGeometryRef()) | 30 | geom : Geometry = copy.deepcopy(f.GetGeometryRef()) |
| 31 | - if geom.GetGeometryType() == 3 or geom.GetGeometryType() == -2147483645: | ||
| 32 | - polygons.append(geom) | ||
| 33 | - if geom.GetGeometryType() == 6 or geom.GetGeometryType() == -2147483642: | 31 | + if geom is None: |
| 32 | + continue | ||
| 33 | + if geom.GetGeometryType() in [3,-2147483645,3001]: | ||
| 34 | + polygons.append(ogr.ForceToPolygon(geom)) | ||
| 35 | + if geom.GetGeometryType() in [6 ,-2147483642 ,3006]: | ||
| 34 | for i in range(geom.GetGeometryCount()): | 36 | for i in range(geom.GetGeometryCount()): |
| 35 | - polygons.append(geom.GetGeometryRef(i)) | 37 | + polygons.append(ogr.ForceToPolygon(geom.GetGeometryRef(i))) |
| 38 | + | ||
| 39 | + # p_cs = [] | ||
| 40 | + # for p in polygons: | ||
| 41 | + # polygon_line: Geometry = self.get_polygon_lines(p) | ||
| 42 | + # print(polygon_line) | ||
| 43 | + # p_cs.append(self.create_polygon(polygon_line.GetPoints())) | ||
| 44 | + # | ||
| 45 | + # return p_cs | ||
| 36 | return polygons | 46 | return polygons |
| 37 | 47 | ||
| 48 | + | ||
| 49 | + def get_polygon_lines(self,polygon): | ||
| 50 | + #无孔Polygon | ||
| 51 | + if polygon.GetGeometryCount() in [0,1]: | ||
| 52 | + polygon_line : Geometry = ogr.ForceToLineString(polygon) | ||
| 53 | + # 有孔Polygon | ||
| 54 | + else: | ||
| 55 | + polygon_line : Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 56 | + | ||
| 57 | + return polygon_line | ||
| 58 | + | ||
| 59 | + | ||
| 60 | + def create_polygon(self,ps): | ||
| 61 | + | ||
| 62 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 63 | + for p in ps: | ||
| 64 | + ring.AddPoint(p[0], p[1],0) | ||
| 65 | + poly = ogr.Geometry(ogr.wkbPolygon) | ||
| 66 | + poly.AddGeometry(ring) | ||
| 67 | + return poly | ||
| 68 | + | ||
| 69 | + | ||
| 70 | + | ||
| 38 | def close(self): | 71 | def close(self): |
| 39 | self.ds.Destroy() | 72 | self.ds.Destroy() |
| 40 | 73 | ||
| @@ -94,4 +127,35 @@ class ShapeData: | @@ -94,4 +127,35 @@ class ShapeData: | ||
| 94 | feat_new = ogr.Feature(layer.GetLayerDefn()) | 127 | feat_new = ogr.Feature(layer.GetLayerDefn()) |
| 95 | feat_new.SetGeometry(geom) | 128 | feat_new.SetGeometry(geom) |
| 96 | layer.CreateFeature(feat_new) | 129 | layer.CreateFeature(feat_new) |
| 97 | - data_source.Destroy() | ||
| 130 | + data_source.Destroy() | ||
| 131 | + | ||
| 132 | + | ||
| 133 | +if __name__ == '__main__': | ||
| 134 | + sd = ShapeData(r"J:\Data\制图综合result\test.shp") | ||
| 135 | + # polygons = sd.get_polygons() | ||
| 136 | + # wkts = [] | ||
| 137 | + # for p in polygons: | ||
| 138 | + # # print(p.ExportToWkt()) | ||
| 139 | + # wkts.append(p.ExportToWkt()) | ||
| 140 | + # result = r"J:\Data\制图综合result\zhongshan_ronghe.shp" | ||
| 141 | + # ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 142 | + | ||
| 143 | + layer = sd.layer | ||
| 144 | + | ||
| 145 | + fn = "PG: user=postgres password=chinadci host=172.26.60.101 port=5432 dbname=ceshi " | ||
| 146 | + driver = ogr.GetDriverByName("PostgreSQL") | ||
| 147 | + if driver is None: | ||
| 148 | + raise Exception("打开PostgreSQL驱动失败,可能是当前GDAL未支持PostgreSQL驱动!") | ||
| 149 | + ds:DataSource = driver.Open(fn, 1) | ||
| 150 | + | ||
| 151 | + | ||
| 152 | + pg_layer = ds.CreateLayer("test", layer.GetSpatialRef(), layer.GetGeomType(), ["overwrite=yes"]) | ||
| 153 | + schema = layer.schema | ||
| 154 | + pg_layer.CreateFields(schema) | ||
| 155 | + for feature in layer: | ||
| 156 | + out_feature: Feature = copy.copy(feature) | ||
| 157 | + out_feature.SetFID(out_feature.GetFID() + 1) | ||
| 158 | + pg_layer.CreateFeature(out_feature) | ||
| 159 | + | ||
| 160 | + | ||
| 161 | + ds.Destroy() |
| @@ -10,19 +10,21 @@ import math | @@ -10,19 +10,21 @@ import math | ||
| 10 | import os | 10 | import os |
| 11 | import copy | 11 | import copy |
| 12 | os.environ["CUDA_VISIBLE_DEVICES"] = "-1" | 12 | os.environ["CUDA_VISIBLE_DEVICES"] = "-1" |
| 13 | - | 13 | +from test.zonghe.ConcaveHull import concaveHull |
| 14 | from test.zonghe.ShapeData import ShapeData | 14 | from test.zonghe.ShapeData import ShapeData |
| 15 | from test.zonghe.Delauney import DelauneyNode,DelauneyLine,DelauneyMinTree | 15 | from test.zonghe.Delauney import DelauneyNode,DelauneyLine,DelauneyMinTree |
| 16 | from test.zonghe.RepresentPoint import RepresentPoint | 16 | from test.zonghe.RepresentPoint import RepresentPoint |
| 17 | from test.zonghe.Util import Util | 17 | from test.zonghe.Util import Util |
| 18 | import cv2 | 18 | import cv2 |
| 19 | +import time | ||
| 20 | +import numpy as np | ||
| 19 | 21 | ||
| 20 | class Zonghe: | 22 | class Zonghe: |
| 21 | 23 | ||
| 22 | data:ShapeData | 24 | data:ShapeData |
| 23 | - area_threshold = 100.0 | 25 | + area_threshold = 10.0 |
| 24 | buffer_threshold = 100.0 | 26 | buffer_threshold = 100.0 |
| 25 | - distance_buffer_threshold = 2.114691025217302e-04 | 27 | + distance_buffer_threshold = 1.114691025217302e-04 |
| 26 | 28 | ||
| 27 | def __init__(self,data): | 29 | def __init__(self,data): |
| 28 | self.data = data | 30 | self.data = data |
| @@ -37,11 +39,8 @@ class Zonghe: | @@ -37,11 +39,8 @@ class Zonghe: | ||
| 37 | 39 | ||
| 38 | line_length = math.sqrt(math.pow(polygon_env[1] - polygon_env[0],2) + math.pow(polygon_env[3] - polygon_env[2],2)) | 40 | line_length = math.sqrt(math.pow(polygon_env[1] - polygon_env[0],2) + math.pow(polygon_env[3] - polygon_env[2],2)) |
| 39 | 41 | ||
| 40 | - | ||
| 41 | short_length = min(polygon_env[1]-polygon_env[0],polygon_env[3]-polygon_env[2]) | 42 | short_length = min(polygon_env[1]-polygon_env[0],polygon_env[3]-polygon_env[2]) |
| 42 | 43 | ||
| 43 | - | ||
| 44 | - | ||
| 45 | center:Geometry = polygon.Centroid() | 44 | center:Geometry = polygon.Centroid() |
| 46 | # print(center) | 45 | # print(center) |
| 47 | 46 | ||
| @@ -80,7 +79,8 @@ class Zonghe: | @@ -80,7 +79,8 @@ class Zonghe: | ||
| 80 | # print("in_hole") | 79 | # print("in_hole") |
| 81 | 80 | ||
| 82 | angle1,angle2=None,None | 81 | angle1,angle2=None,None |
| 83 | - | 82 | + line = None |
| 83 | + oneside_area, otherside_area = None,None | ||
| 84 | for angle in direction: | 84 | for angle in direction: |
| 85 | 85 | ||
| 86 | if in_hole: | 86 | if in_hole: |
| @@ -91,6 +91,10 @@ class Zonghe: | @@ -91,6 +91,10 @@ class Zonghe: | ||
| 91 | oneside_area, otherside_area = self.jude(polygon, line, angle, line_length) | 91 | oneside_area, otherside_area = self.jude(polygon, line, angle, line_length) |
| 92 | 92 | ||
| 93 | 93 | ||
| 94 | + if oneside_area > 0 and otherside_area >0: | ||
| 95 | + if abs(oneside_area-otherside_area) < area_thre: | ||
| 96 | + break | ||
| 97 | + | ||
| 94 | if last_state is None: | 98 | if last_state is None: |
| 95 | 99 | ||
| 96 | angle2 = angle | 100 | angle2 = angle |
| @@ -115,7 +119,14 @@ class Zonghe: | @@ -115,7 +119,14 @@ class Zonghe: | ||
| 115 | else: | 119 | else: |
| 116 | last_state = now_state | 120 | last_state = now_state |
| 117 | 121 | ||
| 118 | - line = self.division(polygon, center, in_hole, line_length, angle1, angle2, area_thre) | 122 | + #第一条线就是均分线 |
| 123 | + if angle1 is None or angle2 is None: | ||
| 124 | + pass | ||
| 125 | + else: | ||
| 126 | + #如果面积差大于阈值,二分法查找 | ||
| 127 | + if abs(oneside_area - otherside_area) > area_thre: | ||
| 128 | + line = self.division(polygon, center, in_hole, line_length, angle1, angle2, area_thre) | ||
| 129 | + | ||
| 119 | 130 | ||
| 120 | # 提前return | 131 | # 提前return |
| 121 | if in_hole: | 132 | if in_hole: |
| @@ -156,6 +167,7 @@ class Zonghe: | @@ -156,6 +167,7 @@ class Zonghe: | ||
| 156 | ylist.append(pi.GetY()) | 167 | ylist.append(pi.GetY()) |
| 157 | plist.append(pi) | 168 | plist.append(pi) |
| 158 | 169 | ||
| 170 | + | ||
| 159 | reprecent_point = [(min(xlist)+max(xlist))/2.0,(min(ylist)+max(ylist))/2.0] | 171 | reprecent_point = [(min(xlist)+max(xlist))/2.0,(min(ylist)+max(ylist))/2.0] |
| 160 | 172 | ||
| 161 | reprecent_point = self.creat_point(reprecent_point) | 173 | reprecent_point = self.creat_point(reprecent_point) |
| @@ -298,6 +310,8 @@ class Zonghe: | @@ -298,6 +310,8 @@ class Zonghe: | ||
| 298 | def division(self,polygon,center,in_hole,line_length,angle1,angle2,area_thre): | 310 | def division(self,polygon,center,in_hole,line_length,angle1,angle2,area_thre): |
| 299 | 311 | ||
| 300 | mid_angle = (angle1 + angle2)/2.0 | 312 | mid_angle = (angle1 + angle2)/2.0 |
| 313 | + | ||
| 314 | + | ||
| 301 | if in_hole: | 315 | if in_hole: |
| 302 | line = self.get_doubleline(center.GetX(), center.GetY(), mid_angle, line_length) | 316 | line = self.get_doubleline(center.GetX(), center.GetY(), mid_angle, line_length) |
| 303 | else: | 317 | else: |
| @@ -373,55 +387,41 @@ class Zonghe: | @@ -373,55 +387,41 @@ class Zonghe: | ||
| 373 | return p | 387 | return p |
| 374 | 388 | ||
| 375 | 389 | ||
| 376 | - | ||
| 377 | - | ||
| 378 | def create_delauney(self,rps): | 390 | def create_delauney(self,rps): |
| 379 | multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) | 391 | multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) |
| 380 | 392 | ||
| 381 | rp_dict = {} | 393 | rp_dict = {} |
| 382 | - line_set = set() | ||
| 383 | delauney_lines = [] | 394 | delauney_lines = [] |
| 384 | 395 | ||
| 396 | + rps_sub = set() | ||
| 385 | for rp in rps: | 397 | for rp in rps: |
| 386 | multipoint.AddGeometry(rp.point) | 398 | multipoint.AddGeometry(rp.point) |
| 399 | + # 多边形代表点相同,需要融合多边形 | ||
| 400 | + if rp_dict.get(rp.point.GetPoint(0).__str__()): | ||
| 401 | + rp_exist = rp_dict.get(rp.point.GetPoint(0).__str__()) | ||
| 402 | + rp_exist.polygon = rp_exist.polygon.Union(rp.polygon) | ||
| 403 | + else: | ||
| 404 | + rp_dict[rp.point.GetPoint(0).__str__()] = rp | ||
| 405 | + rps_sub.add(rp) | ||
| 387 | 406 | ||
| 388 | - rp_dict[rp.point.GetPoint(0).__str__()] = rp | ||
| 389 | - | ||
| 390 | - delauney:Geometry = multipoint.DelaunayTriangulation() | 407 | + delauney:Geometry = multipoint.DelaunayTriangulation(bOnlyEdges=True) |
| 391 | 408 | ||
| 392 | for index in range(delauney.GetGeometryCount()): | 409 | for index in range(delauney.GetGeometryCount()): |
| 393 | - triangle = delauney.GetGeometryRef(index) | ||
| 394 | - | ||
| 395 | - triangle_line:Geometry = ogr.ForceToLineString(triangle) | ||
| 396 | - | 410 | + triangle_line:Geometry = delauney.GetGeometryRef(index) |
| 411 | + p = triangle_line.GetPoint(0) | ||
| 412 | + p_next = triangle_line.GetPoint(1) | ||
| 397 | 413 | ||
| 398 | - for pi in range(triangle_line.GetPointCount()-1): | ||
| 399 | - p = triangle_line.GetPoint(pi) | ||
| 400 | - p_next = triangle_line.GetPoint(pi+1) | 414 | + rp1 = rp_dict.get(p.__str__()) |
| 415 | + rp2 = rp_dict.get(p_next.__str__()) | ||
| 401 | 416 | ||
| 402 | - if p[0] < p_next[0]: | ||
| 403 | - key = "{}{}".format(p.__str__(),p_next.__str__()) | ||
| 404 | - elif p[0] > p_next[0]: | ||
| 405 | - key = "{}{}".format(p_next.__str__(), p.__str__()) | ||
| 406 | - else: | ||
| 407 | - if p[1] < p_next[1]: | ||
| 408 | - key = "{}{}".format(p.__str__(), p_next.__str__()) | ||
| 409 | - else: | ||
| 410 | - key = "{}{}".format(p_next.__str__(), p.__str__()) | ||
| 411 | - | ||
| 412 | - if not line_set.__contains__(key): | ||
| 413 | - line_set.add(key) | ||
| 414 | - rp1 = rp_dict.get(p.__str__()) | ||
| 415 | - rp2 = rp_dict.get(p_next.__str__()) | 417 | + delauney_line = DelauneyLine(rp1,rp2) |
| 418 | + delauney_lines.append(delauney_line) | ||
| 416 | 419 | ||
| 417 | - delauney_line = DelauneyLine(rp1,rp2) | ||
| 418 | - delauney_lines.append(delauney_line) | 420 | + return delauney_lines,rps_sub |
| 419 | 421 | ||
| 420 | - return delauney_lines | ||
| 421 | 422 | ||
| 422 | 423 | ||
| 423 | - | ||
| 424 | - def create_min_delauney(self,delauney_lines,rps,polygons): | 424 | + def create_min_delauney(self,delauney_lines,rps): |
| 425 | ''' | 425 | ''' |
| 426 | 使用prim算法计算最小生成树 | 426 | 使用prim算法计算最小生成树 |
| 427 | :param delauney_lines: | 427 | :param delauney_lines: |
| @@ -429,68 +429,72 @@ class Zonghe: | @@ -429,68 +429,72 @@ class Zonghe: | ||
| 429 | :return: | 429 | :return: |
| 430 | ''' | 430 | ''' |
| 431 | 431 | ||
| 432 | - kv = {} | 432 | + kv = dict() |
| 433 | + print(len(rps)) | ||
| 434 | + | ||
| 435 | + | ||
| 433 | rps_set = set(rps) | 436 | rps_set = set(rps) |
| 434 | 437 | ||
| 435 | for delauney_line in delauney_lines: | 438 | for delauney_line in delauney_lines: |
| 436 | if kv.get(delauney_line.rp1): | 439 | if kv.get(delauney_line.rp1): |
| 437 | - | ||
| 438 | kv[delauney_line.rp1].add(delauney_line) | 440 | kv[delauney_line.rp1].add(delauney_line) |
| 439 | else: | 441 | else: |
| 440 | kv[delauney_line.rp1] = set() | 442 | kv[delauney_line.rp1] = set() |
| 441 | kv[delauney_line.rp1].add(delauney_line) | 443 | kv[delauney_line.rp1].add(delauney_line) |
| 442 | 444 | ||
| 443 | if kv.get(delauney_line.rp2): | 445 | if kv.get(delauney_line.rp2): |
| 444 | - | ||
| 445 | kv[delauney_line.rp2].add(delauney_line) | 446 | kv[delauney_line.rp2].add(delauney_line) |
| 446 | else: | 447 | else: |
| 447 | - | ||
| 448 | kv[delauney_line.rp2] = set() | 448 | kv[delauney_line.rp2] = set() |
| 449 | kv[delauney_line.rp2].add(delauney_line) | 449 | kv[delauney_line.rp2].add(delauney_line) |
| 450 | 450 | ||
| 451 | + print(len(kv)) | ||
| 452 | + | ||
| 453 | + print("完成三角边倒排索引") | ||
| 451 | 454 | ||
| 452 | #初始化树 | 455 | #初始化树 |
| 453 | delauney_lines = sorted(delauney_lines,key=lambda x:x.distance) | 456 | delauney_lines = sorted(delauney_lines,key=lambda x:x.distance) |
| 454 | - | ||
| 455 | - | ||
| 456 | delauney_min_tree = DelauneyMinTree() | 457 | delauney_min_tree = DelauneyMinTree() |
| 457 | - delauney_min_tree.append(delauney_lines[0]) | 458 | + |
| 459 | + delauney_min_tree.append(delauney_lines[0],kv) | ||
| 458 | 460 | ||
| 459 | rps_set.remove(delauney_lines[0].rp1) | 461 | rps_set.remove(delauney_lines[0].rp1) |
| 460 | rps_set.remove(delauney_lines[0].rp2) | 462 | rps_set.remove(delauney_lines[0].rp2) |
| 463 | + | ||
| 461 | kv[delauney_lines[0].rp1].remove(delauney_lines[0]) | 464 | kv[delauney_lines[0].rp1].remove(delauney_lines[0]) |
| 462 | kv[delauney_lines[0].rp2].remove(delauney_lines[0]) | 465 | kv[delauney_lines[0].rp2].remove(delauney_lines[0]) |
| 463 | 466 | ||
| 467 | + print("完成最小生成树初始化") | ||
| 464 | 468 | ||
| 465 | while rps_set.__len__()>0: | 469 | while rps_set.__len__()>0: |
| 466 | 470 | ||
| 467 | - relate_delauney_line = delauney_min_tree.get_other_relate_delauney_lines(kv) | 471 | + print(rps_set.__len__()) |
| 472 | + t1 = time.time() | ||
| 473 | + # relate_delauney_line = delauney_min_tree.get_other_relate_delauney_lines(kv,rps_set) | ||
| 474 | + | ||
| 475 | + relate_delauney_line = delauney_min_tree.touch_delauney_lines | ||
| 476 | + | ||
| 468 | 477 | ||
| 469 | relate_delauney_line_sort = sorted(relate_delauney_line,key=lambda x:x.distance) | 478 | relate_delauney_line_sort = sorted(relate_delauney_line,key=lambda x:x.distance) |
| 470 | 479 | ||
| 471 | min_distance_line = relate_delauney_line_sort[0] | 480 | min_distance_line = relate_delauney_line_sort[0] |
| 472 | - | ||
| 473 | #删除 | 481 | #删除 |
| 474 | other_rp = delauney_min_tree.get_other_rp(min_distance_line) | 482 | other_rp = delauney_min_tree.get_other_rp(min_distance_line) |
| 483 | + | ||
| 475 | if other_rp is None: | 484 | if other_rp is None: |
| 476 | kv[min_distance_line.rp1].remove(min_distance_line) | 485 | kv[min_distance_line.rp1].remove(min_distance_line) |
| 477 | kv[min_distance_line.rp2].remove(min_distance_line) | 486 | kv[min_distance_line.rp2].remove(min_distance_line) |
| 478 | continue | 487 | continue |
| 479 | 488 | ||
| 480 | - delauney_min_tree.append(min_distance_line) | 489 | + delauney_min_tree.append(min_distance_line,kv) |
| 481 | 490 | ||
| 482 | rps_set.remove(other_rp) | 491 | rps_set.remove(other_rp) |
| 483 | 492 | ||
| 484 | kv[min_distance_line.rp1].remove(min_distance_line) | 493 | kv[min_distance_line.rp1].remove(min_distance_line) |
| 485 | kv[min_distance_line.rp2].remove(min_distance_line) | 494 | kv[min_distance_line.rp2].remove(min_distance_line) |
| 486 | 495 | ||
| 487 | - | ||
| 488 | - | ||
| 489 | - for l in delauney_min_tree.delauney_lines_list: | ||
| 490 | - line = l.line | ||
| 491 | - # print("\"" + line.ExportToWkt() + "\",") | ||
| 492 | - | ||
| 493 | - # print(delauney_min_tree.delauney_lines_list.__len__()) | 496 | + # print(time.time() - t2) |
| 497 | + print("完成最小生成树") | ||
| 494 | 498 | ||
| 495 | return delauney_min_tree | 499 | return delauney_min_tree |
| 496 | 500 | ||
| @@ -546,277 +550,154 @@ class Zonghe: | @@ -546,277 +550,154 @@ class Zonghe: | ||
| 546 | 550 | ||
| 547 | return trees | 551 | return trees |
| 548 | 552 | ||
| 549 | - def merge(self,trees): | ||
| 550 | - | ||
| 551 | - polygons = [] | ||
| 552 | - for tree in trees: | ||
| 553 | - | ||
| 554 | - merge_polygon_raw = list() | ||
| 555 | - | ||
| 556 | - dls = tree.get_delauney_lines() | ||
| 557 | - for dl in dls: | ||
| 558 | - p1 = dl.rp1.polygon | ||
| 559 | - p2 = dl.rp2.polygon | ||
| 560 | - | ||
| 561 | - merge_polygon_raw.append(p1) | ||
| 562 | - merge_polygon_raw.append(p2) | ||
| 563 | - line = dl.line | ||
| 564 | - | ||
| 565 | - p1_lines = self.get_polygon_lines(p1) | ||
| 566 | - p2_lines = self.get_polygon_lines(p2) | ||
| 567 | - | ||
| 568 | - p1_intersect_lines = [l for l in p1_lines if l.Intersect(line)] | ||
| 569 | - p2_intersect_lines = [l for l in p2_lines if l.Intersect(line)] | ||
| 570 | - | ||
| 571 | - if p1_intersect_lines.__len__()>1: | ||
| 572 | - p1_intersect_lines = sorted(p1_intersect_lines,key=lambda x:p2.Distance(x)) | ||
| 573 | - p1_intersect_line_rep = p1_intersect_lines[0] | ||
| 574 | - elif p1_intersect_lines.__len__()==1: | ||
| 575 | - p1_intersect_line_rep = p1_intersect_lines[0] | ||
| 576 | - else: | ||
| 577 | - continue | ||
| 578 | - | ||
| 579 | - | ||
| 580 | - if p2_intersect_lines.__len__()>1: | ||
| 581 | - p2_intersect_lines = sorted(p2_intersect_lines,key=lambda x:p1.Distance(x)) | ||
| 582 | - p2_intersect_line_rep = p2_intersect_lines[0] | ||
| 583 | - elif p2_intersect_lines.__len__()==1: | ||
| 584 | - p2_intersect_line_rep = p2_intersect_lines[0] | ||
| 585 | - else: | ||
| 586 | - continue | ||
| 587 | - | ||
| 588 | - | ||
| 589 | - # #两条线没有距离跳过 | ||
| 590 | - # if p2_intersect_line_rep.Distance(p1_intersect_line_rep) == 0: | ||
| 591 | - # continue | ||
| 592 | - # else: | ||
| 593 | - | ||
| 594 | - mid_polygon = self.create_mid_polygon(p1_intersect_line_rep,p2_intersect_line_rep,p1,p2) | ||
| 595 | - | ||
| 596 | - if mid_polygon.GetArea() > 0.0002116361000058077*0.0002116361000058077: | ||
| 597 | - continue | ||
| 598 | 553 | ||
| 599 | - merge_polygon_raw.append(mid_polygon) | ||
| 600 | - | ||
| 601 | - merge_polygon = None | ||
| 602 | - for p in merge_polygon_raw: | ||
| 603 | - if merge_polygon is None: | ||
| 604 | - merge_polygon = p | ||
| 605 | - else: | ||
| 606 | - merge_polygon = merge_polygon.Union(p) | ||
| 607 | - | ||
| 608 | - polygons.append(merge_polygon) | ||
| 609 | - | ||
| 610 | - | ||
| 611 | - return polygons | 554 | + def create_polygon(self,p1,p2,p3,p4): |
| 612 | 555 | ||
| 556 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 557 | + ring.AddPoint(p1[0], p1[1]) | ||
| 558 | + ring.AddPoint(p2[0], p2[1]) | ||
| 559 | + ring.AddPoint(p3[0], p3[1]) | ||
| 560 | + ring.AddPoint(p4[0], p4[1]) | ||
| 561 | + ring.AddPoint(p1[0], p1[1]) | ||
| 613 | 562 | ||
| 614 | - def merge2(self,trees): | 563 | + poly = ogr.Geometry(ogr.wkbPolygon) |
| 564 | + poly.AddGeometry(ring) | ||
| 565 | + return poly | ||
| 615 | 566 | ||
| 616 | - polygons = [] | ||
| 617 | 567 | ||
| 568 | + def get_polygon_lines(self,polygon): | ||
| 569 | + #无孔Polygon | ||
| 570 | + if polygon.GetGeometryCount() in [0,1]: | ||
| 571 | + polygon_line : Geometry = ogr.ForceToLineString(polygon) | ||
| 572 | + # 有孔Polygon | ||
| 573 | + else: | ||
| 574 | + polygon_line : Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 618 | 575 | ||
| 576 | + return polygon_line | ||
| 619 | 577 | ||
| 578 | + def merge_concave(self, trees, distance_threshold): | ||
| 579 | + merge_polygons = [] | ||
| 580 | + count = 1 | ||
| 620 | 581 | ||
| 621 | for tree in trees: | 582 | for tree in trees: |
| 583 | + print(count) | ||
| 584 | + count+=1 | ||
| 585 | + polygons = list(tree.get_polygons()) | ||
| 622 | 586 | ||
| 623 | - tree_polygons = tree.get_polygons() | 587 | + merge_raw: Geometry = polygons[0] |
| 588 | + for p in polygons: | ||
| 589 | + merge_raw = merge_raw.Union(p) | ||
| 624 | 590 | ||
| 625 | points = [] | 591 | points = [] |
| 626 | - for p in tree_polygons: | ||
| 627 | - | ||
| 628 | - if p.GetGeometryCount() == 1: | ||
| 629 | - polygon_line: Geometry = ogr.ForceToLineString(p) | ||
| 630 | - | ||
| 631 | - polygon_line.Con | ||
| 632 | - # 有孔Polygon | ||
| 633 | - else: | ||
| 634 | - polygon_line: Geometry = ogr.ForceToLineString(p.GetGeometryRef(0)) | ||
| 635 | - | ||
| 636 | - points.extend(polygon_line.GetPoints()[:-1]) | ||
| 637 | - | ||
| 638 | - multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) | ||
| 639 | - | ||
| 640 | - for p in points: | ||
| 641 | - poi = ogr.Geometry(ogr.wkbPoint) | ||
| 642 | - poi.AddPoint(p[0],p[1]) | ||
| 643 | - multipoint.AddGeometry(poi) | ||
| 644 | - | ||
| 645 | - delauney: Geometry = multipoint.DelaunayTriangulation() | ||
| 646 | - merge_polygon = None | ||
| 647 | - | ||
| 648 | - for p in delauney: | ||
| 649 | - # if multi_polygon.Contains(p): | ||
| 650 | - # continue | ||
| 651 | - | ||
| 652 | - pline:Geometry = ogr.ForceToLineString(p) | ||
| 653 | - pline :list = pline.GetPoints() | ||
| 654 | - pline.append(pline[1]) | ||
| 655 | - | ||
| 656 | - | ||
| 657 | - pass_or_not = False | ||
| 658 | - for indx in range(3): | ||
| 659 | - p1 = pline[indx] | ||
| 660 | - p2 = pline[indx+1] | ||
| 661 | - | ||
| 662 | - ppline:Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 663 | - ppline.AddPoint(p1[0],p1[1]) | ||
| 664 | - ppline.AddPoint(p2[0], p2[1]) | ||
| 665 | - | ||
| 666 | - | ||
| 667 | - | ||
| 668 | - p3:Geometry = ogr.Geometry(ogr.wkbPoint) | ||
| 669 | - p3.AddPoint(pline[indx+2][0], pline[indx+2][1]) | ||
| 670 | - | ||
| 671 | - if p3.Distance(ppline) > 0.0002116361000058077 or ppline.Length() > 0.0002116361000058077: | ||
| 672 | - pass_or_not = True | ||
| 673 | - break | ||
| 674 | - | ||
| 675 | - if pass_or_not: | ||
| 676 | - continue | ||
| 677 | - | ||
| 678 | - if merge_polygon is None: | ||
| 679 | - merge_polygon = p | ||
| 680 | - else: | ||
| 681 | - merge_polygon = merge_polygon.Union(p) | ||
| 682 | 592 | ||
| 683 | 593 | ||
| 594 | + for i in range(merge_raw.GetGeometryCount()): | ||
| 684 | 595 | ||
| 685 | - polygons.append(merge_polygon) | 596 | + poly = merge_raw.GetGeometryRef(i) |
| 597 | + poly_line :Geometry = self.get_polygon_lines(poly) | ||
| 598 | + if poly_line: | ||
| 599 | + for indx in range(poly_line.GetPointCount() - 1): | ||
| 600 | + poi = poly_line.GetPoint(indx) | ||
| 686 | 601 | ||
| 602 | + points.append(poi) | ||
| 687 | 603 | ||
| 688 | - return polygons | 604 | + poi_next = poly_line.GetPoint(indx + 1) |
| 689 | 605 | ||
| 690 | - def merge_circle(self): | ||
| 691 | - pass | 606 | + dis = math.sqrt(math.pow(poi[0] - poi_next[0], 2) + math.pow(poi[1] - poi_next[1], 2)) |
| 607 | + # print(dis) | ||
| 608 | + if dis > distance_threshold: | ||
| 609 | + times = int(dis / distance_threshold) | ||
| 610 | + # print(times) | ||
| 611 | + for time in range(1, times + 1): | ||
| 612 | + x, y = self.get_subpoint(poi[0], poi[1], poi_next[0], poi_next[1], (time * distance_threshold)) | ||
| 613 | + points.append([x, y]) | ||
| 692 | 614 | ||
| 615 | + points = np.array([[p[0], p[1]] for p in points]) | ||
| 693 | 616 | ||
| 694 | - def create_mid_polygon(self,p1_intersect_line_rep,p2_intersect_line_rep,p1,p2): | ||
| 695 | - ''' | ||
| 696 | - 创建衔接polygon | ||
| 697 | - :param line: | ||
| 698 | - :return: | ||
| 699 | - ''' | ||
| 700 | 617 | ||
| 701 | - if p1_intersect_line_rep.Intersect(p2_intersect_line_rep): | 618 | + cp = [] |
| 619 | + for pp in points: | ||
| 620 | + poi = ogr.Geometry(ogr.wkbPoint) | ||
| 621 | + poi.AddPoint(pp[0], pp[1]) | ||
| 622 | + cp.append(poi) | ||
| 702 | 623 | ||
| 703 | - p1_rep_p1 = p1_intersect_line_rep.GetPoints()[0] | ||
| 704 | - p1_rep_p2 = p1_intersect_line_rep.GetPoints()[1] | 624 | + merge_p_line = concaveHull(points, 3) |
| 705 | 625 | ||
| 706 | - p2_rep_p1 = p2_intersect_line_rep.GetPoints()[0] | ||
| 707 | - p2_rep_p2 = p2_intersect_line_rep.GetPoints()[1] | 626 | + ring = ogr.Geometry(ogr.wkbLinearRing) |
| 708 | 627 | ||
| 709 | - polygon = self.create_polygon(p1_rep_p1, p2_rep_p2, p1_rep_p2, p2_rep_p1) | 628 | + merge_p = ogr.Geometry(ogr.wkbPolygon) |
| 710 | 629 | ||
| 711 | - else: | 630 | + for l in merge_p_line: |
| 631 | + ring.AddPoint(l[0], l[1]) | ||
| 712 | 632 | ||
| 713 | - p1_rep_p1 = p1_intersect_line_rep.GetPoints()[0] | ||
| 714 | - p1_rep_p2 = p1_intersect_line_rep.GetPoints()[1] | 633 | + ring.AddPoint(merge_p_line[0][0], merge_p_line[0][1]) |
| 715 | 634 | ||
| 716 | - p2_rep_p1 = p2_intersect_line_rep.GetPoints()[0] | ||
| 717 | - p2_rep_p2 = p2_intersect_line_rep.GetPoints()[1] | 635 | + merge_p.AddGeometry(ring) |
| 636 | + merge_p = merge_p.Simplify(self.distance_buffer_threshold/10) | ||
| 637 | + merge_polygons.append(merge_p) | ||
| 718 | 638 | ||
| 719 | - line1 = ogr.Geometry(ogr.wkbLineString) | 639 | + return merge_polygons |
| 720 | 640 | ||
| 721 | 641 | ||
| 722 | - line1.AddPoint(p1_rep_p1[0], p1_rep_p1[1]) | ||
| 723 | - line1.AddPoint(p2_rep_p1[0], p2_rep_p1[1]) | 642 | + def get_subpoint(self, x0, y0, x1, y1, len_size): |
| 724 | 643 | ||
| 725 | - line2 = ogr.Geometry(ogr.wkbLineString) | ||
| 726 | - line2.AddPoint(p1_rep_p2[0], p1_rep_p2[1]) | ||
| 727 | - line2.AddPoint(p2_rep_p2[0], p2_rep_p2[1]) | 644 | + len_size = len_size |
| 645 | + tanx = abs(y1 - y0) / abs(x1 - x0) | ||
| 646 | + cosx = 1 / math.sqrt(1 + tanx * tanx) | ||
| 647 | + dx = cosx * len_size | ||
| 648 | + dy = tanx * dx | ||
| 728 | 649 | ||
| 729 | - if line1.Intersect(line2): | ||
| 730 | - polygon = self.create_polygon(p1_rep_p1, p1_rep_p2, p2_rep_p1, p2_rep_p2) | 650 | + if x1 == x0: |
| 651 | + x2 = x0 | ||
| 652 | + if y1 > y0: | ||
| 653 | + y2 = y0 + abs(dy) | ||
| 731 | else: | 654 | else: |
| 732 | - | ||
| 733 | - polygon = self.create_polygon(p1_rep_p1, p1_rep_p2, p2_rep_p2, p2_rep_p1) | ||
| 734 | - if polygon.Intersect(p1) or polygon.Intersect(p2): | ||
| 735 | - polygon = self.create_polygon(p1_rep_p1, p1_rep_p2, p2_rep_p1, p2_rep_p2) | ||
| 736 | - | ||
| 737 | - | ||
| 738 | - return polygon | ||
| 739 | - | ||
| 740 | - def create_polygon(self,p1,p2,p3,p4): | ||
| 741 | - | ||
| 742 | - ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 743 | - ring.AddPoint(p1[0], p1[1]) | ||
| 744 | - ring.AddPoint(p2[0], p2[1]) | ||
| 745 | - ring.AddPoint(p3[0], p3[1]) | ||
| 746 | - ring.AddPoint(p4[0], p4[1]) | ||
| 747 | - ring.AddPoint(p1[0], p1[1]) | ||
| 748 | - | ||
| 749 | - poly = ogr.Geometry(ogr.wkbPolygon) | ||
| 750 | - poly.AddGeometry(ring) | ||
| 751 | - return poly | ||
| 752 | - | ||
| 753 | - | ||
| 754 | - def get_polygon_lines(self,polygon): | ||
| 755 | - #无孔Polygon | ||
| 756 | - if polygon.GetGeometryCount() == 1: | ||
| 757 | - polygon_line : Geometry = ogr.ForceToLineString(polygon) | ||
| 758 | - # 有孔Polygon | 655 | + y2 = y0 - abs(dy) |
| 759 | else: | 656 | else: |
| 760 | - polygon_line : Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 761 | - | ||
| 762 | - points = polygon_line.GetPoints() | ||
| 763 | - | ||
| 764 | - lines = [] | ||
| 765 | - for index in range(len(points)-1): | ||
| 766 | - | ||
| 767 | - point_start = points[index] | ||
| 768 | - point_end = points[index+1] | ||
| 769 | - line = ogr.Geometry(ogr.wkbLineString) | ||
| 770 | - line.AddPoint(point_start[0], point_start[1]) | ||
| 771 | - line.AddPoint(point_end[0], point_end[1]) | 657 | + if x1 < x0: |
| 658 | + x2 = x0 - dx | ||
| 659 | + else: | ||
| 660 | + x2 = x0 + dx | ||
| 772 | 661 | ||
| 773 | - lines.append(line) | 662 | + if y1 < y0: |
| 663 | + y2 = y0 - dy | ||
| 664 | + else: | ||
| 665 | + y2 = y0 + dy | ||
| 774 | 666 | ||
| 775 | - return lines | 667 | + return x2, y2 |
| 776 | 668 | ||
| 777 | def process(self): | 669 | def process(self): |
| 778 | polygons = self.data.get_polygons() | 670 | polygons = self.data.get_polygons() |
| 779 | rps = [] | 671 | rps = [] |
| 672 | + | ||
| 780 | for poly in polygons: | 673 | for poly in polygons: |
| 781 | rp = self.get_polygon_reprecent_point(poly) | 674 | rp = self.get_polygon_reprecent_point(poly) |
| 782 | rps.append(rp) | 675 | rps.append(rp) |
| 676 | + print("完成代表点计算") | ||
| 783 | 677 | ||
| 784 | - delauney_lines = self.create_delauney(rps) | ||
| 785 | - | ||
| 786 | - min_delauney = self.create_min_delauney(delauney_lines,rps,polygons) | 678 | + #代表点要融合 |
| 679 | + delauney_lines,rps_sub = self.create_delauney(rps) | ||
| 787 | 680 | ||
| 681 | + print("完成树生成计算") | ||
| 682 | + min_delauney = self.create_min_delauney(delauney_lines,rps_sub) | ||
| 683 | + print("完成最小生成树计算") | ||
| 788 | trees = self.cut_delauney_min_tree(min_delauney,self.distance_buffer_threshold) | 684 | trees = self.cut_delauney_min_tree(min_delauney,self.distance_buffer_threshold) |
| 685 | + print("完成树裁剪") | ||
| 789 | 686 | ||
| 687 | + polygons = self.merge_concave(trees,self.distance_buffer_threshold) | ||
| 790 | 688 | ||
| 791 | - polygons = self.merge(trees) | ||
| 792 | - | ||
| 793 | - for polygon in polygons: | ||
| 794 | - print("\""+polygon.ExportToWkt() + "\",") | 689 | + return [p.ExportToWkt() for p in polygons] |
| 795 | 690 | ||
| 796 | if __name__ == '__main__': | 691 | if __name__ == '__main__': |
| 797 | 692 | ||
| 798 | 693 | ||
| 799 | - # print(sd.get_polygons()[0]) | ||
| 800 | - # sd.close() | ||
| 801 | - | ||
| 802 | - create = True | ||
| 803 | - create = False | ||
| 804 | - | ||
| 805 | - if create: | ||
| 806 | - | ||
| 807 | - sd = ShapeData(r"J:\Data\制图综合\example.shp") | ||
| 808 | - | ||
| 809 | - ext = sd.layer.GetExtent() | ||
| 810 | - threshold = (ext[1]-ext[0])/20 | ||
| 811 | - print(threshold) | ||
| 812 | - | ||
| 813 | 694 | ||
| 814 | - zh = Zonghe(sd) | ||
| 815 | - zh.process() | ||
| 816 | - else: | ||
| 817 | - wkts = [ | ||
| 818 | - ] | 695 | + t1 = time.time() |
| 696 | + sd = ShapeData(r"J:\Data\制图综合result\zhongshansub.shp") | ||
| 819 | 697 | ||
| 820 | - result = r"J:\Data\制图综合\zhonghe3.shp" | ||
| 821 | - ShapeData.create_shp_fromwkts(result,"zh",wkts) | 698 | + zh = Zonghe(sd) |
| 699 | + wkts = zh.process() | ||
| 700 | + result = r"J:\Data\制图综合result\zhongshan_single.shp" | ||
| 701 | + ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 822 | 702 | ||
| 703 | + print(time.time()-t1) |
test/zonghe/Zonghe_delauney_merge.py
0 → 100644
| 1 | +# coding=utf-8 | ||
| 2 | +#author: 4N | ||
| 3 | +#createtime: 2022/3/8 | ||
| 4 | +#email: nheweijun@sina.com | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +from osgeo import ogr | ||
| 8 | +from osgeo.ogr import * | ||
| 9 | +import math | ||
| 10 | +import os | ||
| 11 | +import copy | ||
| 12 | +os.environ["CUDA_VISIBLE_DEVICES"] = "-1" | ||
| 13 | +from test.zonghe.ConcaveHull import concaveHull | ||
| 14 | +from test.zonghe.ShapeData import ShapeData | ||
| 15 | +from test.zonghe.Delauney import DelauneyNode,DelauneyLine,DelauneyMinTree | ||
| 16 | +from test.zonghe.RepresentPoint import RepresentPoint | ||
| 17 | +from test.zonghe.Util import Util | ||
| 18 | +import cv2 | ||
| 19 | +import time | ||
| 20 | +import numpy as np | ||
| 21 | + | ||
| 22 | +class Zonghe: | ||
| 23 | + | ||
| 24 | + data:ShapeData | ||
| 25 | + area_threshold = 10.0 | ||
| 26 | + buffer_threshold = 100.0 | ||
| 27 | + distance_buffer_threshold = 1.114691025217302e-04 | ||
| 28 | + | ||
| 29 | + def __init__(self,data): | ||
| 30 | + self.data = data | ||
| 31 | + | ||
| 32 | + #只处理Polygon,MultiPolygon要拆开 | ||
| 33 | + def get_polygon_reprecent_point(self,polygon:Geometry): | ||
| 34 | + | ||
| 35 | + polygon_env = polygon.GetEnvelope() | ||
| 36 | + | ||
| 37 | + area_thre = polygon.GetArea()/self.area_threshold | ||
| 38 | + | ||
| 39 | + line_length = math.sqrt(math.pow(polygon_env[1] - polygon_env[0],2) + math.pow(polygon_env[3] - polygon_env[2],2)) | ||
| 40 | + | ||
| 41 | + short_length = min(polygon_env[1]-polygon_env[0],polygon_env[3]-polygon_env[2]) | ||
| 42 | + | ||
| 43 | + center:Geometry = polygon.Centroid() | ||
| 44 | + # print(center) | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + # 提前return | ||
| 48 | + if polygon.Contains(center): | ||
| 49 | + # print("\"" + center.ExportToWkt() + "\",") | ||
| 50 | + return RepresentPoint(center, polygon) | ||
| 51 | + | ||
| 52 | + | ||
| 53 | + last_state = None | ||
| 54 | + line = None | ||
| 55 | + calculate_time = 0 | ||
| 56 | + | ||
| 57 | + direction = self.get_direction(polygon, center, line_length) | ||
| 58 | + | ||
| 59 | + | ||
| 60 | + in_hole = False | ||
| 61 | + in_hole_line = None | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + #无孔Polygon | ||
| 65 | + if polygon.GetGeometryCount() == 1: | ||
| 66 | + polygon_line = ogr.ForceToLineString(polygon) | ||
| 67 | + | ||
| 68 | + # 有孔Polygon,要分2种情况 | ||
| 69 | + else: | ||
| 70 | + polygon_line = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 71 | + for i in range(1,polygon.GetGeometryCount()): | ||
| 72 | + hole_line = polygon.GetGeometryRef(i) | ||
| 73 | + hole_polygon : Geometry = ogr.ForceToPolygon(hole_line) | ||
| 74 | + if hole_polygon.Contains(center): | ||
| 75 | + in_hole = True | ||
| 76 | + direction = range(0,190,10) | ||
| 77 | + in_hole_line = ogr.ForceToLineString(hole_line) | ||
| 78 | + # print("in_hole") | ||
| 79 | + | ||
| 80 | + angle1,angle2=None,None | ||
| 81 | + line = None | ||
| 82 | + oneside_area, otherside_area = None,None | ||
| 83 | + for angle in direction: | ||
| 84 | + | ||
| 85 | + if in_hole: | ||
| 86 | + line = self.get_doubleline(center.GetX(),center.GetY(),angle,line_length) | ||
| 87 | + else: | ||
| 88 | + line = self.get_line(center.GetX(),center.GetY(),angle,line_length) | ||
| 89 | + | ||
| 90 | + oneside_area, otherside_area = self.jude(polygon, line, angle, line_length) | ||
| 91 | + | ||
| 92 | + | ||
| 93 | + if oneside_area > 0 and otherside_area >0: | ||
| 94 | + if abs(oneside_area-otherside_area) < area_thre: | ||
| 95 | + break | ||
| 96 | + | ||
| 97 | + if last_state is None: | ||
| 98 | + | ||
| 99 | + angle2 = angle | ||
| 100 | + | ||
| 101 | + if oneside_area == 0 and otherside_area==0: | ||
| 102 | + last_state = 0 | ||
| 103 | + else: | ||
| 104 | + last_state = 1 if oneside_area < otherside_area else -1 | ||
| 105 | + else: | ||
| 106 | + | ||
| 107 | + angle1 = angle2 | ||
| 108 | + angle2 = angle | ||
| 109 | + | ||
| 110 | + if oneside_area == 0 and otherside_area==0: | ||
| 111 | + now_state = 0 | ||
| 112 | + else: | ||
| 113 | + now_state = 1 if oneside_area < otherside_area else -1 | ||
| 114 | + | ||
| 115 | + if last_state* now_state < 0: | ||
| 116 | + # print(angle) | ||
| 117 | + break | ||
| 118 | + else: | ||
| 119 | + last_state = now_state | ||
| 120 | + | ||
| 121 | + #第一条线就是均分线 | ||
| 122 | + if angle1 is None or angle2 is None: | ||
| 123 | + pass | ||
| 124 | + else: | ||
| 125 | + #如果面积差大于阈值,二分法查找 | ||
| 126 | + if abs(oneside_area - otherside_area) > area_thre: | ||
| 127 | + line = self.division(polygon, center, in_hole, line_length, angle1, angle2, area_thre) | ||
| 128 | + | ||
| 129 | + | ||
| 130 | + # 提前return | ||
| 131 | + if in_hole: | ||
| 132 | + | ||
| 133 | + point_intersection: Geometry = line.Intersection(in_hole_line) | ||
| 134 | + plist = [] | ||
| 135 | + for i in range(point_intersection.GetGeometryCount()): | ||
| 136 | + pi = point_intersection.GetGeometryRef(i) | ||
| 137 | + plist.append(pi) | ||
| 138 | + plist_d = [(pi,center.Distance(pi)) for pi in plist] | ||
| 139 | + plist_d.sort(key=lambda x:x[1]) | ||
| 140 | + | ||
| 141 | + nearest_point= plist_d[0][0] | ||
| 142 | + firt_short_length = short_length/20.0 | ||
| 143 | + radline,other_point = self.get_radline(center.GetX(),center.GetY(),nearest_point.GetX(),nearest_point.GetY(),firt_short_length) | ||
| 144 | + # print("\"" + other_point.ExportToWkt() + "\",") | ||
| 145 | + | ||
| 146 | + | ||
| 147 | + while not polygon.Contains(other_point): | ||
| 148 | + | ||
| 149 | + firt_short_length = firt_short_length / 2 | ||
| 150 | + radline, other_point = self.get_radline(center.GetX(), center.GetY(), nearest_point.GetX(), | ||
| 151 | + nearest_point.GetY(), firt_short_length) | ||
| 152 | + | ||
| 153 | + | ||
| 154 | + | ||
| 155 | + return RepresentPoint(other_point,polygon) | ||
| 156 | + | ||
| 157 | + | ||
| 158 | + point_intersection:Geometry = line.Intersection(polygon_line) | ||
| 159 | + xlist = [] | ||
| 160 | + ylist = [] | ||
| 161 | + plist = [] | ||
| 162 | + | ||
| 163 | + for i in range(point_intersection.GetGeometryCount()): | ||
| 164 | + pi = point_intersection.GetGeometryRef(i) | ||
| 165 | + xlist.append(pi.GetX()) | ||
| 166 | + ylist.append(pi.GetY()) | ||
| 167 | + plist.append(pi) | ||
| 168 | + | ||
| 169 | + | ||
| 170 | + reprecent_point = [(min(xlist)+max(xlist))/2.0,(min(ylist)+max(ylist))/2.0] | ||
| 171 | + | ||
| 172 | + reprecent_point = self.creat_point(reprecent_point) | ||
| 173 | + | ||
| 174 | + if not polygon.Contains(reprecent_point): | ||
| 175 | + plist_d = [(pi,center.Distance(pi)) for pi in plist] | ||
| 176 | + plist_d.sort(key=lambda x:x[1]) | ||
| 177 | + reprecent_point = self.creat_point(((plist_d[0][0].GetX()+ plist_d[1][0].GetX())/2.0, (plist_d[0][0].GetY()+plist_d[1][0].GetY())/2.0)) | ||
| 178 | + | ||
| 179 | + # print("\""+reprecent_point.ExportToWkt() + "\",") | ||
| 180 | + | ||
| 181 | + rp = RepresentPoint(reprecent_point,polygon) | ||
| 182 | + | ||
| 183 | + return rp | ||
| 184 | + | ||
| 185 | + def get_line(self, x0, y0 , angle, r): | ||
| 186 | + | ||
| 187 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 188 | + line.AddPoint(x0, y0) | ||
| 189 | + hudu = angle/360.0 * 2 * math.pi | ||
| 190 | + dx = math.sin(hudu) * r | ||
| 191 | + dy = math.cos(hudu) * r | ||
| 192 | + line.AddPoint(x0+dx, y0+dy) | ||
| 193 | + | ||
| 194 | + return line | ||
| 195 | + | ||
| 196 | + def get_doubleline(self, x0, y0 , angle, r): | ||
| 197 | + | ||
| 198 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 199 | + | ||
| 200 | + hudu = angle/360.0 * 2 * math.pi | ||
| 201 | + dx = math.sin(hudu) * r | ||
| 202 | + dy = math.cos(hudu) * r | ||
| 203 | + | ||
| 204 | + hudu = (angle+180)/360.0 * 2 * math.pi | ||
| 205 | + dx2 = math.sin(hudu) * r | ||
| 206 | + dy2 = math.cos(hudu) * r | ||
| 207 | + | ||
| 208 | + line.AddPoint(x0 + dx2, y0 + dy2) | ||
| 209 | + line.AddPoint(x0+dx, y0+dy) | ||
| 210 | + | ||
| 211 | + return line | ||
| 212 | + | ||
| 213 | + def get_radline(self,x0,y0,x1,y1,len_size): | ||
| 214 | + a2 = math.pow((x1-x0),2) | ||
| 215 | + b2 = math.pow((y1-y0),2) | ||
| 216 | + len_size = len_size+ math.sqrt(a2+b2) | ||
| 217 | + | ||
| 218 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 219 | + line.AddPoint(x0, y0) | ||
| 220 | + tanx = abs(y1-y0) / abs(x1-x0) | ||
| 221 | + cosx = 1 / math.sqrt(1 + tanx *tanx) | ||
| 222 | + dx = cosx* len_size | ||
| 223 | + dy = tanx * dx | ||
| 224 | + | ||
| 225 | + if x1 == x0: | ||
| 226 | + x2 = x0 | ||
| 227 | + if y1 > y0 : | ||
| 228 | + y2 = y0 + abs(dy) | ||
| 229 | + else: | ||
| 230 | + y2 = y0 - abs(dy) | ||
| 231 | + else: | ||
| 232 | + if x1 < x0: | ||
| 233 | + x2 = x0 - dx | ||
| 234 | + else: | ||
| 235 | + x2 = x0 + dx | ||
| 236 | + | ||
| 237 | + if y1 < y0: | ||
| 238 | + y2 = y0 - dy | ||
| 239 | + else: | ||
| 240 | + y2 = y0 + dy | ||
| 241 | + | ||
| 242 | + line.AddPoint(x2, y2) | ||
| 243 | + | ||
| 244 | + other_point = ogr.Geometry(ogr.wkbPoint) | ||
| 245 | + other_point.AddPoint(x2, y2) | ||
| 246 | + | ||
| 247 | + return line , other_point | ||
| 248 | + | ||
| 249 | + def get_direction(self,polygon,center,line_length): | ||
| 250 | + ''' | ||
| 251 | + 判断旋转方向 | ||
| 252 | + :param polygon: | ||
| 253 | + :param center: | ||
| 254 | + :param line_length: | ||
| 255 | + :return: | ||
| 256 | + ''' | ||
| 257 | + | ||
| 258 | + line = self.get_line(center.GetX(),center.GetY(),0,line_length) | ||
| 259 | + | ||
| 260 | + oneside_area, otherside_area = self.jude(polygon,line,0,line_length) | ||
| 261 | + | ||
| 262 | + if oneside_area == 0 and otherside_area == 0 : | ||
| 263 | + return range(0, 390, 30) | ||
| 264 | + else: | ||
| 265 | + line = self.get_line(center.GetX(), center.GetY(), 10, line_length) | ||
| 266 | + oneside_area_contrast, otherside_area_contrast = self.jude(polygon, line, 30, line_length) | ||
| 267 | + | ||
| 268 | + if oneside_area_contrast == 0 and otherside_area_contrast == 0: | ||
| 269 | + return range(360, -30, -30) | ||
| 270 | + else: | ||
| 271 | + if abs(oneside_area - otherside_area) > abs(oneside_area_contrast - otherside_area_contrast): | ||
| 272 | + return range(0, 390, 30) | ||
| 273 | + else: | ||
| 274 | + return range(360, -30, -30) | ||
| 275 | + | ||
| 276 | + def jude(self,polygon,line,angle,line_length): | ||
| 277 | + | ||
| 278 | + line_buffer: Geometry = line.Buffer(line_length / self.buffer_threshold) | ||
| 279 | + clip_geom: Geometry = polygon.Difference(line_buffer) | ||
| 280 | + | ||
| 281 | + oneside_area = 0 | ||
| 282 | + otherside_area = 0 | ||
| 283 | + | ||
| 284 | + gc = clip_geom.GetGeometryCount() | ||
| 285 | + if gc <= 1: | ||
| 286 | + oneside_area = 0 | ||
| 287 | + otherside_area = 0 | ||
| 288 | + else: | ||
| 289 | + triangle1, triangle2 = self.get_side_triangle(line, angle) | ||
| 290 | + | ||
| 291 | + | ||
| 292 | + for gi in range(clip_geom.GetGeometryCount()): | ||
| 293 | + clip_geom_i: Geometry = clip_geom.GetGeometryRef(gi) | ||
| 294 | + it = clip_geom_i.Intersection(triangle1) | ||
| 295 | + | ||
| 296 | + if clip_geom_i.Intersect(triangle1) and it.Buffer(line_length / self.buffer_threshold).Intersect( | ||
| 297 | + line_buffer): | ||
| 298 | + oneside_area += clip_geom_i.GetArea() | ||
| 299 | + else: | ||
| 300 | + otherside_area += clip_geom_i.GetArea() | ||
| 301 | + return oneside_area, otherside_area | ||
| 302 | + | ||
| 303 | + def division(self,polygon,center,in_hole,line_length,angle1,angle2,area_thre): | ||
| 304 | + | ||
| 305 | + mid_angle = (angle1 + angle2)/2.0 | ||
| 306 | + | ||
| 307 | + | ||
| 308 | + if in_hole: | ||
| 309 | + line = self.get_doubleline(center.GetX(), center.GetY(), mid_angle, line_length) | ||
| 310 | + else: | ||
| 311 | + line = self.get_line(center.GetX(), center.GetY(), mid_angle, line_length) | ||
| 312 | + | ||
| 313 | + one,other = self.jude(polygon,line,mid_angle,line_length) | ||
| 314 | + | ||
| 315 | + while abs(one - other) > area_thre: | ||
| 316 | + if one > other: | ||
| 317 | + if angle1 > angle2: | ||
| 318 | + return self.division(polygon, center, in_hole, line_length, angle2, mid_angle, area_thre) | ||
| 319 | + else: | ||
| 320 | + return self.division(polygon, center, in_hole, line_length, mid_angle, angle1, area_thre) | ||
| 321 | + else: | ||
| 322 | + if angle1 > angle2: | ||
| 323 | + return self.division(polygon, center, in_hole, line_length, mid_angle, angle1, area_thre) | ||
| 324 | + else: | ||
| 325 | + return self.division(polygon, center, in_hole, line_length, angle2, mid_angle, area_thre) | ||
| 326 | + return line | ||
| 327 | + | ||
| 328 | + def get_side_triangle(self,line:Geometry,angle): | ||
| 329 | + ''' | ||
| 330 | + 获取方向三角形 | ||
| 331 | + :param line: | ||
| 332 | + :param angle: | ||
| 333 | + :return: | ||
| 334 | + ''' | ||
| 335 | + | ||
| 336 | + start = line.GetPoint(0) | ||
| 337 | + end = line.GetPoint(1) | ||
| 338 | + | ||
| 339 | + | ||
| 340 | + angle_t = angle-30 | ||
| 341 | + hudu = angle_t/360.0 * 2 * math.pi | ||
| 342 | + | ||
| 343 | + r = line.Length() / (2*math.cos( math.pi/6)) | ||
| 344 | + dx = math.sin(hudu) * r | ||
| 345 | + dy = math.cos(hudu) * r | ||
| 346 | + | ||
| 347 | + | ||
| 348 | + ring1 = ogr.Geometry(ogr.wkbLinearRing) | ||
| 349 | + ring1.AddPoint(start[0], start[1]) | ||
| 350 | + ring1.AddPoint(start[0] + dx, start[1] + dy) | ||
| 351 | + ring1.AddPoint(end[0], end[1]) | ||
| 352 | + ring1.AddPoint(start[0], start[1]) | ||
| 353 | + triangle1 = ogr.Geometry(ogr.wkbPolygon) | ||
| 354 | + triangle1.AddGeometry(ring1) | ||
| 355 | + | ||
| 356 | + | ||
| 357 | + angle_t = angle+30 | ||
| 358 | + hudu = angle_t/360.0 * 2 * math.pi | ||
| 359 | + | ||
| 360 | + r = line.Length() / (2*math.cos( math.pi/6)) | ||
| 361 | + | ||
| 362 | + dx = math.sin(hudu) * r | ||
| 363 | + dy = math.cos(hudu) * r | ||
| 364 | + | ||
| 365 | + ring2 = ogr.Geometry(ogr.wkbLinearRing) | ||
| 366 | + ring2.AddPoint(start[0], start[1]) | ||
| 367 | + ring2.AddPoint(start[0]+dx, start[1]+dy) | ||
| 368 | + ring2.AddPoint(end[0], end[1]) | ||
| 369 | + ring2.AddPoint(start[0], start[1]) | ||
| 370 | + triangle2 = ogr.Geometry(ogr.wkbPolygon) | ||
| 371 | + triangle2.AddGeometry(ring2) | ||
| 372 | + | ||
| 373 | + return triangle1,triangle2 | ||
| 374 | + | ||
| 375 | + def creat_point(self,tuple): | ||
| 376 | + p: Geometry = ogr.Geometry(ogr.wkbPoint) | ||
| 377 | + p.AddPoint(tuple[0], tuple[1]) | ||
| 378 | + return p | ||
| 379 | + | ||
| 380 | + def create_delauney(self,rps): | ||
| 381 | + multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) | ||
| 382 | + | ||
| 383 | + rp_dict = {} | ||
| 384 | + delauney_lines = [] | ||
| 385 | + | ||
| 386 | + rps_sub = set() | ||
| 387 | + for rp in rps: | ||
| 388 | + multipoint.AddGeometry(rp.point) | ||
| 389 | + # 多边形代表点相同,需要融合多边形 | ||
| 390 | + if rp_dict.get(rp.point.GetPoint(0).__str__()): | ||
| 391 | + rp_exist = rp_dict.get(rp.point.GetPoint(0).__str__()) | ||
| 392 | + rp_exist.polygon = rp_exist.polygon.Union(rp.polygon) | ||
| 393 | + else: | ||
| 394 | + rp_dict[rp.point.GetPoint(0).__str__()] = rp | ||
| 395 | + rps_sub.add(rp) | ||
| 396 | + | ||
| 397 | + delauney:Geometry = multipoint.DelaunayTriangulation(bOnlyEdges=True) | ||
| 398 | + | ||
| 399 | + for index in range(delauney.GetGeometryCount()): | ||
| 400 | + triangle_line:Geometry = delauney.GetGeometryRef(index) | ||
| 401 | + p = triangle_line.GetPoint(0) | ||
| 402 | + p_next = triangle_line.GetPoint(1) | ||
| 403 | + | ||
| 404 | + rp1 = rp_dict.get(p.__str__()) | ||
| 405 | + rp2 = rp_dict.get(p_next.__str__()) | ||
| 406 | + | ||
| 407 | + delauney_line = DelauneyLine(rp1,rp2) | ||
| 408 | + delauney_lines.append(delauney_line) | ||
| 409 | + | ||
| 410 | + return delauney_lines,rps_sub | ||
| 411 | + | ||
| 412 | + def create_min_delauney(self,delauney_lines,rps): | ||
| 413 | + ''' | ||
| 414 | + 使用prim算法计算最小生成树 | ||
| 415 | + :param delauney_lines: | ||
| 416 | + :param polygons: | ||
| 417 | + :return: | ||
| 418 | + ''' | ||
| 419 | + | ||
| 420 | + kv = dict() | ||
| 421 | + # print(len(rps)) | ||
| 422 | + | ||
| 423 | + | ||
| 424 | + rps_set = set(rps) | ||
| 425 | + | ||
| 426 | + for delauney_line in delauney_lines: | ||
| 427 | + if kv.get(delauney_line.rp1): | ||
| 428 | + kv[delauney_line.rp1].add(delauney_line) | ||
| 429 | + else: | ||
| 430 | + kv[delauney_line.rp1] = set() | ||
| 431 | + kv[delauney_line.rp1].add(delauney_line) | ||
| 432 | + | ||
| 433 | + if kv.get(delauney_line.rp2): | ||
| 434 | + kv[delauney_line.rp2].add(delauney_line) | ||
| 435 | + else: | ||
| 436 | + kv[delauney_line.rp2] = set() | ||
| 437 | + kv[delauney_line.rp2].add(delauney_line) | ||
| 438 | + | ||
| 439 | + | ||
| 440 | + | ||
| 441 | + print("完成三角边倒排索引") | ||
| 442 | + | ||
| 443 | + #初始化树 | ||
| 444 | + delauney_lines = sorted(delauney_lines,key=lambda x:x.distance) | ||
| 445 | + delauney_min_tree = DelauneyMinTree() | ||
| 446 | + | ||
| 447 | + delauney_min_tree.append(delauney_lines[0],kv) | ||
| 448 | + | ||
| 449 | + rps_set.remove(delauney_lines[0].rp1) | ||
| 450 | + rps_set.remove(delauney_lines[0].rp2) | ||
| 451 | + | ||
| 452 | + kv[delauney_lines[0].rp1].remove(delauney_lines[0]) | ||
| 453 | + kv[delauney_lines[0].rp2].remove(delauney_lines[0]) | ||
| 454 | + | ||
| 455 | + print("完成最小生成树初始化") | ||
| 456 | + | ||
| 457 | + while rps_set.__len__()>0: | ||
| 458 | + | ||
| 459 | + relate_delauney_line = delauney_min_tree.touch_delauney_lines | ||
| 460 | + | ||
| 461 | + | ||
| 462 | + relate_delauney_line_sort = sorted(relate_delauney_line,key=lambda x:x.distance) | ||
| 463 | + | ||
| 464 | + min_distance_line = relate_delauney_line_sort[0] | ||
| 465 | + #删除 | ||
| 466 | + other_rp = delauney_min_tree.get_other_rp(min_distance_line) | ||
| 467 | + | ||
| 468 | + if other_rp is None: | ||
| 469 | + kv[min_distance_line.rp1].remove(min_distance_line) | ||
| 470 | + kv[min_distance_line.rp2].remove(min_distance_line) | ||
| 471 | + continue | ||
| 472 | + | ||
| 473 | + delauney_min_tree.append(min_distance_line,kv) | ||
| 474 | + | ||
| 475 | + rps_set.remove(other_rp) | ||
| 476 | + | ||
| 477 | + kv[min_distance_line.rp1].remove(min_distance_line) | ||
| 478 | + kv[min_distance_line.rp2].remove(min_distance_line) | ||
| 479 | + | ||
| 480 | + | ||
| 481 | + print("完成最小生成树") | ||
| 482 | + | ||
| 483 | + return delauney_min_tree | ||
| 484 | + | ||
| 485 | + def cut_delauney_min_tree(self,delauney_min_tree:DelauneyMinTree,threshold): | ||
| 486 | + | ||
| 487 | + trees = [] | ||
| 488 | + kv = {} | ||
| 489 | + | ||
| 490 | + count = 0 | ||
| 491 | + | ||
| 492 | + for delauney_line in delauney_min_tree.delauney_lines_list: | ||
| 493 | + | ||
| 494 | + dn1 = kv.get(delauney_line.rp1) | ||
| 495 | + dn2 = kv.get(delauney_line.rp2) | ||
| 496 | + | ||
| 497 | + | ||
| 498 | + if not dn1: | ||
| 499 | + dn1 = DelauneyNode(delauney_line.rp1) | ||
| 500 | + kv[delauney_line.rp1] = dn1 | ||
| 501 | + | ||
| 502 | + if not dn2: | ||
| 503 | + | ||
| 504 | + trees.append(dn1) | ||
| 505 | + | ||
| 506 | + dn2 = DelauneyNode(delauney_line.rp2) | ||
| 507 | + kv[delauney_line.rp2] = dn2 | ||
| 508 | + | ||
| 509 | + if delauney_line.distance < threshold: | ||
| 510 | + dn1.add_children(dn2,delauney_line) | ||
| 511 | + count +=1 | ||
| 512 | + | ||
| 513 | + else: | ||
| 514 | + #断开 | ||
| 515 | + trees.append(dn2) | ||
| 516 | + else: | ||
| 517 | + | ||
| 518 | + if delauney_line.distance < threshold: | ||
| 519 | + dn2.add_children(dn1,delauney_line) | ||
| 520 | + count += 1 | ||
| 521 | + else: | ||
| 522 | + trees.append(dn1) | ||
| 523 | + else: | ||
| 524 | + | ||
| 525 | + dn2 = DelauneyNode(delauney_line.rp2) | ||
| 526 | + kv[delauney_line.rp2] = dn2 | ||
| 527 | + | ||
| 528 | + if delauney_line.distance < threshold: | ||
| 529 | + dn1.add_children(dn2,delauney_line) | ||
| 530 | + count += 1 | ||
| 531 | + else: | ||
| 532 | + trees.append(dn2) | ||
| 533 | + | ||
| 534 | + | ||
| 535 | + return trees | ||
| 536 | + | ||
| 537 | + def create_polygon(self,p1,p2,p3,p4): | ||
| 538 | + | ||
| 539 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 540 | + ring.AddPoint(p1[0], p1[1]) | ||
| 541 | + ring.AddPoint(p2[0], p2[1]) | ||
| 542 | + ring.AddPoint(p3[0], p3[1]) | ||
| 543 | + ring.AddPoint(p4[0], p4[1]) | ||
| 544 | + ring.AddPoint(p1[0], p1[1]) | ||
| 545 | + | ||
| 546 | + poly = ogr.Geometry(ogr.wkbPolygon) | ||
| 547 | + poly.AddGeometry(ring) | ||
| 548 | + return poly | ||
| 549 | + | ||
| 550 | + def get_polygon_lines(self,polygon): | ||
| 551 | + #无孔Polygon | ||
| 552 | + if polygon.GetGeometryCount() in [0,1]: | ||
| 553 | + polygon_line : Geometry = ogr.ForceToLineString(polygon) | ||
| 554 | + # 有孔Polygon | ||
| 555 | + else: | ||
| 556 | + polygon_line : Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 557 | + | ||
| 558 | + return polygon_line | ||
| 559 | + | ||
| 560 | + def merge_concave(self, trees, distance_threshold): | ||
| 561 | + merge_polygons = [] | ||
| 562 | + count = 1 | ||
| 563 | + | ||
| 564 | + for tree in trees: | ||
| 565 | + print(count) | ||
| 566 | + count+=1 | ||
| 567 | + polygons = list(tree.get_polygons()) | ||
| 568 | + | ||
| 569 | + merge_raw: Geometry = polygons[0] | ||
| 570 | + for p in polygons: | ||
| 571 | + merge_raw = merge_raw.Union(p) | ||
| 572 | + | ||
| 573 | + points = [] | ||
| 574 | + | ||
| 575 | + | ||
| 576 | + for i in range(merge_raw.GetGeometryCount()): | ||
| 577 | + | ||
| 578 | + poly = merge_raw.GetGeometryRef(i) | ||
| 579 | + poly_line :Geometry = self.get_polygon_lines(poly) | ||
| 580 | + if poly_line: | ||
| 581 | + for indx in range(poly_line.GetPointCount() - 1): | ||
| 582 | + poi = poly_line.GetPoint(indx) | ||
| 583 | + | ||
| 584 | + points.append(poi) | ||
| 585 | + | ||
| 586 | + poi_next = poly_line.GetPoint(indx + 1) | ||
| 587 | + | ||
| 588 | + dis = math.sqrt(math.pow(poi[0] - poi_next[0], 2) + math.pow(poi[1] - poi_next[1], 2)) | ||
| 589 | + # print(dis) | ||
| 590 | + if dis > distance_threshold: | ||
| 591 | + times = int(dis / distance_threshold) | ||
| 592 | + # print(times) | ||
| 593 | + for ts in range(1, times + 1): | ||
| 594 | + x, y = self.get_subpoint(poi[0], poi[1], poi_next[0], poi_next[1], (ts * distance_threshold)) | ||
| 595 | + points.append([x, y]) | ||
| 596 | + | ||
| 597 | + points = np.array([[p[0], p[1]] for p in points]) | ||
| 598 | + | ||
| 599 | + | ||
| 600 | + cp = [] | ||
| 601 | + for pp in points: | ||
| 602 | + poi = ogr.Geometry(ogr.wkbPoint) | ||
| 603 | + poi.AddPoint(pp[0], pp[1]) | ||
| 604 | + cp.append(poi) | ||
| 605 | + | ||
| 606 | + | ||
| 607 | + merge_p_line = concaveHull(points, 3) | ||
| 608 | + | ||
| 609 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 610 | + | ||
| 611 | + merge_p = ogr.Geometry(ogr.wkbPolygon) | ||
| 612 | + | ||
| 613 | + for l in merge_p_line: | ||
| 614 | + ring.AddPoint(l[0], l[1]) | ||
| 615 | + | ||
| 616 | + ring.AddPoint(merge_p_line[0][0], merge_p_line[0][1]) | ||
| 617 | + | ||
| 618 | + merge_p.AddGeometry(ring) | ||
| 619 | + merge_p = merge_p.Simplify(self.distance_buffer_threshold/10) | ||
| 620 | + merge_polygons.append(merge_p) | ||
| 621 | + | ||
| 622 | + return merge_polygons | ||
| 623 | + # return cp | ||
| 624 | + | ||
| 625 | + def get_subpoint(self, x0, y0, x1, y1, len_size): | ||
| 626 | + | ||
| 627 | + len_size = len_size | ||
| 628 | + tanx = abs(y1 - y0) / abs(x1 - x0) | ||
| 629 | + cosx = 1 / math.sqrt(1 + tanx * tanx) | ||
| 630 | + dx = cosx * len_size | ||
| 631 | + dy = tanx * dx | ||
| 632 | + | ||
| 633 | + if x1 == x0: | ||
| 634 | + x2 = x0 | ||
| 635 | + if y1 > y0: | ||
| 636 | + y2 = y0 + abs(dy) | ||
| 637 | + else: | ||
| 638 | + y2 = y0 - abs(dy) | ||
| 639 | + else: | ||
| 640 | + if x1 < x0: | ||
| 641 | + x2 = x0 - dx | ||
| 642 | + else: | ||
| 643 | + x2 = x0 + dx | ||
| 644 | + | ||
| 645 | + if y1 < y0: | ||
| 646 | + y2 = y0 - dy | ||
| 647 | + else: | ||
| 648 | + y2 = y0 + dy | ||
| 649 | + | ||
| 650 | + return x2, y2 | ||
| 651 | + | ||
| 652 | + def merge_delauney(self,trees): | ||
| 653 | + | ||
| 654 | + merge_polygons = [] | ||
| 655 | + count = 1 | ||
| 656 | + | ||
| 657 | + for tree in trees: | ||
| 658 | + | ||
| 659 | + polygons = list(tree.get_polygons()) | ||
| 660 | + | ||
| 661 | + mp: Geometry = ogr.Geometry(ogr.wkbMultiPolygon) | ||
| 662 | + for p in polygons: | ||
| 663 | + mp.AddGeometry(p) | ||
| 664 | + | ||
| 665 | + | ||
| 666 | + | ||
| 667 | + delauney: Geometry = mp.DelaunayTriangulation() | ||
| 668 | + | ||
| 669 | + intp = [] | ||
| 670 | + for p in delauney: | ||
| 671 | + | ||
| 672 | + res = p | ||
| 673 | + ispass = False | ||
| 674 | + for pp in polygons: | ||
| 675 | + check:Geometry = res.Difference(pp) | ||
| 676 | + if check.IsEmpty(): | ||
| 677 | + ispass = True | ||
| 678 | + break | ||
| 679 | + else: | ||
| 680 | + res = check | ||
| 681 | + if not ispass: | ||
| 682 | + res_extend = self.extend_tri(res) | ||
| 683 | + intp.append(res_extend) | ||
| 684 | + | ||
| 685 | + # polygons.extend(intp) | ||
| 686 | + # | ||
| 687 | + # mp: Geometry = ogr.Geometry(ogr.wkbMultiPolygon) | ||
| 688 | + # | ||
| 689 | + # for p in polygons: | ||
| 690 | + # mp.AddGeometry(p) | ||
| 691 | + # merge:Geometry = mp.UnionCascaded() | ||
| 692 | + # merge_polygons.append(merge) | ||
| 693 | + | ||
| 694 | + return intp | ||
| 695 | + | ||
| 696 | + | ||
| 697 | + | ||
| 698 | + def extend_tri(self,triangle:Geometry): | ||
| 699 | + | ||
| 700 | + center:Geometry = triangle.Centroid() | ||
| 701 | + tri_line: Geometry = self.get_polygon_lines(triangle) | ||
| 702 | + | ||
| 703 | + result_geo = ogr.Geometry(ogr.wkbPolygon) | ||
| 704 | + result_geo_ring:Geometry = ogr.Geometry(ogr.wkbLinearRing) | ||
| 705 | + for point in tri_line.GetPoints(): | ||
| 706 | + radpoint = self.get_radpoint(center.GetX(),center.GetY(),point[0],point[1],0.00000001) | ||
| 707 | + | ||
| 708 | + result_geo_ring.AddPoint(radpoint.GetX(),radpoint.GetY()) | ||
| 709 | + result_geo.AddGeometry(result_geo_ring) | ||
| 710 | + | ||
| 711 | + return result_geo | ||
| 712 | + | ||
| 713 | + def get_radpoint(self,x0,y0,x1,y1,len_size): | ||
| 714 | + a2 = math.pow((x1-x0),2) | ||
| 715 | + b2 = math.pow((y1-y0),2) | ||
| 716 | + len_size = len_size+ math.sqrt(a2+b2) | ||
| 717 | + | ||
| 718 | + tanx = abs(y1-y0) / abs(x1-x0) | ||
| 719 | + cosx = 1 / math.sqrt(1 + tanx *tanx) | ||
| 720 | + dx = cosx* len_size | ||
| 721 | + dy = tanx * dx | ||
| 722 | + | ||
| 723 | + if x1 == x0: | ||
| 724 | + x2 = x0 | ||
| 725 | + if y1 > y0 : | ||
| 726 | + y2 = y0 + abs(dy) | ||
| 727 | + else: | ||
| 728 | + y2 = y0 - abs(dy) | ||
| 729 | + else: | ||
| 730 | + if x1 < x0: | ||
| 731 | + x2 = x0 - dx | ||
| 732 | + else: | ||
| 733 | + x2 = x0 + dx | ||
| 734 | + | ||
| 735 | + if y1 < y0: | ||
| 736 | + y2 = y0 - dy | ||
| 737 | + else: | ||
| 738 | + y2 = y0 + dy | ||
| 739 | + | ||
| 740 | + other_point = ogr.Geometry(ogr.wkbPoint) | ||
| 741 | + other_point.AddPoint(x2, y2) | ||
| 742 | + | ||
| 743 | + return other_point | ||
| 744 | + | ||
| 745 | + | ||
| 746 | + def process(self): | ||
| 747 | + polygons = self.data.get_polygons() | ||
| 748 | + rps = [] | ||
| 749 | + | ||
| 750 | + for poly in polygons: | ||
| 751 | + rp = self.get_polygon_reprecent_point(poly) | ||
| 752 | + rps.append(rp) | ||
| 753 | + print("完成代表点计算") | ||
| 754 | + | ||
| 755 | + #代表点要融合 | ||
| 756 | + delauney_lines,rps_sub = self.create_delauney(rps) | ||
| 757 | + | ||
| 758 | + print("完成树生成计算") | ||
| 759 | + min_delauney = self.create_min_delauney(delauney_lines,rps_sub) | ||
| 760 | + print("完成最小生成树计算") | ||
| 761 | + trees = self.cut_delauney_min_tree(min_delauney,self.distance_buffer_threshold) | ||
| 762 | + print("完成树裁剪") | ||
| 763 | + | ||
| 764 | + polygons = self.merge_concave(trees,self.distance_buffer_threshold) | ||
| 765 | + # polygons = self.merge_delauney(trees) | ||
| 766 | + | ||
| 767 | + return [p.ExportToWkt() for p in polygons] | ||
| 768 | + | ||
| 769 | +if __name__ == '__main__': | ||
| 770 | + | ||
| 771 | + | ||
| 772 | + # print(sd.get_polygons()[0]) | ||
| 773 | + # sd.close() | ||
| 774 | + | ||
| 775 | + t1 = time.time() | ||
| 776 | + sd = ShapeData(r"J:\Data\制图综合result\zhongshansub2.shp") | ||
| 777 | + | ||
| 778 | + zh = Zonghe(sd) | ||
| 779 | + wkts = zh.process() | ||
| 780 | + result = r"J:\Data\制图综合result\zhongshansub2_m2.shp" | ||
| 781 | + ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 782 | + | ||
| 783 | + print(time.time()-t1) |
test/zonghe/Zonghe_parallel.py
0 → 100644
| 1 | +# coding=utf-8 | ||
| 2 | +#author: 4N | ||
| 3 | +#createtime: 2022/3/8 | ||
| 4 | +#email: nheweijun@sina.com | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +from osgeo import ogr | ||
| 8 | +from osgeo.ogr import * | ||
| 9 | +import math | ||
| 10 | +import os | ||
| 11 | +import copy | ||
| 12 | +os.environ["CUDA_VISIBLE_DEVICES"] = "-1" | ||
| 13 | +from test.zonghe.ConcaveHull import concaveHull | ||
| 14 | +from test.zonghe.ShapeData import ShapeData | ||
| 15 | +from test.zonghe.Delauney import DelauneyNode,DelauneyLine,DelauneyMinTree | ||
| 16 | +from test.zonghe.RepresentPoint import RepresentPoint | ||
| 17 | + | ||
| 18 | +import time | ||
| 19 | + | ||
| 20 | +import numpy as np | ||
| 21 | +from multiprocessing import Process | ||
| 22 | +from threading import Thread | ||
| 23 | +class MyThread(Thread): | ||
| 24 | + def __init__(self,func,args=()): | ||
| 25 | + super(MyThread,self).__init__() | ||
| 26 | + self.func = func | ||
| 27 | + self.args = args | ||
| 28 | + def run(self): | ||
| 29 | + self.result = self.func(*self.args) | ||
| 30 | + def get_result(self): | ||
| 31 | + try: | ||
| 32 | + return self.result | ||
| 33 | + except Exception: | ||
| 34 | + return None | ||
| 35 | + | ||
| 36 | +class Zonghe: | ||
| 37 | + | ||
| 38 | + data:ShapeData | ||
| 39 | + area_threshold = 10.0 | ||
| 40 | + buffer_threshold = 100.0 | ||
| 41 | + distance_buffer_threshold = 1.114691025217302e-04 | ||
| 42 | + | ||
| 43 | + def __init__(self,data): | ||
| 44 | + self.data = data | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + #只处理Polygon,MultiPolygon要拆开 | ||
| 48 | + def get_polygon_reprecent_point(self,polygon:Geometry): | ||
| 49 | + | ||
| 50 | + polygon_env = polygon.GetEnvelope() | ||
| 51 | + | ||
| 52 | + area_thre = polygon.GetArea()/self.area_threshold | ||
| 53 | + | ||
| 54 | + line_length = math.sqrt(math.pow(polygon_env[1] - polygon_env[0],2) + math.pow(polygon_env[3] - polygon_env[2],2)) | ||
| 55 | + | ||
| 56 | + short_length = min(polygon_env[1]-polygon_env[0],polygon_env[3]-polygon_env[2]) | ||
| 57 | + | ||
| 58 | + center:Geometry = polygon.Centroid() | ||
| 59 | + # print(center) | ||
| 60 | + | ||
| 61 | + | ||
| 62 | + # 提前return | ||
| 63 | + if polygon.Contains(center): | ||
| 64 | + # print("\"" + center.ExportToWkt() + "\",") | ||
| 65 | + return RepresentPoint(center, polygon) | ||
| 66 | + | ||
| 67 | + | ||
| 68 | + last_state = None | ||
| 69 | + line = None | ||
| 70 | + calculate_time = 0 | ||
| 71 | + | ||
| 72 | + direction = self.get_direction(polygon, center, line_length) | ||
| 73 | + | ||
| 74 | + | ||
| 75 | + in_hole = False | ||
| 76 | + in_hole_line = None | ||
| 77 | + | ||
| 78 | + | ||
| 79 | + #无孔Polygon | ||
| 80 | + if polygon.GetGeometryCount() == 1: | ||
| 81 | + polygon_line = ogr.ForceToLineString(polygon) | ||
| 82 | + | ||
| 83 | + # 有孔Polygon,要分2种情况 | ||
| 84 | + else: | ||
| 85 | + polygon_line = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 86 | + for i in range(1,polygon.GetGeometryCount()): | ||
| 87 | + hole_line = polygon.GetGeometryRef(i) | ||
| 88 | + hole_polygon : Geometry = ogr.ForceToPolygon(hole_line) | ||
| 89 | + if hole_polygon.Contains(center): | ||
| 90 | + in_hole = True | ||
| 91 | + direction = range(0,190,10) | ||
| 92 | + in_hole_line = ogr.ForceToLineString(hole_line) | ||
| 93 | + # print("in_hole") | ||
| 94 | + | ||
| 95 | + angle1,angle2=None,None | ||
| 96 | + line = None | ||
| 97 | + oneside_area, otherside_area = None,None | ||
| 98 | + for angle in direction: | ||
| 99 | + | ||
| 100 | + if in_hole: | ||
| 101 | + line = self.get_doubleline(center.GetX(),center.GetY(),angle,line_length) | ||
| 102 | + else: | ||
| 103 | + line = self.get_line(center.GetX(),center.GetY(),angle,line_length) | ||
| 104 | + | ||
| 105 | + oneside_area, otherside_area = self.jude(polygon, line, angle, line_length) | ||
| 106 | + | ||
| 107 | + | ||
| 108 | + if oneside_area > 0 and otherside_area >0: | ||
| 109 | + if abs(oneside_area-otherside_area) < area_thre: | ||
| 110 | + break | ||
| 111 | + | ||
| 112 | + if last_state is None: | ||
| 113 | + | ||
| 114 | + angle2 = angle | ||
| 115 | + | ||
| 116 | + if oneside_area == 0 and otherside_area==0: | ||
| 117 | + last_state = 0 | ||
| 118 | + else: | ||
| 119 | + last_state = 1 if oneside_area < otherside_area else -1 | ||
| 120 | + else: | ||
| 121 | + | ||
| 122 | + angle1 = angle2 | ||
| 123 | + angle2 = angle | ||
| 124 | + | ||
| 125 | + if oneside_area == 0 and otherside_area==0: | ||
| 126 | + now_state = 0 | ||
| 127 | + else: | ||
| 128 | + now_state = 1 if oneside_area < otherside_area else -1 | ||
| 129 | + | ||
| 130 | + if last_state* now_state < 0: | ||
| 131 | + # print(angle) | ||
| 132 | + break | ||
| 133 | + else: | ||
| 134 | + last_state = now_state | ||
| 135 | + | ||
| 136 | + #第一条线就是均分线 | ||
| 137 | + if angle1 is None or angle2 is None: | ||
| 138 | + pass | ||
| 139 | + else: | ||
| 140 | + #如果面积差大于阈值,二分法查找 | ||
| 141 | + if abs(oneside_area - otherside_area) > area_thre: | ||
| 142 | + line = self.division(polygon, center, in_hole, line_length, angle1, angle2, area_thre) | ||
| 143 | + | ||
| 144 | + | ||
| 145 | + # 提前return | ||
| 146 | + if in_hole: | ||
| 147 | + | ||
| 148 | + point_intersection: Geometry = line.Intersection(in_hole_line) | ||
| 149 | + plist = [] | ||
| 150 | + for i in range(point_intersection.GetGeometryCount()): | ||
| 151 | + pi = point_intersection.GetGeometryRef(i) | ||
| 152 | + plist.append(pi) | ||
| 153 | + plist_d = [(pi,center.Distance(pi)) for pi in plist] | ||
| 154 | + plist_d.sort(key=lambda x:x[1]) | ||
| 155 | + | ||
| 156 | + nearest_point= plist_d[0][0] | ||
| 157 | + firt_short_length = short_length/20.0 | ||
| 158 | + radline,other_point = self.get_radline(center.GetX(),center.GetY(),nearest_point.GetX(),nearest_point.GetY(),firt_short_length) | ||
| 159 | + # print("\"" + other_point.ExportToWkt() + "\",") | ||
| 160 | + | ||
| 161 | + | ||
| 162 | + while not polygon.Contains(other_point): | ||
| 163 | + | ||
| 164 | + firt_short_length = firt_short_length / 2 | ||
| 165 | + radline, other_point = self.get_radline(center.GetX(), center.GetY(), nearest_point.GetX(), | ||
| 166 | + nearest_point.GetY(), firt_short_length) | ||
| 167 | + | ||
| 168 | + | ||
| 169 | + | ||
| 170 | + return RepresentPoint(other_point,polygon) | ||
| 171 | + | ||
| 172 | + | ||
| 173 | + point_intersection:Geometry = line.Intersection(polygon_line) | ||
| 174 | + xlist = [] | ||
| 175 | + ylist = [] | ||
| 176 | + plist = [] | ||
| 177 | + | ||
| 178 | + for i in range(point_intersection.GetGeometryCount()): | ||
| 179 | + pi = point_intersection.GetGeometryRef(i) | ||
| 180 | + xlist.append(pi.GetX()) | ||
| 181 | + ylist.append(pi.GetY()) | ||
| 182 | + plist.append(pi) | ||
| 183 | + | ||
| 184 | + | ||
| 185 | + reprecent_point = [(min(xlist)+max(xlist))/2.0,(min(ylist)+max(ylist))/2.0] | ||
| 186 | + | ||
| 187 | + reprecent_point = self.creat_point(reprecent_point) | ||
| 188 | + | ||
| 189 | + if not polygon.Contains(reprecent_point): | ||
| 190 | + plist_d = [(pi,center.Distance(pi)) for pi in plist] | ||
| 191 | + plist_d.sort(key=lambda x:x[1]) | ||
| 192 | + reprecent_point = self.creat_point(((plist_d[0][0].GetX()+ plist_d[1][0].GetX())/2.0, (plist_d[0][0].GetY()+plist_d[1][0].GetY())/2.0)) | ||
| 193 | + | ||
| 194 | + # print("\""+reprecent_point.ExportToWkt() + "\",") | ||
| 195 | + | ||
| 196 | + rp = RepresentPoint(reprecent_point,polygon) | ||
| 197 | + | ||
| 198 | + return rp | ||
| 199 | + | ||
| 200 | + def get_line(self, x0, y0 , angle, r): | ||
| 201 | + | ||
| 202 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 203 | + line.AddPoint(x0, y0) | ||
| 204 | + hudu = angle/360.0 * 2 * math.pi | ||
| 205 | + dx = math.sin(hudu) * r | ||
| 206 | + dy = math.cos(hudu) * r | ||
| 207 | + line.AddPoint(x0+dx, y0+dy) | ||
| 208 | + | ||
| 209 | + return line | ||
| 210 | + | ||
| 211 | + def get_doubleline(self, x0, y0 , angle, r): | ||
| 212 | + | ||
| 213 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 214 | + | ||
| 215 | + hudu = angle/360.0 * 2 * math.pi | ||
| 216 | + dx = math.sin(hudu) * r | ||
| 217 | + dy = math.cos(hudu) * r | ||
| 218 | + | ||
| 219 | + hudu = (angle+180)/360.0 * 2 * math.pi | ||
| 220 | + dx2 = math.sin(hudu) * r | ||
| 221 | + dy2 = math.cos(hudu) * r | ||
| 222 | + | ||
| 223 | + line.AddPoint(x0 + dx2, y0 + dy2) | ||
| 224 | + line.AddPoint(x0+dx, y0+dy) | ||
| 225 | + | ||
| 226 | + return line | ||
| 227 | + | ||
| 228 | + def get_radline(self,x0,y0,x1,y1,len_size): | ||
| 229 | + a2 = math.pow((x1-x0),2) | ||
| 230 | + b2 = math.pow((y1-y0),2) | ||
| 231 | + len_size = len_size+ math.sqrt(a2+b2) | ||
| 232 | + | ||
| 233 | + line: Geometry = ogr.Geometry(ogr.wkbLineString) | ||
| 234 | + line.AddPoint(x0, y0) | ||
| 235 | + tanx = abs(y1-y0) / abs(x1-x0) | ||
| 236 | + cosx = 1 / math.sqrt(1 + tanx *tanx) | ||
| 237 | + dx = cosx* len_size | ||
| 238 | + dy = tanx * dx | ||
| 239 | + | ||
| 240 | + if x1 == x0: | ||
| 241 | + x2 = x0 | ||
| 242 | + if y1 > y0 : | ||
| 243 | + y2 = y0 + abs(dy) | ||
| 244 | + else: | ||
| 245 | + y2 = y0 - abs(dy) | ||
| 246 | + else: | ||
| 247 | + if x1 < x0: | ||
| 248 | + x2 = x0 - dx | ||
| 249 | + else: | ||
| 250 | + x2 = x0 + dx | ||
| 251 | + | ||
| 252 | + if y1 < y0: | ||
| 253 | + y2 = y0 - dy | ||
| 254 | + else: | ||
| 255 | + y2 = y0 + dy | ||
| 256 | + | ||
| 257 | + line.AddPoint(x2, y2) | ||
| 258 | + | ||
| 259 | + other_point = ogr.Geometry(ogr.wkbPoint) | ||
| 260 | + other_point.AddPoint(x2, y2) | ||
| 261 | + | ||
| 262 | + return line , other_point | ||
| 263 | + | ||
| 264 | + def get_direction(self,polygon,center,line_length): | ||
| 265 | + ''' | ||
| 266 | + 判断旋转方向 | ||
| 267 | + :param polygon: | ||
| 268 | + :param center: | ||
| 269 | + :param line_length: | ||
| 270 | + :return: | ||
| 271 | + ''' | ||
| 272 | + | ||
| 273 | + line = self.get_line(center.GetX(),center.GetY(),0,line_length) | ||
| 274 | + | ||
| 275 | + oneside_area, otherside_area = self.jude(polygon,line,0,line_length) | ||
| 276 | + | ||
| 277 | + if oneside_area == 0 and otherside_area == 0 : | ||
| 278 | + return range(0, 390, 30) | ||
| 279 | + else: | ||
| 280 | + line = self.get_line(center.GetX(), center.GetY(), 10, line_length) | ||
| 281 | + oneside_area_contrast, otherside_area_contrast = self.jude(polygon, line, 30, line_length) | ||
| 282 | + | ||
| 283 | + if oneside_area_contrast == 0 and otherside_area_contrast == 0: | ||
| 284 | + return range(360, -30, -30) | ||
| 285 | + else: | ||
| 286 | + if abs(oneside_area - otherside_area) > abs(oneside_area_contrast - otherside_area_contrast): | ||
| 287 | + return range(0, 390, 30) | ||
| 288 | + else: | ||
| 289 | + return range(360, -30, -30) | ||
| 290 | + | ||
| 291 | + def jude(self,polygon,line,angle,line_length): | ||
| 292 | + | ||
| 293 | + line_buffer: Geometry = line.Buffer(line_length / self.buffer_threshold) | ||
| 294 | + clip_geom: Geometry = polygon.Difference(line_buffer) | ||
| 295 | + | ||
| 296 | + oneside_area = 0 | ||
| 297 | + otherside_area = 0 | ||
| 298 | + | ||
| 299 | + gc = clip_geom.GetGeometryCount() | ||
| 300 | + if gc <= 1: | ||
| 301 | + oneside_area = 0 | ||
| 302 | + otherside_area = 0 | ||
| 303 | + else: | ||
| 304 | + triangle1, triangle2 = self.get_side_triangle(line, angle) | ||
| 305 | + | ||
| 306 | + | ||
| 307 | + for gi in range(clip_geom.GetGeometryCount()): | ||
| 308 | + clip_geom_i: Geometry = clip_geom.GetGeometryRef(gi) | ||
| 309 | + it = clip_geom_i.Intersection(triangle1) | ||
| 310 | + | ||
| 311 | + if clip_geom_i.Intersect(triangle1) and it.Buffer(line_length / self.buffer_threshold).Intersect( | ||
| 312 | + line_buffer): | ||
| 313 | + oneside_area += clip_geom_i.GetArea() | ||
| 314 | + else: | ||
| 315 | + otherside_area += clip_geom_i.GetArea() | ||
| 316 | + return oneside_area, otherside_area | ||
| 317 | + | ||
| 318 | + def division(self,polygon,center,in_hole,line_length,angle1,angle2,area_thre): | ||
| 319 | + | ||
| 320 | + mid_angle = (angle1 + angle2)/2.0 | ||
| 321 | + | ||
| 322 | + | ||
| 323 | + if in_hole: | ||
| 324 | + line = self.get_doubleline(center.GetX(), center.GetY(), mid_angle, line_length) | ||
| 325 | + else: | ||
| 326 | + line = self.get_line(center.GetX(), center.GetY(), mid_angle, line_length) | ||
| 327 | + | ||
| 328 | + one,other = self.jude(polygon,line,mid_angle,line_length) | ||
| 329 | + | ||
| 330 | + while abs(one - other) > area_thre: | ||
| 331 | + if one > other: | ||
| 332 | + if angle1 > angle2: | ||
| 333 | + return self.division(polygon, center, in_hole, line_length, angle2, mid_angle, area_thre) | ||
| 334 | + else: | ||
| 335 | + return self.division(polygon, center, in_hole, line_length, mid_angle, angle1, area_thre) | ||
| 336 | + else: | ||
| 337 | + if angle1 > angle2: | ||
| 338 | + return self.division(polygon, center, in_hole, line_length, mid_angle, angle1, area_thre) | ||
| 339 | + else: | ||
| 340 | + return self.division(polygon, center, in_hole, line_length, angle2, mid_angle, area_thre) | ||
| 341 | + return line | ||
| 342 | + | ||
| 343 | + def get_side_triangle(self,line:Geometry,angle): | ||
| 344 | + ''' | ||
| 345 | + 获取方向三角形 | ||
| 346 | + :param line: | ||
| 347 | + :param angle: | ||
| 348 | + :return: | ||
| 349 | + ''' | ||
| 350 | + | ||
| 351 | + start = line.GetPoint(0) | ||
| 352 | + end = line.GetPoint(1) | ||
| 353 | + | ||
| 354 | + | ||
| 355 | + angle_t = angle-30 | ||
| 356 | + hudu = angle_t/360.0 * 2 * math.pi | ||
| 357 | + | ||
| 358 | + r = line.Length() / (2*math.cos( math.pi/6)) | ||
| 359 | + dx = math.sin(hudu) * r | ||
| 360 | + dy = math.cos(hudu) * r | ||
| 361 | + | ||
| 362 | + | ||
| 363 | + ring1 = ogr.Geometry(ogr.wkbLinearRing) | ||
| 364 | + ring1.AddPoint(start[0], start[1]) | ||
| 365 | + ring1.AddPoint(start[0] + dx, start[1] + dy) | ||
| 366 | + ring1.AddPoint(end[0], end[1]) | ||
| 367 | + ring1.AddPoint(start[0], start[1]) | ||
| 368 | + triangle1 = ogr.Geometry(ogr.wkbPolygon) | ||
| 369 | + triangle1.AddGeometry(ring1) | ||
| 370 | + | ||
| 371 | + | ||
| 372 | + angle_t = angle+30 | ||
| 373 | + hudu = angle_t/360.0 * 2 * math.pi | ||
| 374 | + | ||
| 375 | + r = line.Length() / (2*math.cos( math.pi/6)) | ||
| 376 | + | ||
| 377 | + dx = math.sin(hudu) * r | ||
| 378 | + dy = math.cos(hudu) * r | ||
| 379 | + | ||
| 380 | + ring2 = ogr.Geometry(ogr.wkbLinearRing) | ||
| 381 | + ring2.AddPoint(start[0], start[1]) | ||
| 382 | + ring2.AddPoint(start[0]+dx, start[1]+dy) | ||
| 383 | + ring2.AddPoint(end[0], end[1]) | ||
| 384 | + ring2.AddPoint(start[0], start[1]) | ||
| 385 | + triangle2 = ogr.Geometry(ogr.wkbPolygon) | ||
| 386 | + triangle2.AddGeometry(ring2) | ||
| 387 | + | ||
| 388 | + return triangle1,triangle2 | ||
| 389 | + | ||
| 390 | + def creat_point(self,tuple): | ||
| 391 | + p: Geometry = ogr.Geometry(ogr.wkbPoint) | ||
| 392 | + p.AddPoint(tuple[0], tuple[1]) | ||
| 393 | + return p | ||
| 394 | + | ||
| 395 | + def create_delauney(self,rps): | ||
| 396 | + multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) | ||
| 397 | + | ||
| 398 | + rp_dict = {} | ||
| 399 | + delauney_lines = [] | ||
| 400 | + | ||
| 401 | + rps_sub = set() | ||
| 402 | + for rp in rps: | ||
| 403 | + multipoint.AddGeometry(rp.point) | ||
| 404 | + # 多边形代表点相同,需要融合多边形 | ||
| 405 | + if rp_dict.get(rp.point.GetPoint(0).__str__()): | ||
| 406 | + rp_exist = rp_dict.get(rp.point.GetPoint(0).__str__()) | ||
| 407 | + rp_exist.polygon = rp_exist.polygon.Union(rp.polygon) | ||
| 408 | + else: | ||
| 409 | + rp_dict[rp.point.GetPoint(0).__str__()] = rp | ||
| 410 | + rps_sub.add(rp) | ||
| 411 | + | ||
| 412 | + delauney:Geometry = multipoint.DelaunayTriangulation(bOnlyEdges=True) | ||
| 413 | + | ||
| 414 | + for index in range(delauney.GetGeometryCount()): | ||
| 415 | + triangle_line:Geometry = delauney.GetGeometryRef(index) | ||
| 416 | + p = triangle_line.GetPoint(0) | ||
| 417 | + p_next = triangle_line.GetPoint(1) | ||
| 418 | + | ||
| 419 | + rp1 = rp_dict.get(p.__str__()) | ||
| 420 | + rp2 = rp_dict.get(p_next.__str__()) | ||
| 421 | + | ||
| 422 | + delauney_line = DelauneyLine(rp1,rp2) | ||
| 423 | + delauney_lines.append(delauney_line) | ||
| 424 | + | ||
| 425 | + return delauney_lines,rps_sub | ||
| 426 | + | ||
| 427 | + def create_min_delauney(self,delauney_lines,rps): | ||
| 428 | + ''' | ||
| 429 | + 使用prim算法计算最小生成树 | ||
| 430 | + :param delauney_lines: | ||
| 431 | + :param polygons: | ||
| 432 | + :return: | ||
| 433 | + ''' | ||
| 434 | + | ||
| 435 | + kv = dict() | ||
| 436 | + print(len(rps)) | ||
| 437 | + | ||
| 438 | + | ||
| 439 | + rps_set = set(rps) | ||
| 440 | + | ||
| 441 | + for delauney_line in delauney_lines: | ||
| 442 | + if kv.get(delauney_line.rp1): | ||
| 443 | + kv[delauney_line.rp1].add(delauney_line) | ||
| 444 | + else: | ||
| 445 | + kv[delauney_line.rp1] = set() | ||
| 446 | + kv[delauney_line.rp1].add(delauney_line) | ||
| 447 | + | ||
| 448 | + if kv.get(delauney_line.rp2): | ||
| 449 | + kv[delauney_line.rp2].add(delauney_line) | ||
| 450 | + else: | ||
| 451 | + kv[delauney_line.rp2] = set() | ||
| 452 | + kv[delauney_line.rp2].add(delauney_line) | ||
| 453 | + | ||
| 454 | + print(len(kv)) | ||
| 455 | + | ||
| 456 | + print("完成三角边倒排索引") | ||
| 457 | + | ||
| 458 | + #初始化树 | ||
| 459 | + delauney_lines = sorted(delauney_lines,key=lambda x:x.distance) | ||
| 460 | + delauney_min_tree = DelauneyMinTree() | ||
| 461 | + | ||
| 462 | + delauney_min_tree.append(delauney_lines[0],kv) | ||
| 463 | + | ||
| 464 | + rps_set.remove(delauney_lines[0].rp1) | ||
| 465 | + rps_set.remove(delauney_lines[0].rp2) | ||
| 466 | + | ||
| 467 | + kv[delauney_lines[0].rp1].remove(delauney_lines[0]) | ||
| 468 | + kv[delauney_lines[0].rp2].remove(delauney_lines[0]) | ||
| 469 | + | ||
| 470 | + print("完成最小生成树初始化") | ||
| 471 | + | ||
| 472 | + while rps_set.__len__()>0: | ||
| 473 | + | ||
| 474 | + print(rps_set.__len__()) | ||
| 475 | + t1 = time.time() | ||
| 476 | + # relate_delauney_line = delauney_min_tree.get_other_relate_delauney_lines(kv,rps_set) | ||
| 477 | + | ||
| 478 | + relate_delauney_line = delauney_min_tree.touch_delauney_lines | ||
| 479 | + | ||
| 480 | + | ||
| 481 | + relate_delauney_line_sort = sorted(relate_delauney_line,key=lambda x:x.distance) | ||
| 482 | + | ||
| 483 | + min_distance_line = relate_delauney_line_sort[0] | ||
| 484 | + #删除 | ||
| 485 | + other_rp = delauney_min_tree.get_other_rp(min_distance_line) | ||
| 486 | + | ||
| 487 | + if other_rp is None: | ||
| 488 | + kv[min_distance_line.rp1].remove(min_distance_line) | ||
| 489 | + kv[min_distance_line.rp2].remove(min_distance_line) | ||
| 490 | + continue | ||
| 491 | + | ||
| 492 | + delauney_min_tree.append(min_distance_line,kv) | ||
| 493 | + | ||
| 494 | + rps_set.remove(other_rp) | ||
| 495 | + | ||
| 496 | + kv[min_distance_line.rp1].remove(min_distance_line) | ||
| 497 | + kv[min_distance_line.rp2].remove(min_distance_line) | ||
| 498 | + | ||
| 499 | + # print(time.time() - t2) | ||
| 500 | + print("完成最小生成树") | ||
| 501 | + | ||
| 502 | + return delauney_min_tree | ||
| 503 | + | ||
| 504 | + def cut_delauney_min_tree(self,delauney_min_tree:DelauneyMinTree,threshold): | ||
| 505 | + | ||
| 506 | + trees = [] | ||
| 507 | + kv = {} | ||
| 508 | + | ||
| 509 | + count = 0 | ||
| 510 | + | ||
| 511 | + for delauney_line in delauney_min_tree.delauney_lines_list: | ||
| 512 | + | ||
| 513 | + dn1 = kv.get(delauney_line.rp1) | ||
| 514 | + dn2 = kv.get(delauney_line.rp2) | ||
| 515 | + | ||
| 516 | + | ||
| 517 | + if not dn1: | ||
| 518 | + dn1 = DelauneyNode(delauney_line.rp1) | ||
| 519 | + kv[delauney_line.rp1] = dn1 | ||
| 520 | + | ||
| 521 | + if not dn2: | ||
| 522 | + | ||
| 523 | + trees.append(dn1) | ||
| 524 | + | ||
| 525 | + dn2 = DelauneyNode(delauney_line.rp2) | ||
| 526 | + kv[delauney_line.rp2] = dn2 | ||
| 527 | + | ||
| 528 | + if delauney_line.distance < threshold: | ||
| 529 | + dn1.add_children(dn2,delauney_line) | ||
| 530 | + count +=1 | ||
| 531 | + | ||
| 532 | + else: | ||
| 533 | + #断开 | ||
| 534 | + trees.append(dn2) | ||
| 535 | + else: | ||
| 536 | + | ||
| 537 | + if delauney_line.distance < threshold: | ||
| 538 | + dn2.add_children(dn1,delauney_line) | ||
| 539 | + count += 1 | ||
| 540 | + else: | ||
| 541 | + trees.append(dn1) | ||
| 542 | + else: | ||
| 543 | + | ||
| 544 | + dn2 = DelauneyNode(delauney_line.rp2) | ||
| 545 | + kv[delauney_line.rp2] = dn2 | ||
| 546 | + | ||
| 547 | + if delauney_line.distance < threshold: | ||
| 548 | + dn1.add_children(dn2,delauney_line) | ||
| 549 | + count += 1 | ||
| 550 | + else: | ||
| 551 | + trees.append(dn2) | ||
| 552 | + | ||
| 553 | + | ||
| 554 | + return trees | ||
| 555 | + | ||
| 556 | + def create_polygon(self,p1,p2,p3,p4): | ||
| 557 | + | ||
| 558 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 559 | + ring.AddPoint(p1[0], p1[1]) | ||
| 560 | + ring.AddPoint(p2[0], p2[1]) | ||
| 561 | + ring.AddPoint(p3[0], p3[1]) | ||
| 562 | + ring.AddPoint(p4[0], p4[1]) | ||
| 563 | + ring.AddPoint(p1[0], p1[1]) | ||
| 564 | + | ||
| 565 | + poly = ogr.Geometry(ogr.wkbPolygon) | ||
| 566 | + poly.AddGeometry(ring) | ||
| 567 | + return poly | ||
| 568 | + | ||
| 569 | + def get_polygon_lines(self,polygon): | ||
| 570 | + #无孔Polygon | ||
| 571 | + if polygon.GetGeometryCount() in [0,1]: | ||
| 572 | + polygon_line : Geometry = ogr.ForceToLineString(polygon) | ||
| 573 | + # 有孔Polygon | ||
| 574 | + else: | ||
| 575 | + polygon_line : Geometry = ogr.ForceToLineString(polygon.GetGeometryRef(0)) | ||
| 576 | + | ||
| 577 | + return polygon_line | ||
| 578 | + | ||
| 579 | + def get_subpoint(self, x0, y0, x1, y1, len_size): | ||
| 580 | + | ||
| 581 | + len_size = len_size | ||
| 582 | + tanx = abs(y1 - y0) / abs(x1 - x0) | ||
| 583 | + cosx = 1 / math.sqrt(1 + tanx * tanx) | ||
| 584 | + dx = cosx * len_size | ||
| 585 | + dy = tanx * dx | ||
| 586 | + | ||
| 587 | + if x1 == x0: | ||
| 588 | + x2 = x0 | ||
| 589 | + if y1 > y0: | ||
| 590 | + y2 = y0 + abs(dy) | ||
| 591 | + else: | ||
| 592 | + y2 = y0 - abs(dy) | ||
| 593 | + else: | ||
| 594 | + if x1 < x0: | ||
| 595 | + x2 = x0 - dx | ||
| 596 | + else: | ||
| 597 | + x2 = x0 + dx | ||
| 598 | + | ||
| 599 | + if y1 < y0: | ||
| 600 | + y2 = y0 - dy | ||
| 601 | + else: | ||
| 602 | + y2 = y0 + dy | ||
| 603 | + | ||
| 604 | + return x2, y2 | ||
| 605 | + | ||
| 606 | + def merge_concave_parallel(self, trees, distance_threshold): | ||
| 607 | + merge_polygons = [] | ||
| 608 | + | ||
| 609 | + tree_set = set(trees) | ||
| 610 | + thread_set = set() | ||
| 611 | + | ||
| 612 | + while len(tree_set) > 0 : | ||
| 613 | + while len(thread_set) < 16 and len(tree_set) > 0: | ||
| 614 | + | ||
| 615 | + print(len(tree_set)) | ||
| 616 | + tree = tree_set.pop() | ||
| 617 | + polygons = list(tree.get_polygons()) | ||
| 618 | + merge_threading = MyThread(self.merge,args=(polygons,distance_threshold)) | ||
| 619 | + merge_threading.start() | ||
| 620 | + thread_set.add(merge_threading) | ||
| 621 | + | ||
| 622 | + | ||
| 623 | + remove_list = [] | ||
| 624 | + for thread in thread_set: | ||
| 625 | + | ||
| 626 | + | ||
| 627 | + if not thread.is_alive(): | ||
| 628 | + merge_polygons.append(thread.get_result()) | ||
| 629 | + remove_list.append(thread) | ||
| 630 | + for re in remove_list: | ||
| 631 | + thread_set.remove(re) | ||
| 632 | + del re | ||
| 633 | + | ||
| 634 | + for thread in thread_set: | ||
| 635 | + thread.join() | ||
| 636 | + merge_polygons.append(thread.get_result()) | ||
| 637 | + | ||
| 638 | + return merge_polygons | ||
| 639 | + | ||
| 640 | + def merge(self,polygons,distance_threshold): | ||
| 641 | + merge_raw: Geometry = polygons[0] | ||
| 642 | + for p in polygons: | ||
| 643 | + merge_raw = merge_raw.Union(p) | ||
| 644 | + | ||
| 645 | + points = [] | ||
| 646 | + | ||
| 647 | + for i in range(merge_raw.GetGeometryCount()): | ||
| 648 | + | ||
| 649 | + poly = merge_raw.GetGeometryRef(i) | ||
| 650 | + poly_line: Geometry = self.get_polygon_lines(poly) | ||
| 651 | + if poly_line: | ||
| 652 | + for indx in range(poly_line.GetPointCount() - 1): | ||
| 653 | + poi = poly_line.GetPoint(indx) | ||
| 654 | + | ||
| 655 | + points.append(poi) | ||
| 656 | + | ||
| 657 | + poi_next = poly_line.GetPoint(indx + 1) | ||
| 658 | + | ||
| 659 | + dis = math.sqrt(math.pow(poi[0] - poi_next[0], 2) + math.pow(poi[1] - poi_next[1], 2)) | ||
| 660 | + # print(dis) | ||
| 661 | + if dis > distance_threshold: | ||
| 662 | + times = int(dis / distance_threshold) | ||
| 663 | + # print(times) | ||
| 664 | + for time in range(1, times + 1): | ||
| 665 | + x, y = self.get_subpoint(poi[0], poi[1], poi_next[0], poi_next[1], | ||
| 666 | + (time * distance_threshold)) | ||
| 667 | + points.append([x, y]) | ||
| 668 | + | ||
| 669 | + points = np.array([[p[0], p[1]] for p in points]) | ||
| 670 | + | ||
| 671 | + cp = [] | ||
| 672 | + for pp in points: | ||
| 673 | + poi = ogr.Geometry(ogr.wkbPoint) | ||
| 674 | + poi.AddPoint(pp[0], pp[1]) | ||
| 675 | + cp.append(poi) | ||
| 676 | + | ||
| 677 | + merge_p_line = concaveHull(points, 3) | ||
| 678 | + | ||
| 679 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
| 680 | + | ||
| 681 | + merge_p = ogr.Geometry(ogr.wkbPolygon) | ||
| 682 | + | ||
| 683 | + for l in merge_p_line: | ||
| 684 | + ring.AddPoint(l[0], l[1]) | ||
| 685 | + | ||
| 686 | + ring.AddPoint(merge_p_line[0][0], merge_p_line[0][1]) | ||
| 687 | + | ||
| 688 | + merge_p.AddGeometry(ring) | ||
| 689 | + merge_p = merge_p.Simplify(self.distance_buffer_threshold / 10) | ||
| 690 | + | ||
| 691 | + return merge_p | ||
| 692 | + | ||
| 693 | + def process(self): | ||
| 694 | + polygons = self.data.get_polygons() | ||
| 695 | + rps = [] | ||
| 696 | + | ||
| 697 | + for poly in polygons: | ||
| 698 | + rp = self.get_polygon_reprecent_point(poly) | ||
| 699 | + rps.append(rp) | ||
| 700 | + print("完成代表点计算") | ||
| 701 | + | ||
| 702 | + #代表点要融合 | ||
| 703 | + delauney_lines,rps_sub = self.create_delauney(rps) | ||
| 704 | + | ||
| 705 | + print("完成树生成计算") | ||
| 706 | + min_delauney = self.create_min_delauney(delauney_lines,rps_sub) | ||
| 707 | + print("完成最小生成树计算") | ||
| 708 | + trees = self.cut_delauney_min_tree(min_delauney,self.distance_buffer_threshold) | ||
| 709 | + print("完成树裁剪") | ||
| 710 | + | ||
| 711 | + polygons = self.merge_concave_parallel(trees,self.distance_buffer_threshold) | ||
| 712 | + | ||
| 713 | + return [p.ExportToWkt() for p in polygons] | ||
| 714 | + | ||
| 715 | +if __name__ == '__main__': | ||
| 716 | + | ||
| 717 | + | ||
| 718 | + # print(sd.get_polygons()[0]) | ||
| 719 | + # sd.close() | ||
| 720 | + | ||
| 721 | + t1 = time.time() | ||
| 722 | + sd = ShapeData(r"J:\Data\制图综合result\zhongshansub.shp") | ||
| 723 | + | ||
| 724 | + zh = Zonghe(sd) | ||
| 725 | + wkts = zh.process() | ||
| 726 | + result = r"J:\Data\制图综合result\zhongshansub_pm.shp" | ||
| 727 | + ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 728 | + | ||
| 729 | + print(time.time()-t1) |
test/zonghe/de_merge.py
0 → 100644
| 1 | +# coding=utf-8 | ||
| 2 | +#author: 4N | ||
| 3 | +#createtime: 2022/3/8 | ||
| 4 | +#email: nheweijun@sina.com | ||
| 5 | + | ||
| 6 | +import math | ||
| 7 | + | ||
| 8 | +from osgeo import ogr | ||
| 9 | +from osgeo.ogr import * | ||
| 10 | + | ||
| 11 | +from test.zonghe.ShapeData import ShapeData | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +class Zonghe: | ||
| 15 | + | ||
| 16 | + data:ShapeData | ||
| 17 | + area_threshold = 100.0 | ||
| 18 | + buffer_threshold = 100.0 | ||
| 19 | + distance_buffer_threshold = 2.114691025217302e-04 | ||
| 20 | + | ||
| 21 | + def __init__(self,data): | ||
| 22 | + self.data = data | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + def creat_point(self,tuple): | ||
| 26 | + p: Geometry = ogr.Geometry(ogr.wkbPoint) | ||
| 27 | + p.AddPoint(tuple[0], tuple[1]) | ||
| 28 | + return p | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + def merge2(self,p1,p2): | ||
| 33 | + | ||
| 34 | + polygons = [] | ||
| 35 | + points = [] | ||
| 36 | + | ||
| 37 | + for p in [p1,p2]: | ||
| 38 | + | ||
| 39 | + if p.GetGeometryCount() == 1: | ||
| 40 | + polygon_line: Geometry = ogr.ForceToLineString(p) | ||
| 41 | + # 有孔Polygon | ||
| 42 | + else: | ||
| 43 | + polygon_line: Geometry = ogr.ForceToLineString(p.GetGeometryRef(0)) | ||
| 44 | + | ||
| 45 | + points.extend(polygon_line.GetPoints()[:-1]) | ||
| 46 | + | ||
| 47 | + multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + for p in points: | ||
| 51 | + poi = ogr.Geometry(ogr.wkbPoint) | ||
| 52 | + poi.AddPoint(p[0],p[1]) | ||
| 53 | + multipoint.AddGeometry(poi) | ||
| 54 | + | ||
| 55 | + delauney: Geometry = multipoint.DelaunayTriangulation() | ||
| 56 | + merge_polygon = None | ||
| 57 | + | ||
| 58 | + for p in delauney: | ||
| 59 | + | ||
| 60 | + p_c = p.Centroid() | ||
| 61 | + | ||
| 62 | + # print("\"" + p_c.ExportToWkt() + "\",") | ||
| 63 | + if p1.Contains(p) or p2.Contains(p): | ||
| 64 | + continue | ||
| 65 | + print("\"" + p.ExportToWkt() + "\",") | ||
| 66 | + | ||
| 67 | + | ||
| 68 | + return polygons | ||
| 69 | + | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + #这个是融合面 | ||
| 73 | + def merge(self,p1,p2): | ||
| 74 | + | ||
| 75 | + if p1.GetGeometryCount() == 1: | ||
| 76 | + polygon_line1: Geometry = ogr.ForceToLineString(p1) | ||
| 77 | + # 有孔Polygon | ||
| 78 | + else: | ||
| 79 | + polygon_line1: Geometry = ogr.ForceToLineString(p1.GetGeometryRef(0)) | ||
| 80 | + | ||
| 81 | + | ||
| 82 | + p1_points = polygon_line1.GetPoints()[:-1] | ||
| 83 | + | ||
| 84 | + if p2.GetGeometryCount() == 1: | ||
| 85 | + polygon_line2: Geometry = ogr.ForceToLineString(p2) | ||
| 86 | + # 有孔Polygon | ||
| 87 | + else: | ||
| 88 | + polygon_line2: Geometry = ogr.ForceToLineString(p2.GetGeometryRef(0)) | ||
| 89 | + | ||
| 90 | + p2_points = polygon_line2.GetPoints()[:-1] | ||
| 91 | + multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) | ||
| 92 | + | ||
| 93 | + p1_int = [] | ||
| 94 | + for indx,p in enumerate(p1_points): | ||
| 95 | + | ||
| 96 | + p_t = False | ||
| 97 | + for pp in p2_points: | ||
| 98 | + line = ogr.Geometry(ogr.wkbLineString) | ||
| 99 | + line.AddPoint(p[0], p[1]) | ||
| 100 | + line.AddPoint(pp[0], pp[1]) | ||
| 101 | + | ||
| 102 | + ggg:Geometry = line.Intersection(p1) | ||
| 103 | + | ||
| 104 | + if ggg.GetGeometryType() in [1,-2147483647,3001]: | ||
| 105 | + p_t = True | ||
| 106 | + break | ||
| 107 | + if p_t: | ||
| 108 | + pppp = ogr.Geometry(ogr.wkbPoint) | ||
| 109 | + pppp.AddPoint(p[0],p[1]) | ||
| 110 | + p1_int.append(p) | ||
| 111 | + multipoint.AddGeometry(pppp) | ||
| 112 | + | ||
| 113 | + | ||
| 114 | + for indx,p in enumerate(p2_points): | ||
| 115 | + | ||
| 116 | + p_t = False | ||
| 117 | + for pp in p1_int: | ||
| 118 | + line = ogr.Geometry(ogr.wkbLineString) | ||
| 119 | + line.AddPoint(p[0], p[1]) | ||
| 120 | + line.AddPoint(pp[0], pp[1]) | ||
| 121 | + | ||
| 122 | + ggg:Geometry = line.Intersection(p2) | ||
| 123 | + | ||
| 124 | + | ||
| 125 | + if ggg.GetGeometryType() in [1,-2147483647,3001]: | ||
| 126 | + p_t = True | ||
| 127 | + break | ||
| 128 | + if p_t: | ||
| 129 | + | ||
| 130 | + pppp = ogr.Geometry(ogr.wkbPoint) | ||
| 131 | + pppp.AddPoint(p[0],p[1]) | ||
| 132 | + | ||
| 133 | + | ||
| 134 | + multipoint.AddGeometry(pppp) | ||
| 135 | + | ||
| 136 | + | ||
| 137 | + | ||
| 138 | + delauney: Geometry = multipoint.DelaunayTriangulation() | ||
| 139 | + | ||
| 140 | + for indx in range(delauney.GetGeometryCount()): | ||
| 141 | + tri:Geometry = delauney.GetGeometryRef(indx) | ||
| 142 | + dif1:Geometry = tri.Difference(p1) | ||
| 143 | + dif2:Geometry = tri.Difference(p2) | ||
| 144 | + | ||
| 145 | + # return [multipoint.ExportToWkt()] | ||
| 146 | + | ||
| 147 | + return [p.ExportToWkt() for p in delauney] | ||
| 148 | + | ||
| 149 | + | ||
| 150 | + | ||
| 151 | + #这个是融合面 | ||
| 152 | + def mergebac(self,p1,p2): | ||
| 153 | + | ||
| 154 | + if p1.GetGeometryCount() == 1: | ||
| 155 | + polygon_line1: Geometry = ogr.ForceToLineString(p1) | ||
| 156 | + # 有孔Polygon | ||
| 157 | + else: | ||
| 158 | + polygon_line1: Geometry = ogr.ForceToLineString(p1.GetGeometryRef(0)) | ||
| 159 | + | ||
| 160 | + | ||
| 161 | + p1_points = polygon_line1.GetPoints()[:-1] | ||
| 162 | + | ||
| 163 | + if p2.GetGeometryCount() == 1: | ||
| 164 | + polygon_line2: Geometry = ogr.ForceToLineString(p2) | ||
| 165 | + # 有孔Polygon | ||
| 166 | + else: | ||
| 167 | + polygon_line2: Geometry = ogr.ForceToLineString(p2.GetGeometryRef(0)) | ||
| 168 | + | ||
| 169 | + p2_points = polygon_line2.GetPoints()[:-1] | ||
| 170 | + multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) | ||
| 171 | + | ||
| 172 | + | ||
| 173 | + p1_point_start = None | ||
| 174 | + p1_point_end = None | ||
| 175 | + | ||
| 176 | + for indx,p in enumerate(p1_points): | ||
| 177 | + | ||
| 178 | + p_t = False | ||
| 179 | + for pp in p2_points: | ||
| 180 | + line = ogr.Geometry(ogr.wkbLineString) | ||
| 181 | + line.AddPoint(p[0], p[1]) | ||
| 182 | + line.AddPoint(pp[0], pp[1]) | ||
| 183 | + | ||
| 184 | + ggg:Geometry = line.Intersection(p1) | ||
| 185 | + | ||
| 186 | + if ggg.GetGeometryType() in [1,-2147483647,3001]: | ||
| 187 | + p_t = True | ||
| 188 | + break | ||
| 189 | + if p_t: | ||
| 190 | + pppp = ogr.Geometry(ogr.wkbPoint) | ||
| 191 | + pppp.AddPoint(p[0],p[1]) | ||
| 192 | + | ||
| 193 | + if p1_point_start is None: | ||
| 194 | + p1_point_start = indx | ||
| 195 | + | ||
| 196 | + multipoint.AddGeometry(pppp) | ||
| 197 | + p1_point_end = indx | ||
| 198 | + | ||
| 199 | + p1_int = p1_points[p1_point_start:p1_point_end+1] | ||
| 200 | + | ||
| 201 | + | ||
| 202 | + p2_point_start = None | ||
| 203 | + p2_point_end = None | ||
| 204 | + | ||
| 205 | + | ||
| 206 | + for indx,p in enumerate(p2_points): | ||
| 207 | + | ||
| 208 | + p_t = False | ||
| 209 | + for pp in p1_int: | ||
| 210 | + line = ogr.Geometry(ogr.wkbLineString) | ||
| 211 | + line.AddPoint(p[0], p[1]) | ||
| 212 | + line.AddPoint(pp[0], pp[1]) | ||
| 213 | + | ||
| 214 | + ggg:Geometry = line.Intersection(p2) | ||
| 215 | + | ||
| 216 | + | ||
| 217 | + if ggg.GetGeometryType() in [1,-2147483647,3001]: | ||
| 218 | + p_t = True | ||
| 219 | + break | ||
| 220 | + if p_t: | ||
| 221 | + | ||
| 222 | + pppp = ogr.Geometry(ogr.wkbPoint) | ||
| 223 | + pppp.AddPoint(p[0],p[1]) | ||
| 224 | + | ||
| 225 | + if p2_point_start is None: | ||
| 226 | + p2_point_start = indx | ||
| 227 | + | ||
| 228 | + multipoint.AddGeometry(pppp) | ||
| 229 | + | ||
| 230 | + p2_point_end = indx | ||
| 231 | + | ||
| 232 | + delauney: Geometry = multipoint.DelaunayTriangulation() | ||
| 233 | + | ||
| 234 | + p2_int = p2_points[p2_point_start:p2_point_end + 1] | ||
| 235 | + if p2_point_end == len(p2_points)-1: | ||
| 236 | + p2_int = p2_points[p2_point_start:p2_point_end + 1] | ||
| 237 | + | ||
| 238 | + p1_int.extend(p2_int) | ||
| 239 | + | ||
| 240 | + print(p2_point_start,p2_point_end) | ||
| 241 | + | ||
| 242 | + multipoint: Geometry = ogr.Geometry(ogr.wkbMultiPoint) | ||
| 243 | + | ||
| 244 | + for p in p1_int: | ||
| 245 | + pppp = ogr.Geometry(ogr.wkbPoint) | ||
| 246 | + pppp.AddPoint(p[0], p[1]) | ||
| 247 | + multipoint.AddGeometry(pppp) | ||
| 248 | + | ||
| 249 | + return [multipoint.ExportToWkt()] | ||
| 250 | + | ||
| 251 | + # return [p.ExportToWkt() for p in delauney] | ||
| 252 | + | ||
| 253 | + | ||
| 254 | + def merge4(self,polygons): | ||
| 255 | + | ||
| 256 | + | ||
| 257 | + mp: Geometry = ogr.Geometry(ogr.wkbMultiPolygon) | ||
| 258 | + for p in polygons: | ||
| 259 | + mp.AddGeometry(p) | ||
| 260 | + | ||
| 261 | + | ||
| 262 | + | ||
| 263 | + delauney: Geometry = mp.DelaunayTriangulation() | ||
| 264 | + | ||
| 265 | + intp = [] | ||
| 266 | + for p in delauney: | ||
| 267 | + | ||
| 268 | + res = p | ||
| 269 | + ispass = False | ||
| 270 | + for pp in polygons: | ||
| 271 | + check:Geometry = res.Difference(pp) | ||
| 272 | + if check.IsEmpty(): | ||
| 273 | + ispass = True | ||
| 274 | + break | ||
| 275 | + else: | ||
| 276 | + res = check | ||
| 277 | + if not ispass: | ||
| 278 | + res_buffer = self.extend_tri(res) | ||
| 279 | + | ||
| 280 | + intp.append(res_buffer) | ||
| 281 | + | ||
| 282 | + | ||
| 283 | + polygons.extend(intp) | ||
| 284 | + | ||
| 285 | + mp: Geometry = ogr.Geometry(ogr.wkbMultiPolygon) | ||
| 286 | + | ||
| 287 | + for p in polygons: | ||
| 288 | + mp.AddGeometry(p) | ||
| 289 | + | ||
| 290 | + | ||
| 291 | + | ||
| 292 | + merge:Geometry = mp.UnionCascaded() | ||
| 293 | + | ||
| 294 | + return [merge.ExportToWkt()] | ||
| 295 | + | ||
| 296 | + # return [p.ExportToWkt() for p in intp] | ||
| 297 | + | ||
| 298 | + | ||
| 299 | + def extend_tri(self,triangle:Geometry): | ||
| 300 | + | ||
| 301 | + center:Geometry = triangle.Centroid() | ||
| 302 | + tri_line: Geometry = ogr.ForceToLineString(triangle) | ||
| 303 | + | ||
| 304 | + result_geo = ogr.Geometry(ogr.wkbPolygon) | ||
| 305 | + result_geo_ring:Geometry = ogr.Geometry(ogr.wkbLinearRing) | ||
| 306 | + for point in tri_line.GetPoints(): | ||
| 307 | + radpoint = self.get_radpoint(center.GetX(),center.GetY(),point[0],point[1],0.00000001) | ||
| 308 | + | ||
| 309 | + result_geo_ring.AddPoint(radpoint.GetX(),radpoint.GetY()) | ||
| 310 | + result_geo.AddGeometry(result_geo_ring) | ||
| 311 | + | ||
| 312 | + return result_geo | ||
| 313 | + | ||
| 314 | + def get_radpoint(self,x0,y0,x1,y1,len_size): | ||
| 315 | + a2 = math.pow((x1-x0),2) | ||
| 316 | + b2 = math.pow((y1-y0),2) | ||
| 317 | + len_size = len_size+ math.sqrt(a2+b2) | ||
| 318 | + | ||
| 319 | + tanx = abs(y1-y0) / abs(x1-x0) | ||
| 320 | + cosx = 1 / math.sqrt(1 + tanx *tanx) | ||
| 321 | + dx = cosx* len_size | ||
| 322 | + dy = tanx * dx | ||
| 323 | + | ||
| 324 | + if x1 == x0: | ||
| 325 | + x2 = x0 | ||
| 326 | + if y1 > y0 : | ||
| 327 | + y2 = y0 + abs(dy) | ||
| 328 | + else: | ||
| 329 | + y2 = y0 - abs(dy) | ||
| 330 | + else: | ||
| 331 | + if x1 < x0: | ||
| 332 | + x2 = x0 - dx | ||
| 333 | + else: | ||
| 334 | + x2 = x0 + dx | ||
| 335 | + | ||
| 336 | + if y1 < y0: | ||
| 337 | + y2 = y0 - dy | ||
| 338 | + else: | ||
| 339 | + y2 = y0 + dy | ||
| 340 | + | ||
| 341 | + other_point = ogr.Geometry(ogr.wkbPoint) | ||
| 342 | + other_point.AddPoint(x2, y2) | ||
| 343 | + | ||
| 344 | + return other_point | ||
| 345 | + | ||
| 346 | + | ||
| 347 | + | ||
| 348 | + def merge5(self,p1:Geometry,p2): | ||
| 349 | + | ||
| 350 | + | ||
| 351 | + | ||
| 352 | + ext = p1.GetEnvelope() | ||
| 353 | + | ||
| 354 | + tor = min(ext[1]-ext[0],ext[3]-ext[2]) | ||
| 355 | + | ||
| 356 | + pp = p1.Simplify(tor/20) | ||
| 357 | + | ||
| 358 | + pp2 = p2.Simplify(tor / 20) | ||
| 359 | + | ||
| 360 | + return [pp.ExportToWkt(),pp2.ExportToWkt() ] | ||
| 361 | + | ||
| 362 | + def process(self): | ||
| 363 | + polygons = self.data.get_polygons() | ||
| 364 | + | ||
| 365 | + # return self.merge(polygons[0],polygons[1]) | ||
| 366 | + | ||
| 367 | + return self.merge4(polygons) | ||
| 368 | + | ||
| 369 | + | ||
| 370 | +if __name__ == '__main__': | ||
| 371 | + | ||
| 372 | + | ||
| 373 | + # print(sd.get_polygons()[0]) | ||
| 374 | + # sd.close() | ||
| 375 | + | ||
| 376 | + # create = True | ||
| 377 | + # create = False | ||
| 378 | + # | ||
| 379 | + # if create: | ||
| 380 | + # | ||
| 381 | + # sd = ShapeData(r"J:\Data\制图综合\me.shp") | ||
| 382 | + # | ||
| 383 | + # ext = sd.layer.GetExtent() | ||
| 384 | + # threshold = (ext[1]-ext[0])/20 | ||
| 385 | + # print(threshold) | ||
| 386 | + # | ||
| 387 | + # | ||
| 388 | + # zh = Zonghe(sd) | ||
| 389 | + # zh.process() | ||
| 390 | + # else: | ||
| 391 | + # 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))" | ||
| 392 | + # ] | ||
| 393 | + # result = r"J:\Data\制图综合\mes.shp" | ||
| 394 | + # ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 395 | + # | ||
| 396 | + | ||
| 397 | + | ||
| 398 | + sd = ShapeData(r"J:\Data\制图综合result\ex1.shp") | ||
| 399 | + | ||
| 400 | + ext = sd.layer.GetExtent() | ||
| 401 | + threshold = (ext[1]-ext[0])/20 | ||
| 402 | + | ||
| 403 | + zh = Zonghe(sd) | ||
| 404 | + wkts = zh.process() | ||
| 405 | + | ||
| 406 | + result = r"J:\Data\制图综合result\ex1_1.shp" | ||
| 407 | + ShapeData.create_shp_fromwkts(result,"zh",wkts) | ||
| 408 | + |
| @@ -150,26 +150,53 @@ class Zonghe: | @@ -150,26 +150,53 @@ class Zonghe: | ||
| 150 | 150 | ||
| 151 | return None | 151 | return None |
| 152 | 152 | ||
| 153 | - def merge3(self,polygons): | 153 | + def merge3(self,polygons,distance_threshold): |
| 154 | + | ||
| 155 | + merge_raw :Geometry = polygons[0] | ||
| 156 | + for p in polygons: | ||
| 157 | + merge_raw = merge_raw.Union(p) | ||
| 154 | 158 | ||
| 155 | - multi_poly = ogr.Geometry(ogr.wkbMultiPolygon) | ||
| 156 | 159 | ||
| 157 | points = [] | 160 | points = [] |
| 158 | - for poly in polygons: | ||
| 159 | - multi_poly.AddGeometry(poly) | 161 | + |
| 162 | + for i in range(merge_raw.GetGeometryCount()): | ||
| 163 | + | ||
| 164 | + poly = merge_raw.GetGeometryRef(i) | ||
| 160 | if poly.GetGeometryCount() == 1: | 165 | if poly.GetGeometryCount() == 1: |
| 161 | poly_line: Geometry = ogr.ForceToLineString(poly) | 166 | poly_line: Geometry = ogr.ForceToLineString(poly) |
| 162 | # 有孔Polygon | 167 | # 有孔Polygon |
| 163 | else: | 168 | else: |
| 164 | poly_line: Geometry = ogr.ForceToLineString(poly.GetGeometryRef(0)) | 169 | poly_line: Geometry = ogr.ForceToLineString(poly.GetGeometryRef(0)) |
| 165 | 170 | ||
| 166 | - points.extend(poly_line.GetPoints()[:-1]) | ||
| 167 | 171 | ||
| 172 | + for indx in range(poly_line.GetPointCount() -1) : | ||
| 173 | + poi = poly_line.GetPoint(indx) | ||
| 174 | + | ||
| 175 | + points.append(poi) | ||
| 176 | + | ||
| 177 | + poi_next = poly_line.GetPoint(indx+1) | ||
| 178 | + | ||
| 179 | + dis = math.sqrt(math.pow(poi[0] - poi_next[0],2) + math.pow(poi[1] - poi_next[1],2)) | ||
| 180 | + # print(dis) | ||
| 181 | + if dis > distance_threshold: | ||
| 182 | + times = int(dis/distance_threshold) | ||
| 183 | + # print(times) | ||
| 184 | + for time in range(1,times+1): | ||
| 185 | + x,y = self.get_radline(poi[0],poi[1],poi_next[0],poi_next[1],(time*distance_threshold)) | ||
| 186 | + points.append([x,y]) | ||
| 168 | 187 | ||
| 169 | points = np.array([[p[0],p[1]] for p in points]) | 188 | points = np.array([[p[0],p[1]] for p in points]) |
| 170 | 189 | ||
| 190 | + | ||
| 191 | + for pp in points: | ||
| 192 | + poi = ogr.Geometry(ogr.wkbPoint) | ||
| 193 | + poi.AddPoint(pp[0],pp[1]) | ||
| 194 | + print("\"" + poi.ExportToWkt() + "\",") | ||
| 195 | + | ||
| 196 | + | ||
| 171 | merge_p_line = concaveHull(points, 3) | 197 | merge_p_line = concaveHull(points, 3) |
| 172 | 198 | ||
| 199 | + | ||
| 173 | ring = ogr.Geometry(ogr.wkbLinearRing) | 200 | ring = ogr.Geometry(ogr.wkbLinearRing) |
| 174 | 201 | ||
| 175 | merge_p = ogr.Geometry(ogr.wkbPolygon) | 202 | merge_p = ogr.Geometry(ogr.wkbPolygon) |
| @@ -194,32 +221,46 @@ class Zonghe: | @@ -194,32 +221,46 @@ class Zonghe: | ||
| 194 | return [merge_p.ExportToWkt()] | 221 | return [merge_p.ExportToWkt()] |
| 195 | 222 | ||
| 196 | 223 | ||
| 224 | + def get_radline(self,x0,y0,x1,y1,len_size): | ||
| 197 | 225 | ||
| 226 | + len_size = len_size | ||
| 227 | + tanx = abs(y1-y0) / abs(x1-x0) | ||
| 228 | + cosx = 1 / math.sqrt(1 + tanx *tanx) | ||
| 229 | + dx = cosx* len_size | ||
| 230 | + dy = tanx * dx | ||
| 231 | + | ||
| 232 | + if x1 == x0: | ||
| 233 | + x2 = x0 | ||
| 234 | + if y1 > y0 : | ||
| 235 | + y2 = y0 + abs(dy) | ||
| 236 | + else: | ||
| 237 | + y2 = y0 - abs(dy) | ||
| 238 | + else: | ||
| 239 | + if x1 < x0: | ||
| 240 | + x2 = x0 - dx | ||
| 241 | + else: | ||
| 242 | + x2 = x0 + dx | ||
| 198 | 243 | ||
| 199 | - def merge4(self,p1,p2): | 244 | + if y1 < y0: |
| 245 | + y2 = y0 - dy | ||
| 246 | + else: | ||
| 247 | + y2 = y0 + dy | ||
| 200 | 248 | ||
| 201 | - polygons = [] | ||
| 202 | - points = [] | 249 | + return x2,y2 |
| 203 | 250 | ||
| 204 | - mp: Geometry = ogr.Geometry(ogr.wkbMultiPolygon) | ||
| 205 | - mp.AddGeometry(p1) | ||
| 206 | - mp.AddGeometry(p2) | 251 | + def merge4(self,polygons): |
| 207 | 252 | ||
| 208 | 253 | ||
| 209 | - delauney: Geometry = mp.DelaunayTriangulation(bOnlyEdges=True) | ||
| 210 | - merge_polygon = None | 254 | + mp: Geometry = ogr.Geometry(ogr.wkbMultiPolygon) |
| 255 | + for p in polygons: | ||
| 256 | + mp.AddGeometry(p) | ||
| 211 | 257 | ||
| 212 | - for p in delauney: | ||
| 213 | 258 | ||
| 214 | - p_c = p.Centroid() | ||
| 215 | 259 | ||
| 216 | - # print("\"" + p_c.ExportToWkt() + "\",") | ||
| 217 | - # if p1.Contains(p) or p2.Contains(p): | ||
| 218 | - # continue | ||
| 219 | - print("\"" + p.ExportToWkt() + "\",") | 260 | + delauney: Geometry = mp.DelaunayTriangulation() |
| 220 | 261 | ||
| 221 | 262 | ||
| 222 | - return polygons | 263 | + return [p.ExportToWkt() for p in delauney] |
| 223 | 264 | ||
| 224 | def merge5(self,p1:Geometry,p2): | 265 | def merge5(self,p1:Geometry,p2): |
| 225 | 266 | ||
| @@ -239,7 +280,9 @@ class Zonghe: | @@ -239,7 +280,9 @@ class Zonghe: | ||
| 239 | def process(self): | 280 | def process(self): |
| 240 | polygons = self.data.get_polygons() | 281 | polygons = self.data.get_polygons() |
| 241 | 282 | ||
| 242 | - return self.merge3(polygons) | 283 | + # return self.merge3(polygons,0.00007) |
| 284 | + | ||
| 285 | + return self.merge4(polygons) | ||
| 243 | 286 | ||
| 244 | 287 | ||
| 245 | if __name__ == '__main__': | 288 | if __name__ == '__main__': |
| @@ -270,7 +313,7 @@ if __name__ == '__main__': | @@ -270,7 +313,7 @@ if __name__ == '__main__': | ||
| 270 | # | 313 | # |
| 271 | 314 | ||
| 272 | 315 | ||
| 273 | - sd = ShapeData(r"J:\Data\制图综合\concave.shp") | 316 | + sd = ShapeData(r"J:\Data\制图综合\concave5.shp") |
| 274 | 317 | ||
| 275 | ext = sd.layer.GetExtent() | 318 | ext = sd.layer.GetExtent() |
| 276 | threshold = (ext[1]-ext[0])/20 | 319 | threshold = (ext[1]-ext[0])/20 |
| @@ -280,7 +323,6 @@ if __name__ == '__main__': | @@ -280,7 +323,6 @@ if __name__ == '__main__': | ||
| 280 | zh = Zonghe(sd) | 323 | zh = Zonghe(sd) |
| 281 | wkts = zh.process() | 324 | wkts = zh.process() |
| 282 | 325 | ||
| 283 | - | ||
| 284 | - result = r"J:\Data\制图综合\concave_merge.shp" | 326 | + result = r"J:\Data\制图综合\concave5_merge.shp" |
| 285 | ShapeData.create_shp_fromwkts(result,"zh",wkts) | 327 | ShapeData.create_shp_fromwkts(result,"zh",wkts) |
| 286 | 328 |
请
注册
或
登录
后发表评论