提交 9c2719526ef1069a2634995ce6365062fe8f6bff
1 个父辈
031121d5
ÐÞ¸´»ñȡͼ²ãÒªËØÊýÁ¿bugºÍ²»ÄÜʶ±ðͼ²ãÀàÐÍbug
正在显示
25 个修改的文件
包含
1028 行增加
和
153 行删除
@@ -119,20 +119,22 @@ class Task(db.Model): | @@ -119,20 +119,22 @@ class Task(db.Model): | ||
119 | create_time = Column(DateTime) | 119 | create_time = Column(DateTime) |
120 | update_time = Column(DateTime) | 120 | update_time = Column(DateTime) |
121 | state = Column(Integer) | 121 | state = Column(Integer) |
122 | - # 数据源外键 | 122 | + #数据源外键 |
123 | database_guid = Column(String(256), ForeignKey('dmdms_database.guid')) | 123 | database_guid = Column(String(256), ForeignKey('dmdms_database.guid')) |
124 | - # 目录外键 | 124 | + #目录外键 |
125 | catalog_guid = Column(String(256), ForeignKey('dmdms_catalog.guid')) | 125 | catalog_guid = Column(String(256), ForeignKey('dmdms_catalog.guid')) |
126 | - | 126 | + #抽稀任务指定表的guid |
127 | table_guid = Column(String(256)) | 127 | table_guid = Column(String(256)) |
128 | #任务类型 | 128 | #任务类型 |
129 | + #1:入库任务 | ||
130 | + #2:抽稀任务 | ||
131 | + #3:数据库刷新任务 | ||
132 | + #4:影像金字塔任务 | ||
133 | + #5:数据下载任务 | ||
129 | task_type=Column(Integer) | 134 | task_type=Column(Integer) |
130 | - | ||
131 | creator = Column(Text) | 135 | creator = Column(Text) |
132 | file_name = Column(Text) | 136 | file_name = Column(Text) |
133 | - | ||
134 | relate_processes = relationship('Process', backref='relate_task', lazy='dynamic') | 137 | relate_processes = relationship('Process', backref='relate_task', lazy='dynamic') |
135 | - | ||
136 | # 入库参数 | 138 | # 入库参数 |
137 | parameter= Column(Text) | 139 | parameter= Column(Text) |
138 | 140 | ||
@@ -177,12 +179,9 @@ class Database(db.Model): | @@ -177,12 +179,9 @@ class Database(db.Model): | ||
177 | description = Column(Text) | 179 | description = Column(Text) |
178 | # 唯一性约束,不能注册相同连接的库 | 180 | # 唯一性约束,不能注册相同连接的库 |
179 | connectstr= Column(Text,unique=True) | 181 | connectstr= Column(Text,unique=True) |
180 | - | ||
181 | creator = Column(String(256)) | 182 | creator = Column(String(256)) |
182 | - | ||
183 | create_time = Column(DateTime) | 183 | create_time = Column(DateTime) |
184 | update_time = Column(DateTime) | 184 | update_time = Column(DateTime) |
185 | - | ||
186 | relate_catalogs = relationship('Catalog', backref='relate_database', lazy='dynamic') | 185 | relate_catalogs = relationship('Catalog', backref='relate_database', lazy='dynamic') |
187 | relate_tables = relationship('Table', backref='relate_database', lazy='dynamic') | 186 | relate_tables = relationship('Table', backref='relate_database', lazy='dynamic') |
188 | relate_tasks = relationship('Task', backref='relate_database', lazy='dynamic') | 187 | relate_tasks = relationship('Task', backref='relate_database', lazy='dynamic') |
@@ -118,7 +118,7 @@ class Api(ApiTemplate): | @@ -118,7 +118,7 @@ class Api(ApiTemplate): | ||
118 | 118 | ||
119 | # 范围统计和数量统计以100w为界限 | 119 | # 范围统计和数量统计以100w为界限 |
120 | query_count_layer: Layer = pg_ds.ExecuteSQL( | 120 | query_count_layer: Layer = pg_ds.ExecuteSQL( |
121 | - "SELECT reltuples::bigint AS ec FROM pg_class WHERE oid = 'public.{}'::regclass".format(l_name)) | 121 | + '''SELECT reltuples::bigint AS ec FROM pg_class WHERE oid = 'public."{}"'::regclass'''.format(l_name)) |
122 | feature_count = query_count_layer.GetFeature(0).GetField("ec") | 122 | feature_count = query_count_layer.GetFeature(0).GetField("ec") |
123 | # 要素少于100w可以精确统计 | 123 | # 要素少于100w可以精确统计 |
124 | if feature_count < 1000000: | 124 | if feature_count < 1000000: |
@@ -141,7 +141,7 @@ class Api(ApiTemplate): | @@ -141,7 +141,7 @@ class Api(ApiTemplate): | ||
141 | database_guid=database.guid, | 141 | database_guid=database.guid, |
142 | # alias=layer.GetName(), | 142 | # alias=layer.GetName(), |
143 | name=layer.GetName(), create_time=this_time, update_time=this_time, | 143 | name=layer.GetName(), create_time=this_time, update_time=this_time, |
144 | - table_type=GeometryAdapter.get_table_type(layer.GetGeomType()), | 144 | + table_type=GeometryAdapter.get_table_type(GeometryAdapter.get_geometry_type(layer)), |
145 | extent=extent, | 145 | extent=extent, |
146 | feature_count=feature_count | 146 | feature_count=feature_count |
147 | ) | 147 | ) |
app/modules/featureservice/__init__.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +#author: 4N | ||
3 | +#createtime: 2021/8/11 | ||
4 | +#email: nheweijun@sina.com | ||
5 | + | ||
6 | +from flasgger import swag_from | ||
7 | +from flask import Blueprint | ||
8 | +from app.util import BlueprintApi | ||
9 | +from . import feature_query | ||
10 | +from . import feature_add | ||
11 | +from . import feature_buffer_query | ||
12 | +from . import feature_info | ||
13 | +from . import feature_delete | ||
14 | +from . import feature_schema | ||
15 | +from . import feature_edit | ||
16 | + | ||
17 | +class DataManager(BlueprintApi): | ||
18 | + | ||
19 | + bp = Blueprint("FeatureService", __name__, url_prefix="/API/FeatureService") | ||
20 | + | ||
21 | + @staticmethod | ||
22 | + @bp.route('/Query', methods=['POST']) | ||
23 | + @swag_from(feature_query.Api.api_doc) | ||
24 | + def feature_query(): | ||
25 | + """ | ||
26 | + 要素查询 | ||
27 | + """ | ||
28 | + return feature_query.Api().result | ||
29 | + | ||
30 | + @staticmethod | ||
31 | + @bp.route('/BufferQuery', methods=['POST']) | ||
32 | + @swag_from(feature_buffer_query.Api.api_doc) | ||
33 | + def feature_buffer_query(): | ||
34 | + """ | ||
35 | + 缓冲区查询 | ||
36 | + """ | ||
37 | + return feature_buffer_query.Api().result | ||
38 | + | ||
39 | + @staticmethod | ||
40 | + @bp.route('/Info', methods=['POST']) | ||
41 | + @swag_from(feature_info.Api.api_doc) | ||
42 | + def feature_info(): | ||
43 | + """ | ||
44 | + 要素info | ||
45 | + """ | ||
46 | + return feature_info.Api().result | ||
47 | + | ||
48 | + | ||
49 | + @staticmethod | ||
50 | + @bp.route('/Delete', methods=['POST']) | ||
51 | + @swag_from(feature_delete.Api.api_doc) | ||
52 | + def feature_delete(): | ||
53 | + """ | ||
54 | + 要素删除 | ||
55 | + """ | ||
56 | + return feature_delete.Api().result | ||
57 | + | ||
58 | + @staticmethod | ||
59 | + @bp.route('/Add', methods=['POST']) | ||
60 | + @swag_from(feature_add.Api.api_doc) | ||
61 | + def feature_add(): | ||
62 | + """ | ||
63 | + 要素增加 | ||
64 | + """ | ||
65 | + return feature_add.Api().result | ||
66 | + | ||
67 | + @staticmethod | ||
68 | + @bp.route('/Edit', methods=['POST']) | ||
69 | + @swag_from(feature_edit.Api.api_doc) | ||
70 | + def feature_edit(): | ||
71 | + """ | ||
72 | + 要素修改 | ||
73 | + """ | ||
74 | + return feature_edit.Api().result | ||
75 | + | ||
76 | + @staticmethod | ||
77 | + @bp.route('/Schema', methods=['POST']) | ||
78 | + @swag_from(feature_schema.Api.api_doc) | ||
79 | + def feature_schema(): | ||
80 | + """ | ||
81 | + 要素schema | ||
82 | + """ | ||
83 | + return feature_schema.Api().result |
app/modules/featureservice/feature_add.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +# author: 4N | ||
3 | +# createtime: 2021/8/4 | ||
4 | +# email: nheweijun@sina.com | ||
5 | +import datetime | ||
6 | + | ||
7 | + | ||
8 | + | ||
9 | +from app.models import Task | ||
10 | +from app.util.component.ApiTemplate import ApiTemplate | ||
11 | +from app.util.component.ModelVisitor import ModelVisitor | ||
12 | +class Api(ApiTemplate): | ||
13 | + api_name = "要素增加" | ||
14 | + def para_check(self): | ||
15 | + pass | ||
16 | + | ||
17 | + def process(self): | ||
18 | + | ||
19 | + res = {} | ||
20 | + res["data"] = {} | ||
21 | + try: | ||
22 | + pass | ||
23 | + except Exception as e: | ||
24 | + raise e | ||
25 | + return res | ||
26 | + | ||
27 | + | ||
28 | + | ||
29 | + api_doc={ | ||
30 | + "tags":["要素接口"], | ||
31 | + "parameters":[ | ||
32 | + | ||
33 | + ], | ||
34 | + "responses":{ | ||
35 | + 200:{ | ||
36 | + "schema":{ | ||
37 | + "properties":{ | ||
38 | + } | ||
39 | + } | ||
40 | + } | ||
41 | + } | ||
42 | + } |
1 | +# coding=utf-8 | ||
2 | +# author: 4N | ||
3 | +# createtime: 2021/8/4 | ||
4 | +# email: nheweijun@sina.com | ||
5 | +import datetime | ||
6 | + | ||
7 | + | ||
8 | + | ||
9 | +from app.models import Table,Database | ||
10 | +from app.util.component.ApiTemplate import ApiTemplate | ||
11 | +from app.util.component.GeometryAdapter import GeometryAdapter | ||
12 | +from app.util.component.LayerUtil import LayerUtil | ||
13 | +from app.util.component.PGUtil import PGUtil | ||
14 | +from osgeo.ogr import Geometry,Layer,DataSource,Feature | ||
15 | +from app.models import DES | ||
16 | +from osgeo import ogr | ||
17 | +import gzip | ||
18 | +from flask import make_response | ||
19 | +class Api(ApiTemplate): | ||
20 | + api_name = "缓冲区查询" | ||
21 | + def para_check(self): | ||
22 | + pass | ||
23 | + | ||
24 | + def process(self): | ||
25 | + | ||
26 | + res = {} | ||
27 | + pg_ds:DataSource = None | ||
28 | + try: | ||
29 | + table:Table = Table.query.filter_by(guid=self.para.get("guid")).one_or_none() | ||
30 | + if not table: | ||
31 | + raise Exception("数据不存在!") | ||
32 | + if table.table_type == 0: | ||
33 | + raise Exception("非空间数据!") | ||
34 | + | ||
35 | + database:Database = table.relate_database | ||
36 | + pg_ds:DataSource = PGUtil.open_pg_data_source(0,DES.decode(database.sqlalchemy_uri)) | ||
37 | + layer:Layer = pg_ds.GetLayerByName(table.name) | ||
38 | + | ||
39 | + #缓冲区查询 | ||
40 | + point = GeometryAdapter.tuple_2_point([float(x) for x in self.para.get("point").split(",")]) | ||
41 | + layer.SetSpatialFilter(point.Buffer(float(self.para.get("buffer")))) | ||
42 | + | ||
43 | + feature_collection = LayerUtil.layer_to_feature_collection(layer,limit=1000) | ||
44 | + res["data"] = feature_collection | ||
45 | + res["result"] = True | ||
46 | + | ||
47 | + except Exception as e: | ||
48 | + raise e | ||
49 | + finally: | ||
50 | + if pg_ds: | ||
51 | + pg_ds.Destroy() | ||
52 | + | ||
53 | + # 使用gzip 压缩传输 | ||
54 | + content = gzip.compress(bytes('{}'.format(json.dumps(res,ensure_ascii=False)), 'utf-8'), 2) | ||
55 | + response = make_response(content) | ||
56 | + response.headers['Content-length'] = len(content) | ||
57 | + response.headers['Content-Encoding'] = 'gzip' | ||
58 | + return response | ||
59 | + | ||
60 | + api_doc={ | ||
61 | + "tags":["要素接口"], | ||
62 | + "parameters":[ | ||
63 | + {"name": "guid", | ||
64 | + "in": "formData", | ||
65 | + "type": "string", | ||
66 | + "description": "guid"}, | ||
67 | + {"name": "point", | ||
68 | + "in": "formData", | ||
69 | + "type": "string", | ||
70 | + "description": "point"}, | ||
71 | + {"name": "buffer", | ||
72 | + "in": "formData", | ||
73 | + "type": "float", | ||
74 | + "description": "buffer"} | ||
75 | + ], | ||
76 | + "responses":{ | ||
77 | + 200:{ | ||
78 | + "schema":{ | ||
79 | + "properties":{ | ||
80 | + } | ||
81 | + } | ||
82 | + } | ||
83 | + } | ||
84 | + } |
app/modules/featureservice/feature_delete.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +# author: 4N | ||
3 | +# createtime: 2021/8/4 | ||
4 | +# email: nheweijun@sina.com | ||
5 | +from app.models import Table,Database | ||
6 | +from app.util.component.ApiTemplate import ApiTemplate | ||
7 | +from app.util.component.GeometryAdapter import GeometryAdapter | ||
8 | +from app.util.component.LayerUtil import LayerUtil | ||
9 | +from app.util.component.PGUtil import PGUtil | ||
10 | +from osgeo.ogr import Geometry,Layer,DataSource,Feature | ||
11 | +from app.models import DES | ||
12 | +import json | ||
13 | +class Api(ApiTemplate): | ||
14 | + api_name = "要素删除" | ||
15 | + def para_check(self): | ||
16 | + pass | ||
17 | + | ||
18 | + def process(self): | ||
19 | + | ||
20 | + res = {} | ||
21 | + pg_ds:DataSource = None | ||
22 | + try: | ||
23 | + table:Table = Table.query.filter_by(guid=self.para.get("guid")).one_or_none() | ||
24 | + if not table: | ||
25 | + raise Exception("数据不存在!") | ||
26 | + if table.table_type == 0: | ||
27 | + raise Exception("非空间数据!") | ||
28 | + | ||
29 | + database:Database = table.relate_database | ||
30 | + pg_ds:DataSource = PGUtil.open_pg_data_source(1,DES.decode(database.sqlalchemy_uri)) | ||
31 | + layer:Layer = pg_ds.GetLayerByName(table.name) | ||
32 | + | ||
33 | + fid = int(self.para.get("fid")) | ||
34 | + is_success = layer.DeleteFeature(fid) | ||
35 | + if is_success == 0: | ||
36 | + res["msg"] = "删除成功!" | ||
37 | + res["result"] = True | ||
38 | + else : | ||
39 | + res["msg"] = "要素不存在,删除失败!" | ||
40 | + res["result"] = False | ||
41 | + | ||
42 | + except Exception as e: | ||
43 | + raise e | ||
44 | + finally: | ||
45 | + if pg_ds: | ||
46 | + pg_ds.Destroy() | ||
47 | + return res | ||
48 | + | ||
49 | + | ||
50 | + | ||
51 | + | ||
52 | + api_doc={ | ||
53 | + "tags":["要素接口"], | ||
54 | + "parameters":[ | ||
55 | + {"name": "guid", | ||
56 | + "in": "formData", | ||
57 | + "type": "string", | ||
58 | + "description": "guid"}, | ||
59 | + {"name": "fid", | ||
60 | + "in": "formData", | ||
61 | + "type": "string", | ||
62 | + "description": "fid"} | ||
63 | + ], | ||
64 | + "responses":{ | ||
65 | + 200:{ | ||
66 | + "schema":{ | ||
67 | + "properties":{ | ||
68 | + } | ||
69 | + } | ||
70 | + } | ||
71 | + } | ||
72 | + } |
app/modules/featureservice/feature_edit.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +# author: 4N | ||
3 | +# createtime: 2021/8/4 | ||
4 | +# email: nheweijun@sina.com | ||
5 | +import datetime | ||
6 | + | ||
7 | + | ||
8 | + | ||
9 | +from app.models import Task | ||
10 | +from app.util.component.ApiTemplate import ApiTemplate | ||
11 | +from app.util.component.ModelVisitor import ModelVisitor | ||
12 | +class Api(ApiTemplate): | ||
13 | + api_name = "要素编辑" | ||
14 | + def para_check(self): | ||
15 | + pass | ||
16 | + | ||
17 | + def process(self): | ||
18 | + | ||
19 | + res = {} | ||
20 | + res["data"] = {} | ||
21 | + try: | ||
22 | + pass | ||
23 | + except Exception as e: | ||
24 | + raise e | ||
25 | + return res | ||
26 | + | ||
27 | + | ||
28 | + | ||
29 | + api_doc={ | ||
30 | + "tags":["要素接口"], | ||
31 | + "parameters":[ | ||
32 | + | ||
33 | + ], | ||
34 | + "responses":{ | ||
35 | + 200:{ | ||
36 | + "schema":{ | ||
37 | + "properties":{ | ||
38 | + } | ||
39 | + } | ||
40 | + } | ||
41 | + } | ||
42 | + } |
app/modules/featureservice/feature_info.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +# author: 4N | ||
3 | +# createtime: 2021/8/4 | ||
4 | +# email: nheweijun@sina.com | ||
5 | + | ||
6 | + | ||
7 | +from app.models import Table,Database | ||
8 | +from app.util.component.ApiTemplate import ApiTemplate | ||
9 | +from app.util.component.GeometryAdapter import GeometryAdapter | ||
10 | +from app.util.component.LayerUtil import LayerUtil | ||
11 | +from app.util.component.PGUtil import PGUtil | ||
12 | +from osgeo.ogr import Geometry,Layer,DataSource,Feature | ||
13 | +from app.models import DES | ||
14 | +import json | ||
15 | +import gzip | ||
16 | +from flask import make_response | ||
17 | +class Api(ApiTemplate): | ||
18 | + api_name = "要素info" | ||
19 | + def para_check(self): | ||
20 | + pass | ||
21 | + | ||
22 | + def process(self): | ||
23 | + | ||
24 | + res = {} | ||
25 | + pg_ds:DataSource = None | ||
26 | + try: | ||
27 | + table:Table = Table.query.filter_by(guid=self.para.get("guid")).one_or_none() | ||
28 | + if not table: | ||
29 | + raise Exception("数据不存在!") | ||
30 | + if table.table_type == 0: | ||
31 | + raise Exception("非空间数据!") | ||
32 | + | ||
33 | + database:Database = table.relate_database | ||
34 | + pg_ds:DataSource = PGUtil.open_pg_data_source(0,DES.decode(database.sqlalchemy_uri)) | ||
35 | + layer:Layer = pg_ds.GetLayerByName(table.name) | ||
36 | + | ||
37 | + #info查询 | ||
38 | + point = GeometryAdapter.tuple_2_point([float(x) for x in self.para.get("point").split(",")]) | ||
39 | + layer.SetSpatialFilter(point) | ||
40 | + intersect_feats = [] | ||
41 | + for feature in layer: | ||
42 | + if feature.geometry().Intersect(point): | ||
43 | + intersect_feats.append(feature) | ||
44 | + feature_collection = LayerUtil.layer_to_feature_collection(intersect_feats,limit=1000) | ||
45 | + res["data"] = feature_collection | ||
46 | + res["result"] = True | ||
47 | + | ||
48 | + except Exception as e: | ||
49 | + raise e | ||
50 | + finally: | ||
51 | + if pg_ds: | ||
52 | + pg_ds.Destroy() | ||
53 | + | ||
54 | + # 使用gzip 压缩传输 | ||
55 | + content = gzip.compress(bytes("{}".format(json.dumps(res,ensure_ascii=False)), "utf-8"), 2) | ||
56 | + response = make_response(content) | ||
57 | + response.headers['Content-length'] = len(content) | ||
58 | + response.headers['Content-Encoding'] = "gzip" | ||
59 | + return response | ||
60 | + | ||
61 | + | ||
62 | + api_doc={ | ||
63 | + "tags":["要素接口"], | ||
64 | + "parameters":[ | ||
65 | + {"name": "guid", | ||
66 | + "in": "formData", | ||
67 | + "type": "string", | ||
68 | + "description": "guid"}, | ||
69 | + {"name": "point", | ||
70 | + "in": "formData", | ||
71 | + "type": "string", | ||
72 | + "description": "point"} | ||
73 | + ], | ||
74 | + "responses":{ | ||
75 | + 200:{ | ||
76 | + "schema":{ | ||
77 | + "properties":{ | ||
78 | + } | ||
79 | + } | ||
80 | + } | ||
81 | + } | ||
82 | + } |
app/modules/featureservice/feature_query.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +# author: 4N | ||
3 | +# createtime: 2021/8/4 | ||
4 | +# email: nheweijun@sina.com | ||
5 | +import datetime | ||
6 | + | ||
7 | + | ||
8 | + | ||
9 | +from app.models import Table,Database | ||
10 | +from app.util.component.ApiTemplate import ApiTemplate | ||
11 | +from app.util.component.GeometryAdapter import GeometryAdapter | ||
12 | +from app.util.component.LayerUtil import LayerUtil | ||
13 | +from app.util.component.PGUtil import PGUtil | ||
14 | +from osgeo.ogr import Geometry,Layer,DataSource,Feature | ||
15 | +from app.models import DES | ||
16 | +import json | ||
17 | +import gzip | ||
18 | +from flask import make_response | ||
19 | +class Api(ApiTemplate): | ||
20 | + api_name = "空间查询" | ||
21 | + def para_check(self): | ||
22 | + pass | ||
23 | + | ||
24 | + def process(self): | ||
25 | + | ||
26 | + res = {} | ||
27 | + pg_ds:DataSource = None | ||
28 | + try: | ||
29 | + table:Table = Table.query.filter_by(guid=self.para.get("guid")).one_or_none() | ||
30 | + if not table: | ||
31 | + raise Exception("数据不存在!") | ||
32 | + if table.table_type == 0: | ||
33 | + raise Exception("非空间数据!") | ||
34 | + | ||
35 | + database:Database = table.relate_database | ||
36 | + pg_ds:DataSource = PGUtil.open_pg_data_source(0,DES.decode(database.sqlalchemy_uri)) | ||
37 | + layer:Layer = pg_ds.GetLayerByName(table.name) | ||
38 | + | ||
39 | + #空间查询 | ||
40 | + if self.para.get("bbox"): | ||
41 | + bbox:Geometry = GeometryAdapter.envelop_2_polygon([float(x) for x in self.para.get("bbox").split(",")]) | ||
42 | + layer.SetSpatialFilter(bbox) | ||
43 | + #属性查询 | ||
44 | + if self.para.get("filter"): | ||
45 | + conditions = json.loads(self.para.get("filter")) | ||
46 | + filter_conds = [] | ||
47 | + for cond in conditions: | ||
48 | + if cond["type"].__eq__("range"): | ||
49 | + filter_conds.append("{}>{} AND {}<{}".format(cond["name"],cond["lower"], | ||
50 | + cond["name"], cond["higher"])) | ||
51 | + if cond["type"].__eq__("value"): | ||
52 | + try: | ||
53 | + val = float(cond["value"]) | ||
54 | + filter_conds.append("{}={}".format(cond["name"], val)) | ||
55 | + except: | ||
56 | + filter_conds.append("{} like '%{}%'".format(cond["name"], cond["value"])) | ||
57 | + if cond["type"].__eq__("time"): | ||
58 | + filter_conds.append("{} > timestamp '{}' AND {} < timestamp '{}'".format(cond["name"], | ||
59 | + cond["lower"], | ||
60 | + cond["name"], | ||
61 | + cond["higher"])) | ||
62 | + layer.SetAttributeFilter(" AND ".join(filter_conds)) | ||
63 | + | ||
64 | + | ||
65 | + feature_collection = LayerUtil.layer_to_feature_collection(layer,limit=1000) | ||
66 | + res["data"] = feature_collection | ||
67 | + res["result"] = True | ||
68 | + | ||
69 | + except Exception as e: | ||
70 | + raise e | ||
71 | + finally: | ||
72 | + if pg_ds: | ||
73 | + pg_ds.Destroy() | ||
74 | + | ||
75 | + # 使用gzip 压缩传输 | ||
76 | + content = gzip.compress(bytes('{}'.format(json.dumps(res,ensure_ascii=False)), 'utf-8'), 2) | ||
77 | + response = make_response(content) | ||
78 | + response.headers['Content-length'] = len(content) | ||
79 | + response.headers['Content-Encoding'] = 'gzip' | ||
80 | + return response | ||
81 | + | ||
82 | + api_doc={ | ||
83 | + "tags":["要素接口"], | ||
84 | + "parameters":[ | ||
85 | + {"name": "guid", | ||
86 | + "in": "formData", | ||
87 | + "type": "string", | ||
88 | + "description": "guid"}, | ||
89 | + {"name": "bbox", | ||
90 | + "in": "formData", | ||
91 | + "type": "string", | ||
92 | + "description": "bbox"}, | ||
93 | + {"name": "filter", | ||
94 | + "in": "formData", | ||
95 | + "type": "string", | ||
96 | + "description": "filter"} | ||
97 | + ], | ||
98 | + "responses":{ | ||
99 | + 200:{ | ||
100 | + "schema":{ | ||
101 | + "properties":{ | ||
102 | + } | ||
103 | + } | ||
104 | + } | ||
105 | + } | ||
106 | + } |
app/modules/featureservice/feature_schema.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +# author: 4N | ||
3 | +# createtime: 2021/8/4 | ||
4 | +# email: nheweijun@sina.com | ||
5 | + | ||
6 | + | ||
7 | +from app.models import Table,Database | ||
8 | +from app.util.component.ApiTemplate import ApiTemplate | ||
9 | +from app.util.component.GeometryAdapter import GeometryAdapter | ||
10 | +from app.util.component.LayerUtil import LayerUtil | ||
11 | +from app.util.component.PGUtil import PGUtil | ||
12 | +from osgeo.ogr import Geometry,Layer,DataSource,Feature,FieldDefn | ||
13 | +from app.models import DES | ||
14 | +import json | ||
15 | +class Api(ApiTemplate): | ||
16 | + api_name = "要素info" | ||
17 | + def para_check(self): | ||
18 | + pass | ||
19 | + | ||
20 | + def process(self): | ||
21 | + | ||
22 | + res = {} | ||
23 | + pg_ds:DataSource = None | ||
24 | + try: | ||
25 | + table:Table = Table.query.filter_by(guid=self.para.get("guid")).one_or_none() | ||
26 | + if not table: | ||
27 | + raise Exception("数据不存在!") | ||
28 | + if table.table_type == 0: | ||
29 | + raise Exception("非空间数据!") | ||
30 | + | ||
31 | + database:Database = table.relate_database | ||
32 | + pg_ds:DataSource = PGUtil.open_pg_data_source(0,DES.decode(database.sqlalchemy_uri)) | ||
33 | + layer:Layer = pg_ds.GetLayerByName(table.name) | ||
34 | + | ||
35 | + res["data"] = [] | ||
36 | + | ||
37 | + schema = layer.schema | ||
38 | + for s in schema: | ||
39 | + field :FieldDefn = s | ||
40 | + d1 = field.GetName() | ||
41 | + d2 = field.GetTypeName() | ||
42 | + res["data"].append({"name":field.GetName(),"type":field.GetTypeName(),"pricision":field.GetWidth()}) | ||
43 | + res["result"] = True | ||
44 | + | ||
45 | + except Exception as e: | ||
46 | + raise e | ||
47 | + finally: | ||
48 | + if pg_ds: | ||
49 | + pg_ds.Destroy() | ||
50 | + return res | ||
51 | + | ||
52 | + | ||
53 | + | ||
54 | + | ||
55 | + api_doc={ | ||
56 | + "tags":["要素接口"], | ||
57 | + "parameters":[ | ||
58 | + {"name": "guid", | ||
59 | + "in": "formData", | ||
60 | + "type": "string", | ||
61 | + "description": "guid"} | ||
62 | + ], | ||
63 | + "responses":{ | ||
64 | + 200:{ | ||
65 | + "schema":{ | ||
66 | + "properties":{ | ||
67 | + } | ||
68 | + } | ||
69 | + } | ||
70 | + } | ||
71 | + } |
@@ -85,18 +85,12 @@ class Api(ApiTemplate): | @@ -85,18 +85,12 @@ class Api(ApiTemplate): | ||
85 | if parameter.get("tilecol"): | 85 | if parameter.get("tilecol"): |
86 | self.col = int(parameter.get("tilecol")) | 86 | self.col = int(parameter.get("tilecol")) |
87 | 87 | ||
88 | - | ||
89 | - | ||
90 | image_type = parameter.get("format") if parameter.get("format") else "image/png" | 88 | image_type = parameter.get("format") if parameter.get("format") else "image/png" |
91 | - | ||
92 | quality = int(parameter.get("quality")) if parameter.get("quality") else 30 | 89 | quality = int(parameter.get("quality")) if parameter.get("quality") else 30 |
93 | - | ||
94 | slice_para = json.loads(image_service.slice_scheme) | 90 | slice_para = json.loads(image_service.slice_scheme) |
95 | - | ||
96 | extent = SliceScheme.get_polygon(slice_para, self.level, self.row, self.col) | 91 | extent = SliceScheme.get_polygon(slice_para, self.level, self.row, self.col) |
97 | 92 | ||
98 | # 结果矩阵 | 93 | # 结果矩阵 |
99 | - | ||
100 | empty_list = [numpy.zeros((256, 256), dtype=int) + 65536, | 94 | empty_list = [numpy.zeros((256, 256), dtype=int) + 65536, |
101 | numpy.zeros((256, 256), dtype=int) + 65536, | 95 | numpy.zeros((256, 256), dtype=int) + 65536, |
102 | numpy.zeros((256, 256), dtype=int) + 65536] | 96 | numpy.zeros((256, 256), dtype=int) + 65536] |
@@ -108,134 +102,23 @@ class Api(ApiTemplate): | @@ -108,134 +102,23 @@ class Api(ApiTemplate): | ||
108 | pixel_array = numpy.zeros((256, 256,3), dtype=int) | 102 | pixel_array = numpy.zeros((256, 256,3), dtype=int) |
109 | 103 | ||
110 | for image in intersect_image: | 104 | for image in intersect_image: |
111 | - | ||
112 | if image.host.__eq__("本地服务器"): | 105 | if image.host.__eq__("本地服务器"): |
113 | - | ||
114 | - pixel_array = numpy.zeros((256, 256, 3), dtype=int) | ||
115 | - ceng = 0 | ||
116 | - img: Dataset = gdal.Open(image.path, 0) | ||
117 | - t1 = time.time() | ||
118 | - for band in bands: | ||
119 | - | ||
120 | - # 自决定金字塔等级 | ||
121 | - xysize = [img.RasterXSize, img.RasterYSize] | ||
122 | - origin_extent = image.extent | ||
123 | - band_data: Band = img.GetRasterBand(band) | ||
124 | - max_level = band_data.GetOverviewCount() | ||
125 | - | ||
126 | - # 超出空间范围 | ||
127 | - if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[ | ||
128 | - 3] or extent[3] < origin_extent[1]: | ||
129 | - empty = numpy.zeros((256, 256), dtype=int) + 65536 | ||
130 | - # 空间范围相交 | ||
131 | - else: | ||
132 | - image_level = self.determine_level(xysize, origin_extent, extent, max_level) | ||
133 | - | ||
134 | - if image_level == -1: | ||
135 | - overview = band_data | ||
136 | - else: | ||
137 | - try: | ||
138 | - overview: Band = band_data.GetOverview(image_level) | ||
139 | - except: | ||
140 | - raise Exception("该影像不存在该级别的金字塔数据!") | ||
141 | - ox = overview.XSize | ||
142 | - oy = overview.YSize | ||
143 | - | ||
144 | - # 网格大小 | ||
145 | - grid_x = (origin_extent[2] - origin_extent[0]) / (ox * 1.0) | ||
146 | - grid_y = (origin_extent[3] - origin_extent[1]) / (oy * 1.0) | ||
147 | - | ||
148 | - # 完全在影像范围内 | ||
149 | - if extent[0] > origin_extent[0] and extent[1] > origin_extent[1] and extent[2] < \ | ||
150 | - origin_extent[2] and extent[3] < origin_extent[3]: | ||
151 | - | ||
152 | - # 网格偏移量 | ||
153 | - off_x = math.floor((extent[0] - origin_extent[0]) / grid_x) | ||
154 | - off_y = math.floor((origin_extent[3] - extent[3]) / grid_y) | ||
155 | - | ||
156 | - # 截取后网格个数 | ||
157 | - x_g = math.ceil((extent[2] - extent[0]) / grid_x) | ||
158 | - | ||
159 | - y_g = math.ceil((extent[3] - extent[1]) / grid_y) | ||
160 | - | ||
161 | - empty = overview.ReadAsArray(off_x, off_y, x_g, y_g, 256, 256) | ||
162 | - | ||
163 | - | ||
164 | - # 部分相交 | ||
165 | - else: | ||
166 | - | ||
167 | - inter_extent = [0, 0, 0, 0] | ||
168 | - inter_extent[0] = origin_extent[0] if origin_extent[0] > extent[0] else extent[0] | ||
169 | - inter_extent[1] = origin_extent[1] if origin_extent[1] > extent[1] else extent[1] | ||
170 | - inter_extent[2] = origin_extent[2] if origin_extent[2] < extent[2] else extent[2] | ||
171 | - inter_extent[3] = origin_extent[3] if origin_extent[3] < extent[3] else extent[3] | ||
172 | - | ||
173 | - # 网格偏移量 | ||
174 | - off_x = math.floor((inter_extent[0] - origin_extent[0]) / grid_x) | ||
175 | - off_y = math.floor((origin_extent[3] - inter_extent[3]) / grid_y) | ||
176 | - | ||
177 | - # 截取后网格个数 | ||
178 | - x_g = math.floor((inter_extent[2] - inter_extent[0]) / grid_x) | ||
179 | - y_g = math.floor((inter_extent[3] - inter_extent[1]) / grid_y) | ||
180 | - | ||
181 | - # 相对于出图的偏移量 | ||
182 | - | ||
183 | - # 出图的网格大小 | ||
184 | - out_grid_x = (extent[2] - extent[0]) / (256 * 1.0) | ||
185 | - out_grid_y = (extent[3] - extent[1]) / (256 * 1.0) | ||
186 | - | ||
187 | - out_off_x = int(math.ceil((inter_extent[0] - extent[0]) / out_grid_x)) | ||
188 | - out_off_y = int(math.ceil((extent[3] - inter_extent[3]) / out_grid_y)) | ||
189 | - | ||
190 | - out_x_g = int(math.floor((inter_extent[2] - inter_extent[0]) / out_grid_x)) | ||
191 | - out_y_g = int(math.floor((inter_extent[3] - inter_extent[1]) / out_grid_y)) | ||
192 | - | ||
193 | - # 相交部分在出图的哪个位置 | ||
194 | - | ||
195 | - overview_raster: ndarray = overview.ReadAsArray(off_x, off_y, x_g, y_g, out_x_g, | ||
196 | - out_y_g) | ||
197 | - | ||
198 | - dat = numpy.zeros((256, 256), dtype=int) + 65536 | ||
199 | - dat[out_off_y:out_off_y + out_y_g, out_off_x:out_off_x + out_x_g] = overview_raster | ||
200 | - | ||
201 | - empty = dat | ||
202 | - | ||
203 | - pixel_array[:, :, ceng] = empty | ||
204 | - ceng += 1 | ||
205 | - | ||
206 | - data = pixel_array | ||
207 | - | 106 | + data = self.get_local_data(image,extent,bands) |
208 | else: | 107 | else: |
209 | ser = "{}:{}".format(image.host,image.port) | 108 | ser = "{}:{}".format(image.host,image.port) |
210 | if zoo.exists("/rpc/{}".format(ser)): | 109 | if zoo.exists("/rpc/{}".format(ser)): |
211 | - | ||
212 | - transport = TSocket.TSocket(image.host, image.port) | ||
213 | - transport = TTransport.TBufferedTransport(transport) | ||
214 | - protocol = TBinaryProtocol.TBinaryProtocol(transport) | ||
215 | - client = ImageDataService.Client(protocol) | ||
216 | - transport.open() | ||
217 | - t1 = time.time() | ||
218 | - data = client.getData(image.path, extent, json.loads(image.extent), bands) | ||
219 | - transport.close() | ||
220 | - current_app.logger.info("time {}".format(time.time()-t1)) | ||
221 | - | ||
222 | - data = gzip.decompress(data) | ||
223 | - data = numpy.frombuffer(data, dtype=int) | ||
224 | - data= data.reshape((256, 256, 3)) | 110 | + data= self.get_remote_data(image,extent,bands) |
225 | else: | 111 | else: |
226 | data = numpy.zeros((256, 256, 3), dtype=int) + 65536 | 112 | data = numpy.zeros((256, 256, 3), dtype=int) + 65536 |
227 | 113 | ||
228 | - | ||
229 | # 掩膜在中央接口生成 | 114 | # 掩膜在中央接口生成 |
230 | mask = numpy.zeros((256, 256), dtype=int) | 115 | mask = numpy.zeros((256, 256), dtype=int) |
231 | mask2 = numpy.zeros((256, 256), dtype=int) | 116 | mask2 = numpy.zeros((256, 256), dtype=int) |
232 | jizhun = data[:, :, 0] | 117 | jizhun = data[:, :, 0] |
233 | - | ||
234 | mask[jizhun == 65536] = 1 | 118 | mask[jizhun == 65536] = 1 |
235 | mask[jizhun != 65536] = 0 | 119 | mask[jizhun != 65536] = 0 |
236 | mask2[jizhun == 65536] = 0 | 120 | mask2[jizhun == 65536] = 0 |
237 | mask2[jizhun != 65536] = 1 | 121 | mask2[jizhun != 65536] = 1 |
238 | - | ||
239 | # 掩膜计算 | 122 | # 掩膜计算 |
240 | for i, d in enumerate(empty_list): | 123 | for i, d in enumerate(empty_list): |
241 | empty_list[i] = empty_list[i] * mask + data[:, :, i] * mask2 | 124 | empty_list[i] = empty_list[i] * mask + data[:, :, i] * mask2 |
@@ -290,7 +173,7 @@ class Api(ApiTemplate): | @@ -290,7 +173,7 @@ class Api(ApiTemplate): | ||
290 | image_out = buf.tobytes() | 173 | image_out = buf.tobytes() |
291 | return image_out | 174 | return image_out |
292 | 175 | ||
293 | - def get_data(self,image,extent,bands): | 176 | + def get_remote_data(self,image,extent,bands): |
294 | ''' | 177 | ''' |
295 | 通过RPC获取远程数据 | 178 | 通过RPC获取远程数据 |
296 | :param image: | 179 | :param image: |
@@ -298,16 +181,123 @@ class Api(ApiTemplate): | @@ -298,16 +181,123 @@ class Api(ApiTemplate): | ||
298 | :param bands: | 181 | :param bands: |
299 | :return: | 182 | :return: |
300 | ''' | 183 | ''' |
184 | + | ||
301 | transport = TSocket.TSocket(image.host, image.port) | 185 | transport = TSocket.TSocket(image.host, image.port) |
302 | transport = TTransport.TBufferedTransport(transport) | 186 | transport = TTransport.TBufferedTransport(transport) |
303 | protocol = TBinaryProtocol.TBinaryProtocol(transport) | 187 | protocol = TBinaryProtocol.TBinaryProtocol(transport) |
304 | client = ImageDataService.Client(protocol) | 188 | client = ImageDataService.Client(protocol) |
305 | - | ||
306 | transport.open() | 189 | transport.open() |
307 | - data = client.getData(image.path,extent,json.loads(image.extent), bands) | 190 | + t1 = time.time() |
191 | + data = client.getData(image.path, extent, json.loads(image.extent), bands) | ||
308 | transport.close() | 192 | transport.close() |
193 | + current_app.logger.info("time {}".format(time.time() - t1)) | ||
194 | + | ||
195 | + data = gzip.decompress(data) | ||
196 | + data = numpy.frombuffer(data, dtype=int) | ||
197 | + data = data.reshape((256, 256, 3)) | ||
198 | + | ||
199 | + return data | ||
200 | + | ||
201 | + def get_local_data(self,image,extent,bands): | ||
202 | + ''' | ||
203 | + 获取本地数据 | ||
204 | + :param image: | ||
205 | + :param extent: | ||
206 | + :param bands: | ||
207 | + :return: | ||
208 | + ''' | ||
209 | + pixel_array = numpy.zeros((256, 256, 3), dtype=int) | ||
210 | + ceng = 0 | ||
211 | + img: Dataset = gdal.Open(image.path, 0) | ||
212 | + t1 = time.time() | ||
213 | + for band in bands: | ||
214 | + | ||
215 | + # 自决定金字塔等级 | ||
216 | + xysize = [img.RasterXSize, img.RasterYSize] | ||
217 | + origin_extent = image.extent | ||
218 | + band_data: Band = img.GetRasterBand(band) | ||
219 | + max_level = band_data.GetOverviewCount() | ||
220 | + | ||
221 | + # 超出空间范围 | ||
222 | + if extent[2] < origin_extent[0] or extent[0] > origin_extent[2] or extent[1] > origin_extent[ | ||
223 | + 3] or extent[3] < origin_extent[1]: | ||
224 | + empty = numpy.zeros((256, 256), dtype=int) + 65536 | ||
225 | + # 空间范围相交 | ||
226 | + else: | ||
227 | + image_level = self.determine_level(xysize, origin_extent, extent, max_level) | ||
228 | + | ||
229 | + if image_level == -1: | ||
230 | + overview = band_data | ||
231 | + else: | ||
232 | + try: | ||
233 | + overview: Band = band_data.GetOverview(image_level) | ||
234 | + except: | ||
235 | + raise Exception("该影像不存在该级别的金字塔数据!") | ||
236 | + ox = overview.XSize | ||
237 | + oy = overview.YSize | ||
238 | + | ||
239 | + # 网格大小 | ||
240 | + grid_x = (origin_extent[2] - origin_extent[0]) / (ox * 1.0) | ||
241 | + grid_y = (origin_extent[3] - origin_extent[1]) / (oy * 1.0) | ||
242 | + | ||
243 | + # 完全在影像范围内 | ||
244 | + if extent[0] > origin_extent[0] and extent[1] > origin_extent[1] and extent[2] < \ | ||
245 | + origin_extent[2] and extent[3] < origin_extent[3]: | ||
246 | + | ||
247 | + # 网格偏移量 | ||
248 | + off_x = math.floor((extent[0] - origin_extent[0]) / grid_x) | ||
249 | + off_y = math.floor((origin_extent[3] - extent[3]) / grid_y) | ||
250 | + | ||
251 | + # 截取后网格个数 | ||
252 | + x_g = math.ceil((extent[2] - extent[0]) / grid_x) | ||
253 | + | ||
254 | + y_g = math.ceil((extent[3] - extent[1]) / grid_y) | ||
255 | + | ||
256 | + empty = overview.ReadAsArray(off_x, off_y, x_g, y_g, 256, 256) | ||
257 | + | ||
258 | + | ||
259 | + # 部分相交 | ||
260 | + else: | ||
261 | + | ||
262 | + inter_extent = [0, 0, 0, 0] | ||
263 | + inter_extent[0] = origin_extent[0] if origin_extent[0] > extent[0] else extent[0] | ||
264 | + inter_extent[1] = origin_extent[1] if origin_extent[1] > extent[1] else extent[1] | ||
265 | + inter_extent[2] = origin_extent[2] if origin_extent[2] < extent[2] else extent[2] | ||
266 | + inter_extent[3] = origin_extent[3] if origin_extent[3] < extent[3] else extent[3] | ||
267 | + | ||
268 | + # 网格偏移量 | ||
269 | + off_x = math.floor((inter_extent[0] - origin_extent[0]) / grid_x) | ||
270 | + off_y = math.floor((origin_extent[3] - inter_extent[3]) / grid_y) | ||
271 | + | ||
272 | + # 截取后网格个数 | ||
273 | + x_g = math.floor((inter_extent[2] - inter_extent[0]) / grid_x) | ||
274 | + y_g = math.floor((inter_extent[3] - inter_extent[1]) / grid_y) | ||
275 | + | ||
276 | + # 相对于出图的偏移量 | ||
277 | + | ||
278 | + # 出图的网格大小 | ||
279 | + out_grid_x = (extent[2] - extent[0]) / (256 * 1.0) | ||
280 | + out_grid_y = (extent[3] - extent[1]) / (256 * 1.0) | ||
281 | + | ||
282 | + out_off_x = int(math.ceil((inter_extent[0] - extent[0]) / out_grid_x)) | ||
283 | + out_off_y = int(math.ceil((extent[3] - inter_extent[3]) / out_grid_y)) | ||
284 | + | ||
285 | + out_x_g = int(math.floor((inter_extent[2] - inter_extent[0]) / out_grid_x)) | ||
286 | + out_y_g = int(math.floor((inter_extent[3] - inter_extent[1]) / out_grid_y)) | ||
287 | + | ||
288 | + # 相交部分在出图的哪个位置 | ||
289 | + | ||
290 | + overview_raster: ndarray = overview.ReadAsArray(off_x, off_y, x_g, y_g, out_x_g, | ||
291 | + out_y_g) | ||
292 | + | ||
293 | + dat = numpy.zeros((256, 256), dtype=int) + 65536 | ||
294 | + dat[out_off_y:out_off_y + out_y_g, out_off_x:out_off_x + out_x_g] = overview_raster | ||
295 | + | ||
296 | + empty = dat | ||
309 | 297 | ||
310 | - return numpy.array(json.loads(data)) | 298 | + pixel_array[:, :, ceng] = empty |
299 | + ceng += 1 | ||
300 | + return pixel_array | ||
311 | 301 | ||
312 | def determin_intersect(self,extent1,extent2): | 302 | def determin_intersect(self,extent1,extent2): |
313 | g1 = GeometryAdapter.envelop_2_polygon(extent1) | 303 | g1 = GeometryAdapter.envelop_2_polygon(extent1) |
@@ -4,11 +4,11 @@ | @@ -4,11 +4,11 @@ | ||
4 | #email: nheweijun@sina.com | 4 | #email: nheweijun@sina.com |
5 | 5 | ||
6 | 6 | ||
7 | -from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time | 7 | +from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time,Binary |
8 | from app.models import db | 8 | from app.models import db |
9 | -from sqlalchemy.ext.declarative import declarative_base | ||
10 | 9 | ||
11 | -Base = declarative_base() | 10 | + |
11 | + | ||
12 | class Image(db.Model): | 12 | class Image(db.Model): |
13 | ''' | 13 | ''' |
14 | 影像元数据 | 14 | 影像元数据 |
@@ -27,7 +27,10 @@ class Image(db.Model): | @@ -27,7 +27,10 @@ class Image(db.Model): | ||
27 | path=Column(String) | 27 | path=Column(String) |
28 | host=Column(String) | 28 | host=Column(String) |
29 | port=Column(Integer) | 29 | port=Column(Integer) |
30 | - | 30 | + #坐标wkt |
31 | + projection = Column(Text) | ||
32 | + #年份 | ||
33 | + ym= Column(String(256)) | ||
31 | 34 | ||
32 | dmdms_image_rel = db.Table('dmdms_image_rel', | 35 | dmdms_image_rel = db.Table('dmdms_image_rel', |
33 | Column('image_guid',String, ForeignKey('dmdms_image.guid')), | 36 | Column('image_guid',String, ForeignKey('dmdms_image.guid')), |
@@ -50,6 +53,10 @@ class ImageService(db.Model): | @@ -50,6 +53,10 @@ class ImageService(db.Model): | ||
50 | description = Column(Text) | 53 | description = Column(Text) |
51 | slice_scheme = Column(Text) | 54 | slice_scheme = Column(Text) |
52 | extent = Column(String(256)) | 55 | extent = Column(String(256)) |
56 | + #可视范围geojson | ||
57 | + visual_range = Column(Text) | ||
58 | + #影像服务缩略图 | ||
59 | + overview = Column(Binary) | ||
53 | images = db.relationship('Image', | 60 | images = db.relationship('Image', |
54 | secondary=dmdms_image_rel, | 61 | secondary=dmdms_image_rel, |
55 | backref='image_services', | 62 | backref='image_services', |
@@ -37,7 +37,7 @@ class Api(ApiTemplate): | @@ -37,7 +37,7 @@ class Api(ApiTemplate): | ||
37 | 37 | ||
38 | sort = int(self.para.get("sort","1")) | 38 | sort = int(self.para.get("sort","1")) |
39 | if sort.__eq__(1): | 39 | if sort.__eq__(1): |
40 | - tables = Table.query.order_by(Table.update_time.desc()) | 40 | + tables = Table.query.order_by(Table.update_time.desc(),Table.name) |
41 | else: | 41 | else: |
42 | tables = Table.query.order_by(Table.name) | 42 | tables = Table.query.order_by(Table.name) |
43 | 43 |
@@ -198,7 +198,7 @@ class Api(ApiTemplate): | @@ -198,7 +198,7 @@ class Api(ApiTemplate): | ||
198 | 198 | ||
199 | # 范围统计和数量统计以100w为界限 | 199 | # 范围统计和数量统计以100w为界限 |
200 | query_count_layer: Layer = pg_ds.ExecuteSQL( | 200 | query_count_layer: Layer = pg_ds.ExecuteSQL( |
201 | - "SELECT reltuples::bigint AS ec FROM pg_class WHERE oid = 'public.{}'::regclass".format( | 201 | + '''SELECT reltuples::bigint AS ec FROM pg_class WHERE oid = 'public."{}"'::regclass'''.format( |
202 | l_name)) | 202 | l_name)) |
203 | feature_count = query_count_layer.GetFeature(0).GetField("ec") | 203 | feature_count = query_count_layer.GetFeature(0).GetField("ec") |
204 | # 要素少于100w可以精确统计 | 204 | # 要素少于100w可以精确统计 |
@@ -223,7 +223,7 @@ class Api(ApiTemplate): | @@ -223,7 +223,7 @@ class Api(ApiTemplate): | ||
223 | database_guid=database.guid, | 223 | database_guid=database.guid, |
224 | # alias=layer.GetName(), | 224 | # alias=layer.GetName(), |
225 | name=layer.GetName(), create_time=this_time, update_time=this_time, | 225 | name=layer.GetName(), create_time=this_time, update_time=this_time, |
226 | - table_type=GeometryAdapter.get_table_type(layer.GetGeomType()), | 226 | + table_type=GeometryAdapter.get_table_type(GeometryAdapter.get_geometry_type(layer)), |
227 | extent=extent, | 227 | extent=extent, |
228 | feature_count=feature_count | 228 | feature_count=feature_count |
229 | ) | 229 | ) |
@@ -331,7 +331,7 @@ class Api(ApiTemplate): | @@ -331,7 +331,7 @@ class Api(ApiTemplate): | ||
331 | 331 | ||
332 | # 范围统计和数量统计以100w为界限 | 332 | # 范围统计和数量统计以100w为界限 |
333 | query_count_layer: Layer = pg_ds.ExecuteSQL( | 333 | query_count_layer: Layer = pg_ds.ExecuteSQL( |
334 | - "SELECT reltuples::bigint AS ec FROM pg_class WHERE oid = 'public.{}'::regclass".format( | 334 | + '''SELECT reltuples::bigint AS ec FROM pg_class WHERE oid = 'public."{}"'::regclass'''.format( |
335 | l_name)) | 335 | l_name)) |
336 | feature_count = query_count_layer.GetFeature(0).GetField("ec") | 336 | feature_count = query_count_layer.GetFeature(0).GetField("ec") |
337 | # 要素少于100w可以精确统计 | 337 | # 要素少于100w可以精确统计 |
app/util/component/CopyData.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +#author: 4N | ||
3 | +#createtime: 2021/6/11 | ||
4 | +#email: nheweijun@sina.com | ||
5 | +import copy | ||
6 | +from osgeo.ogr import * | ||
7 | +from osgeo import gdal,ogr | ||
8 | +import uuid | ||
9 | +import time | ||
10 | +import os | ||
11 | + | ||
12 | +def get_info_from_sqlachemy_uri(uri): | ||
13 | + parts = uri.split(":") | ||
14 | + user = parts[1][2:] | ||
15 | + | ||
16 | + password_list = parts[2].split("@") | ||
17 | + if password_list.__len__() > 2: | ||
18 | + password = "@".join(password_list[:-1]) | ||
19 | + else: | ||
20 | + password = parts[2].split("@")[0] | ||
21 | + host = parts[2].split("@")[-1] | ||
22 | + port = parts[3].split("/")[0] | ||
23 | + database = parts[3].split("/")[1] | ||
24 | + | ||
25 | + return user, password, host, port, database | ||
26 | + | ||
27 | +def open_pg_data_source(iswrite, uri): | ||
28 | + """ | ||
29 | + # 获取PostGIS数据源 | ||
30 | + :return: | ||
31 | + """ | ||
32 | + db_conn_tuple = get_info_from_sqlachemy_uri(uri) | ||
33 | + fn = "PG: user=%s password=%s host=%s port=%s dbname=%s " % db_conn_tuple | ||
34 | + driver = ogr.GetDriverByName("PostgreSQL") | ||
35 | + if driver is None: | ||
36 | + raise Exception("打开PostgreSQL驱动失败,可能是当前GDAL未支持PostgreSQL驱动!") | ||
37 | + ds = driver.Open(fn, iswrite) | ||
38 | + if ds is None: | ||
39 | + raise Exception("打开数据源失败!") | ||
40 | + return ds | ||
41 | + | ||
42 | +def move(geo:Geometry,offx,offy): | ||
43 | + | ||
44 | + g = geo.GetGeometryRef(0) | ||
45 | + num = g.GetPointCount() | ||
46 | + | ||
47 | + coor = [] | ||
48 | + try: | ||
49 | + for j in range(num): | ||
50 | + point = g.GetPoint(j) | ||
51 | + x = point[0] | ||
52 | + y = point[1] | ||
53 | + x += offx | ||
54 | + y += offy | ||
55 | + coor.append([x, y]) | ||
56 | + if num==1: | ||
57 | + point = ogr.Geometry(ogr.wkbPoint) | ||
58 | + point.AddPoint(coor[0][0], coor[0][1]) | ||
59 | + return point | ||
60 | + elif coor[0].__eq__(coor[-1]): | ||
61 | + ring = ogr.Geometry(ogr.wkbLinearRing) | ||
62 | + for co in coor: | ||
63 | + ring.AddPoint(co[0], co[1]) | ||
64 | + poly = ogr.Geometry(ogr.wkbPolygon) | ||
65 | + poly.AddGeometry(ring) | ||
66 | + return poly | ||
67 | + else : | ||
68 | + line = ogr.Geometry(ogr.wkbLineString) | ||
69 | + for co in coor: | ||
70 | + line.AddPoint(co[0], co[1]) | ||
71 | + return line | ||
72 | + except: | ||
73 | + return None | ||
74 | + | ||
75 | + | ||
76 | +def copydata(): | ||
77 | + | ||
78 | + | ||
79 | + bound = "" | ||
80 | + | ||
81 | + work_dir =r"E:\D2\桌面\FSSD_RES_PY_FWM" | ||
82 | + | ||
83 | + data_path=r"E:\D2\桌面\FSSD_RES_PY_FWM\fs4326.shp" | ||
84 | + | ||
85 | + base_name="fs900w" | ||
86 | + | ||
87 | + driver: Driver = ogr.GetDriverByName("ESRI Shapefile") | ||
88 | + ds: DataSource = driver.Open(data_path, 1) | ||
89 | + | ||
90 | + bound_ds : DataSource = driver.Open(bound, 1) | ||
91 | + bound_layer :Layer = bound_ds.GetLayer(0) | ||
92 | + bound_geom = bound_layer.GetNextFeature().GetGeometryRef() | ||
93 | + | ||
94 | + | ||
95 | + if not ds: | ||
96 | + raise Exception("打开数据失败!") | ||
97 | + | ||
98 | + layer: Layer = ds.GetLayer(0) | ||
99 | + | ||
100 | + | ||
101 | + | ||
102 | + schema = layer.schema | ||
103 | + schema = [s for s in schema if not s.GetName().lower().__eq__("objectid")] | ||
104 | + for s in schema : | ||
105 | + if s.GetName().lower().__eq__("objectid") and not s.GetTypeName().__eq__("Interger"): | ||
106 | + s.SetType(ogr.OFTInteger) | ||
107 | + | ||
108 | + | ||
109 | + | ||
110 | + gdb_driver:Driver = ogr.GetDriverByName("FileGDB") | ||
111 | + gdb_ds: DataSource = gdb_driver.CreateDataSource(os.path.join(work_dir,"{}.gdb".format(base_name))) | ||
112 | + gdb_layer:Layer = gdb_ds.CreateLayer(base_name, layer.GetSpatialRef(),layer.GetGeomType()) | ||
113 | + | ||
114 | + # gdb_layer.CreateFields(schema) | ||
115 | + | ||
116 | + print(gdb_layer.GetFIDColumn()) | ||
117 | + | ||
118 | + extent = layer.GetExtent() | ||
119 | + xxrange=extent[1]-extent[0] | ||
120 | + yrange = extent[3]-extent[2] | ||
121 | + feature_defn: FeatureDefn = layer.GetLayerDefn() | ||
122 | + | ||
123 | + begin = time.time() | ||
124 | + count=0 | ||
125 | + work_dir =os.path.dirname(os.path.abspath(__file__)) | ||
126 | + | ||
127 | + for f in layer: | ||
128 | + | ||
129 | + if count%10000==0: | ||
130 | + print(count) | ||
131 | + with open(os.path.join(work_dir, "copy.txt"), "w") as fi: | ||
132 | + fi.write("已完成{}".format(count)) | ||
133 | + g:Geometry=f.GetGeometryRef() | ||
134 | + new_f:Feature = copy.copy(f) | ||
135 | + for xt in range(3): | ||
136 | + for yt in range(3): | ||
137 | + out_g = move(g,xxrange*xt,yrange*yt) | ||
138 | + new_f.SetGeometry(out_g) | ||
139 | + new_f.SetFID(count) | ||
140 | + dd:FieldDefn=new_f.GetField("OBJECTID") | ||
141 | + # new_f.UnsetField("OBJECTID") | ||
142 | + gdb_layer.CreateFeature(new_f) | ||
143 | + count += 1 | ||
144 | + | ||
145 | + print(time.time()-begin) | ||
146 | + | ||
147 | + gdb_ds.Destroy() | ||
148 | + | ||
149 | + | ||
150 | + | ||
151 | +if __name__ == '__main__': | ||
152 | + copydata() | ||
153 | + | ||
154 | + | ||
155 | + | ||
156 | + | ||
157 | + | ||
158 | + | ||
159 | + | ||
160 | + | ||
161 | + | ||
162 | + | ||
163 | + |
@@ -323,7 +323,7 @@ class ThisTask: | @@ -323,7 +323,7 @@ class ThisTask: | ||
323 | database_guid=self.database.guid, | 323 | database_guid=self.database.guid, |
324 | creator=creator, | 324 | creator=creator, |
325 | name=new_layer_name, create_time=this_time, update_time=this_time, | 325 | name=new_layer_name, create_time=this_time, update_time=this_time, |
326 | - catalog_guid=self.catalog_guid, table_type=GeometryAdapter.get_table_type(layer.GetGeomType()), | 326 | + catalog_guid=self.catalog_guid, table_type=GeometryAdapter.get_table_type(GeometryAdapter.get_geometry_type(layer)), |
327 | extent=extent, | 327 | extent=extent, |
328 | feature_count=layer.GetFeatureCount(), | 328 | feature_count=layer.GetFeatureCount(), |
329 | is_vacuate=is_vacuate | 329 | is_vacuate=is_vacuate |
@@ -152,4 +152,21 @@ class GeometryAdapter: | @@ -152,4 +152,21 @@ class GeometryAdapter: | ||
152 | # Create polygon | 152 | # Create polygon |
153 | poly = ogr.Geometry(ogr.wkbPolygon) | 153 | poly = ogr.Geometry(ogr.wkbPolygon) |
154 | poly.AddGeometry(ring) | 154 | poly.AddGeometry(ring) |
155 | - return poly | ||
155 | + return poly | ||
156 | + | ||
157 | + @classmethod | ||
158 | + def tuple_2_point(cls,tup): | ||
159 | + point = ogr.Geometry(ogr.wkbPoint) | ||
160 | + point.AddPoint(tup[0], tup[1]) | ||
161 | + return point | ||
162 | + | ||
163 | + @classmethod | ||
164 | + def get_geometry_type(cls,layer): | ||
165 | + geom_type = layer.GetGeomType() | ||
166 | + if geom_type.__eq__(0): | ||
167 | + fea = layer.GetNextFeature() | ||
168 | + if fea: | ||
169 | + g: Geometry = fea.geometry() | ||
170 | + geom_type = g.GetGeometryType() | ||
171 | + layer.ResetReading() | ||
172 | + return geom_type |
app/util/component/GzipUtil.py
0 → 100644
app/util/component/LayerUtil.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +#author: 4N | ||
3 | +#createtime: 2021/8/12 | ||
4 | +#email: nheweijun@sina.com | ||
5 | +from osgeo.ogr import Layer,Feature | ||
6 | +import json | ||
7 | + | ||
8 | + | ||
9 | +class LayerUtil: | ||
10 | + | ||
11 | + @classmethod | ||
12 | + def layer_to_feature_collection(cls,layer,limit=None): | ||
13 | + ''' | ||
14 | + 图层转feature collection | ||
15 | + :param layer: | ||
16 | + :param limit: 读取限制数 | ||
17 | + :return: | ||
18 | + ''' | ||
19 | + feature_collection = dict() | ||
20 | + feature_collection["type"]="FeatureCollection" | ||
21 | + feature_collection["features"] = [] | ||
22 | + count = 0 | ||
23 | + for feature in layer : | ||
24 | + feature:Feature = feature | ||
25 | + feature_collection["features"].append(json.loads(feature.ExportToJson())) | ||
26 | + #超过限制不再读取 | ||
27 | + if limit: | ||
28 | + if count>limit: | ||
29 | + break | ||
30 | + return feature_collection |
@@ -27,6 +27,11 @@ class PGUtil: | @@ -27,6 +27,11 @@ class PGUtil: | ||
27 | 27 | ||
28 | @classmethod | 28 | @classmethod |
29 | def get_info_from_sqlachemy_uri(cls,uri): | 29 | def get_info_from_sqlachemy_uri(cls,uri): |
30 | + ''' | ||
31 | + 解析sqlachemy_uri | ||
32 | + :param uri: | ||
33 | + :return: | ||
34 | + ''' | ||
30 | parts = uri.split(":") | 35 | parts = uri.split(":") |
31 | user = parts[1][2:] | 36 | user = parts[1][2:] |
32 | 37 | ||
@@ -51,7 +56,12 @@ class PGUtil: | @@ -51,7 +56,12 @@ class PGUtil: | ||
51 | 56 | ||
52 | @classmethod | 57 | @classmethod |
53 | def get_geo_column(cls,table_name,db_session): | 58 | def get_geo_column(cls,table_name,db_session): |
59 | + ''' | ||
54 | # 判断空间列 | 60 | # 判断空间列 |
61 | + :param table_name: | ||
62 | + :param db_session: | ||
63 | + :return: | ||
64 | + ''' | ||
55 | geom_col_sql = ''' | 65 | geom_col_sql = ''' |
56 | SELECT a.attname AS field,t.typname AS type | 66 | SELECT a.attname AS field,t.typname AS type |
57 | FROM | 67 | FROM |
@@ -74,7 +84,13 @@ class PGUtil: | @@ -74,7 +84,13 @@ class PGUtil: | ||
74 | 84 | ||
75 | @classmethod | 85 | @classmethod |
76 | def get_table_count(cls,table_name,db_session): | 86 | def get_table_count(cls,table_name,db_session): |
77 | - count_result = db_session.execute("SELECT reltuples::bigint AS ec FROM pg_class WHERE oid = 'public.{}'::regclass".format( | 87 | + ''' |
88 | + 获取图层数量 | ||
89 | + :param table_name: | ||
90 | + :param db_session: | ||
91 | + :return: | ||
92 | + ''' | ||
93 | + count_result = db_session.execute('''SELECT reltuples::bigint AS ec FROM pg_class WHERE oid = 'public."{}"'::regclass'''.format( | ||
78 | table_name)).fetchone() | 94 | table_name)).fetchone() |
79 | count = count_result[0] | 95 | count = count_result[0] |
80 | if count< 1000000: | 96 | if count< 1000000: |
@@ -84,6 +100,11 @@ class PGUtil: | @@ -84,6 +100,11 @@ class PGUtil: | ||
84 | 100 | ||
85 | @classmethod | 101 | @classmethod |
86 | def check_space(cls, sqlachemy_uri): | 102 | def check_space(cls, sqlachemy_uri): |
103 | + ''' | ||
104 | + 判断数据库是否为空间库 | ||
105 | + :param sqlachemy_uri: | ||
106 | + :return: | ||
107 | + ''' | ||
87 | system_session = None | 108 | system_session = None |
88 | check = True | 109 | check = True |
89 | try: | 110 | try: |
app/util/component/WMSTest.py
0 → 100644
1 | +# coding=utf-8 | ||
2 | +#author: 4N | ||
3 | +#createtime: 2021/8/18 | ||
4 | +#email: nheweijun@sina.com | ||
5 | +import random | ||
6 | + | ||
7 | +def create(extent,example:dict,path,num): | ||
8 | + with open(path, 'w') as f: | ||
9 | + each_num = int(num/len(example.keys())) | ||
10 | + for i in range(each_num): | ||
11 | + for ext in example.values(): | ||
12 | + x_leng = ext[2] - ext[0] | ||
13 | + y_leng = ext[3] - ext[1] | ||
14 | + randomx = random.random() * (extent[2] - extent[0]) + extent[0] | ||
15 | + randomy = random.random() * (extent[3] - extent[1]) + extent[1] | ||
16 | + | ||
17 | + wms = [randomx, randomy, randomx + x_leng, randomy + y_leng] | ||
18 | + wms = [str(x) for x in wms] | ||
19 | + f.write(",".join(wms)) | ||
20 | + f.write("\n") | ||
21 | + | ||
22 | + | ||
23 | + | ||
24 | +if __name__ == '__main__': | ||
25 | + extent=[113.060008,22.765613,115.062014,24.470024] | ||
26 | + | ||
27 | + example={"10km":[114.2578125, 23.37890625, 114.43359375, 23.5546875], | ||
28 | + "5km": [113.73046875, 23.466796875, 113.818359375, 23.5546875], | ||
29 | + "3km": [114.1259765625, 23.466796875, 114.169921875, 23.5107421875], | ||
30 | + "1km": [113.97216796875, 23.48876953125, 113.994140625, 23.5107421875], | ||
31 | + "500m": [113.97216796875, 23.499755859375, 113.983154296875, 23.5107421875], | ||
32 | + "300m": [113.9886474609375,23.5107421875,113.994140625,23.5162353515625], | ||
33 | + "200m":[113.9776611328125,23.51348876953125,113.98040771484375,23.5162353515625], | ||
34 | + "100m":[113.98590087890625,23.52447509765625,113.98727416992188,23.525848388671875], | ||
35 | + "50":[113.983154296875,23.530654907226562,113.98384094238281,23.531341552734375]} | ||
36 | + path = "wms.bat" | ||
37 | + num = 100000 | ||
38 | + create(extent,example,path,num) |
app/util/component/WMTSTest.py
0 → 100644
@@ -4,8 +4,8 @@ | @@ -4,8 +4,8 @@ | ||
4 | deploy_ip_host = "172.26.99.160:8840" | 4 | deploy_ip_host = "172.26.99.160:8840" |
5 | # 系统数据库 | 5 | # 系统数据库 |
6 | 6 | ||
7 | -SQLALCHEMY_DATABASE_URI = "postgresql://postgres:postgres@172.26.40.254:5433/dmap_dms_test" | ||
8 | -# SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.99.160:5432/dmap_dms_test" | 7 | +# SQLALCHEMY_DATABASE_URI = "postgresql://postgres:postgres@172.26.40.254:5433/dmap_dms_test" |
8 | +SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.99.160:5432/dmap_dms_test" | ||
9 | 9 | ||
10 | 10 | ||
11 | # 部署模式cluster,standalone | 11 | # 部署模式cluster,standalone |
@@ -33,7 +33,7 @@ IncludeOptional conf.d/*.conf | @@ -33,7 +33,7 @@ IncludeOptional conf.d/*.conf | ||
33 | LoadModule wsgi_module "/usr/lib/apache2/modules/mod_wsgi-py39.cpython-39-x86_64-linux-gnu.so" | 33 | LoadModule wsgi_module "/usr/lib/apache2/modules/mod_wsgi-py39.cpython-39-x86_64-linux-gnu.so" |
34 | WSGIPythonHome "/usr" | 34 | WSGIPythonHome "/usr" |
35 | 35 | ||
36 | -WSGIScriptAlias / /usr/DMapManager/run.wsgi | 36 | +WSGIScriptAlias /DMapManager /usr/DMapManager/run.wsgi |
37 | <Directory /usr/> | 37 | <Directory /usr/> |
38 | Require all granted | 38 | Require all granted |
39 | </Directory> | 39 | </Directory> |
@@ -9,12 +9,25 @@ import numpy | @@ -9,12 +9,25 @@ import numpy | ||
9 | import gzip | 9 | import gzip |
10 | import sys | 10 | import sys |
11 | import json | 11 | import json |
12 | -pixel_array = numpy.empty((256,256,3),dtype=int)+3 | 12 | +# pixel_array = numpy.empty((256,256,3),dtype=int)+3 |
13 | +# | ||
14 | +# | ||
15 | +# | ||
16 | +# # 使用gzip 压缩传输 | ||
17 | +# content = gzip.compress(pixel_array, 2) | ||
18 | +# | ||
19 | +# print(sys.getsizeof(json.dumps(pixel_array.tolist()))) | ||
20 | +# print(sys.getsizeof((content))) | ||
13 | 21 | ||
22 | +def c(dd): | ||
23 | + return 1 | ||
14 | 24 | ||
25 | +dd = numpy.zeros((2000, 2000), dtype=int) + 2 | ||
15 | 26 | ||
16 | -# 使用gzip 压缩传输 | ||
17 | -content = gzip.compress(pixel_array, 2) | ||
18 | 27 | ||
19 | -print(sys.getsizeof(json.dumps(pixel_array.tolist()))) | ||
20 | -print(sys.getsizeof((content))) | ||
28 | +dd[range(0, 5), 1]=1 | ||
29 | + | ||
30 | + | ||
31 | + | ||
32 | + | ||
33 | +print(dd) |
请
注册
或
登录
后发表评论