|
@@ -4,47 +4,175 @@
|
|
2. 业务空间有外轮廓
|
|
2. 业务空间有外轮廓
|
|
3. 有2个或2个以上的楼层的ModelId相同(意思是一个模型划分成了多个楼层)
|
|
3. 有2个或2个以上的楼层的ModelId相同(意思是一个模型划分成了多个楼层)
|
|
4. 这些ModelId相同的楼层下有所属的业务空间关系
|
|
4. 这些ModelId相同的楼层下有所属的业务空间关系
|
|
|
|
+ 5. 业务空间所属楼层表内维护的关系是正确的
|
|
## 处理流程
|
|
## 处理流程
|
|
- 1. 查出所有有所在楼层, 并且外轮廓不是null的业务空间
|
|
|
|
- 2. 根据所在楼层, 业务空间分区来将业务空间分组
|
|
|
|
- 3. 计算每个分组内的业务空间的相邻关系
|
|
|
|
- 计算相邻算法:
|
|
|
|
- 1. 首先判断围成业务空间的线段, 两两空间之间是否有近似平行的线段(线段偏转误差小于1度)
|
|
|
|
- 1). 近似平行判断: 首先获取两个线段的斜率, 再计算斜率的反正切(即与x轴的角度, 不过是以pi为单位), 再判断两个角度差的绝对值是否小于1度
|
|
|
|
- 2. 如果有近似平行的线段, 判断是否相互有投影在线段上, 有投影在线段上, 则认为是两平行线段有重合部分, 业务空间有相邻的可能性
|
|
|
|
- 3. 在判断互相有投影点在对方线段上之后, 判断投影线的长度, 是否小于250mm(墙的最大厚度), 如果小于250mm则认为两空间相邻
|
|
|
|
|
|
+ 1. 查出项目内所有ModelId相同的楼层(如果没有则返回)
|
|
|
|
+ 2. 按照ModelId将楼层分组, 相同ModelId的楼层为一组, 每组内按照以下规则计算
|
|
|
|
+ 3. 获取组内所有楼层下的业务空间, 将查出的业务空间的轮廓与楼层的轮廓比对是否有重叠部分(所有业务空间 X 所有楼层次对比), 如果有重叠则认为该业务空间和该楼层有关系
|
|
|
|
+ 4. 在业务空间所属楼层表内删除该组楼层下的所有业务空间关系, 并插入新计算出的业务空间所属楼层的关系
|
|
## 函数
|
|
## 函数
|
|
```
|
|
```
|
|
-create or replace function public.rel_sp2sp1(project_id character varying) returns boolean
|
|
|
|
-as
|
|
|
|
-$$
|
|
|
|
-from relations.src.business_space_adjacent.adjacent import calc_space_adjacent
|
|
|
|
|
|
+
|
|
|
|
+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:
|
|
try:
|
|
# 将下面对数据库的操作作为一个事务, 出异常则自动rollback
|
|
# 将下面对数据库的操作作为一个事务, 出异常则自动rollback
|
|
- with plpy.subtransaction():
|
|
|
|
- delete_plan = plpy.prepare("delete from r_spatial_connection where project_id = $1 and sign = 2", ["text"])
|
|
|
|
- delete_plan.execute([project_id])
|
|
|
|
- space_data_plan = plpy.prepare("SELECT id, project_id, floor_id, object_type, bim_location, outline FROM zone_space_base where project_id = $1 and outline is not null and floor_id is not null order by floor_id, object_type", ["text"])
|
|
|
|
- space_data = space_data_plan.execute([project_id])
|
|
|
|
- rel_data = calc_space_adjacent(space_data)
|
|
|
|
- for single_rel in rel_data:
|
|
|
|
- delete_duplicate_plan = plpy.prepare("delete from r_spatial_connection where space_id_one = $1 and space_id_two = $2", ["text", "text"])
|
|
|
|
- delete_duplicate_plan.execute([single_rel['space_id_one'], single_rel['space_id_two']])
|
|
|
|
- insert_plan = plpy.prepare("insert into r_spatial_connection(project_id, location_one, location_two, space_id_one, space_id_two, sign, graph_type, floor_id, zone_type) values($1, $2, $3, $4, $5, 2, 'SpaceNeighborhood', $6, $7)", ["text", "text", "text", "text", "text", "text", "text"])
|
|
|
|
- insert_plan.execute([project_id, single_rel['location_one'], single_rel['location_two'], single_rel['space_id_one'], single_rel['space_id_two'], single_rel['floor_id'], single_rel['zone_type']])
|
|
|
|
|
|
+
|
|
|
|
+ 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:
|
|
except Exception as e:
|
|
plpy.warning(e)
|
|
plpy.warning(e)
|
|
return False
|
|
return False
|
|
-else:
|
|
|
|
- return True
|
|
|
|
-$$
|
|
|
|
-LANGUAGE 'plpython3u' VOLATILE;
|
|
|
|
|
|
+$BODY$
|
|
|
|
+ LANGUAGE plpython3u VOLATILE
|
|
|
|
+ COST 100;
|
|
|
|
|
|
|
|
|
|
-select public.rel_sp2sp1('Pj1101050001')
|
|
|
|
|
|
+select public.rel_sp2fl('Pj1101050001')
|
|
```
|
|
```
|
|
|
|
|
|
## 入参
|
|
## 入参
|
|
1. 项目id
|
|
1. 项目id
|
|
## 例子
|
|
## 例子
|
|
- select public.rel_sp2sp1('Pj1102290002');
|
|
|
|
|
|
+ select public.rel_sp2fl('Pj1102290002');
|