def test_add_merge(): aabbs = standard_aabbs() for indices in itertools.permutations(range(4)): tree = AABBTree() for i in indices: tree.add(aabbs[i]) aabb_merge(tree)
def test_len(): tree = AABBTree() assert len(tree) == 0 for i, aabb in enumerate(standard_aabbs()): tree.add(aabb) assert len(tree) == i + 1
class WayContainerAABBTree: def __init__(self, d_max=0): self.d_max = d_max self.data = AABBTree() def __del__(self): pass def insert(self, element): a, b = element.get_axis_aligned_bounding_box() aabb = AABB([(a[0], b[0]), (a[1], b[1])]) self.data.add(aabb, element) def find_near_candidates(self, lat_lon, d_max): if not math.isfinite(lat_lon[0]) or not math.isfinite(lat_lon[1]): return [] # transfer bounding box of +/- d_max (in meter) to a +/- d_lon and d_lat # (approximate, but very good for d_max << circumference earth) d_lat, d_lon = LocalMap.get_scale_at(lat_lon[0], lat_lon[1]) d_lat *= d_max d_lon *= d_max # define an axis-aligned bounding box (in lat/lon) around the queried point lat_lon bb = AABB([(lat_lon[0] - d_lat, lat_lon[0] + d_lat), (lat_lon[1] - d_lon, lat_lon[1] + d_lon)]) # and query all overlapping bounding boxes of ways candidates = self.data.overlap_values(bb) return candidates @staticmethod def axis_aligned_bounding_boxes_overlap(a1, b1, a2, b2): return np.all(a1 < b2) and np.all(a2 < b1)
def test_str_str(): aabb = standard_aabbs()[0] value = 7 leaf = AABBTree(aabb) tree = AABBTree(aabb=aabb, value=value, left=leaf, right=leaf) fmt = 'AABB: {}\nValue: {}\nLeft:\n{}\nRight:\n{}' assert str(tree) == fmt.format(str(aabb), str(value), leaf.__str__(1), leaf.__str__(1))
def __init__(self, objects=None): self.tree = AABBTree() if objects: for item in objects: if item["type"] == "CUBE": self.add_object(item["pos"], (item["scale"][0] / 2, item["scale"][1] / 2, item["scale"][2] / 2), item["goal"]) elif item["type"] == "SPHERE": self.add_object(item["pos"], item["scale"], item["goal"])
def test_return_the_origin_pass_in_value(): class Foo: pass tree = AABBTree() value_set = {Foo() for _ in range(10)} for value in value_set: tree.add(AABB([(0, 1), (0, 1)]), value=value) retrieved_value_set = set( tree.overlap_values(AABB([(0, 2), (0, 2)]), unique=False)) assert retrieved_value_set == value_set
def CheckCollisions(self , rects): self.tree = AABBTree() d = {i:rects[i] for i in range(len(rects))} j = 0 for i in rects: aabb = AABB([(i.x, i.x+i.w),(i.y, i.y+i.h)]) self.tree.add(aabb, j) j += 1 s = set() for i in rects: a = self.tree.overlap_values(AABB([(i.x, i.x+i.w), (i.y, i.y+i.h)])) s = s.union({frozenset([i,d[j]]) for j in a if i != d[j]}) return s
def test_init(): aabb = AABB([(-2.3, 4.5), (3.6, 8.2)]) val = 3.1415 tree = AABBTree() assert tree.aabb == AABB() tree = AABBTree(aabb, val) assert tree.aabb == aabb assert tree.value == val assert tree.left is None assert tree.right is None tree2 = AABBTree(aabb, val, tree, tree) assert tree2.left == tree assert tree2.right == tree
def standard_tree(): aabb1, aabb2, aabb3, aabb4 = standard_aabbs() tree = AABBTree() tree.add(aabb1, 'value 1') tree.add(aabb2, 3.14) tree.add(aabb3) tree.add(aabb4) return tree
def test_str_repr(): aabb = 'a' value = 'v' left = 'left' right = 'right' tree = AABBTree(aabb=aabb, value=value, left=left, right=right) fmt = 'AABBTree(aabb={}, value={}, left={}, right={})' assert repr(tree) == fmt.format(repr(aabb), repr(value), repr(left), repr(right))
class RoadContainerAABBtree: def __init__(self, d_max=0): self.d_max = d_max self.data = AABBTree() def __del__(self): pass def insert(self, element): a, b = element.get_axis_aligned_bounding_box() e = AABB([(a[0], b[0]), (a[1], b[1])]) self.data.add(e, element) def find_near(self, x, direction): # find candidates, exclude only those which are safe to exclude candidates = self.find_near_candidates(x, self.d_max) # then enumerate all candidates an do precise search dist_x_list = [] dist_dir_list = [] x_projected_list = [] way_direction_list = [] for r in candidates: dist_x, x_projected, dist_dir, way_direction = r.distance_of_point( x, direction) dist_x_list.append(dist_x) dist_dir_list.append(dist_dir) x_projected_list.append(x_projected) way_direction_list.append(way_direction) return candidates, dist_x_list, x_projected_list, dist_dir_list, way_direction_list def find_near_candidates(self, x, d_max): if not math.isfinite(x[0]) or not math.isfinite(x[1]): return [] # the point x and a square environment bb = AABB([(x[0] - d_max, x[0] + d_max), (x[1] - d_max, x[1] + d_max)]) candidates = self.data.overlap_values(bb) return candidates def axis_aligned_bounding_boxes_overlap(self, a1, b1, a2, b2): return np.all(a1 < b2) and np.all(a2 < b1)
def test_is_leaf(): assert AABBTree().is_leaf assert AABBTree(AABB([(2, 5)])).is_leaf tree = AABBTree(AABB([(4, 5)])) tree2 = AABBTree() tree2.add(tree.aabb) tree2.add(tree.aabb) assert not tree2.is_leaf
def test_add(): tree = AABBTree() aabb = AABB([(3, 4), (5, 6), (-3, 5)]) tree.add(aabb) tree2 = AABBTree(aabb) assert tree == tree2 assert AABBTree() != tree
def test_does_overlap(): aabb5 = AABB([(-3, 3), (-3, 3)]) aabb6 = AABB([(0, 1), (5, 6)]) aabb7 = AABB([(6.5, 6.5), (5.5, 5.5)]) for aabb in (aabb5, aabb6, aabb7): assert not AABBTree().does_overlap(aabb) aabbs = standard_aabbs() for indices in itertools.permutations(range(4)): tree = AABBTree() for i in indices: tree.add(aabbs[i]) assert tree.does_overlap(aabb5) assert not tree.does_overlap(aabb6) assert not tree.does_overlap(aabb7)
def test_unique(): tree = AABBTree() aabb1 = AABB([(0, 1)]) aabb2 = AABB([(0, 1)]) aabb3 = AABB([(0, 1)]) tree.add(aabb1, 'box 1') tree.add(aabb2, 'box 2') vals = tree.overlap_values(aabb3, unique=True) assert len(vals) == 1 vals = tree.overlap_values(aabb3, unique=False) assert len(vals) == 2 assert 'box 1' in vals assert 'box 2' in vals
def test_overlap_values(): aabbs = standard_aabbs() values = ['value 1', 3.14, None, None] aabb5 = AABB([(-3, 3.1), (-3, 3)]) aabb6 = AABB([(0, 1), (5, 6)]) aabb7 = AABB([(6.5, 6.5), (5.5, 5.5)]) for indices in itertools.permutations(range(4)): tree = AABBTree() for i in indices: tree.add(aabbs[i], values[i]) vals5 = tree.overlap_values(aabb5) assert len(vals5) == 2 for val in ('value 1', 3.14): assert val in vals5 assert tree.overlap_values(aabb6) == [] assert tree.overlap_values(aabb7) == [] assert AABBTree(aabb5).overlap_values(aabb7) == []
def test_overlap_aabbs(): aabbs = standard_aabbs() values = ['value 1', 3.14, None, None] aabb5 = AABB([(-3, 3.1), (-3, 3)]) aabb6 = AABB([(0, 1), (5, 6)]) aabb7 = AABB([(6.5, 6.5), (5.5, 5.5)]) for indices in itertools.permutations(range(4)): tree = AABBTree() for i in indices: tree.add(aabbs[i], values[i]) for m in ('DFS', 'BFS'): aabbs5 = tree.overlap_aabbs(aabb5, method=m) assert len(aabbs5) == 2 for aabb in aabbs5: assert aabb in aabbs[:2] assert tree.overlap_aabbs(aabb6) == [] assert tree.overlap_aabbs(aabb7) == [] for m in ('DFS', 'BFS'): assert AABBTree(aabb5).overlap_aabbs(aabb7, method=m) == []
def init(): glfw.init() m = glfw.get_primary_monitor() mode = glfw.get_video_mode(m) width = mode.size.width // 4 height = mode.size.height // 4 window = glfw.create_window(width, height, 'Ray Tracer', None, None) glfw.make_context_current(window) window_dict = { 'width': width, 'height': height, 'W': np.array([0, 0, 1]), 'E': np.array([0, 0.15, -1]), 'b': np.array([0, 1, 0]), 'd': 1.5, 'mouse': None, 'yaw': 0, 'pitch': 0, 'up': False, 'down': False, 'left': False, 'right': False, 'show_cursor': False, 'num_triangles': 0, 'num_objects': 2, 'fov': 90, 'delta_t': 0, 'sprint': False, 'num_aabb': 0 } window_dict = struct(window_dict) glfw.set_window_size_callback( window, lambda *args: window_size_callback(window_dict, *args)) glfw.set_cursor_pos_callback( window, lambda *args: cursor_position_callback(window_dict, *args)) glfw.set_key_callback(window, lambda *args: key_callback(window_dict, *args)) glfw.set_mouse_button_callback( window, lambda *args: mouse_button_callback(window_dict, *args)) set_cursor(window, window_dict) quad = pyglet.graphics.vertex_list( 4, ('v2f', (-1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0))) try: shader = from_files_names("quad_vshader.glsl", "quad_fshader.glsl") except ShaderCompilationError as e: print(e.logs) exit() GL_SHADER_STORAGE_BUFFER = GLuint(0x90D2) f_obj = '(1f)[type](3f)[pos](1f)[size1](1f)[size2](3f)[color](3f)[direction]' object_buffer = Buffer.array(format=f_obj, usage=GL_DYNAMIC_DRAW) object_buffer.bind(GL_SHADER_STORAGE_BUFFER) #object_buffer.reserve(3) #attach_uniform_buffer(object_buffer, shader, b'object_data', GLuint(1)) glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, object_buffer.bid) f_tr = '(3f)[vertex1](3f)[vertex2](3f)[vertex3](3f)[color](3f)[normal]' tr_buffer = Buffer.array(format=f_tr, usage=GL_DYNAMIC_DRAW) tr_buffer.bind(GL_SHADER_STORAGE_BUFFER) #attach_uniform_buffer(tr_buffer, shader, b'triangle_data', GLuint(2)) glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, tr_buffer.bid) #f_aabb = '(2f)[xlim](2f)[ylim](2f)[zlim](1i)[left](1i)[right]' tree = AABBTree() data = get_obj_data('bunny.obj', tree, window_dict.num_objects) print(tree.depth) aabb = AABB([(-1, 1), (-1, 1), (9, 11)]) tree.add(aabb, 0) aabb = AABB([(-15, 15), (-1.1, 0.9), (-15, 15)]) tree.add(aabb, 1) # print(tree) tree_arr = [] def f(tree_arr, tree): left = tree.left.num if tree.left else -1 right = tree.right.num if tree.right else tree.value limits = [list(x) for x in tree.aabb.limits] l = [[2], limits[0] + [limits[1][0]], [left], [right], [0, 0, 0], [limits[1][1]] + limits[2]] tree_arr += [l] def g(tree, num): tree.num = num['num'] num['num'] += 1 num = {'num': 0} traverse(tree, lambda x: g(x, num)) traverse(tree, lambda x: f(tree_arr, x)) window_dict.num_aabb = len(tree_arr) object_data = [] object_data += [[[0], [0, 0, 10], [1], [0], [1, 0, 0], [0, 0, 0]]] object_data += [[[1], [0, -1, 1], [0], [0], [1, 0, 1], [0, 1, 0]]] object_data += tree_arr object_buffer.init(object_data) print(tree.depth) #for e, i in zip(object_data, range(len(object_data))): # print(i, e) #aabb_buf.init(tree_arr) # aabb_buf.reserve(1) # aabb_buf[0] = [[1, 0], [0, 0], [0, 0], [0], [0]] window_dict.num_triangles = len(data) tr_buffer.init(data) return window, window_dict, object_buffer, tr_buffer, shader, quad
gExposedDay = 10 # 潜伏期 gSelfRecoveryDay = 50 gSelfRecoverRate = 0. gDeathDay = 50 gDeathRate = 0. N = 2000 #总数 gN0 = 10 # 初始感染人数 MaxSize = 10000 #地图尺寸 MoveStep = 160 # 每个人移动距离 personList = [] MaxTime = 300 # 执行时间 keyFrames = [] frames = 30.0 #录像频数 tree = AABBTree() gif_name = r'D:\Timyy\project\python\covid-19\ShowVirus.1.3.3.gif' gtmpFolder = r'D:\Timyy\project\python\covid-19\tmp\\' gMethod = 1 gUsePP = False # 使用并行算法。python 是单线程的。这个方法用了多线程,使用多个CPU计算 class Hosptal: def __init__(self): self.HosptalBedMax = 4 # 医院床位数 self.HosptalBedRemain = 4 # 床位剩余 self.HosptalRecoveryTime = 10 #康复时间 self.HosptalResponse = 10 #响应时间 def heal(self): if self.HosptalBedRemain > 0:
def __init__(self, d_max=0): self.d_max = d_max self.data = AABBTree()
class Collision: def __init__(self, objects=None): self.tree = AABBTree() if objects: for item in objects: if item["type"] == "CUBE": self.add_object(item["pos"], (item["scale"][0] / 2, item["scale"][1] / 2, item["scale"][2] / 2), item["goal"]) elif item["type"] == "SPHERE": self.add_object(item["pos"], item["scale"], item["goal"]) # Returns AABB object with coorect values based on a point and offset def get_aabb(self, point, bound): return AABB([(point.x - bound[0], point.x + bound[0]), (point.y - bound[1], point.y + bound[1]), (point.z - bound[2], point.z + bound[2])]) # Add object with position and scale to the tree # Sets the position as the value returned in case of collision def add_object(self, position, scale, goal): self.tree.add(self.get_aabb(position, scale), { "pos": position, "scale": scale, "goal": goal }) # Makes checking for collision on point easier def point_collision(self, point, bound): return self.tree.does_overlap(self.get_aabb(point, bound)) # Returns the point object of collided objects def collision_objects(self, point, bound): return self.tree.overlap_values(self.get_aabb(point, bound)) # checks if player is between bounds of object on an axis with respect to size def is_between(self, player, obj, axis): return obj["pos"][axis] - obj["scale"][axis] - player["scale"][ axis] < player["pos"][axis] < obj["pos"][axis] + obj["scale"][ axis] + player["scale"][axis] # Finds which side of a cube the player is touching def get_colliding_face(self, player, obj): # Zeroes the axis of the plane on the object the player is touching return (1 if self.is_between(player, obj, 0) else 0, 1 if self.is_between(player, obj, 1) else 0, 1 if self.is_between(player, obj, 2) else 0) # Returns surface vector based on player direction def get_surface_vector(self, player, obj): directions = self.get_colliding_face(player, obj) # Returns a normalized vector that represents the direction of the surface # Direction on the non zeroed axes based on player movement return Vector(player["direction"].x * directions[0], player["direction"].y * directions[1], player["direction"].z * directions[2]).normalize() # Returns slide vector for player on collided object def get_slide_vector(self, player, obj): surface_vector = self.get_surface_vector(player, obj) return surface_vector * player["direction"].dot(surface_vector) # Returns motion vector of player def move(self, player): # collision member set to advoid key error player["collision"] = [] # If no collision return player directly if not self.point_collision(player["newpos"], player["scale"]): return player else: # If collision, get slide vector for each object collided with for item in self.collision_objects(player["newpos"], player["scale"]): player["direction"] = self.get_slide_vector(player, item) player["collision"].append( self.get_colliding_face(player, item)) if item["goal"]: player["collision"].append((0, 0, 0)) return player
def test_add_raises(): tree = AABBTree() with pytest.raises(ValueError): for aabb in standard_aabbs(): tree.add(aabb, method=3.14)
def t_junction_close(paths, distance, snapped): def t_junction_close_recursive(pt_with_index, distance, pre_seg_with_index, paths, bbtree, depth, snapped): # Search in AABB tree for overlap bboxes if depth == 0: return paths if pt_with_index[1] in snapped: return paths depth = depth - 1 bbox_edge = 2 * distance pt = pt_with_index[0] path_index, seg_index, t = pt_with_index[1] query = AABB([(pt[0] - bbox_edge, pt[0] + bbox_edge), (pt[1] - bbox_edge, pt[1] + bbox_edge)]) min_j_dist = float('inf') min_t = None min_path_index = None min_seg_index = None min_seg = None for other_path_index, other_seg_index, seg in bbtree.overlap_values( query): if other_path_index == path_index and other_seg_index == seg_index: continue try: j_dist, j_t = seg.radialrange(complex(*pt))[0] except Exception as e: print(str(e)) continue if min_j_dist > j_dist: min_j_dist = j_dist min_t = j_t min_path_index = other_path_index min_seg_index = other_seg_index min_seg = seg # if find target segment if min_j_dist < distance and min_j_dist > eps: # if the fixment of current pt(seg) depends on pre_seg, then fixment of pre_seg also depends on current pt # in other word, seg and pre_seg need to be fixed that the same time if (min_path_index, min_seg_index) == pre_seg_with_index[1]: # find closest point of two segmet endpoints to each other # cloeset point on min_seg(pre_seg) to cur_seg endpoint point1 = min_seg.point(min_t) # cloeset point on cur_seg to min_seg(pre_seg) endpoint t1 = 0 if min_t < 0.5 else 1 dist2, t2 = paths[path_index][seg_index].radialrange( min_seg.point(t1))[0] point2 = paths[path_index][seg_index].point(t2) # point2 should also satisfy the distance requirement assert (dist2 < distance and dist2 > eps) # fix both segments avg_point = (point1 + point2) / 2 # set current segment if t == 0: new_seg_1 = set_segment_by_point( paths[path_index][seg_index], start=avg_point) elif t == 1: new_seg_1 = set_segment_by_point( paths[path_index][seg_index], end=avg_point) else: raise ValueError("Invalid point value %f" % t) paths[path_index][seg_index] = new_seg_1 # set previous segment if t1 == 0: new_seg_2 = set_segment_by_point(min_seg, start=avg_point) elif t1 == 1: new_seg_2 = set_segment_by_point(min_seg, end=avg_point) else: raise ValueError("Invalid point value %f" % t1) paths[min_path_index][min_seg_index] = new_seg_2 # return result return paths else: org_seg = paths[path_index][seg_index] # call it self recursively by two endpoints of min_seg to find if there is addtional dependency pt_start = ((min_seg.start.real, min_seg.start.imag), (min_path_index, min_seg_index, 0)) pre_seg = (paths[path_index][seg_index], (path_index, seg_index)) paths = t_junction_close_recursive(pt_start, distance, pre_seg, paths, bbtree, depth, snapped) pt_end = ((min_seg.end.real, min_seg.end.imag), (min_path_index, min_seg_index, 1)) paths = t_junction_close_recursive(pt_end, distance, pre_seg, paths, bbtree, depth, snapped) # generate current new segments after all denpent segments are fixed if org_seg == paths[path_index][seg_index]: t_point = paths[min_path_index][min_seg_index].point(min_t) if t == 0: new_seg = set_segment_by_point( paths[path_index][seg_index], start=t_point) elif t == 1: new_seg = set_segment_by_point( paths[path_index][seg_index], end=t_point) else: raise ValueError("Invalid point value %f" % t) paths[path_index][seg_index] = new_seg return paths else: # nothing need to change, return paths directly return paths ## Close T-junctions endpoints, endpoint_addresses = endpoint_generate(paths) # Build an axis-aligned bounding box tree for the segments. bbtree = AABBTree() for path_index, path in enumerate(paths): for seg_index, seg in enumerate(path): xmin, xmax, ymin, ymax = seg.bbox() bbtree.add(AABB([(xmin, xmax), (ymin, ymax)]), (path_index, seg_index, seg)) # for each point, find the hit segments and fix them if necessary for i, (pt, (path_index, seg_index, t)) in enumerate(zip(endpoints, endpoint_addresses)): pt_with_index = (pt, (path_index, seg_index, t)) pre_seg_with_index = (None, None) paths = t_junction_close_recursive(pt_with_index, distance, pre_seg_with_index, paths, bbtree, 10, snapped) return paths
def test_does_overlap(): aabb5 = AABB([(-3, 3), (-3, 3)]) aabb6 = AABB([(0, 1), (5, 6)]) aabb7 = AABB([(6.5, 6.5), (5.5, 5.5)]) not_tree = AABBTree() not_tree.add(aabb6) not_tree.add(aabb7) for aabb in (aabb5, aabb6, aabb7): for m in ('DFS', 'BFS'): assert not AABBTree().does_overlap(aabb, method=m) aabbs = standard_aabbs() for indices in itertools.permutations(range(4)): tree = AABBTree() alt_tree = AABBTree() for i_ind, i in enumerate(indices): tree.add(aabbs[i]) alt_tree.add(aabbs[i_ind]) for m in ('DFS', 'BFS'): assert tree.does_overlap(tree, method=m) assert alt_tree.does_overlap(tree, method=m) assert tree.does_overlap(alt_tree, method=m) assert tree.does_overlap(aabb5, method=m) assert not tree.does_overlap(aabb6, method=m) assert not tree.does_overlap(aabb7, method=m) assert not tree.does_overlap(not_tree, method=m) assert not not_tree.does_overlap(tree, method=m)
def endpoint_statistics(path_to_svg): ''' Given: path_to_svg: A path to an SVG file. Normalizes by the svg's long edge as defined by its viewBox. Ignores <svg> width or height attributes. ''' global_scale = 1.0 try: doc = Document(path_to_svg) flatpaths = doc.flatten_all_paths() paths = [path for (path, _, _) in flatpaths] except: global_scale = get_global_scale(doc.tree) ## Let's truly fail if there are transform nodes we can't handle. # try: global_scale = get_global_scale( doc.tree ) # except: print( "WARNING: There are transforms, but flatten_all_paths() failed. Falling back to unflattened paths and ignoring transforms.", file = sys.stderr ) paths, _ = svg2paths(path_to_svg) ## First pass: Gather all endpoints, path index, segment index, t value endpoints = [] # a copy of point coordinations endpoints_p = [ ] # real points, we will do the snapping by changing points in this list endpoint_addresses = [] for path_index, path in enumerate(paths): for seg_index, seg in enumerate(path): for t in (0, 1): pt = seg.point(t) endpoints.append((pt.real, pt.imag)) endpoint_addresses.append((path_index, seg_index, t)) print("Creating spatial data structures:") ## Point-point queries. dist_finder = scipy.spatial.cKDTree(endpoints) ## Build an axis-aligned bounding box tree for the segments. bbtree = AABBTree() # but, why? # for path_index, path in tqdm( enumerate( paths ), total = len( paths ), ncols = 50 ): for path_index, path in enumerate(paths): for seg_index, seg in enumerate(path): xmin, xmax, ymin, ymax = seg.bbox( ) # record bbox of each segmentation? bbtree.add(AABB([(xmin, xmax), (ymin, ymax)]), (path_index, seg_index, seg)) # Second pass: Gather all minimum distances print("Finding minimum distances:") minimum_distances = [] for i, (pt, (path_index, seg_index, t)) in enumerate(zip(endpoints, endpoint_addresses)): ## 1. Find the minimum distance to any other endpoints ## Find two closest points, since the point itself is in dist_finder with distance 0. mindist, closest_pt_indices = dist_finder.query([pt], k=2) ## These come back as 1-by-2 matrices. mindist = mindist[0] closest_pt_indices = closest_pt_indices[0] ## If we didn't find 2 points, then pt is the only point in this file. ## There is no point element in SVG, so that should never happen. assert len(closest_pt_indices) == 2 ## If there are two or more other points identical to pt, ## then pt might not actually be one of the two returned, but both distances ## should be zero. assert i in closest_pt_indices or (mindist < eps).all() assert min(mindist) <= eps ## The larger distance corresponds to the point that is not pt. mindist = max(mindist) ## If we already found the minimum distance is 0, then there's no point also ## searching for T-junctions. if mindist < eps: minimum_distances.append(mindist) continue ## 2. Find the closest point on any other paths (T-junction). ## We are looking for any segments closer than mindist to pt. # why? why mindist? query = AABB([(pt[0] - mindist, pt[0] + mindist), (pt[1] - mindist, pt[1] + mindist)]) for other_path_index, other_seg_index, seg in bbtree.overlap_values( query): ## Don't compare the point with its own segment. if other_path_index == path_index and other_seg_index == seg_index: continue ## Optimization: If the distance to the bounding box is larger ## than mindist, skip it. ## This is still relevant, because mindist will shrink as we iterate over ## the results of our AABB tree query. # why? this is also not reasonable to me xmin, xmax, ymin, ymax = seg.bbox() if (pt[0] < xmin - mindist or pt[0] > xmax + mindist or pt[1] < ymin - mindist or pt[1] > ymin + mindist): continue ## Get the point to segment distance. dist_to_other_path = distance_point_to_segment(pt, seg) ## Keep it if it's smaller. if mindist is None or dist_to_other_path < mindist: mindist = dist_to_other_path ## Terminate early if the minimum distance found already is 0 if mindist < eps: break ## Accumulate the minimum distance minimum_distances.append(mindist) minimum_distances = global_scale * asfarray(minimum_distances) ## Divide by long edge. if 'viewBox' in doc.root.attrib: import re _, _, width, height = [ float(v) for v in re.split('[ ,]+', doc.root.attrib['viewBox'].strip()) ] long_edge = max(width, height) print("Normalizing by long edge:", long_edge) minimum_distances /= long_edge elif "width" in doc.root.attrib and "height" in doc.root.attrib: width = doc.root.attrib["width"].strip().strip("px") height = doc.root.attrib["height"].strip().strip("px") long_edge = max(float(width), float(height)) print("Normalizing by long edge:", long_edge) minimum_distances /= long_edge else: print( "WARNING: No viewBox found in <svg>. Not normalizing by long edge." ) print("Done") return minimum_distances
def test_depth(): assert AABBTree().depth == 0 assert standard_tree().depth == 2
def test_leaf_repr(): aabb = standard_aabbs()[0] tree = AABBTree() tree.add(aabb) assert repr(tree) == 'AABBTree(aabb={})'.format(repr(aabb))
def test_eq(): tree = AABBTree() tree.add(AABB([(2, 3)])) tree.add(AABB([(4, 5)])) tree.add(AABB([(-2, 2)])) tree2 = AABBTree(tree.aabb) assert tree == tree assert AABBTree() == AABBTree() assert tree != AABBTree() assert AABBTree() != tree assert AABBTree() != AABB() assert tree != tree2 assert tree2 != tree assert not tree != tree assert not AABBTree() != AABBTree() assert not tree == AABBTree() assert not AABBTree() == tree assert not AABBTree() == AABB() assert not tree == tree2 assert not tree2 == tree
def test_empty_repr(): assert repr(AABBTree()) == 'AABBTree()'
def test_empty_str(): empty_str = 'AABB: None\nValue: None\nLeft: None\nRight: None' assert str(AABBTree()) == empty_str