adjacent.py 4.7 KB

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