Beispiel #1
0
 def ordered_intersect(left_parabola, right_parabola):
     ''' return only one of the functions from intersect '''
     # check degenerate cases
     if left_parabola.get_focus() == Point.NEG_INF():
         return lambda d: Point.NEG_INF()
     if right_parabola.get_focus() == Point.INF():
         return lambda d: Point.INF()
     # do something normal
     intersections = left_parabola.intersect(right_parabola)
     # if a left parabola has focus above the right one, it will be wider
     # and there are two intersection points to the right; we want
     # the closer one
     ind = 0 if left_parabola.get_focus().get_y(
     ) > right_parabola.get_focus().get_y() else 1
     return intersections[ind]
Beispiel #2
0
 def NEG_INF():
     ''' return pseudo parabola object all the way to the left '''
     return Parabola(Point.NEG_INF())
Beispiel #3
0
    def circle_handle(self, beachline, voronoi_edges, voronoi_vertices,
                      verbose):
        ''' handle a circle event by modifying the beachline and graph
        remove the corresponding arc from the beachline
        return list of new events
        '''
        # get current sweep line location
        directrix = self.location.get_y() - self.radius

        #        print("CIRCLE EVENT HERE:")
        #        print(self)
        # first check if this event actually occurs, i.e. parabolas do intersect here
        if len(beachline.find_exact(self.location.get_x(), directrix)) <= 3:
            if verbose:
                print(self.location)
                print(
                    "THIS EVENT DOES NOT OCCUR OR HAS ALREADY BEEN PROCESSED")
            return []  # do nothing
        # this line is for testing only
        exact_find = beachline.find_exact(self.location.get_x(), directrix)
        if len(exact_find) == 3:
            print("ALREADY PROCESSED")

        ### maintain beachline ###
        # remove and replace beachline objects above this site
        nodes = beachline.delete(self.location.get_x(), directrix)
        # if there are multiple intersections here, the only ones that
        # survive are the leftmost and rightmost arcs
        # nodes should take the form arc, breakpoint, arc, breakpoint, arc, etc.
        # where the arcs in the middle have all degenerated
        # get the list of foci associated with these beachline elements
        foci = [
            nodes[0].pointer[0]
        ]  # determines the parabola for the left breakpoint of the first arc
        for i in range(len(nodes) // 2):  # nodes has odd length
            breakpoint = nodes[2 * i +
                               1]  # extract the breakpoints to get the foci
            foci.append(breakpoint.pointer[0])  # add only the left parabolas
        foci = foci + nodes[-1].pointer[
            1:]  # add rightmost parabola + determinator of its right breakpoint
        # remember middle arcs all disappear, leaving only two arcs
        left_arc = Arc(None, Parabola(foci[1]), Parabola(foci[0]),
                       Parabola(foci[-2]))
        breakpoint = BreakPoint(None, Parabola(foci[1]), Parabola(foci[-2]))
        right_arc = Arc(None, Parabola(foci[-2]), Parabola(foci[1]),
                        Parabola(foci[-1]))
        beachline.insert(left_arc, directrix)
        beachline.insert(breakpoint, directrix)
        beachline.insert(right_arc, directrix)

        ### graph maintenance using voronoi_edges and voronoi_vertices ###
        collisions = frozenset(foci[1:-1])  # all sites colliding here
        #        if len(collisions) != 3:
        #            print("voronoi vertex determined by")
        #            for point in collisions:
        #                print(point)
        #            print("current location")
        #            print(self.location)
        #            print("exact find")
        #            for node in exact_find:
        #                print(node._str__())
        #                print("Break points")
        #                for break_point in node.keyfunc(directrix):
        #                    print(break_point)
        #            print("deleted nodes")
        #            for node in nodes:
        #                print(node._str__())
        #            print("beachline")
        #            print(beachline)
        #            raise StopIteration
        # all arcs except the leftmost and rightmost disappear
        for i in range(1, len(foci) - 2):  # len(foci)-2 is the rightmost arc
            edge = Edge(foci[i], foci[i + 1])
            other = foci[i - 1] if i > 1 else foci[
                -2]  # some vertex for comparison
            # foci[i], foci[i+1] are adjacent
            if edge in voronoi_edges:
                voronoi_edges[edge].add(self.location)
                voronoi_vertices[edge].add(collisions)
            elif foci[i] != foci[i + 1]:
                voronoi_edges[edge] = {self.location}
                voronoi_vertices[edge] = {collisions}
        edge = Edge(foci[1], foci[-2])
        if edge in voronoi_edges:
            voronoi_edges[edge].add(self.location)
            voronoi_vertices[edge].add(collisions)
        elif foci[1] != foci[-2]:
            voronoi_edges[edge] = {self.location}
            voronoi_vertices[edge] = {collisions}

        ### event creation ###
        # new adjacent arcs are foci[0], foci[1], foci[-2] and foci[1], foci[-2], foci[-1]
        new_event_list = []
        left_point_set = {foci[0], foci[1], foci[-2]}
        right_point_set = {foci[1], foci[-2], foci[-1]}
        if foci[0] != Point.NEG_INF() and len(left_point_set) == 3:
            if not are_collinear(foci[0], foci[1], foci[-2]):
                left_circle = compute_circumcenter(foci[0], foci[1], foci[-2])
                left_radius = left_circle.distance(foci[1])
                left_event = Event(left_circle, EventType.CIRCLE, left_radius)
                if self < left_event:
                    new_event_list.append(left_event)
        if foci[-1] != Point.INF() and len(right_point_set) == 3:
            if not are_collinear(foci[1], foci[-2], foci[-1]):
                right_circle = compute_circumcenter(foci[1], foci[-2],
                                                    foci[-1])
                right_radius = right_circle.distance(foci[-2])
                right_event = Event(right_circle, EventType.CIRCLE,
                                    right_radius)
                #                print("CIRCLE EVENT CREATED %s" %(right_event,))
                if self < right_event:
                    new_event_list.append(right_event)
        return new_event_list
Beispiel #4
0
    def site_handle(self, beachline, voronoi_edges, voronoi_vertices, verbose):
        ''' handle a site event by modifying the beachline and graph
        add an arc to the beachline, possibly splitting arcs
        return list of new events
        '''
        ### beachline maintenance ###

        # currently the sweep line goes through self.location
        directrix = self.location.get_y()
        parabola = Parabola(self.location)  # new parabola with this focus
        # remove and replace the beachline objects above this site
        nodes = beachline.delete(self.location.get_x(), directrix)

        if len(nodes
               ) == 0:  # no objects yet, first insert; handle this by itself
            #            print("NO NODES FOUND")
            arc = Arc(None, parabola, Parabola.NEG_INF(), Parabola.INF())
            beachline.insert(arc, directrix)
            return []

        # nodes is nicely sorted from left to right, may contain 1 or 3 objects
        foci = [
        ]  # list of foci of parabolas from left to right (by parabola order)
        #        print("PRINTING NODES HERE")
        #        for node in nodes:
        #            print(node.pointer[1])
        if len(nodes) == 3:  # this site lies below a breakpoint
            left_pointer = nodes[0].pointer
            right_pointer = nodes[2].pointer
            foci = left_pointer[:2] + [self.location] + right_pointer[1:]
        elif len(nodes) == 1:
            pointer = nodes[0].pointer  # nodes[0] is a single arc
            foci = pointer[0:2] + [self.location] + pointer[1:]
        else:
            #            print("shouldn't get here!!!")
            #            print(self)
            #            for node in nodes:
            #                print(node._str__())
            raise Exception("should not get here")
        new_nodes = [
        ]  # new arcs and breakpoints to be inserted; should be 3/2 unless two points have the same y coord
        if self.location.get_y() == foci[1].get_y(
        ):  # same y coordinates, parabolas will only have one intersection
            # events are processed left to right, the rightmost arc will also have to change
            far_left = Parabola(foci[0])
            center_left = Parabola(foci[1])  # which is equal to foci[3]
            center_right = Parabola(foci[2])
            far_right = Parabola(foci[4])
            arc1 = Arc(None, center_left, far_left, center_right)
            breakpoint1 = BreakPoint(None, center_left, center_right)
            arc2 = Arc(None, center_right, center_left, far_right)
            breakpoint2 = BreakPoint(None, center_right, far_right)
            new_nodes.append(arc1)
            new_nodes.append(breakpoint1)
            new_nodes.append(arc2)
            new_nodes.append(breakpoint2)
            # the arc of far_right has not been removed, but its left parabola needs to be changed
            try:
                far_right_arc = nodes[-1].successor().successor()
                if verbose:
                    print("This is the far right arc")
                    print(far_right_arc)
                # manually reset for far_right_arc
                far_right_arc.pointer[0] = self.location

                def f(directrix):
                    left_breakpoint = Parabola.ordered_intersect(
                        center_right, far_right)(directrix)
                    right_breakpoint = Parabola.ordered_intersect(
                        far_right,
                        Parabola(far_right_arc.pointer[-1]))(directrix)
                    return (left_breakpoint, right_breakpoint)

                # reset keyfunc as well
                far_right_arc.keyfunc = f
                assert far_right_arc.pointer[1] == foci[4]
                new_nodes.append(
                    None)  # because iteration will not see the last item
            except:  # this point lies below the rightmost arc
                if verbose:
                    print("beneath rightmost arc")

        else:  # non-degenerate case
            for i in range(1, len(foci) - 1):  # len(foci) should be 5
                arc = Arc(None, Parabola(foci[i]), Parabola(foci[i - 1]),
                          Parabola(foci[i + 1]))
                #               print("New breakpoint added")
                breakpoint = BreakPoint(None, Parabola(foci[i]),
                                        Parabola(foci[i + 1]))
                #               print(breakpoint)
                new_nodes.append(arc)
                new_nodes.append(breakpoint)
            # this gives an extra duplicated breakpoint at the end of the list
        # NOTE: make sure to insert in left to right order to handle degeneracies
        for i in range(len(new_nodes) - 1):
            #            print("Inserting")
            #            print(new_nodes[i])
            beachline.insert(new_nodes[i], directrix)
#            print("resulting beachline:")
#            print(beachline)
#            print("end beachline")

### graph maintenance using voronoi_edges ###
# first handle the common case
        if foci[1] == foci[
                3]:  # site point breaks up a single arc, tracing new edge
            assert foci[1] != foci[2]
            voronoi_edges[Edge(foci[1], foci[2])] = set()
            voronoi_vertices[Edge(foci[1], foci[2])] = set()
        else:  # site event coincides with circle event
            circumcenter = compute_circumcenter(foci[1], foci[2], foci[3])
            new_vertex = nodes[1].keyfunc(
                directrix
            )[0]  # nodes[1] is a BreakPoint representing the collision point, coord is repeated
            #            print("ADDING EDGES AMONG:")
            #            print(foci[1], foci[2], foci[3])
            collision = frozenset({foci[1], foci[2], foci[3]})
            # handle each triangle edge separately
            # edge between 1, 3
            voronoi_edges[Edge(foci[1], foci[3])].add(new_vertex)
            voronoi_vertices[Edge(foci[1], foci[3])].add(collision)
            # edge between 1 and 2
            voronoi_edges[Edge(foci[1], foci[2])] = {new_vertex}
            voronoi_vertices[Edge(foci[1], foci[2])] = {collision}
            # edge between 2 and 3
            voronoi_edges[Edge(foci[2], foci[3])] = {new_vertex}
            voronoi_vertices[Edge(foci[2], foci[3])] = {collision}

        ### compute new events ###
        # the only potential circle events added by this vertex so far are
        # ones in which the arcs to the left and right disappear
        # circle event occurs when sweep line hits the bottom of the circle
        # recall foci has length 5 and contains the 5 foci associated with
        # the relevant parabolas here; degeneracy when this site event
        # is also a circle event is handled by the site event
        new_event_list = []
        #        print("FOCUS FOR EVENTS FROM SITE HERE")
        #        for focus in foci:
        #            print(focus)
        # check for extreme cases
        if foci[0] != Point.NEG_INF():
            if not are_collinear(foci[0], foci[1], foci[2]):
                #                print("%s, %s, %s not collinear" %(foci[0], foci[1], foci[2]))
                left_circle = compute_circumcenter(foci[0], foci[1], foci[2])
                # left_circle is where the arc to the left of this site disappears
                left_radius = foci[2].distance(left_circle)
                left_event = Event(left_circle, EventType.CIRCLE, left_radius)
                # only add if this event is new
                #                if not left_circle.get_y() - left_radius == directrix:
                if self < left_event:
                    #                    print("CIRCLE EVENT CREATED %s" %(left_event))
                    new_event_list.append(left_event)
        if foci[4] != Point.INF():
            if not are_collinear(foci[2], foci[3], foci[4]):
                #                print("%s, %s, %s not collinear" %(foci[2], foci[3], foci[4]))
                right_circle = compute_circumcenter(foci[2], foci[3], foci[4])
                right_radius = foci[2].distance(right_circle)
                right_event = Event(right_circle, EventType.CIRCLE,
                                    right_radius)
                #                if not right_circle.get_y() - right_radius == directrix:
                if self < right_event:
                    #                    print("CIRCLE EVENT CREATED %s" %(right_event,))
                    new_event_list.append(right_event)
                    # recall new_nodes has an extra breakpoint at the end
        return new_event_list