|
@@ -188,4 +188,742 @@ LANGUAGE 'plpython3u' VOLATILE;
|
|
|
# type_map[object_type] = []
|
|
|
# arr = type_map[object_type]
|
|
|
# arr.append(row)
|
|
|
-# return building_map
|
|
|
+# return building_map
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION "public"."rel_sp2fl"("project_id" varchar)
|
|
|
+ RETURNS "pg_catalog"."bool" AS $BODY$
|
|
|
+from matplotlib.path import Path
|
|
|
+import json
|
|
|
+from shapely.geometry import Polygon
|
|
|
+
|
|
|
+# 获取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)
|
|
|
+
|
|
|
+# 判断业务空间轮廓是否跟楼层轮廓有重叠
|
|
|
+def is_space_floor_overlap(space_outline, floor_outline):
|
|
|
+ try:
|
|
|
+ if space_outline is None or floor_outline is None:
|
|
|
+ return False
|
|
|
+ space_json = json.loads(space_outline)
|
|
|
+ floor_json = json.loads(floor_outline)
|
|
|
+ if len(floor_json) < 3 or len(space_json) == 0:
|
|
|
+ return False
|
|
|
+ floor_poly = get_polygon(floor_json)
|
|
|
+ for i in range(len(space_json)):
|
|
|
+ sub_space = space_json[i]
|
|
|
+ sub_space_poly = get_polygon(sub_space[0])
|
|
|
+ if floor_poly.contains(sub_space_poly) or floor_poly.equals(sub_space_poly) or floor_poly.overlaps(sub_space_poly) or sub_space_poly.contains(floor_poly):
|
|
|
+ return True
|
|
|
+ return False
|
|
|
+ except Exception as e:
|
|
|
+ plpy.info('计算轮廓异常')
|
|
|
+ plpy.info(e)
|
|
|
+ return False
|
|
|
+
|
|
|
+column_model_id = 'model_id'
|
|
|
+column_space_id = 'space_id'
|
|
|
+column_floor_id1 = 'id1'
|
|
|
+column_floor_outline1 = 'outline1'
|
|
|
+column_floor_building1 = 'bd1'
|
|
|
+column_floor_id2 = 'id2'
|
|
|
+column_floor_outline2 = 'outline2'
|
|
|
+column_floor_building2 = 'bd2'
|
|
|
+column_space_zone = 'object_type'
|
|
|
+
|
|
|
+# 构建一个 model_id --> set{floor_id} 的dict
|
|
|
+def compose_model_id_floor_dict(involved_floors):
|
|
|
+ model_id_floor_dict = dict()
|
|
|
+ floor_outline_dict = dict()
|
|
|
+ floor_building_dict = dict()
|
|
|
+ for row in involved_floors:
|
|
|
+ model_id = row.get(column_model_id)
|
|
|
+ if model_id not in model_id_floor_dict:
|
|
|
+ model_id_floor_dict[model_id] = set()
|
|
|
+ floor_set = model_id_floor_dict[model_id]
|
|
|
+ id1 = row.get(column_floor_id1)
|
|
|
+ outline1 = row.get(column_floor_outline1)
|
|
|
+ building_id1 = row.get(column_floor_building1)
|
|
|
+ id2 = row.get(column_floor_id2)
|
|
|
+ outline2 = row.get(column_floor_outline2)
|
|
|
+ building_id2 = row.get(column_floor_building2)
|
|
|
+ floor_set.add(id1)
|
|
|
+ floor_set.add(id2)
|
|
|
+ floor_building_dict[id1] = building_id1
|
|
|
+ floor_building_dict[id2] = building_id2
|
|
|
+ if id1 not in floor_outline_dict:
|
|
|
+ floor_outline_dict[id1] = outline1
|
|
|
+ if id2 not in floor_outline_dict:
|
|
|
+ floor_outline_dict[id2] = outline2
|
|
|
+ return model_id_floor_dict, floor_outline_dict, floor_building_dict
|
|
|
+
|
|
|
+# 计算一个楼层组内的业务空间与楼层的轮廓关系
|
|
|
+def calc_floor_group(floor_set, floor_outline_dict):
|
|
|
+ sql_str = ""
|
|
|
+ for floor_id in floor_set:
|
|
|
+ sql_str += '\'' + floor_id + '\','
|
|
|
+ if sql_str.endswith(','):
|
|
|
+ sql_str = sql_str[0:-1]
|
|
|
+ plpy.info('sql : {0}'.format(sql_str))
|
|
|
+ involved_space_plan = plpy.prepare("SELECT distinct rel.space_id space_id, sp.outline outline1, sp.object_type object_type " +
|
|
|
+ "FROM r_sp_in_fl rel inner join zone_space_base sp on sp.id = rel.space_id where rel.floor_id in ({0}) and sp.outline is not null".format(sql_str), ["text"])
|
|
|
+ involved_space = involved_space_plan.execute([project_id])
|
|
|
+ plpy.info("involved space:{}".format(len(involved_space)))
|
|
|
+ result_dict = dict() # space_id --> set{floor_id}
|
|
|
+ space_zone_dict = dict() # space_id --> object_type
|
|
|
+ for space_row in involved_space:
|
|
|
+ space_outline = space_row.get(column_floor_outline1)
|
|
|
+ space_id = space_row.get(column_space_id)
|
|
|
+ space_zone = space_row.get(column_space_zone)
|
|
|
+ space_zone_dict[space_id] = space_zone
|
|
|
+ result_dict[space_id] = set()
|
|
|
+ rel_floor_set = result_dict[space_id]
|
|
|
+ for floor_id in floor_set:
|
|
|
+ #for floor_id, floor_outline in floor_outline_dict.items():
|
|
|
+ floor_outline = floor_outline_dict[floor_id]
|
|
|
+ if is_space_floor_overlap(space_outline, floor_outline):
|
|
|
+ plpy.info('{0} : {1}'.format(space_id, floor_id))
|
|
|
+ rel_floor_set.add(floor_id)
|
|
|
+ return result_dict, space_zone_dict
|
|
|
+
|
|
|
+# 删除以前的关系
|
|
|
+def delete_prev_rel(floor_set):
|
|
|
+ sql_str = ''
|
|
|
+ for floor_id in floor_set:
|
|
|
+ sql_str += '\'{0}\','.format(floor_id)
|
|
|
+ if sql_str.endswith(','):
|
|
|
+ sql_str = sql_str[0:-1]
|
|
|
+ delete_rel_plan = plpy.prepare("delete from public.r_sp_in_fl where floor_id in ({0})".format(sql_str), [])
|
|
|
+ delete_rel_plan.execute([])
|
|
|
+
|
|
|
+# 添加关系到数据库
|
|
|
+def add_rel(result_dict, space_zone_dict, floor_building_dict):
|
|
|
+ for space_id, floor_set in result_dict.items():
|
|
|
+ space_zone = space_zone_dict[space_id]
|
|
|
+ for floor_id in floor_set:
|
|
|
+ floor_building = floor_building_dict[floor_id]
|
|
|
+ plpy.info("space_id : {0}, floor_id : {1}".format(space_id, floor_id))
|
|
|
+ insert_rel_plan = plpy.prepare("insert into public.r_sp_in_fl(floor_id, space_id, object_type, project_id, sign, building_id) " +
|
|
|
+ "values($1, $2, $3, $4, 2, $5)", ["text", "text", "text", "text", "text"])
|
|
|
+ try:
|
|
|
+ insert_rel_plan.execute([floor_id, space_id, space_zone, project_id, floor_building])
|
|
|
+ except Exception as e:
|
|
|
+ plpy.info(e)
|
|
|
+
|
|
|
+try:
|
|
|
+ # 将下面对数据库的操作作为一个事务, 出异常则自动rollback
|
|
|
+
|
|
|
+ involved_floors_plan = plpy.prepare("select f1.id id1, f1.building_id bd1, f2.id id2, f2.building_id bd2, f1.model_id model_id, f1.outline outline1, f2.outline outline2 " +
|
|
|
+ "from floor f1 inner join floor f2 on f1.model_id = f2.model_id " +
|
|
|
+ "where f1.id != f2.id and f1.outline is not null and f2.outline is not null and f1.project_id = $1 and f2.project_id = $1", ["text"])
|
|
|
+ involved_floors = involved_floors_plan.execute([project_id])
|
|
|
+ if len(involved_floors) == 0 :
|
|
|
+ plpy.info('没有需要计算的改变')
|
|
|
+ return True
|
|
|
+ plpy.info(len(involved_floors))
|
|
|
+ model_id_floor_dict, floor_outline_dict, floor_building_dict = compose_model_id_floor_dict(involved_floors)
|
|
|
+ plpy.info(len(floor_outline_dict))
|
|
|
+ plpy.info(len(floor_building_dict))
|
|
|
+ plpy.info(len(model_id_floor_dict))
|
|
|
+ for model_id, floor_set in model_id_floor_dict.items():
|
|
|
+ with plpy.subtransaction():
|
|
|
+ plpy.info(model_id)
|
|
|
+ plpy.info(floor_set)
|
|
|
+ result_dict, space_zone_dict = calc_floor_group(floor_set, floor_outline_dict) # space_id -->所属 set{floor_id}, space_id --> object_type
|
|
|
+ delete_prev_rel(floor_set)
|
|
|
+ add_rel(result_dict, space_zone_dict, floor_building_dict)
|
|
|
+ return True
|
|
|
+except Exception as e:
|
|
|
+ plpy.warning(e)
|
|
|
+ return False
|
|
|
+$BODY$
|
|
|
+ LANGUAGE plpython3u VOLATILE
|
|
|
+ COST 100;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION "public"."rel_eq2sp"("tables" text, "out_tables" text, "project_id" varchar, "sign1" int4, "sign2" int4)
|
|
|
+ RETURNS "pg_catalog"."bool" AS $BODY$
|
|
|
+from matplotlib.path import Path
|
|
|
+import json
|
|
|
+
|
|
|
+def is_in_meta_polygon(point, single_poly, radius):
|
|
|
+ poly_len = len(single_poly)
|
|
|
+ poly = []
|
|
|
+ for i in range(poly_len):
|
|
|
+ pair = single_poly[i]
|
|
|
+ poly.append((pair["X"], pair["Y"]))
|
|
|
+ p = Path(poly)
|
|
|
+ return p.contains_points([point], None, radius)
|
|
|
+
|
|
|
+
|
|
|
+def is_in_polygon(point, polygons):
|
|
|
+ polygons_length = len(polygons)
|
|
|
+ if polygons_length == 0:
|
|
|
+ return False
|
|
|
+ for j in range(polygons_length):
|
|
|
+ polygon = polygons[j]
|
|
|
+ if j == 0:
|
|
|
+ if not is_in_meta_polygon(point, polygon, -0.001):
|
|
|
+ return False
|
|
|
+ else:
|
|
|
+ if is_in_meta_polygon(point, polygon, 0.001):
|
|
|
+ return False
|
|
|
+ return True
|
|
|
+
|
|
|
+
|
|
|
+def is_point_in_polygon(x, y, json_poly):
|
|
|
+ try:
|
|
|
+ polygon_list = json.loads(json_poly)
|
|
|
+ total_len = len(polygon_list)
|
|
|
+ point_pair = (float(x), float(y))
|
|
|
+ for index in range(total_len):
|
|
|
+ if is_in_polygon(point_pair, polygon_list[index]):
|
|
|
+ return True
|
|
|
+ return False
|
|
|
+ except Exception as e:
|
|
|
+ plpy.info(e)
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+# 将下面对数据库的操作作为一个事务, 出异常则自动rollback
|
|
|
+input_table_list = tables.split(',')
|
|
|
+output_table_list = out_tables.split(',')
|
|
|
+with plpy.subtransaction():
|
|
|
+ for i in range(0, len(input_table_list)):
|
|
|
+ in_table_name = input_table_list[i]
|
|
|
+ out_table_name = output_table_list[i]
|
|
|
+ # 删除原来关系表中的数据
|
|
|
+ plan1 = plpy.prepare("delete from {0} where project_id = $1 and (sign = $2 or sign = $3)".format(out_table_name.strip()), ["text", "integer", "integer"])
|
|
|
+ plan1.execute([project_id, sign1, sign2])
|
|
|
+ # 计算关系
|
|
|
+ plan_floor = plpy.prepare("select id from floor where project_id = $1", ["text"])
|
|
|
+ floors = plan_floor.execute([project_id])
|
|
|
+ # 按楼层计算
|
|
|
+ for floor in floors:
|
|
|
+ floor_id = floor['id']
|
|
|
+ # 获取楼层下的设备
|
|
|
+ plan_equip = plpy.prepare("select id, bim_location from equipment where project_id = $1 and bim_location is not null and floor_id = $2", ["text", "text"])
|
|
|
+ equips = plan_equip.execute([project_id, floor_id])
|
|
|
+ if len(equips) == 0:
|
|
|
+ continue
|
|
|
+ # 获取楼层下的业务空间
|
|
|
+
|
|
|
+ space_plan = plpy.prepare("select sp.id, sp.outline, sp.object_type from public.r_sp_in_fl rel inner join {0} sp on rel.space_id = sp.id where outline is not null and rel.floor_id = $1".format(in_table_name), ["text"])
|
|
|
+ spaces = space_plan.execute([floor_id])
|
|
|
+ if len(spaces) == 0:
|
|
|
+ continue
|
|
|
+ # 判断设备的bim_location是否在业务空间的outline内
|
|
|
+ for equip in equips:
|
|
|
+ for space in spaces:
|
|
|
+ try:
|
|
|
+ location = equip['bim_location'].split(',')
|
|
|
+ if is_point_in_polygon(location[0], location[1], space['outline']):
|
|
|
+ # 设备在业务空间内, 添加关系
|
|
|
+ insert_plan = plpy.prepare("insert into {0}(eq_id, sp_id, project_id, sign, type, zone_type) values($1, $2, $3, 2, 'eq2sp_in', $4)".format(out_table_name.strip()), ["text", "text", "text", "text"])
|
|
|
+ insert_plan.execute([equip['id'], space['id'], project_id, space['object_type']])
|
|
|
+ except Exception as ex:
|
|
|
+ plpy.warning(ex)
|
|
|
+ continue
|
|
|
+return True
|
|
|
+$BODY$
|
|
|
+ LANGUAGE plpython3u VOLATILE
|
|
|
+ COST 100
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION "revit_calc"."check_grid_valid"("project_id" varchar, "folder_id" varchar, "model_id" varchar)
|
|
|
+ RETURNS TABLE("id" varchar, "floor_name" varchar, "project_id" varchar, "folder_id" varchar, "fid" varchar, "accept_time" timestamptz, "version" int4, "note" text, "user_id" varchar, "user_name" varchar, "log" jsonb, "url" text, "md5" varchar, "status" int2, "group_id" int4, "plan_name" varchar) AS $BODY$
|
|
|
+ from relations.src.grid.check_grid import check_grid_upright
|
|
|
+
|
|
|
+
|
|
|
+ involved_model_sql = "select * from revit.model_floor_file_func('" + project_id + "') where folder_id = '"+ folder_id +"' and ( status in (4) or fid = '" + model_id + "')"
|
|
|
+ grid_sql = "select * from revit.grid where model_id = "
|
|
|
+
|
|
|
+ involved_model = plpy.execute(involved_model_sql)
|
|
|
+ grid_data = dict()
|
|
|
+ for item in involved_model:
|
|
|
+ current_grid_sql = grid_sql + '\'{model_id}\''.format(model_id=item.get('fid'))
|
|
|
+ single_model_grid = plpy.execute(current_grid_sql)
|
|
|
+ grid_data[item.get('fid')] = single_model_grid
|
|
|
+ result = check_grid_upright(involved_model, grid_data)
|
|
|
+ return involved_model
|
|
|
+$BODY$
|
|
|
+ LANGUAGE plpython3u VOLATILE
|
|
|
+ COST 100
|
|
|
+ ROWS 1000
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION "public"."is_vertically_overlap"("project_id" varchar)
|
|
|
+ RETURNS "pg_catalog"."bool" AS $BODY$
|
|
|
+
|
|
|
+from shapely.geometry import Polygon
|
|
|
+import json
|
|
|
+
|
|
|
+# 获取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])
|
|
|
+ try:
|
|
|
+ if poly1.overlaps(poly2):
|
|
|
+ return True
|
|
|
+ except Exception as e:
|
|
|
+ return False
|
|
|
+ if poly1.equals(poly2) or poly1.contains(poly2):
|
|
|
+ return False
|
|
|
+ return True
|
|
|
+
|
|
|
+def is_sub_outline_overlap(polygon1, polygon2):
|
|
|
+ try:
|
|
|
+ poly1 = get_polygon(polygon1[0])
|
|
|
+ poly2 = get_polygon(polygon2[0])
|
|
|
+ if poly1.overlaps(poly2) or poly1.equals(poly2):
|
|
|
+ return True
|
|
|
+ if poly1.contains(poly2):
|
|
|
+ return is_include(polygon1, poly2)
|
|
|
+ if poly2.contains(poly1):
|
|
|
+ return is_include(polygon2, poly1)
|
|
|
+ except Exception as e:
|
|
|
+ return False
|
|
|
+ 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
|
|
|
+
|
|
|
+
|
|
|
+try:
|
|
|
+ # 获取所有建筑, for循环获取每个建筑下所有的业务空间, 按楼层分类
|
|
|
+ zone_plan = plpy.prepare("SELECT rel.space_id, fl.building_id, rel.floor_id, rel.object_type, sp.outline FROM r_sp_in_fl rel LEFT JOIN public.floor fl on fl.id = rel.floor_id left join zone_space_base sp on rel.space_id = sp.id where rel.project_id = $1 and sp.outline is not null", ["text"])
|
|
|
+ zone_data = zone_plan.execute([project_id])
|
|
|
+ if len(zone_data) <2:
|
|
|
+ return True
|
|
|
+ row_map = compose_dict(zone_data)
|
|
|
+
|
|
|
+ space_outline_json_map = dict()
|
|
|
+ result_arr = []
|
|
|
+ # 每个楼层的每个业务空间分别和别的楼层的每个业务空间判断is_vertically_overlap
|
|
|
+ # 将结果是true的两个业务空间保存起来
|
|
|
+ for building_id, floor_map in row_map.items():
|
|
|
+ checked_floor = set()
|
|
|
+ for floor_id, type_map in floor_map.items():
|
|
|
+ checked_floor.add(floor_id)
|
|
|
+ for object_type, row_arr in type_map.items():
|
|
|
+ # 要被对比的楼层
|
|
|
+ for other_floor_id in floor_map.keys():
|
|
|
+ if other_floor_id in checked_floor:
|
|
|
+ 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
|
|
|
+ plpy.info(len(result_arr))
|
|
|
+ # 删除旧业务空间的垂直交通关系(自动计算的), 添加新关系
|
|
|
+ # 将下面对数据库的操作作为一个事务, 出异常则自动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]])
|
|
|
+ return True
|
|
|
+except Exception as e:
|
|
|
+ plpy.info(e)
|
|
|
+ return False
|
|
|
+$BODY$
|
|
|
+ LANGUAGE plpython3u VOLATILE
|
|
|
+ COST 100
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION "public"."f_lock"("func_name" varchar, "project_id" varchar)
|
|
|
+ RETURNS "pg_catalog"."bool" AS $BODY$
|
|
|
+
|
|
|
+lock_plan = plpy.prepare("select func_name, func_param, reentry from public.func_lock where func_name = $1 and func_param = $2", ["text", "text"])
|
|
|
+lock = lock_plan.execute([func_name, project_id])
|
|
|
+if len(lock) == 0:
|
|
|
+ try:
|
|
|
+ insert_lock_plan = plpy.prepare("insert into public.func_lock(func_name, func_param) values($1, $2)",["text", "text"])
|
|
|
+ lock = insert_lock_plan.execute([func_name, project_id])
|
|
|
+ except Exception as e:
|
|
|
+ plpy.info("insert lock error : {0}".format(e))
|
|
|
+retry_times = 10
|
|
|
+while retry_times > 0:
|
|
|
+ retry_times = retry_times - 1
|
|
|
+ lock_plan = plpy.prepare("select func_name, func_param, reentry from public.func_lock where func_name = $1 and func_param = $2", ["text", "text"])
|
|
|
+ lock = lock_plan.execute([func_name, project_id])
|
|
|
+ if len(lock) == 1:
|
|
|
+ reentry_count = lock[0].get('reentry')
|
|
|
+ if reentry_count > 0:
|
|
|
+ update_lock_plan = plpy.prepare("update public.func_lock set reentry = $1 where func_name = $2 and func_param = $3 and reentry = $4", ["integer", "text", "text", "integer"])
|
|
|
+ result = update_lock_plan.execute([reentry_count - 1, func_name, project_id, reentry_count])
|
|
|
+ if result.nrows() > 0:
|
|
|
+ return True
|
|
|
+return False
|
|
|
+$BODY$
|
|
|
+ LANGUAGE plpython3u VOLATILE
|
|
|
+ COST 100
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION "public"."f_unlock"("func_name" varchar, "project_id" varchar)
|
|
|
+ RETURNS "pg_catalog"."bool" AS $BODY$
|
|
|
+
|
|
|
+retry_times = 10
|
|
|
+while retry_times > 0:
|
|
|
+ retry_times = retry_times - 1
|
|
|
+ lock_plan = plpy.prepare("select func_name, func_param, reentry from public.func_lock where func_name = $1 and func_param = $2", ["text", "text"])
|
|
|
+ lock = lock_plan.execute([func_name, project_id])
|
|
|
+ if len(lock) == 0:
|
|
|
+ return True
|
|
|
+
|
|
|
+ reentry_count = lock[0].get('reentry')
|
|
|
+ reentry_total = lock[0].get('reentry_total')
|
|
|
+ plpy.info(reentry_count)
|
|
|
+ plpy.info(reentry_total)
|
|
|
+ if reentry_count >= reentry_total :
|
|
|
+ return True
|
|
|
+ update_lock_plan = plpy.prepare("update public.func_lock set reentry = $1 where func_name = $2 and func_param = $3 and reentry = $4", ["integer", "text", "text", "integer"])
|
|
|
+ result = update_lock_plan.execute([reentry_count + 1, func_name, project_id, reentry_count])
|
|
|
+ if result.nrows() > 0:
|
|
|
+ return True
|
|
|
+return False
|
|
|
+$BODY$
|
|
|
+ LANGUAGE plpython3u VOLATILE
|
|
|
+ COST 100
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION public.is_vertically_overlap(project_id varchar, _building_id varchar, zone_type varchar, space_ids _varchar)
|
|
|
+ RETURNS "pg_catalog"."bool" AS $BODY$
|
|
|
+
|
|
|
+from shapely.geometry import Polygon
|
|
|
+import json
|
|
|
+
|
|
|
+# 获取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])
|
|
|
+ try:
|
|
|
+ if poly1.overlaps(poly2):
|
|
|
+ return True
|
|
|
+ except Exception as e:
|
|
|
+ return False
|
|
|
+ if poly1.equals(poly2) or poly1.contains(poly2):
|
|
|
+ return False
|
|
|
+ return True
|
|
|
+
|
|
|
+def is_sub_outline_overlap(polygon1, polygon2):
|
|
|
+ try:
|
|
|
+ poly1 = get_polygon(polygon1[0])
|
|
|
+ poly2 = get_polygon(polygon2[0])
|
|
|
+ if poly1.overlaps(poly2) or poly1.equals(poly2):
|
|
|
+ return True
|
|
|
+ if poly1.contains(poly2):
|
|
|
+ return is_include(polygon1, poly2)
|
|
|
+ if poly2.contains(poly1):
|
|
|
+ return is_include(polygon2, poly1)
|
|
|
+ except Exception as e:
|
|
|
+ return False
|
|
|
+ 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_map 结构 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
|
|
|
+
|
|
|
+def build_sql_str(space_ids_set):
|
|
|
+ sql_str = ""
|
|
|
+ for space_id in space_ids_set:
|
|
|
+ sql_str += '\'' + space_id + '\','
|
|
|
+ if sql_str.endswith(','):
|
|
|
+ sql_str = sql_str[0:-1]
|
|
|
+ return sql_str
|
|
|
+
|
|
|
+try:
|
|
|
+ if len(space_ids) < 1:
|
|
|
+ plpy.info("no input space_ids")
|
|
|
+ return True
|
|
|
+ # 获取建筑下所有的业务空间, 按楼层分类
|
|
|
+ zone_plan = plpy.prepare("SELECT rel.space_id, fl.building_id, rel.floor_id, rel.object_type, sp.outline FROM r_sp_in_fl rel LEFT JOIN public.floor fl on fl.id = rel.floor_id " +
|
|
|
+ "left join zone_space_base sp on rel.space_id = sp.id where rel.project_id = $1 and sp.outline is not null and fl.building_id = $2 and sp.object_type = $3", ["text", "text", "text"])
|
|
|
+ zone_data = zone_plan.execute([project_id, _building_id, zone_type])
|
|
|
+ plpy.info('all space size : {0}'.format(len(zone_data)))
|
|
|
+ if len(zone_data) <2:
|
|
|
+ plpy.info("no enough space to calc")
|
|
|
+ return True
|
|
|
+ # 转换space_ids为set类型
|
|
|
+ space_ids_set = set(space_ids)
|
|
|
+ row_map = compose_dict(zone_data)
|
|
|
+
|
|
|
+ space_outline_json_map = dict()
|
|
|
+ result_arr = []
|
|
|
+ # 每个楼层的每个业务空间分别和别的楼层的每个业务空间判断is_vertically_overlap
|
|
|
+ # 将结果是true的两个业务空间保存起来
|
|
|
+ for building_id, floor_map in row_map.items():
|
|
|
+ checked_floor = set()
|
|
|
+ for floor_id, type_map in floor_map.items():
|
|
|
+ checked_floor.add(floor_id)
|
|
|
+ for object_type, row_arr in type_map.items():
|
|
|
+ # 要被对比的楼层
|
|
|
+ for other_floor_id in floor_map.keys():
|
|
|
+ if other_floor_id in checked_floor:
|
|
|
+ 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 not in space_ids_set and other_space_id not in space_ids_set:
|
|
|
+ continue
|
|
|
+ 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():
|
|
|
+ sql_str = build_sql_str(space_ids_set)
|
|
|
+ del_plan = plpy.prepare("delete from r_sp_vertical_sp where space_id in ({0}) or space_other_id in ({0})".format(sql_str), [])
|
|
|
+ del_plan.execute([])
|
|
|
+ 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"])
|
|
|
+ #plpy.info(single_result)
|
|
|
+ insert_plan.execute([single_result[0], single_result[1], project_id, single_result[2]])
|
|
|
+ return True
|
|
|
+except Exception as e:
|
|
|
+ plpy.info(e)
|
|
|
+ return False
|
|
|
+
|
|
|
+$BODY$
|
|
|
+ LANGUAGE plpython3u VOLATILE
|
|
|
+ COST 100
|