Пример #1
0
    def top_view(self):
        sorted_endpoints = []
        for segment_ in self.segments:
            sorted_endpoints.append(Endpoint(True, segment_))
            sorted_endpoints.append(Endpoint(False, segment_))
        sorted_endpoints.sort(
            key=lambda end_point: end_point.value())  # O n(log n)

        resulted_segments = []
        # sweeper = SortedDict(key=lambda ep: ep.height)
        sweeper = SortedDict()
        print(sweeper)

        for endpoint_ in sorted_endpoints:
            if sweeper.__len__() == 0:
                sweeper[endpoint_] = endpoint_.segment
            elif not endpoint_.is_left:  # right of some segment
                left_ep = Endpoint(True, endpoint_.segment)
                if left_ep.__eq__(
                        sweeper.peekitem(0)[0]):  # "top most" is ending now
                    sweeper.pop(sweeper.peekitem(0)[0])
                    prev_seg = resulted_segments[resulted_segments.__len__() -
                                                 1]
                    resulted_segments.append(
                        Segment(prev_seg.right, endpoint_.segment.right,
                                endpoint_.segment.height,
                                endpoint_.segment.name))
                else:  # some segment "not at top" needs to end now
                    sweeper.pop(left_ep)
            elif sweeper.peekitem(
                    0
            )[0].segment.height < endpoint_.segment.height:  # crossover, a higher segment found
                current_top = sweeper.peekitem(0)[0]
                if resulted_segments.__len__() > 0:
                    last_segment = resulted_segments[
                        resulted_segments.__len__() - 1]
                    resulted_segments.append(
                        Segment(last_segment.right, endpoint_.segment.left,
                                current_top.segment.height,
                                current_top.segment.name))
                else:
                    resulted_segments.append(
                        Segment(current_top.segment.left,
                                endpoint_.segment.left,
                                current_top.segment.height,
                                current_top.segment.name))
                sweeper[endpoint_] = endpoint_.segment
            elif sweeper.peekitem(
                    0
            )[0].segment.height > endpoint_.segment.height:  # non contributing end found
                sweeper[endpoint_] = endpoint_.segment

        return resulted_segments
Пример #2
0
class NameSortedList(Sequence[_T]):  # pylint: disable=too-many-ancestors
    """Name sorted list is a sorted sequence which contains NameMixin.

    It is maintained in sorted order according to the 'name' of :class:`NameMixin`.

    """
    def __init__(self) -> None:
        self._data = SortedDict()

    def __len__(self) -> int:
        return self._data.__len__()  # type: ignore[no-any-return]

    @overload
    def __getitem__(self, index: int) -> _T:
        ...

    @overload
    def __getitem__(self, index: slice) -> List[_T]:
        ...

    def __getitem__(self, index: Union[int, slice]) -> Union[_T, List[_T]]:
        return self._data.values()[index]  # type: ignore[no-any-return]

    def __iter__(self) -> Iterator[_T]:
        return self._data.values().__iter__()  # type: ignore[no-any-return]

    def add(self, value: _T) -> None:
        """Store element in name sorted list.

        Arguments:
            value: :class:`NameMixin` instance.

        """
        self._data[value.name] = value

    def get_from_name(self, name: str) -> _T:
        """Get element in name sorted list from name of NameMixin.

        Arguments:
            name: Name of :class:`NameMixin` instance.

        Returns:
            The element to be get.

        """
        return self._data[name]  # type: ignore[no-any-return]
Пример #3
0
class LeafSet(object):
    __slots__ = ('peers', 'capacity')
    __passthru = {'get', 'clear', 'pop', 'popitem', 'peekitem', 'key'}
    __iters = {'keys', 'values', 'items'}

    def __init__(self, my_key, iterable=(), capacity=8):
        try:
            iterable = iterable.items()  # view object
        except AttributeError:
            pass
        tuple_itemgetter = Peer.distance(my_key, itemgetter(0))
        key_itemgetter = Peer.distance(my_key)
        self.capacity = capacity
        self.peers = SortedDict(key_itemgetter)
        if iterable:
            l = sorted(iterable, key=tuple_itemgetter)
            self.peers.update(islice(l, capacity))

    def clear(self):
        self.peers.clear()

    def prune(self):
        extra = len(self) - self.capacity
        for i in range(extra):
            self.peers.popitem(last=True)

    def update(self, iterable):
        try:
            iterable = iterable.items()  # view object
        except AttributeError:
            pass
        iterable = iter(iterable)
        items = tuple(islice(iterable, 500))
        while items:
            self.peers.update(items)
            items = tuple(islice(iterable, 500))


    def setdefault(self, *args, **kwargs):
        self.peers.setdefault(*args, **kwargs)
        self.prune()

    def __setitem__(self, *args, **kwargs):
        self.peers.__setitem__(*args, **kwargs)
        self.prune()

    def __getitem__(self, *args, **kwargs):
        return self.peers.__getitem__(*args, **kwargs)

    def __delitem__(self, *args, **kwargs):
        return self.peers.__delitem__(*args, **kwargs)

    def __iter__(self, *args, **kwargs):
        return self.peers.__iter__(*args, **kwargs)

    def __reversed__(self, *args, **kwargs):
        return self.peers.__reversed__(*args, **kwargs)

    def __contains__(self, *args, **kwargs):
        return self.peers.__contains__(*args, **kwargs)

    def __len__(self, *args, **kwargs):
        return self.peers.__len__(*args, **kwargs)

    def __getattr__(self, key):
        if key in self.__class__.__passthru:
            return getattr(self.peers, key)
        elif key in self.__class__.__iters:
            return getattr(self.peers, 'iter' + key)
        else:
            return super().__getattr__(key)

    def __repr__(self):
        return '<%s keys=%r capacity=%d/%d>' % (
            self.__class__.__name__, list(self), len(self), self.capacity)
Пример #4
0
class Visibility_polygon_class(object):
    def __init__(self):
        self.origin = (0, 0)
        self.refvec = (0, 1)
        self.segments = []
        self.event_queue = []
        self.status = 0
        self.status = SortedDict()
        self.visibility_polygon = []

    def order_segments(self, arg):
        return arg

    # Starts here!
    def get_visibility_polygon(self, segments, origin):
        self.origin = origin
        self.segments = segments
        self.add_bounding_box()
        self.create_event_queue_from_segments()
        self.sort_event_queue()
        self.initialize_status()
        #return self.status
        self.perform_sweep()
        return self.visibility_polygon

    def add_bounding_box(self):
        # Find extreme points
        margin = 40
        top_y = 400 + margin  #uppermost_point_index(self.event_queue)
        bottom_y = 130 - margin  #lowermost_point_index(self.event_queue)
        right_x = 600 + margin  #rightmost_point_index(self.event_queue)
        left_x = 200 - margin  #leftmost_point_index(self.event_queue)
        # Create the bounding box and add it to event queue
        s1 = Segment(Point(right_x, top_y), Point(right_x, bottom_y))
        s2 = Segment(Point(right_x - 5, bottom_y), Point(left_x, bottom_y))
        s3 = Segment(Point(left_x, bottom_y + 5), Point(left_x, top_y))
        s4 = Segment(Point(left_x + 5, top_y), Point(right_x, top_y + 5))

        p = [s1, s2, s3, s4]
        self.segments.extend(p)

    # Create an event queue with all points and their connections (not sorted yet!)
    def create_event_queue_from_segments(self):
        for s in self.segments:
            p1 = EventPoint(s.p1)
            p2 = EventPoint(s.p2)
            p1.twin = p2
            p2.twin = p1
            self.event_queue.append(p1)
            self.event_queue.append(p2)

    # Create event queue
    def sort_event_queue(self):
        # Sort the points in clockwise order
        self.event_queue = sorted(self.event_queue, key=self.get_key)

    def initialize_status(self):
        sweep_ray = Ray(self.origin, self.event_queue[0].p)
        i = 0
        for ep in self.event_queue:
            if ep.type == DEFAULT_VERTEX:
                segment = Segment(ep.p, ep.twin.p)
                intersection_point = sweep_ray.intersection(segment)

                if len(intersection_point) > 0:
                    # If the segments first point is the current event-point
                    if intersection_point[
                            0] == ep.p:  # if the point is on the initial ray
                        if len(
                                Ray(self.origin, self.event_queue[
                                    i + 1].p).intersection(segment)
                        ) > 0:  #if the point was a start point
                            self.initialize_segment(ep, intersection_point)
                        else:
                            self.initialize_segment(ep.twin,
                                                    intersection_point)
                    else:
                        self.initialize_segment(ep.twin, intersection_point)
                else:
                    # Event-points not hit by the ray gets a type
                    ep.type = START_VERTEX
                    ep.twin.type = END_VERTEX
            i += 1

    def initialize_segment(self, ep, intersection_point):
        status_segment = StatusSegment(ep, ep.twin, self.origin)
        status_segment.current_distance = distance(intersection_point[0],
                                                   self.origin)
        ep.status_segment = status_segment
        ep.twin.status_segment = status_segment
        ep.type = START_VERTEX
        ep.twin.type = END_VERTEX
        if ep != self.event_queue[0]:
            self.status.update(
                {status_segment.current_distance: status_segment})

    def perform_sweep(self):
        print("\nStatus at start: " + str(len(self.status)))

        for ep in self.event_queue:
            print("\nStatus: " + str(len(self.status)))

            if ep.type == START_VERTEX:
                print("START_VERTEX")
                status_segment = StatusSegment(ep, ep.twin, self.origin)

                print("current segment: " + str(status_segment.segment) +
                      str(status_segment.current_distance))

                ep.status_segment = status_segment
                ep.twin.status_segment = status_segment
                if self.status.__len__() == 0:
                    self.status.update(
                        {status_segment.current_distance: status_segment})
                    self.visibility_polygon.append(ep.p)
                    print("empty status. Append")
                else:
                    first_in_status = self.status.peekitem(index=0)

                    print("first in status and distance: " +
                          str(first_in_status[1].segment) + ": " +
                          str(first_in_status[1].current_distance))

                    current_ray = Ray(self.origin, ep.p)
                    intersection_point = current_ray.intersection(
                        first_in_status[1].segment)
                    first_in_status[1].current_distance = distance(
                        intersection_point[0], self.origin)
                    print("First in status new distance: " +
                          str(first_in_status[1].current_distance))
                    self.status.update(
                        {status_segment.current_distance:
                         status_segment})  # insert the new segment to status
                    self.status.__delitem__(first_in_status[0])
                    self.status.update({
                        first_in_status[1].current_distance:
                        first_in_status[1]
                    })  #update the key distance to the origin
                    new_first_in_status = self.status.peekitem(index=0)
                    if new_first_in_status[1] != first_in_status[1]:
                        self.visibility_polygon.append(intersection_point[0])
                        self.visibility_polygon.append(ep.p)
                        print("normal status. Append")

            elif ep.type == END_VERTEX:
                print("END_VERTEX")
                first_in_status = self.status.peekitem(index=0)
                print("first in status and distance: " +
                      str(first_in_status[1].segment) + ": " +
                      str(first_in_status[1].current_distance))
                self.status.__delitem__(ep.status_segment.current_distance)
                print("ep status segment and distance: " +
                      str(ep.status_segment.segment) + ": " +
                      str(ep.status_segment.current_distance))
                if self.status.__len__() == 0:
                    self.visibility_polygon.append(ep.p)
                    print("empty status. Append")
                else:
                    new_first_in_status = self.status.peekitem(index=0)
                    if new_first_in_status[1] != first_in_status[1]:
                        current_ray = Ray(self.origin, ep.p)
                        intersection_point = current_ray.intersection(
                            new_first_in_status[1].segment)
                        self.visibility_polygon.append(ep.p)
                        self.visibility_polygon.append(intersection_point[0])
                        print("normal status. Append")

    # Gets key for sorting
    def get_key(self, point):
        return self.clockwiseangle_and_distance(point.p)

    # returns the angle and length vector from the origin to the point
    def clockwiseangle_and_distance(self, point):
        # Vector between point and the origin: v = p - o
        vector = [point[0] - self.origin[0], point[1] - self.origin[1]]
        # Length of vector: ||v||
        lenvector = math.hypot(vector[0], vector[1])
        # If length is zero there is no angle
        if lenvector == 0:
            return -math.pi, 0
        # Normalize vector: v/||v||
        normalized = [vector[0] / lenvector, vector[1] / lenvector]
        dotprod = normalized[0] * self.refvec[0] + normalized[1] * self.refvec[
            1]  # x1*x2 + y1*y2
        diffprod = self.refvec[1] * normalized[0] - self.refvec[
            0] * normalized[1]  # x1*y2 - y1*x2
        angle = math.atan2(diffprod, dotprod)
        # Negative angles represent counter-clockwise angles so we need to subtract them
        # from 2*pi (360 degrees)
        if angle < 0:
            return 2 * math.pi + angle, lenvector
        # I return first the angle because that's the primary sorting criterium
        # but if two vectors have the same angle then the shorter distance should come first.
        return angle, lenvector
Пример #5
0
class DotMap(MutableMapping):

    def __init__(self, *args, **kwargs):
        self._map = SortedDict()
        if args:
            d = args[0]
            if type(d) is dict:
                for k, v in self.__call_items(d):
                    if type(v) is dict:
                        v = DotMap(v)
                    self._map[k] = v
        if kwargs:
            for k, v in self.__call_items(kwargs):
                self._map[k] = v

    @staticmethod
    def __call_items(obj):
        if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
            return obj.iteritems()
        else:
            return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def __setitem__(self, k, v):
        self._map[k] = v

    def __getitem__(self, k):
        if k not in self._map:
            # automatically extend to new DotMap
            self[k] = DotMap()
        return self._map[k]

    def __setattr__(self, k, v):
        if k == '_map':
            super(DotMap, self).__setattr__(k, v)
        else:
            self[k] = v

    def __getattr__(self, k):
        if k == '_map':
            return self._map
        else:
            return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __str__(self):
        items = []
        for k, v in self.__call_items(self._map):
            items.append('{0}={1}'.format(k, repr(v)))
        out = 'DotMap({0})'.format(', '.join(items))
        return out

    def __repr__(self):
        return str(self)

    def to_dict(self):
        d = {}
        for k, v in self.items():
            if type(v) is DotMap:
                v = v.to_dict()
            d[k] = v
        return d

    def pprint(self):
        pprint(self.to_dict())

    # proper dict subclassing
    def values(self):
        return self._map.values()

    @staticmethod
    def parse_other(other):
        if type(other) is DotMap:
            return other._map
        else:
            return other

    def __cmp__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__cmp__(other)

    def __eq__(self, other):
        other = DotMap.parse_other(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)

    def __ge__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__ge__(other)

    def __gt__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__gt__(other)

    def __le__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__le__(other)

    def __lt__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__lt__(other)

    def __ne__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)

    def __len__(self):
        return self._map.__len__()

    def copy(self):
        return self

    def get(self, key, default=None):
        return self._map.get(key, default)

    def has_key(self, key):
        return key in self._map

    def iterkeys(self):
        return self._map.iterkeys()

    def itervalues(self):
        return self._map.itervalues()

    def keys(self):
        return self._map.keys()

    def pop(self, key, default=None):
        return self._map.pop(key, default)

    def setdefault(self, key, default=None):
        return self._map.setdefault(key, default)

    def viewitems(self):
        if version_info.major == 2 and version_info.minor >= 7:
            return self._map.viewitems()
        else:
            return self._map.items()

    def viewkeys(self):
        if version_info.major == 2 and version_info.minor >= 7:
            return self._map.viewkeys()
        else:
            return self._map.keys()

    def viewvalues(self):
        if version_info.major == 2 and version_info.minor >= 7:
            return self._map.viewvalues()
        else:
            return self._map.values()

    @classmethod
    def fromkeys(cls, seq, value=None):
        d = DotMap()
        d._map = SortedDict.fromkeys(seq, value)
        return d