adjacent.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # -*- coding: utf-8 -*-
  2. from collections import ChainMap
  3. from itertools import groupby
  4. from operator import itemgetter
  5. import numpy as np
  6. import vg
  7. from .utils import BinaryRelationItem, BinaryRelationCollection
  8. np.seterr(divide='ignore', invalid='ignore')
  9. def calc_adjacent_relation(columns, segments, v_walls, walls):
  10. columns = list(map(load_location, columns))
  11. segments = list(map(load_curve, segments))
  12. v_walls = list(map(load_location, v_walls))
  13. walls = list(map(load_location, walls))
  14. columns_dic = list_to_dict(columns)
  15. v_walls_dic = list_to_dict(v_walls)
  16. walls_dic = list_to_dict(walls)
  17. unit_dic = ChainMap(
  18. columns_dic,
  19. walls_dic,
  20. v_walls_dic,
  21. )
  22. grouped_segments = group_segments(segments, unit_dic)
  23. binary_space_list = []
  24. space_relation = BinaryRelationCollection()
  25. for group in grouped_segments:
  26. for i in range(len(group)):
  27. for j in range(i, len(group)):
  28. if are_adjacent(group[i], group[j], unit_dic):
  29. space1 = group[i]['space_id']
  30. space2 = group[j]['space_id']
  31. binary_space_list.append((space1, space2))
  32. if space1 != space2:
  33. binary_space_relations = BinaryRelationItem(space1, space2)
  34. space_relation.update(binary_space_relations)
  35. relations = []
  36. for relation in relations:
  37. relations.append(relation)
  38. return relations
  39. def group_segments(segments, units):
  40. grouped_by_reference = dict()
  41. for idx, item in groupby(segments, key=itemgetter('reference')):
  42. if idx:
  43. if idx in grouped_by_reference:
  44. grouped_by_reference[idx] += list(item)
  45. else:
  46. # print(item)
  47. grouped_by_reference[idx] = list(item)
  48. binary_list = []
  49. reference_list = list(grouped_by_reference.keys())
  50. for i in range(len(reference_list)):
  51. for j in range(i + 1, len(reference_list)):
  52. if are_clung(reference_list[i], reference_list[j], units):
  53. binary_list.append((reference_list[i], reference_list[j]))
  54. results = []
  55. for reference in grouped_by_reference.keys():
  56. merged_group = []
  57. merged_group += grouped_by_reference[reference]
  58. for binary in [item for item in binary_list if reference in item]:
  59. binary_relation = BinaryRelationItem(binary[0], binary[1])
  60. another = binary_relation.get_another(reference)
  61. merged_group += grouped_by_reference[another]
  62. results.append(merged_group)
  63. return results
  64. def list_to_dict(lis):
  65. ids = [idx.get('revit_id') for idx in lis]
  66. dic = dict(zip(ids, lis))
  67. return dic
  68. def are_clung(unit1_id, unit2_id, units):
  69. if unit1_id == unit2_id:
  70. return False
  71. unit1, unit2 = units[unit1_id], units[unit2_id]
  72. if unit1.get('type') == unit2.get('type') == 'Wall':
  73. if unit1['location']['Type'] == unit2['location']['Type'] == 'Line':
  74. location1 = np.array([list(p.values()) for p in unit1['location']['Points']])
  75. location2 = np.array([list(p.values()) for p in unit2['location']['Points']])
  76. v1 = location1[1] - location1[0]
  77. v2 = location2[1] - location2[0]
  78. # Judge parallel
  79. if vg.almost_collinear(v1, v2, atol=1e-08):
  80. # Calculate the distance between line segments
  81. v3 = location2[1] - location1[0]
  82. angle = vg.angle(v1, v3, units='rad')
  83. distance = np.around(vg.magnitude(v3) * np.sin(angle), decimals=4)
  84. wall_width = (float(unit1['width']) + float(unit2['width'])) / 2.0
  85. if distance <= wall_width:
  86. return True
  87. return False
  88. def are_adjacent(segment1, segment2, units):
  89. base = units[segment1['reference']]
  90. base_location = base['location']
  91. if base_location['Type'] == 'Line':
  92. line1, line2 = segment1['curve'], segment2['curve']
  93. if len(line1) == len(line2) == 2:
  94. l1_p1 = np.array(list(line1[0].values()))
  95. l1_p2 = np.array(list(line1[1].values()))
  96. l2_p1 = np.array(list(line2[0].values()))
  97. l2_p2 = np.array(list(line2[1].values()))
  98. base_line = base_location['Points']
  99. base_vec = np.array(list(base_line[1].values())) - np.array(list(base_line[0].values()))
  100. base_vec = vg.normalize(base_vec)
  101. l1_p1_projection = vg.dot(l1_p1, base_vec)
  102. l1_p2_projection = vg.dot(l1_p2, base_vec)
  103. l2_p1_projection = vg.dot(l2_p1, base_vec)
  104. l2_p2_projection = vg.dot(l2_p2, base_vec)
  105. projection1_min = min(l1_p1_projection, l1_p2_projection)
  106. projection1_max = max(l1_p1_projection, l1_p2_projection)
  107. projection2_min = min(l2_p1_projection, l2_p2_projection)
  108. projection2_max = max(l2_p1_projection, l2_p2_projection)
  109. return projection1_max > projection2_min and projection2_max > projection1_min
  110. return False
  111. def load_location(x):
  112. x['location'] = json.loads(x['location'])
  113. return x
  114. def load_curve(x):
  115. x['curve'] = json.loads(x['curve'])
  116. return x