def classify(centroids: Iterable[AnyVec]): new_clusters: Dict[AnyVec, List[AnyVec]] = defaultdict(list) tree = RTree(centroids) for point in points: nn, _ = tree.nearest_neighbor(point) new_clusters[nn].append(point) return new_clusters
def test_Vec2_compatibility(): tree = RTree([Vec2(x, 0) for x in range(100)], max_node_size=5) bbox = BoundingBox([(45, 0, 0), (55, 0, 0)]) points = list(tree.points_in_bbox(bbox)) assert len(points) == 11 expected_x_coords = set(range(45, 56)) x_coords = set(int(p.x) for p in points) assert x_coords == expected_x_coords assert any(isinstance(p, Vec2) for p in points)
def dbscan( points: List[AnyVec], *, radius: float, min_points: int = 4, rtree: RTree = None, max_node_size: int = 5, ) -> List[List[AnyVec]]: """DBSCAN clustering. https://en.wikipedia.org/wiki/DBSCAN Args: points: list of points to cluster radius: radius of the dense regions min_points: minimum number of points that needs to be within the `radius` for a point to be a core point (must be >= 2) rtree: optional RTree max_node_size: max node size for internally created RTree Returns: list of clusters, each cluster is a list of points .. versionadded:: 0.18 """ if min_points < 2: raise ValueError("min_points must be >= 2") if rtree is None: rtree = RTree(points, max_node_size) clusters: List[Set[AnyVec]] = [] point_set = set(points) while len(point_set): point = point_set.pop() todo = {point} cluster = {point} # the cluster has only a single entry if noise clusters.append(cluster) while len(todo): chk_point = todo.pop() neighbors = set(rtree.points_in_sphere(chk_point, radius)) if len(neighbors) < min_points: continue cluster.add(chk_point) point_set.discard(chk_point) todo |= neighbors.intersection(point_set) return [list(cluster) for cluster in clusters]
def profile_rtree_contains_all_points(repeat: int, max_size: int): log = [] for size in range(100, 2000, 100): points = random_points(size, 50.0) tree = RTree(points, max_size) name = f"RTree({size}, {max_size})" t0 = profile( profile_tree_contains_points, repeat, tree, points ) time_str = f"{t0:6.2f}s" print(f"{name} contains all points, {repeat}x , {time_str}") log.append((size, t0)) return log
def profile_rtree_nearest_neighbor(repeat: int, max_size: int): log = [] for size in range(100, 2000, 100): points = random_points(size, 50.0) tree = RTree(points, max_size) name = f"RTree({size}, {max_size})" search_points = random_points(100, 50.0) t0 = profile( profile_tree_nearest_neighbor, repeat, tree, search_points ) time_str = f"{t0:6.2f}s" print(f"{name} nearest neighbor, {repeat}x , {time_str}") log.append((size, t0)) return log
def test_from_two_points(self): tree = RTree([Vec3(1, 2, 3), Vec3(3, 2, 1)]) assert len(tree) == 2
def test_iter_tree(self): point = Vec3(1, 2, 3) tree = RTree([point]) assert list(tree) == [point]
def test_contains_point(self): point = Vec3(1, 2, 3) tree = RTree([point]) assert tree.contains(point)
def test_avg_methods_return_0_for_too_small_trees(): tree = RTree([Vec3()]) assert tree.avg_leaf_size() == 0.0 assert tree.avg_spherical_envelope_radius() == 0.0 assert tree.avg_nn_distance() == 0.0
def test_avg_nn_distance_of_random_points(): tree = RTree([Vec3.random(100) for _ in range(100)]) nn_dist = tree.avg_nn_distance() assert nn_dist > 10.0
def test_contains_all_random_points(self): points = [Vec3.random(50) for _ in range(100)] tree = RTree(points, 5) for point in points: assert tree.contains(point) is True
def test_average_leaf_size_of_random_points(): tree = RTree([Vec3.random(100) for _ in range(100)]) size = tree.avg_leaf_size() assert size > 10.0
def test_collect_leafs(): tree = RTree([Vec3.random(100) for _ in range(100)]) assert sum(len(leaf) for leaf in rtree.collect_leafs(tree._root)) == 100
def profile_build_time_random_rtree(count: int, points, max_node_size: int): for _ in range(count): RTree(points, max_node_size)
def test_store_duplicate_points(self): p = Vec3(1, 2, 3) tree = RTree([p, p]) assert len(tree) == 2
def tree(self): return RTree([Vec3(x, 0, 0) for x in range(100)], max_node_size=5)
def test_avg_spherical_envelope_radius_of_random_points(): tree = RTree([Vec3.random(100) for _ in range(100)]) radius = tree.avg_spherical_envelope_radius() assert radius > 10.0
def test_can_not_build_empty_tree(): with pytest.raises(ValueError): RTree([])
def test_from_one_point(self): tree = RTree([Vec3(1, 2, 3)]) assert len(tree) == 1