Jelajahi Sumber

在新模型上传时, 计算受影响的业务空间

jxing 5 tahun lalu
induk
melakukan
413a32f830

+ 0 - 0
src/affected_space/__init__.py


+ 119 - 0
src/affected_space/affected_space.py

@@ -0,0 +1,119 @@
+
+from shapely.geometry import Polygon
+import json
+
+
+column_space_id = 'space_id'
+column_outline = 'outline'
+column_floor_id = 'floor_id'
+column_revit_id = 'revit_id'
+
+
+# 获取Polygon对象
+def get_polygon(single_poly):
+    poly_len = len(single_poly)
+    poly = []
+    for i in range(poly_len):
+        pair = single_poly[i]
+        poly.append((pair["X"], pair["Y"]))
+    return Polygon(poly)
+
+# 在polygon1包含polygon2的时候, 检测是否polygon1内的空洞也包含polygon2
+def is_include(polygon1, poly2):
+    length1 = len(polygon1)
+    for i in range(1, length1):
+        poly1 = get_polygon(polygon1[i])
+        if poly1.overlaps(poly2):
+            return True
+        if poly1.equals(poly2) or poly1.contains(poly2):
+            return False
+    return True
+
+def is_sub_outline_overlap(polygon1, polygon2):
+    poly1 = get_polygon(polygon1[0])
+    poly2 = get_polygon(polygon2[0])
+    if poly1.overlaps(poly2) or poly1.equals(poly2):
+        return True
+    if poly1.contains(poly2) or poly1.equals(poly2):
+        return is_include(polygon1, poly2)
+    if poly2.contains(poly1) or poly2.equals(poly1):
+        return is_include(polygon2, poly1)
+    return False
+
+# 是否面积有重叠
+def is_overlap(polygon1, ispace_polygon):
+    length1 = len(polygon1)
+    length2 = len(ispace_polygon)
+    if length1 == 0 or length2 == 0:
+        return False
+
+    for i in range(length1):
+        for j in range(length2):
+            if is_sub_outline_overlap(polygon1[i], ispace_polygon):
+                return True
+    return False
+
+# 根据业务空间轮廓和元空间轮廓是否有重叠部分来判断关系
+# 返回dict, 格式 {space_id  --> {ispace_id}}
+def build_rel_space_ispace(space_data, ispace_data):
+    rel_dict = {}
+    for space in space_data:
+        space_id = space.get(column_space_id)
+        for ispace in ispace_data:
+            space_outline = json.loads(space.get(column_outline))
+            ispace_outline = json.loads(ispace.get(column_outline))
+            if is_overlap(space_outline, ispace_outline):
+                if space_id not in rel_dict:
+                    rel_dict[space_id] = set()
+                revit_set = rel_dict.get(space_id)
+                revit_set.add(ispace.get(column_revit_id))
+    return rel_dict
+
+# 返回被删除的元空间的revit_id
+def get_deleted_ispace_revit_id(new_ispace_data, prev_ispace_data):
+    deleted = []
+    prev_ispace_revit_id_set = set()
+    for prev_ispace in prev_ispace_data:
+        prev_ispace_revit_id_set.add(prev_ispace.get(column_revit_id))
+    for new_ispace in new_ispace_data:
+        prev_id = new_ispace.get(column_revit_id)
+        if prev_id in prev_ispace_revit_id_set:
+            prev_ispace_revit_id_set.remove(prev_id)
+    deleted.extend(prev_ispace_revit_id_set)
+    return deleted
+
+# 返回被修改的元空间的revit_id
+def get_updated_ispace_revit_id(new_ispace_data, prev_ispace_data):
+    updated = []
+    new_ispace_dict = {}
+    prev_ispace_dict = {}
+    for prev_ispace in prev_ispace_data:
+        prev_id = prev_ispace.get(column_revit_id)
+        prev_outline = json.loads(prev_ispace.get(column_revit_id))
+        prev_ispace_dict[prev_id] = prev_outline
+    for new_ispace in new_ispace_data:
+        new_id = new_ispace.get(column_revit_id)
+        new_outline = json.loads(new_ispace.get(column_revit_id))
+        new_ispace_dict[new_id] = new_outline
+    for prev_id, prev_outline in prev_ispace_dict.items():
+        if prev_id in new_ispace_dict:
+            new_outline = new_ispace_dict.get(prev_id)
+            prev_poly = get_polygon(prev_outline[0])
+            new_poly = get_polygon(new_outline[0])
+            if not prev_poly.equals(new_poly):
+                updated.append(prev_id)
+    return updated
+
+# 获取受影响的业务空间的id数组
+# space_data是可能受影响的业务空间的数据, new_ispace_data 是新模型的元空间数据, prev_ispace_data是上一个模型的元空间数据
+def get_affected_spaced(space_data, new_ispace_data, prev_ispace_data):
+    affected_spaces = []
+    space_ispace_rel = build_rel_space_ispace(space_data, prev_ispace_data)
+    affected_ispace_revit_id = get_deleted_ispace_revit_id(new_ispace_data, prev_ispace_data)
+    affected_ispace_revit_id.extend(get_updated_ispace_revit_id(new_ispace_data, prev_ispace_data))
+    for space_id, ispace_id_dict in space_ispace_rel.items():
+        for revit_id in affected_ispace_revit_id:
+            if revit_id in ispace_id_dict:
+                affected_spaces.append(space_id)
+                break
+    return affected_spaces

+ 182 - 0
src/affected_space/function.py

@@ -0,0 +1,182 @@
+# floor_id 是revit的楼层id
+
+CREATE OR REPLACE FUNCTION rel_affected_space(project_id character varying, floor_id character varying) RETURNS boolean AS
+$$
+from shapely.geometry import Polygon
+import json
+
+# try:
+# 获取当前楼层绑定的数据中心楼层的id
+floor_plan = plpy.prepare("SELECT current_model_id, bind_floor_ids FROM revit.model_floor where id = $1", ["text"])
+floor_data = floor_plan.execute([floor_id])
+if len(floor_data) != 1:
+    plpy.info("no floor")
+    return True
+floor_arr = json.loads(floor_data[0]['bind_floor_ids'])
+if len(floor_arr) == 0:
+    plpy.info("no binding floor")
+    return True
+floor_str = ""
+for fl in floor_arr:
+    floor_str = (floor_str + fl + ',')
+floor_str = floor_str.strip(',')
+plpy.info(floor_str)
+# 获取当前模型和前一个版本的模型id
+model_plan = plpy.prepare("select id from revit.model_file where model_floor_id = $1 and removed = false and status = 4 and version is not null order by version desc", ["text"])
+model_data = model_plan.execute([floor_id], 2)
+if len(model_data) != 2:
+    plpy.info("no previous model")
+    return True
+sql_str = "select rel.floor_id, rel.space_id, sp.outline from r_sp_in_fl rel left join zone_space_base sp on rel.space_id = sp.id where rel.floor_id in (" + floor_str + ")"
+# 查询出来的跟模型可能相关的所有业务空间
+space_data = plpy.execute(sql_str)
+if len(space_data) == 0:
+    plpy.info("no space relation under binding floor")
+    return True
+plpy.info(space_data)
+plpy.info(len(space_data))
+# 获取新模型的元空间
+new_ispace_plan = plpy.prepare("select revit_id, outline where model_id = $1", ["text"])
+new_ispace_data = new_ispace_plan.execute([model_data[0]['id']])
+
+# 获取旧模型的所有元空间
+prev_ispace_plan = plpy.prepare("select revit_id, outline where model_id = $1", ["text"])
+prev_ispace_data = prev_ispace_plan.execute([model_data[1]['id']])
+
+affected_space_ids = get_affected_spaced(space_data, new_ispace_data, prev_ispace_data)
+
+plpy.info(affected_space_ids)
+for space_id in affected_space_ids:
+    space_plan = plpy.prepare("update zone_space_base set state = 1 where id = $1", ["text"])
+    space_plan.execute([space_id])
+
+return True
+# except Exception as e:
+#     plpy.info(e)
+#     return False
+$$
+LANGUAGE 'plpython3u' VOLATILE;
+
+space_outline_json_map = dict()
+result_arr = []
+# 每个楼层的每个业务空间分别和别的楼层的每个业务空间判断is_vertically_overlap
+# 将结果是true的两个业务空间保存起来
+for building_id, floor_map in row_map.items():
+    for floor_id, type_map in floor_map.items():
+        for object_type, row_arr in type_map.items():
+            # 要被对比的楼层
+            for other_floor_id in floor_map.keys():
+                if other_floor_id == floor_id:
+                    continue
+                other_type_map = floor_map.get(other_floor_id)
+                if object_type not in other_type_map:
+                    continue
+                other_row_arr = other_type_map.get(object_type)
+                for row in row_arr:
+                    for other_row in other_row_arr:
+                        space_id = row['space_id']
+                        other_space_id = other_row['space_id']
+                        if space_id == other_space_id:
+                            continue
+                        if space_id not in space_outline_json_map:
+                            outline_json = json.loads(row['outline'])
+                            space_outline_json_map[space_id] = outline_json
+                        if other_space_id not in space_outline_json_map:
+                            other_outline_json = json.loads(other_row['outline'])
+                            space_outline_json_map[other_space_id] = other_outline_json
+                        outline = space_outline_json_map[space_id]
+                        other_outline = space_outline_json_map[other_space_id]
+                        if is_vertically_overlap(outline, other_outline):
+                            single_result = []
+                            single_result.append(space_id)
+                            single_result.append(other_space_id)
+                            single_result.append(object_type)
+                            result_arr.append(single_result)
+if len(result_arr) == 0:
+    return True
+# 删除旧业务空间的垂直交通关系(自动计算的), 添加新关系
+# 将下面对数据库的操作作为一个事务, 出异常则自动rollback
+with plpy.subtransaction():
+    del_plan = plpy.prepare("delete from r_sp_vertical_sp where project_id = $1 and sign = 2", ["text"])
+    del_plan.execute([project_id])
+    for single_result in result_arr:
+        del_manual_plan = plpy.prepare(
+            "delete from r_sp_vertical_sp where (space_id = $1 and space_other_id = $2) or (space_other_id = $1 and space_id = $2)",
+            ["text", "text"])
+        del_manual_plan.execute([single_result[0], single_result[1]])
+        insert_plan = plpy.prepare(
+            "insert into r_sp_vertical_sp(space_id, space_other_id, project_id, sign, object_type) values($1, $2, $3, 2, $4)",
+            ["text", "text", "text", "text"])
+        insert_plan.execute([single_result[0], single_result[1], project_id, single_result[2]])
+
+
+
+
+
+
+
+
+
+
+# 获取Polygon对象
+def get_polygon(single_poly):
+    poly_len = len(single_poly)
+    poly = []
+    for i in range(poly_len):
+        pair = single_poly[i]
+        poly.append((pair["X"], pair["Y"]))
+    return Polygon(poly)
+
+# 在polygon1包含polygon2的时候, 检测是否polygon1内的空洞也包含polygon2
+def is_include(polygon1, poly2):
+    length1 = len(polygon1)
+    for i in range(1, length1):
+        poly1 = get_polygon(polygon1[i])
+        if poly1.overlaps(poly2):
+            return True
+        if poly1.equals(poly2) or poly1.contains(poly2):
+            return False
+    return True
+
+def is_sub_outline_overlap(polygon1, polygon2):
+    poly1 = get_polygon(polygon1[0])
+    poly2 = get_polygon(polygon2[0])
+    if poly1.overlaps(poly2) or poly1.equals(poly2):
+        return True
+    if poly1.contains(poly2) or poly1.equals(poly2):
+        return is_include(polygon1, poly2)
+    if poly2.contains(poly1) or poly2.equals(poly1):
+        return is_include(polygon2, poly1)
+    return False
+
+# 是否垂直方向上面积有重叠
+def is_vertically_overlap(polygon1, polygon2):
+    length1 = len(polygon1)
+    length2 = len(polygon2)
+    if length1 == 0 or length2 == 0:
+        return False
+
+    for i in range(length1):
+        for j in range(length2):
+            if is_sub_outline_overlap(polygon1[i], polygon2[j]):
+                return True
+    return False
+
+# building -> floor -> object_type -> [space_id]
+def compose_dict(zone_data):
+    building_map = dict()
+    for row in zone_data:
+        building_id = row['building_id']
+        floor_id = row['floor_id']
+        object_type = row['object_type']
+        if building_id not in building_map:
+            building_map[building_id] = dict()
+        floor_map = building_map[building_id]
+        if floor_id not in floor_map:
+            floor_map[floor_id] = dict()
+        type_map = floor_map[floor_id]
+        if object_type not in type_map:
+            type_map[object_type] = []
+        arr = type_map[object_type]
+        arr.append(row)
+    return building_map

+ 106 - 0
src/affected_space/test.py

@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+
+import json
+
+import psycopg2
+from shapely.geometry import Polygon
+import sys
+
+from src.grid.check_grid import check_grid_upright
+
+involved_space = [
+    'id',
+    'floor_name',
+    'project_id',
+    'folder_id',
+    'fid',
+    'accept_time',
+    'version',
+    'note',
+    'user_id',
+    'user_name',
+    'log',
+    'url',
+    'md5',
+    'status'
+]
+
+grid_keys = [
+    'id',
+    'model_id',
+    'name',
+    'type',
+    'last_update',
+    'create_time',
+    'revit_id',
+    'source_id',
+    'location',
+]
+
+
+def get_data(sql):
+    global connection, cursor
+    record = []
+    try:
+        connection = psycopg2.connect(
+            database='datacenter',
+            user='postgres',
+            password='123456',
+            host='192.168.20.234',
+            port='5432'
+        )
+        cursor = connection.cursor()
+        cursor.execute(sql)
+        record = cursor.fetchall()
+    except (Exception, psycopg2.Error) as error:
+        print("Error while connecting to PostgreSQL", error)
+    finally:
+        if connection:
+            cursor.close()
+            connection.close()
+            print('PostgreSQL connection is closed')
+    return record
+
+
+def loads(x):
+    x['location'] = json.loads(x['location'])
+    return x
+
+
+def loads_curve(x):
+    x['curve'] = json.loads(x['curve'])
+    return x
+
+
+if __name__ == '__main__':
+    points1 = [(0, 0), (0, 1), (1, 1), (1, 0)]
+    points2 = [(0, 0), (0.00, 0.5), (0, 1), (1, 1), (1, 0)]
+    poly1 = Polygon(points1)
+    poly2 = Polygon(points2)
+
+    print(poly1.equals(poly2))
+    print(poly1.almost_equals(poly2, 0.99))
+    print(poly1.almost_equals(poly2, 0))
+    print(poly1.almost_equals(poly2, -10))
+    print(poly1.almost_equals(poly2, 2))
+    print(poly1.almost_equals(poly2, 0.0001))
+
+
+
+    # involved_space = "select * from  where folder_id = " \
+    #                      "'bbe510dbe26011e999b69b669ea08505' and status in (3, 31, 4) "
+    # grid_sql = "select * from revit.grid where model_id = "
+    # columns_data = get_data(involved_model_sql)
+    #
+    # model_list = [dict(zip(involved_model_keys, item)) for item in columns_data]
+    # if len(model_list) < 2:
+    #     sys.exit()
+    # grid_data = dict()
+    # for item in model_list:
+    #     current_grid_sql = grid_sql + '\'{model_id}\''.format(model_id=item.get('fid'))
+    #     single_model_grid = get_data(current_grid_sql)
+    #     single_model_grid = [dict(zip(grid_keys, item)) for item in single_model_grid]
+    #     grid_data[item.get('fid')] = single_model_grid
+    #
+    # print(check_grid_upright(model_list, grid_data))
+