# 业务空间邻接关系
## 前置条件
    1. 业务空间有所在楼层
    2. 业务空间有外轮廓
## 处理逻辑
    1. 查出所有有所在楼层, 并且外轮廓不是null的业务空间
    2. 根据所在楼层, 业务空间分区类型来将业务空间分组
    3. 分别计算每个分组内的业务空间的相邻关系
    计算相邻算法:
    1. 首先判断围成业务空间轮廓的线段, 两两业务空间之间是否有近似平行的线段(线段平行偏转误差小于1度算作近似平行)
        1). 近似平行判断: 首先获取两个线段的斜率, 再计算斜率的反正切(即与x轴的角度, 不过是以pi为单位), 再判断两个角度差的绝对值是否小于1度
    2. 如果有近似平行的线段, 判断是否相互有投影在线段上, 有投影在线段上, 则认为是两平行线段有重合部分, 业务空间有相邻的可能性
    3. 再判断互相有投影点在对方线段上之后, 判断投影线的长度, 是否小于250mm(墙的最大厚度), 如果小于250mm则认为两空间相邻
## 函数

<details>
<summary>源码</summary>

```
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
try:
    # 将下面对数据库的操作作为一个事务, 出异常则自动rollback
    with plpy.subtransaction():
        delete_plan = plpy.prepare("delete from r_spatial_connection where project_id = $1 and sign = 2 and graph_type = 'SpaceNeighborhood'", ["text"])
        delete_plan.execute([project_id])
        space_data_plan = plpy.prepare("SELECT sp.id, sp.project_id, rel.floor_id, sp.object_type, sp.bim_location, sp.outline FROM zone_space_base sp inner join r_sp_in_fl rel on rel.space_id = sp.id where sp.project_id = $1 and rel.project_id = $1 and outline 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 and graph_type = 'SpaceNeighborhood'", ["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']])
except Exception as e:
    plpy.warning(e)
    return False
else:
    return True
$$
LANGUAGE 'plpython3u' VOLATILE;


select public.rel_sp2sp1('Pj1101050001')
```

</details>

## 入参
    1. 项目id
## 例子
    select public.rel_sp2sp1('Pj1102290002');