| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -25,12 +25,16 @@ class Point: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.__point_size = point_size | 
					 | 
					 | 
					 | 
					        self.__point_size = point_size | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.__x = x | 
					 | 
					 | 
					 | 
					        self.__x = x | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.__y = y | 
					 | 
					 | 
					 | 
					        self.__y = y | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.__selected = False | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.__viewport_width = viewport_width | 
					 | 
					 | 
					 | 
					        self.__viewport_width = viewport_width | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.__viewport_height = viewport_height | 
					 | 
					 | 
					 | 
					        self.__viewport_height = viewport_height | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        half_point = floor(point_size / 2.0) | 
					 | 
					 | 
					 | 
					        half_point = floor(point_size / 2.0) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.__check_window_bounds(x, y) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.__selected = False | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.__top_left_corner = (self.__x - half_point, | 
					 | 
					 | 
					 | 
					        self.__top_left_corner = (self.__x - half_point, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                                  self.__y + half_point) | 
					 | 
					 | 
					 | 
					                                  self.__y + half_point) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -52,30 +56,41 @@ class Point: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def selected(self): | 
					 | 
					 | 
					 | 
					    def selected(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return self.__selected | 
					 | 
					 | 
					 | 
					        return self.__selected | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def move(self, dx, dy): | 
					 | 
					 | 
					 | 
					    def __check_window_bounds(self, x, y): | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        Adds the deltas dx and dy to the point. | 
					 | 
					 | 
					 | 
					        Simple window bound check that raises an exception when | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        the point (x, y) exceeds the known viewport bounds. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        @param dx The delta in the x direction. | 
					 | 
					 | 
					 | 
					        @param x The x-coordinate under test. | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        @param dy The delta in the y direction. | 
					 | 
					 | 
					 | 
					        @param y The y-coordinate under test. | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        @raises ExceededWindowBoundsError If the viewport bounds are exceeded. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        half_point = floor(self.point_size / 2.0) | 
					 | 
					 | 
					 | 
					        half_point = floor(self.point_size / 2.0) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        # Screen size in pixels is always positive | 
					 | 
					 | 
					 | 
					        # Screen size in pixels is always positive | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        # We need to include the half point here because | 
					 | 
					 | 
					 | 
					        # We need to include the half point here because | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        # the (x, y) for a point is the center of the square and we | 
					 | 
					 | 
					 | 
					        # the (x, y) for a point is the center of the square and we | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        # do not want the EDGES to exceed the viewport bounds. | 
					 | 
					 | 
					 | 
					        # do not want the EDGES to exceed the viewport bounds. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (self.__x + dx > self.__viewport_width - half_point or | 
					 | 
					 | 
					 | 
					        if (x > self.__viewport_width - half_point or | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            self.__y + dy > self.__viewport_height - half_point  or | 
					 | 
					 | 
					 | 
					            y > self.__viewport_height - half_point  or | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            self.__x + dx < half_point or self.__y + dy < half_point): | 
					 | 
					 | 
					 | 
					            x < half_point or | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            y < half_point): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            raise ExceededWindowBoundsError | 
					 | 
					 | 
					 | 
					            raise ExceededWindowBoundsError | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    def move(self, dx, dy): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        Adds the deltas dx and dy to the point. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        @param dx The delta in the x direction. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        @param dy The delta in the y direction. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.__check_window_bounds(self.__x + dx, self.__y + dy) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.__x += dx | 
					 | 
					 | 
					 | 
					        self.__x += dx | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        self.__y += dy | 
					 | 
					 | 
					 | 
					        self.__y += dy | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					     | 
					 | 
					 | 
					 | 
					     | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					     | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def __eq__(self, other): | 
					 | 
					 | 
					 | 
					    def __eq__(self, other): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        Override for class equality. | 
					 | 
					 | 
					 | 
					        Override for class equality. | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -86,7 +101,6 @@ class Point: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                self.__y == other.y and | 
					 | 
					 | 
					 | 
					                self.__y == other.y and | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                self.__point_size == other.point_size) | 
					 | 
					 | 
					 | 
					                self.__point_size == other.point_size) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def __hash__(self): | 
					 | 
					 | 
					 | 
					    def __hash__(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        Overridden hashing function so it can be used as a dictionary key | 
					 | 
					 | 
					 | 
					        Overridden hashing function so it can be used as a dictionary key | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -94,7 +108,6 @@ class Point: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return hash((self.__x, self.__y, self.__point_size)) | 
					 | 
					 | 
					 | 
					        return hash((self.__x, self.__y, self.__point_size)) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def __repr__(self): | 
					 | 
					 | 
					 | 
					    def __repr__(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return "POINT<X :{} Y: {} SIZE: {}>".format(self.__x, | 
					 | 
					 | 
					 | 
					        return "POINT<X :{} Y: {} SIZE: {}>".format(self.__x, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                                                    self.__y, | 
					 | 
					 | 
					 | 
					                                                    self.__y, | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -182,6 +195,22 @@ class PointSet: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def point_size(self): | 
					 | 
					 | 
					 | 
					    def point_size(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return self.__point_size | 
					 | 
					 | 
					 | 
					        return self.__point_size | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    @property | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    def viewport_height(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        return self.__viewport_height | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    @property | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    def viewport_width(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        return self.__viewport_width | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    @viewport_height.setter | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    def viewport_height(self, height): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.__viewport_height = height | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    @viewport_width.setter | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    def viewport_width(self, width): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.__viewport_width = width | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def clear_selection(self): | 
					 | 
					 | 
					 | 
					    def clear_selection(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        Handy helper function to clear all selected points. | 
					 | 
					 | 
					 | 
					        Handy helper function to clear all selected points. | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -197,6 +226,9 @@ class PointSet: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        @param x The x-coordinate. | 
					 | 
					 | 
					 | 
					        @param x The x-coordinate. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        @param y The y-coordinate. | 
					 | 
					 | 
					 | 
					        @param y The y-coordinate. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        @param attr An optional attribute. | 
					 | 
					 | 
					 | 
					        @param attr An optional attribute. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        @raises ExceededWindowBoundsError If the point could not be constructed | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                                          because it would be outside the window | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                                          bounds. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if attrs != [] and not all(isinstance(x, Attribute) for x in attrs): | 
					 | 
					 | 
					 | 
					        if attrs != [] and not all(isinstance(x, Attribute) for x in attrs): | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
  |