예제 #1
0
파일: network.py 프로젝트: sunpoet/pysal
    def __init__(self, network):
        """
        Test tag <tc>#is#Snapper.__init__</tc>
        """

        """
        Generate a list of the edge lengths and pick a maximum length
        allowed based on the median length. This maximum length will be
        used to use multiple midpoints to represent edges which are 
        exceptionally long, lest they ruin the efficiency of the algorithm.
        """

        # Generate list of lengths
        self.network = network
        edge_lens = []
        for n in network:
            for m in network[n]:
                if n != m:
                    edge_lens.append(pysal.cg.get_points_dist(Point(n), Point(m)))  # it can be optional
        if edge_lens == []:
            raise ValueError, "Network has no positive-length edges"
        edge_lens.sort()
        max_allowed_edge_len = 5 * edge_lens[len(edge_lens) / 2]

        """ 
        Create a bin structures with proper range to hold all of the edges.
        The size of the bin is on the order of the length of the longest edge (and
        of the neighborhoods searched around each query point.
        """
        endpoints = network.keys()
        endpoints_start, endpoints_end = [ep[0] for ep in endpoints], [ep[1] for ep in endpoints]
        bounds = Rectangle(min(endpoints_start), min(endpoints_end), max(endpoints_start), max(endpoints_end))
        self.grid = Grid(bounds, max_allowed_edge_len)

        """
        Insert the midpoint of each edge into the grid. If an edge is too long, 
        break it into edges of length less than the maximum allowed length and
        add the midpoint of each.
        """
        self.search_rad = max_allowed_edge_len * 0.55
        for n in network:
            for m in network[n]:
                edge_len = pysal.cg.get_points_dist(Point(n), Point(m))  # it can be a direct extraction
                if edge_len > max_allowed_edge_len:
                    mid_edge = []
                    num_parts = int(math.ceil(edge_len / max_allowed_edge_len))
                    part_step = 1.0 / num_parts
                    dx = m[0] - n[0]
                    dy = m[1] - n[1]
                    midpoint = (n[0] + dx * part_step / 2, n[1] + dy * part_step / 2)
                    for r in [part_step * t for t in xrange(num_parts)]:
                        mid_edge.append(((n, m), midpoint))
                        midpoint = (midpoint[0] + dx * part_step, midpoint[1] + dy * part_step)
                    for me in mid_edge:
                        self.grid.add(me[0], Point(me[1]))
                else:
                    self.grid.add((n, m), Point(((n[0] + m[0]) / 2, (n[1] + m[1]) / 2)))

        """
        During the snapping of a query point we will initialize the closest point on the network
        to be a dummy location known to be invalid. This must be done in case the neighborhood
        search does not find any edge midpoints and it must be grown repeatedly. In this case
        we want to make sure we don't give up having not found a valid closest edge.
        """
        self.dummy_proj = (None, None, 0, 0)  # Src, dest, dist_from_src, dist_from_dest)
    def __init__(self, network):
        """
        Test tag <tc>#is#Snapper.__init__</tc>
        """
        """
        Generate a list of the edge lengths and pick a maximum length
        allowed based on the median length. This maximum length will be
        used to use multiple midpoints to represent edges which are 
        exceptionally long, lest they ruin the efficiency of the algorithm.
        """

        # Generate list of lengths
        self.network = network
        edge_lens = []
        for n in network:
            for m in network[n]:
                if n != m:
                    edge_lens.append(
                        pysal.cg.get_points_dist(
                            Point(n), Point(m)))  # it can be optional
        if edge_lens == []:
            raise ValueError('Network has no positive-length edges')
        edge_lens.sort()
        max_allowed_edge_len = 5 * edge_lens[len(edge_lens) / 2]
        """ 
        Create a bin structures with proper range to hold all of the edges.
        The size of the bin is on the order of the length of the longest edge (and
        of the neighborhoods searched around each query point.
        """
        endpoints = list(network.keys())
        endpoints_start, endpoints_end = [ep[0] for ep in endpoints
                                          ], [ep[1] for ep in endpoints]
        bounds = Rectangle(min(endpoints_start), min(endpoints_end),
                           max(endpoints_start), max(endpoints_end))
        self.grid = Grid(bounds, max_allowed_edge_len)
        """
        Insert the midpoint of each edge into the grid. If an edge is too long, 
        break it into edges of length less than the maximum allowed length and
        add the midpoint of each.
        """
        self.search_rad = max_allowed_edge_len * 0.55
        for n in network:
            for m in network[n]:
                edge_len = pysal.cg.get_points_dist(
                    Point(n), Point(m))  # it can be a direct extraction
                if edge_len > max_allowed_edge_len:
                    mid_edge = []
                    num_parts = int(math.ceil(edge_len / max_allowed_edge_len))
                    part_step = 1.0 / num_parts
                    dx = m[0] - n[0]
                    dy = m[1] - n[1]
                    midpoint = (n[0] + dx * part_step / 2,
                                n[1] + dy * part_step / 2)
                    for r in [part_step * t for t in range(num_parts)]:
                        mid_edge.append(((n, m), midpoint))
                        midpoint = (midpoint[0] + dx * part_step,
                                    midpoint[1] + dy * part_step)
                    for me in mid_edge:
                        self.grid.add(me[0], Point(me[1]))
                else:
                    self.grid.add((n, m),
                                  Point(
                                      ((n[0] + m[0]) / 2, (n[1] + m[1]) / 2)))
        """
        During the snapping of a query point we will initialize the closest point on the network
        to be a dummy location known to be invalid. This must be done in case the neighborhood
        search does not find any edge midpoints and it must be grown repeatedly. In this case
        we want to make sure we don't give up having not found a valid closest edge.
        """
        self.dummy_proj = (None, None, 0, 0
                           )  # Src, dest, dist_from_src, dist_from_dest)
예제 #3
0
파일: network.py 프로젝트: sunpoet/pysal
class Snapper:
    """
    Snaps points to their nearest location on the network.

    Uses a novel algorithm which relies on two properties of the input network:
    1.  Most of the edges are very short relative to the total area 
        encompassed by the network.
    2.  The edges have a relatively constant density throughout this area.

    The algorithm works by creating a binning of the midpoints of all the edges.
    When a query point is given, all the edges in a region around the query
    point (located by their binned midpoints) are compared to the query point. 
    If none are found, the neighborhood is enlarged. When a closest edge is found, 
    the neighborhood is enlarged slightly and checked again. The enlargement is 
    such that if the closest edge found remains the closest edge, then it will
    always be the closest edge.
    """

    def __init__(self, network):
        """
        Test tag <tc>#is#Snapper.__init__</tc>
        """

        """
        Generate a list of the edge lengths and pick a maximum length
        allowed based on the median length. This maximum length will be
        used to use multiple midpoints to represent edges which are 
        exceptionally long, lest they ruin the efficiency of the algorithm.
        """

        # Generate list of lengths
        self.network = network
        edge_lens = []
        for n in network:
            for m in network[n]:
                if n != m:
                    edge_lens.append(pysal.cg.get_points_dist(Point(n), Point(m)))  # it can be optional
        if edge_lens == []:
            raise ValueError, "Network has no positive-length edges"
        edge_lens.sort()
        max_allowed_edge_len = 5 * edge_lens[len(edge_lens) / 2]

        """ 
        Create a bin structures with proper range to hold all of the edges.
        The size of the bin is on the order of the length of the longest edge (and
        of the neighborhoods searched around each query point.
        """
        endpoints = network.keys()
        endpoints_start, endpoints_end = [ep[0] for ep in endpoints], [ep[1] for ep in endpoints]
        bounds = Rectangle(min(endpoints_start), min(endpoints_end), max(endpoints_start), max(endpoints_end))
        self.grid = Grid(bounds, max_allowed_edge_len)

        """
        Insert the midpoint of each edge into the grid. If an edge is too long, 
        break it into edges of length less than the maximum allowed length and
        add the midpoint of each.
        """
        self.search_rad = max_allowed_edge_len * 0.55
        for n in network:
            for m in network[n]:
                edge_len = pysal.cg.get_points_dist(Point(n), Point(m))  # it can be a direct extraction
                if edge_len > max_allowed_edge_len:
                    mid_edge = []
                    num_parts = int(math.ceil(edge_len / max_allowed_edge_len))
                    part_step = 1.0 / num_parts
                    dx = m[0] - n[0]
                    dy = m[1] - n[1]
                    midpoint = (n[0] + dx * part_step / 2, n[1] + dy * part_step / 2)
                    for r in [part_step * t for t in xrange(num_parts)]:
                        mid_edge.append(((n, m), midpoint))
                        midpoint = (midpoint[0] + dx * part_step, midpoint[1] + dy * part_step)
                    for me in mid_edge:
                        self.grid.add(me[0], Point(me[1]))
                else:
                    self.grid.add((n, m), Point(((n[0] + m[0]) / 2, (n[1] + m[1]) / 2)))

        """
        During the snapping of a query point we will initialize the closest point on the network
        to be a dummy location known to be invalid. This must be done in case the neighborhood
        search does not find any edge midpoints and it must be grown repeatedly. In this case
        we want to make sure we don't give up having not found a valid closest edge.
        """
        self.dummy_proj = (None, None, 0, 0)  # Src, dest, dist_from_src, dist_from_dest)

    def snap(self, p):
        """
        Test tag <tc>#is#Snapper.snap</tc>
        """

        """
        Initialize the closest location found so far to be infinitely far away.
        Then begin with a neighborhood on the order of the maximum edge allowed and
        repeatedly growing it. When a closest edge is found, grow once more and check again.
        """

        cur_s_rad = self.search_rad
        found_something = False
        # Whle neighborhood is empty, enlarge and check again
        while not found_something:
            if self.grid.proximity(Point(p), cur_s_rad) != []:
                found_something = True
            cur_s_rad *= 2
        # Expand to include any edges whose endpoints might lie just outside
        # the search radius
        cur_s_rad += self.search_rad
        # Now find closest in this neighborhood
        best_seg_dist = 1e600
        for e in self.grid.proximity(Point(p), cur_s_rad):
            seg = LineSegment(Point(e[0]), Point(e[1]))
            p2seg = pysal.cg.get_segment_point_dist(seg, Point(p))
            dist = p2seg[0]
            if p2seg[0] < best_seg_dist:
                # (src, dest, dist_from_src, dist_from_dest)
                best_proj = (e[0], e[1], dist * p2seg[1], dist * (1 - p2seg[1]))
                best_seg_dist = p2seg[0]
        return best_proj
class Snapper:
    """
    Snaps points to their nearest location on the network.

    Uses a novel algorithm which relies on two properties of the input network:
    1.  Most of the edges are very short relative to the total area 
        encompassed by the network.
    2.  The edges have a relatively constant density throughout this area.

    The algorithm works by creating a binning of the midpoints of all the edges.
    When a query point is given, all the edges in a region around the query
    point (located by their binned midpoints) are compared to the query point. 
    If none are found, the neighborhood is enlarged. When a closest edge is found, 
    the neighborhood is enlarged slightly and checked again. The enlargement is 
    such that if the closest edge found remains the closest edge, then it will
    always be the closest edge.
    """
    def __init__(self, network):
        """
        Test tag <tc>#is#Snapper.__init__</tc>
        """
        """
        Generate a list of the edge lengths and pick a maximum length
        allowed based on the median length. This maximum length will be
        used to use multiple midpoints to represent edges which are 
        exceptionally long, lest they ruin the efficiency of the algorithm.
        """

        # Generate list of lengths
        self.network = network
        edge_lens = []
        for n in network:
            for m in network[n]:
                if n != m:
                    edge_lens.append(
                        pysal.cg.get_points_dist(
                            Point(n), Point(m)))  # it can be optional
        if edge_lens == []:
            raise ValueError('Network has no positive-length edges')
        edge_lens.sort()
        max_allowed_edge_len = 5 * edge_lens[len(edge_lens) / 2]
        """ 
        Create a bin structures with proper range to hold all of the edges.
        The size of the bin is on the order of the length of the longest edge (and
        of the neighborhoods searched around each query point.
        """
        endpoints = list(network.keys())
        endpoints_start, endpoints_end = [ep[0] for ep in endpoints
                                          ], [ep[1] for ep in endpoints]
        bounds = Rectangle(min(endpoints_start), min(endpoints_end),
                           max(endpoints_start), max(endpoints_end))
        self.grid = Grid(bounds, max_allowed_edge_len)
        """
        Insert the midpoint of each edge into the grid. If an edge is too long, 
        break it into edges of length less than the maximum allowed length and
        add the midpoint of each.
        """
        self.search_rad = max_allowed_edge_len * 0.55
        for n in network:
            for m in network[n]:
                edge_len = pysal.cg.get_points_dist(
                    Point(n), Point(m))  # it can be a direct extraction
                if edge_len > max_allowed_edge_len:
                    mid_edge = []
                    num_parts = int(math.ceil(edge_len / max_allowed_edge_len))
                    part_step = 1.0 / num_parts
                    dx = m[0] - n[0]
                    dy = m[1] - n[1]
                    midpoint = (n[0] + dx * part_step / 2,
                                n[1] + dy * part_step / 2)
                    for r in [part_step * t for t in range(num_parts)]:
                        mid_edge.append(((n, m), midpoint))
                        midpoint = (midpoint[0] + dx * part_step,
                                    midpoint[1] + dy * part_step)
                    for me in mid_edge:
                        self.grid.add(me[0], Point(me[1]))
                else:
                    self.grid.add((n, m),
                                  Point(
                                      ((n[0] + m[0]) / 2, (n[1] + m[1]) / 2)))
        """
        During the snapping of a query point we will initialize the closest point on the network
        to be a dummy location known to be invalid. This must be done in case the neighborhood
        search does not find any edge midpoints and it must be grown repeatedly. In this case
        we want to make sure we don't give up having not found a valid closest edge.
        """
        self.dummy_proj = (None, None, 0, 0
                           )  # Src, dest, dist_from_src, dist_from_dest)

    def snap(self, p):
        """
        Test tag <tc>#is#Snapper.snap</tc>
        """
        """
        Initialize the closest location found so far to be infinitely far away.
        Then begin with a neighborhood on the order of the maximum edge allowed and
        repeatedly growing it. When a closest edge is found, grow once more and check again.
        """

        cur_s_rad = self.search_rad
        found_something = False
        # Whle neighborhood is empty, enlarge and check again
        while not found_something:
            if self.grid.proximity(Point(p), cur_s_rad) != []:
                found_something = True
            cur_s_rad *= 2
        # Expand to include any edges whose endpoints might lie just outside
        # the search radius
        cur_s_rad += self.search_rad
        # Now find closest in this neighborhood
        best_seg_dist = 1e600
        for e in self.grid.proximity(Point(p), cur_s_rad):
            seg = LineSegment(Point(e[0]), Point(e[1]))
            p2seg = pysal.cg.get_segment_point_dist(seg, Point(p))
            dist = p2seg[0]
            if p2seg[0] < best_seg_dist:
                # (src, dest, dist_from_src, dist_from_dest)
                best_proj = (e[0], e[1], dist * p2seg[1],
                             dist * (1 - p2seg[1]))
                best_seg_dist = p2seg[0]
        return best_proj