浏览代码

计算业务空间与业务空间相邻关系

jxing 5 年之前
父节点
当前提交
02c695fdf5
共有 3 个文件被更改,包括 253 次插入0 次删除
  1. 0 0
      src/business_space_adjacent/__init__.py
  2. 190 0
      src/business_space_adjacent/adjacent.py
  3. 63 0
      src/business_space_adjacent/test.py

+ 0 - 0
src/business_space_adjacent/__init__.py


+ 190 - 0
src/business_space_adjacent/adjacent.py

@@ -0,0 +1,190 @@
+import math
+import json
+
+
+class Point(object):
+    """点类"""
+
+    def __init__(self, x=0, y=0):
+        self.x = x
+        self.y = y
+
+    def distance(self, pt):
+        x_diff = self.x - pt.x
+        y_diff = self.y - pt.y
+        return math.sqrt(x_diff ** 2 + y_diff ** 2)
+
+# 1度的角度误差
+slope_delta = 1 / 180 * math.pi
+
+
+class Segment:
+    """线段类"""
+
+    @classmethod
+    def create_by_point(cls, x1, y1, x2, y2):
+        # point1 = Point(x1, y1)
+        # point2 = Point(x2, y2)
+        return cls(Point(x1, y1), Point(x2, y2))
+
+    def __init__(self, p1, p2):
+        self.point1 = p1
+        self.point2 = p2
+
+    # 获取线段的斜率
+    def get_slope(self):
+        if self.point1.x == self.point2.x:
+            return None
+        return (self.point2.y - self.point1.y) / (self.point2.x - self.point1.x)
+
+    # 获取点在线段(直线)上的投影点
+    def get_projective_point(self, out_point):
+        slope = self.get_slope()
+        if slope is None:
+            return Point(self.point1.x, out_point.y)
+        if slope == 0:
+            return Point(out_point.x, self.point1.y)
+        tmp_x = ((slope * self.point1.x + out_point.x / slope + out_point.y - self.point1.y) / (1 / slope + slope))
+        tmp_y = (-1 / slope * (tmp_x - out_point.x) + out_point.y)
+        return Point(tmp_x, tmp_y)
+
+    # 是否投影点在线段上
+    def is_projective_point_on_segment(self, point):
+        if (point.x > self.point1.x and point.x > self.point2.x) or (
+                point.x < self.point1.x and point.x < self.point2.x):
+            return False
+        if (point.y > self.point1.y and point.y > self.point2.y) or (
+                point.y < self.point1.y and point.y < self.point2.y):
+            return False
+        return True
+
+    # 是否近似相等
+    def is_similar_parallel(self, other_segment):
+        k1 = self.get_slope()
+        k2 = other_segment.get_slope()
+        # 计算反正切 (与x轴的角度)
+        if k1 is None:
+            angle1 = math.pi / 2
+        else:
+            angle1 = abs(math.atan(k1))
+        if k2 is None:
+            angle2 = math.pi / 2
+        else:
+            angle2 = abs(math.atan(k2))
+        if abs(angle1 - angle2) < slope_delta:
+            return True
+        return False
+
+    # 在近似相等后, 是否有线段端点的投影点在线段上并且垂线距离小于25cm
+    def is_projective_point_satisfy(self, oupoint):
+        project_point = self.get_projective_point(oupoint)
+        if self.is_projective_point_on_segment(project_point):
+            distance = project_point.distance(oupoint)
+            if distance < 250:
+                return True
+            else:
+                return False
+        else:
+            return False
+
+
+column_project_id = 'project_id'
+column_location_one = 'location_one'
+column_location_two = 'location_two'
+column_space_id_one = 'space_id_one'
+column_space_id_two = 'space_id_two'
+column_zone_type = 'zone_type'
+
+column_id = 'id'
+column_bim_location = 'bim_location'
+column_floor_id = 'floor_id'
+column_object_type = 'object_type'
+column_outline = 'outline'
+key_x = 'X'
+key_y = 'Y'
+
+
+# 将输入数据按照楼层id, 业务空间类型分类
+def classify(space_list):
+    current_floor_id = ''
+    current_object_type = ''
+    current_sub_arr = []
+    space_arr = []
+    for row in space_list:
+        if row.get(column_floor_id) == current_floor_id and row.get(column_object_type) == current_object_type:
+            current_sub_arr.append(row)
+        else:
+            current_floor_id = row.get(column_floor_id)
+            current_object_type = row.get(column_object_type)
+            current_sub_arr = [row]
+            space_arr.append(current_sub_arr)
+    for sub_arr in space_arr:
+        if len(sub_arr) == 1:
+            space_arr.remove(sub_arr)
+    return space_arr
+
+
+# 根据空间分组, 获取一个分组的外轮廓线段数组
+def get_outline_segment(space_sub_arr):
+    segment_arr = []
+    for single_space in space_sub_arr:
+        single_space_segments = []
+        segment_arr.append(single_space_segments)
+        json_str = single_space.get(column_outline)
+        outline_json = json.loads(str(json_str).replace('\'', '"'))
+        if outline_json is None or len(outline_json) == 0:
+            continue
+        for i in range(0, len(outline_json)):
+            single_area = outline_json[0]
+            if single_area is None or len(single_area) == 0:
+                continue
+            single_area_outline = single_area[0]
+            for j in range(0, len(single_area_outline) - 1):
+                point1_json = single_area_outline[j]
+                point2_json = single_area_outline[j + 1]
+                seg = Segment.create_by_point(point1_json.get(key_x), point1_json.get(key_y), point2_json.get(key_x), point2_json.get(key_y))
+                single_space_segments.append(seg)
+    return segment_arr
+
+
+# 是否一个空间(线段集合)与另外一个空间(线段集合)相邻
+def is_satisfy_adjacent(single_space_segments, other_space_segments):
+    for segment1 in single_space_segments:
+        for segment2 in other_space_segments:
+            # 如果两个线段近似平行, 则获取线段两端在另外一条线段上的投影,
+            # 投影点如果有一个在线段上并且垂线长度小于25cm, 则认为是满足相邻条件
+            if segment1.is_similar_parallel(segment2):
+                if segment1.is_projective_point_satisfy(segment2.point1):
+                    return True
+                elif segment1.is_projective_point_satisfy(segment2.point2):
+                    return True
+    return False
+
+
+# 计算一个分组内的邻接关系
+def calc_adjacent_sub_arr(space_sub_arr, space_adjacent):
+    segment_arr = get_outline_segment(space_sub_arr)
+    for i in range(0, len(segment_arr) - 1):
+        single_space_segments = segment_arr[i]
+        for j in range(i + 1, len(segment_arr)):
+            other_space_segments = segment_arr[j]
+            result = is_satisfy_adjacent(single_space_segments, other_space_segments)
+            if result:
+                single_result_row = dict()
+                space_one = space_sub_arr[i]
+                space_two = space_sub_arr[j]
+                single_result_row[column_zone_type] = space_one.get(column_object_type)
+                single_result_row[column_location_one] = space_one.get(column_bim_location)
+                single_result_row[column_location_two] = space_two.get(column_bim_location)
+                single_result_row[column_space_id_one] = space_one.get(column_id)
+                single_result_row[column_space_id_two] = space_two.get(column_id)
+                single_result_row[column_floor_id] = space_one.get(column_floor_id)
+                space_adjacent.append(single_result_row)
+
+
+def calc_space_adjacent(space_list):
+    space_arr = classify(space_list)
+    space_adjacent = []
+    for space_sub_arr in space_arr:
+        calc_adjacent_sub_arr(space_sub_arr, space_adjacent)
+    return space_adjacent

+ 63 - 0
src/business_space_adjacent/test.py

@@ -0,0 +1,63 @@
+
+
+import json
+import psycopg2
+import sys
+import matplotlib.pyplot as plt
+import numpy as np
+from src.business_space_adjacent.adjacent import calc_space_adjacent
+
+involved_model_keys = [
+    'id',
+    'project_id',
+    'floor_id',
+    'object_type',
+    'bim_location',
+    'outline'
+]
+
+def get_data(sql):
+    global connection, cursor
+    record = []
+    try:
+        connection = psycopg2.connect(
+            database='datacenter',
+            user='postgres',
+            password='123456',
+            host='192.168.20.236',
+            port='5432'
+        )
+        cursor = connection.cursor()
+        cursor.execute(sql)
+        record = cursor.fetchall()
+    except (Exception, psycopg2.Error) as error:
+        print("Error while connecting to PostgreSQL", error)
+    finally:
+        if connection:
+            cursor.close()
+            connection.close()
+            print('PostgreSQL connection is closed')
+    return record
+
+from numpy import *
+
+if __name__ == '__main__':
+    # x = [118511.27, 118423.6, 118258.41, 118101.35, 117952.95, 117813.7, 117684.07, 117564.49, 117455.36, 117357.04, 117269.87, 117194.14, 118080.04, 119738.01, 119115.06, 118511.27]
+    # y = [23054.67, 23262.08, 23126.16, 22980.93, 22826.85, 22664.46, 22494.29, 22316.92, 22132.93, 21942.94, 21747.59, 21547.53, 19451.69, 20152.51, 21626.26, 23054.67]
+    # plt.figure()
+    # plt.plot(x, y)
+    # plt.pause(1)
+    # plt.close()
+
+    # v1 = array([[1, 8], [1, 9]])
+    # v2 = array([1, 100])
+    # re = linalg.det(v1)
+    # print(re)
+
+    involved_model_sql = "SELECT id, project_id, floor_id, object_type, bim_location, outline FROM zone_space_base where project_id = 'Pj1101010015' and outline is not null and floor_id is not null order by floor_id, object_type"
+    columns_data = get_data(involved_model_sql)
+
+    model_list = [dict(zip(involved_model_keys, item)) for item in columns_data]
+
+    print(calc_space_adjacent(model_list))
+