adjacent.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. for relation in relations:
  38. relations.append(relation)
  39. return relations
  40. def group_segments(segments, units):
  41. grouped_by_reference = dict()
  42. for idx, item in groupby(segments, key=itemgetter('reference')):
  43. if idx:
  44. if idx in grouped_by_reference:
  45. grouped_by_reference[idx] += list(item)
  46. else:
  47. # print(item)
  48. grouped_by_reference[idx] = list(item)
  49. binary_list = []
  50. reference_list = list(grouped_by_reference.keys())
  51. for i in range(len(reference_list)):
  52. for j in range(i + 1, len(reference_list)):
  53. if are_clung(reference_list[i], reference_list[j], units):
  54. binary_list.append((reference_list[i], reference_list[j]))
  55. results = []
  56. for reference in grouped_by_reference.keys():
  57. merged_group = []
  58. merged_group += grouped_by_reference[reference]
  59. for binary in [item for item in binary_list if reference in item]:
  60. binary_relation = BinaryRelationItem(binary[0], binary[1])
  61. another = binary_relation.get_another(reference)
  62. merged_group += grouped_by_reference[another]
  63. results.append(merged_group)
  64. return results
  65. def list_to_dict(lis):
  66. ids = [idx.get('revit_id') for idx in lis]
  67. dic = dict(zip(ids, lis))
  68. return dic
  69. def are_clung(unit1_id, unit2_id, units):
  70. if unit1_id == unit2_id:
  71. return False
  72. unit1, unit2 = units[unit1_id], units[unit2_id]
  73. if unit1.get('type') == unit2.get('type') == 'Wall':
  74. if unit1['location']['Type'] == unit2['location']['Type'] == 'Line':
  75. location1 = np.array([list(p.values()) for p in unit1['location']['Points']])
  76. location2 = np.array([list(p.values()) for p in unit2['location']['Points']])
  77. v1 = location1[1] - location1[0]
  78. v2 = location2[1] - location2[0]
  79. # Judge parallel
  80. if vg.almost_collinear(v1, v2, atol=1e-08):
  81. # Calculate the distance between line segments
  82. v3 = location2[1] - location1[0]
  83. angle = vg.angle(v1, v3, units='rad')
  84. distance = np.around(vg.magnitude(v3) * np.sin(angle), decimals=4)
  85. wall_width = (float(unit1['width']) + float(unit2['width'])) / 2.0
  86. if distance <= wall_width:
  87. return True
  88. return False
  89. def are_adjacent(segment1, segment2, units):
  90. base = units[segment1['reference']]
  91. base_location = base['location']
  92. if base_location['Type'] == 'Line':
  93. line1, line2 = segment1['curve'], segment2['curve']
  94. if len(line1) == len(line2) == 2:
  95. l1_p1 = np.array(list(line1[0].values()))
  96. l1_p2 = np.array(list(line1[1].values()))
  97. l2_p1 = np.array(list(line2[0].values()))
  98. l2_p2 = np.array(list(line2[1].values()))
  99. base_line = base_location['Points']
  100. base_vec = np.array(list(base_line[1].values())) - np.array(list(base_line[0].values()))
  101. base_vec = vg.normalize(base_vec)
  102. l1_p1_projection = vg.dot(l1_p1, base_vec)
  103. l1_p2_projection = vg.dot(l1_p2, base_vec)
  104. l2_p1_projection = vg.dot(l2_p1, base_vec)
  105. l2_p2_projection = vg.dot(l2_p2, base_vec)
  106. projection1_min = min(l1_p1_projection, l1_p2_projection)
  107. projection1_max = max(l1_p1_projection, l1_p2_projection)
  108. projection2_min = min(l2_p1_projection, l2_p2_projection)
  109. projection2_max = max(l2_p1_projection, l2_p2_projection)
  110. return projection1_max > projection2_min and projection2_max > projection1_min
  111. return False
  112. def load_location(x):
  113. x['location'] = json.loads(x['location'])
  114. return x
  115. def load_curve(x):
  116. x['curve'] = json.loads(x['curve'])
  117. return x