def neighbors(self, state):
        max_angle = utils.max_angle(self.min_turn_radius, state.radius)
        self.thetas = np.linspace(-max_angle,
                                  max_angle,
                                  num=self.branch_factor)
        self.euclidean_neighbors[:, 0] = state.radius * np.cos(
            self.thetas + state.angle) + state.center[0]
        self.euclidean_neighbors[:, 1] = state.radius * np.sin(
            self.thetas + state.angle) + state.center[1]

        # we use this several times, so compute this icky math here to avoid unnecessary computation
        euc = self.euclidean_neighbors.copy()
        utils.world_to_map(euc, self.map.map_info)
        euc = np.round(euc).astype(int)
        radii = self.map.get_distances(euc,
                                       coord_convert=False,
                                       check_bounds=True)
        mask = np.logical_and(
            np.invert(self.map.get_explored(euc, coord_convert=False)),
            self.map.get_permissible(euc, coord_convert=False))

        neighbors = map(
            lambda c, r, t: Circle(
                center=c.copy(
                ), radius=r, angle=state.angle + t, deflection=t),
            self.euclidean_neighbors[mask, :], radii[mask], self.thetas[mask])
        return neighbors
    def neighbors(self, state):
        ''' This function determines the set of points along the perimeter of the given
		    circle state that are accessible according to ackermann geometry and steering
		    angle limitations. Then it samples the permissible theta space to generate neighbors.

		    TODO: computation of neighboring thetas is not accurate - it should actually be
		          the direction tangent to the path arc at the intersection with the circle radius.
		          For now this works, and is a strict underestimate of the reachable thetas
		'''
        max_angle = utils.max_angle(self.min_turn_radius, state.radius)
        percentage = np.power(2.0 * self.branch_factor / np.pi, 0.9)
        actual_branch_factor = 2 * int(max_angle * percentage / 2.0) + 1
        thetas = np.linspace(-max_angle, max_angle, num=actual_branch_factor)

        euclidean_neighbors = np.zeros((actual_branch_factor, 2))
        euclidean_neighbors[:, 0] = state.radius * np.cos(
            thetas + state.angle) + state.center[0]
        euclidean_neighbors[:, 1] = state.radius * np.sin(
            thetas + state.angle) + state.center[1]

        # perform coordinate space conversion here and then index into the exploration and permissible
        # buffers to prune states which are not permissible or already explored
        euc = euclidean_neighbors.copy()
        utils.world_to_map(euc, self.map.map_info)
        euc = np.round(euc).astype(int)
        radii = self.map.get_distances(
            euc, coord_convert=False, check_bounds=True) - 0.05
        radii = np.clip(radii, 0.0, self.max_circle_radius)
        mask = np.logical_and(
            np.invert(self.map.get_explored(euc, coord_convert=False)),
            self.map.get_permissible(euc, coord_convert=False))

        # generate a neighbor state for each of the permissible
        neighbors = map(
            lambda c, r, t: Circle(
                center=c.copy(), radius=r, angle=state.angle + t, deflection=t
            ), euclidean_neighbors[mask, :], radii[mask], thetas[mask])
        return neighbors