adjacent.py 5.3 KB

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