def get_next_edge(self, ground_tin, tr, origin, destination): """ Explanation: returns the next edge in the triangle which the path crosses --------------- Input: receiver : tuple(x,y,z) - the receiver point we walk from ground_tin : ground_Tin object - stores the whole tin tr : integer - id of the current triangle --------------- Output: list - two vertices of the edge. """ edges = ( (ground_tin.trs[tr][0], ground_tin.trs[tr][1]), (ground_tin.trs[tr][1], ground_tin.trs[tr][2]), (ground_tin.trs[tr][2], ground_tin.trs[tr][0]) ) # Go over the edges for i, edge in enumerate(edges): # Check if the orientation is correct if (misc.side_test(origin, destination, ground_tin.vts[edge[0]]) <= 0 and misc.side_test(origin, destination, ground_tin.vts[edge[1]]) > 0): return i, edge print("something went wrong here") assert(False)
def intersection_point(self, edge, source, receiver): """ Explanation: --------------- Input: edge: (vi, vj) - vi is the index of a vertex in the vertex list source: (x,y,z) - the source point we want to walk to receiver: (x,y,z) - the receiver point we walk from --------------- Output: np.array((x,y,z)) - intersection between edge and receiver-source segment """ vertex_right = np.array(self.vts[edge[0]]) vertex_left = np.array(self.vts[edge[1]]) # get the absolute area of the 2* the triangle (the rectangle of length from source to receiver and width the perpendicular distance to point p) area_right = abs(misc.side_test(receiver, source, vertex_right)) area_left = abs(misc.side_test(receiver, source, vertex_left)) # quick check, debug: if ((area_left + area_right) < 0.1): # if edge and both triangles are collinear, put the point half way. part_right = 0.5 else: # find where on the line (percentile) the cross section is. part_right = area_right / (area_left + area_right) # take vertex_right and append a part of the vector from right to left to it intersection_point = vertex_right + (vertex_left - vertex_right) * part_right return intersection_point
def get_offsets_perpendicular(self, start, end): """ Explination: calculates the perpendicular distance from points to the the line --------------- Input: Start: integer - id of the start point end: integer - id of the end point --------------- Output: numpy array - array of the offsets of points along line segment """ p_start = self.vts[start] p_end = self.vts[end] line_length = ((p_end[2] - p_start[2])**2 + (p_end[0] - p_start[0])**2)**0.5 offsets = [] for id in range(start + 1, end): # do side test (return lenght of line x perpendicualr distace) so devide it by the length and voila diff = abs( misc.side_test( (p_start[0], p_start[2]), (p_end[0], p_end[2]), (self.vts[id, 0], self.vts[id, 2]))) / line_length offsets.append(diff) return np.array(offsets)
def find_receiver_triangle(self, tr_init, p_receiver): """ Explanation: Find the triangle in which the p_source is located, by means of walking from tr_init to the right triangle --------------- Input: tr_init : integer - An (arbitrary) triangle id to start from. p_receiver : [x,y,z] - The receiver point. --------------- Output: integer - triangle id of triangle underneath source point """ #print("=== find_receiver_triangle ===") tr = tr_init for i in range(1000): # max 1000 triangles to walk. # do the side test for all sides, returns the value d1 = misc.side_test(self.vts[self.trs[tr][0]], self.vts[self.trs[tr][1]], p_receiver) d2 = misc.side_test(self.vts[self.trs[tr][1]], self.vts[self.trs[tr][2]], p_receiver) d3 = misc.side_test(self.vts[self.trs[tr][2]], self.vts[self.trs[tr][0]], p_receiver) # If all side_tests are positive (point is either exactly on the edge, or on the inside) if d1 >= 0 and d2 >= 0 and d3 >= 0: return tr # when one the the tests returns negative, we have to go to the next triangle, # first find the direction to go to: # turn it into a list, and get the minimum d = [d1, d2, d3] d_min = d.index(min(d)) # find the right neighbouring triangle to go to. nbs = [5, 3, 4] nb_index = nbs[d_min] # get the index of the neighbour triangle tr = self.trs[tr][nb_index] print("no tr found after 1000 loops") assert (False)
def check_validity(self, building_id, building_manager, tin, reflection_point, building_height, minimal_height_difference): triangle_index_building = np.where(tin.attributes == building_id) triangle_index_building = triangle_index_building[0][0] #print("random tr index of building: {}".format(triangle_index_building)) # find the triangle where the reflection point is in (it is on the line though.) reflection_triangle = tin.find_receiver_triangle( triangle_index_building, reflection_point) #print("correct tr of building: {}".format(tin.attributes[reflection_triangle])) # can be either on the building side, or on the outerside # If the triangle is on the inside, get the triangle on the outside if (tin.attributes[reflection_triangle] == building_id): #print("triangle is on inside") # the triangle is on the inside of the building # now get neighbor edges = ((tin.vts[tin.trs[reflection_triangle][0]], tin.vts[tin.trs[reflection_triangle][1]]), (tin.vts[tin.trs[reflection_triangle][1]], tin.vts[tin.trs[reflection_triangle][2]]), (tin.vts[tin.trs[reflection_triangle][2]], tin.vts[tin.trs[reflection_triangle][0]])) # find which edge intersects with the point. neighbor = -1 for i, edge in enumerate(edges): # side the side test is very much close to 0, it is the right edge if (abs(misc.side_test(edge[0], edge[1], reflection_point)) < 0.05): neighbor = i assert (neighbor != -1) nbs = [5, 3, 4] reflection_triangle = tin.trs[reflection_triangle][nbs[neighbor]] #print("triangle type on outside: {}".format(tin.attributes[reflection_triangle])) # we should have the correct triangle at hand if (tin.attributes[reflection_triangle][0] == 'b'): #print("other triangle is building") # it is a building outside_building_height = building_manager.buildings[ tin.attributes[reflection_triangle]].roof_level if (building_height - outside_building_height > minimal_height_difference): # building is atleast 20 centimeters higher then return True else: return False else: # not a building, so its fine (should be, there should not be buildings below ground level in the dataset) return True
def point_in_triangle(self, pt, tr): """ Explanation: Do a side test for all edges with the pt, if they are all positive. --------------- Input: pt : [x,y,z] - The point to check. tr : integer - triangle ID. --------------- Output: Boolean - True if the point is inside the triangle. """ e = 10**(-4) d1 = misc.side_test(self.vts[self.trs[tr][0]], self.vts[self.trs[tr][1]], pt) d2 = misc.side_test(self.vts[self.trs[tr][1]], self.vts[self.trs[tr][2]], pt) d3 = misc.side_test(self.vts[self.trs[tr][2]], self.vts[self.trs[tr][0]], pt) if d1 >= -e and d2 >= -e and d3 >= -e: return True # the point is in the triangle else: return False
def get_first_order_reflection(self, building_manager, tin, minimal_height_difference, radius_buffer=2000): """ Explanation: A function that reads a buildings_dict and computes all possible first-ORDER reflection paths, according to the receivers and sources that are provided from main.py --------------- Input: buildings_dict : BuildingManager object - stores all the building objects --------------- Output: Stores reflection points, and their corresponding heights in the class. return True if reflections are found, False if not """ query_geom = Point(self.receiver).buffer( radius_buffer) # 2000 m buffer around receiver chosen_buildings = building_manager.buildings_tree.query(query_geom) for chosen_building in chosen_buildings: building_id = building_manager.polygon_id_to_building_id[id( chosen_building)] building = building_manager.buildings[building_id] if building.underground: continue number_of_walls = len(building.walls) for wall_id, wall in enumerate(building.walls): test_r = misc.side_test(wall[0], wall[1], self.receiver) test_s = misc.side_test(wall[0], wall[1], self.source.source_coords) # COS: Not sure if this is actually true!!!! if test_r > 0 and test_s > 0: # This statement guarantees that the source and receiver are both on the outer side of the wall # Get the mirrored source over the wall segment s_mirror = self.get_mirror_point( misc.parametric_line_equation(wall[0], wall[1])) # find the intersection point, returns False is they do not intersect. reflection_point = misc.line_intersect( wall, [s_mirror, self.receiver]) # ref is false if there is no reflection. if reflection_point: angle = 0.01745329252 # Hardcoded Angle in radians (1 degree or 2.pi / 360) # take the mirror point and check if reflection path is longer than 2Km receiver_array = np.array(self.receiver) mirrored_source_array = np.array(s_mirror) # check distance between reflection point and mirrored source reflection_point_array = np.array(reflection_point) dist = np.linalg.norm(reflection_point_array - mirrored_source_array) if dist <= 2000: # rotate the mirrored point 1 degree to the left and look for an intersection with the building left_point = misc.get_rotated_point( receiver_array, mirrored_source_array, angle) wall_adjusted_order_left = np.array( range(wall_id, number_of_walls + wall_id, 1)) % number_of_walls is_left_valid = self.check_relative_size( wall_adjusted_order_left, building, left_point) if is_left_valid: # rotate the mirrored point 1 degree to the right and look for an intersection with the building right_point = misc.get_rotated_point( receiver_array, mirrored_source_array, -angle) wall_adjusted_order_right = np.array( range(number_of_walls + wall_id, wall_id, -1)) % number_of_walls is_right_valid = self.check_relative_size( wall_adjusted_order_right, building, right_point) if is_right_valid: # Check if reflection is valid, ie if there is no other taller building in front. if (self.check_validity( building_id, building_manager, tin, reflection_point, building.roof_level, minimal_height_difference)): # If the reflection object is of sufficient size, and the reflection is valid, store it self.reflection_points.append( [reflection_point]) self.reflection_heights.append( [building.roof_level]) if len(self.reflection_points) > 0: return True return False