Eq2Fl.md 4.1 KB

设备所在楼层

前置条件

1. 设备有ModelId信息点  (模型web服务的模型id)
2. 楼层有ModelId信息点  (模型web服务的楼层id)
3. 设备没有所在楼层关系
4. 设备有Location(非必要)
5. 楼层有Outline(非必要)

处理逻辑

1. 如果楼层有Outline, 设备有Location, 做点(Location)在多边形(Outline)内的判断, 点在多边形内则认为有关系
2. 如果不满足条件1, 即楼层没有Outline, 设备没有Location, 则判断它们ModelId信息点的值, 相等则认为有关系   
    (此处的相等表示设备上的ModelId信息点在关系上从属于楼层上的ModelId信息点, 即模型web服务中的模型id属于楼层id)

技术细节

1. 做点在多边形内的判断, 使用到了python的 shapely 库 中的 Path 类的contains_points 方法

函数

代码

源码
-- 设备所在楼层
CREATE OR REPLACE FUNCTION "public"."rel_eq2fl"("project_id" varchar)
  RETURNS "pg_catalog"."bool" AS $BODY$
from matplotlib.path import Path
import json

def is_in_meta_polygon(x, y, json_poly):
    try:
        poly = []
        polygon = json.loads(json_poly)
        l = len(polygon)
        points = (float(x), float(y))
        for i in range(l):
            pair = polygon[i]
            poly.append((pair["X"], pair["Y"]))

        p = Path(poly)
    except Exception as e:
        plpy.info(e)
        return False
    else:
        return p.contains_points([points], None, -0.0001)


model_floor_map = dict()

def get_model_floor(model_id):
    try:
        if model_id in model_floor_map :
            return model_floor_map[model_id]
        model_floor_plan = plpy.prepare("select model_floor_id from revit.model_file where id = $1", ["text"])
        model_floor_arr = model_floor_plan.execute([model_id])
        if len(model_floor_arr) == 0:
            return None
        model_floor = model_floor_arr[0].get('model_floor_id')
        model_floor_map[model_id] = model_floor
        return model_floor
    except Exception as e:
        return None

try:
    # 将下面对数据库的操作作为一个事务, 出异常则自动rollback
    with plpy.subtransaction():
        floor_plan = plpy.prepare("select id, outline, model_id from floor where project_id = $1 and model_id is not null", ["text"])
        floors = floor_plan.execute([project_id])
        equip_plan = plpy.prepare("select id, bim_location, model_id from equipment where project_id = $1 and model_id is not null", ["text"])
        equips = equip_plan.execute([project_id])
        for floor in floors:
            for equip in equips:
                outline = floor['outline']
                location = equip['bim_location']
                if outline == None or len(outline) == 0 or location == None or len(location) == 0:
                    model_floor_id = get_model_floor(equip['model_id'])
                    if model_floor_id is None:
                        continue
                    if floor['model_id'] == model_floor_id:
                        equip['floor_id'] = floor['id']
                    continue
                location = location.split(',')
                try:
                    if floor['model_id'] == model_floor_id:
                        if is_in_meta_polygon(location[0], location[1], outline):
                            equip['floor_id'] = floor['id']
                except Exception as ex:
                    continue
        for equip in equips:
            if equip.__contains__('floor_id'):
                try:
                    #plpy.info("equip id {0}, floor id {1}".format(equip['id'], equip['floor_id']))
                    plan = plpy.prepare("update equipment set floor_id = $1 where id = $2", ["text", "text"])
                    plan.execute([equip['floor_id'], equip['id']])
                except Exception as ex:
                    continue
except Exception as e:
    plpy.warning(e)
    return False
else:
    return True
$BODY$
  LANGUAGE plpython3u VOLATILE
  COST 100


select public.rel_eq2fl('Pj1101010015');

输入

1. 项目id

返回结果

true    成功
false   失败