设备所在楼层 ## 前置条件 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 失败