Example #1
0
    def _contains_point(self, point):
        """Tests whether or not the current room cointains a specific point

      Return true if this room object contains the supplied object
      Uses the ray casting algorithm:
      http://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm
      For simplicity we assume the ray is casted horizontally to the left
   """

        # We first compare against the bounding box. For most points this will be
        # enough
        min_point, max_point = self.bounding_box

        if ((point.x > max_point.x) or (point.x < min_point.x)
                or (point.y > max_point.y) or (point.y < min_point.y)):
            return False

        # Amount of intersections counted
        match_count = 0

        # Handle some special cases
        counted_vertices = []
        for (a, b) in circular_pairwise(self.points):

            # Is the y coordinate of the point valid? I.e.: is it between
            # the y coordinates of a and b?
            if (a.y <= point.y <= b.y or a.y >= point.y >= b.y):

                # The following function returns -1 if the point is to the left
                # of the segment, 0 if it is on the same line as the segment,
                # +1 if it is to the right
                comparison = Polygon._compare_line_and_point(a, b, point)

                # If the point is on the same line, we can conclude it belongs
                # to the shape if its x coordinates are between a's and b's
                if (comparison == 0
                        and max(a.x, b.x) >= point.x >= min(a.x, b.x)
                        and max(a.y, b.y) >= point.y >= min(a.y, b.y)):
                    return True  # the point is over a border

                # If the point is not over the line, is it to the right?
                # Being to the right means that the ray being cast to the left
                # might actually intersect the segment.
                elif (comparison > 0):

                    # Simple case, the ray does not match any vertice, so it
                    # intersects inside the segment.
                    if ((point.y != a.y) and (point.y != b.y)):
                        match_count = match_count + 1
                    else:
                        # Special cases, the ray intersects precisely one of the vertices
                        if a.y == point.y and a.x <= point.x and a not in counted_vertices:
                            counted_vertices.append(a)
                            match_count = match_count + 1
                        if b.y == point.y and b.x <= point.x and (
                                b not in counted_vertices):
                            counted_vertices.append(b)
                            match_count = match_count + 1

        # After analyzing all segments, if we found an even amount of intersections
        # it means the point is outside of the polygon
        return match_count % 2 != 0
Example #2
0
 def as_segment_list(self):
     return [
         Segment(a.clone(), b.clone())
         for a, b in circular_pairwise(self.points)
     ]
Example #3
0
    def test_polygon_contains_point(self):
        def polygon_contains(polygon, x, y):
            self.assertTrue(polygon._contains_point(Point(x, y)),
                            "{} should contain {}, {}".format(polygon, x, y))

        def polygon_not_contains(polygon, x, y):
            self.assertFalse(
                polygon._contains_point(Point(x, y)),
                "{} should not contain {}, {}".format(polygon, x, y))

        # Generic points inside the square polygon
        for x, y in circular_pairwise(range(1, 10)):
            polygon_contains(self.polygon1, x, y)

        test_data = [
            {
                "polygon":
                self.polygon1,
                "truths": [
                    # Inside, but near borders
                    (0.1, 0.001),
                    (9.99, 9.7),
                    (5, 9.99),
                    (0.1, 8),

                    # Close to the border
                    (0.001, 0.001),
                    (9.999, 9.999),

                    # Points precisely on the border
                    (5, 0),
                    (10, 5),
                    (5, 10),
                    (0, 5),
                    (0, 0),
                    (10, 0),
                    (10, 10),
                    (0, 10)
                ],
                "falses": [(5, -4), (5, 11), (10.001, 10.001), (-2, 5)]
            },
            {
                "polygon":
                self.polygon2,
                "truths": [
                    # Close to the vertices
                    (9.9, 0),
                    (0, 9.9),
                    (-9.9, 0),
                    (0, -9.9),
                    # Close to the center
                    (0.001, 0.001),
                    (3, 3),
                    (-4.8, -4.8),
                    (4.1, 3.8),

                    # Points precisely over the border
                    (10, 0),
                    (0, 10),
                    (-10, 0),
                    (0, -10)
                ],
                "falses": [
                    # Points definetely outside
                    (9.9, 9.9),
                    (10.2, 0),
                    (0, -10.1),
                    (10.001, 10.001),
                    (33, 12)
                ]
            },
            {
                "polygon":
                self.polygon3,
                "truths": [
                    # Close to the vertices
                    (1, 2),
                    (0.1, 0.1),
                    (9.9, 0.1),
                    (0.1, 9.9),
                    # Close to the center
                    (2, 3),
                    (4, 5),
                    (8, 2),
                    (1, 7),

                    # Points precisely over the vertices
                    (0, 0),
                    (10, 0),
                    (10, 5),
                    (5, 5),
                    (5, 10),
                    (0, 10)
                ],
                "falses": [
                    # Points definetely outside
                    (10.1, 0.3),
                    (-0.1, 1),
                    (2, 10.1),
                    (-0.1, -0.1),
                    (1, -0.1),
                    (6, 6),
                    (5.1, 5.1)
                ]
            },
            {
                "polygon": self.polygon4,
                "truths": [(5, 5)],
                "falses": [
                    # Points definetely outside
                    (11, 5)
                ]
            }
        ]

        for test_polygon in test_data:
            for (x, y) in test_polygon["truths"]:
                polygon_contains(test_polygon["polygon"], x, y)

            for (x, y) in test_polygon["falses"]:
                polygon_not_contains(test_polygon["polygon"], x, y)
   def test_polygon_contains_point(self):
      def polygon_contains(polygon, x, y):
            self.assertTrue( polygon._contains_point(Point(x, y)), "{} should contain {}, {}".format(polygon, x, y) )

      def polygon_not_contains(polygon, x, y):
            self.assertFalse( polygon._contains_point(Point(x, y)), "{} should not contain {}, {}".format(polygon, x, y) )

      # Generic points inside the square polygon
      for x, y in circular_pairwise(range(1,10)):
         polygon_contains(self.polygon1, x, y)

      test_data = [
         {
            "polygon"   : self.polygon1,
            "truths" : [
               # Inside, but near borders
               (0.1, 0.001),
               (9.99, 9.7),
               (5, 9.99),
               (0.1, 8),

               # Close to the border
               (0.001, 0.001),
               (9.999, 9.999),

               # Points precisely on the border
               (5, 0),
               (10, 5),
               (5, 10),
               (0, 5),
               (0, 0),
               (10, 0),
               (10, 10),
               (0, 10)
            ],
            "falses" : [
               (5, -4),
               (5, 11),
               (10.001, 10.001),
               (-2, 5)
            ]
         },
         {
            "polygon"   : self.polygon2,
            "truths" : [
               # Close to the vertices
               (9.9, 0), (0, 9.9), (-9.9, 0), (0, -9.9),
               # Close to the center
               (0.001, 0.001), (3, 3), (-4.8, -4.8), (4.1, 3.8),

               # Points precisely over the border
               (10, 0), (0, 10), (-10, 0), (0, -10)
            ],
            "falses" : [
               # Points definetely outside
               (9.9, 9.9), (10.2, 0), (0, -10.1), (10.001, 10.001), (33, 12)
            ]
         },

         {
            "polygon"   : self.polygon3,
            "truths" : [
               # Close to the vertices
               (1, 2), (0.1, 0.1), (9.9, 0.1), (0.1, 9.9),
               # Close to the center
               (2, 3), (4, 5), (8, 2), (1, 7),

               # Points precisely over the vertices
               (0,0),(10,0),(10,5),(5,5),(5,10),(0,10)
            ],
            "falses" : [
               # Points definetely outside
               (10.1, 0.3), (-0.1, 1), (2, 10.1), (-0.1, -0.1), (1, -0.1),
               (6,6), (5.1, 5.1)
            ]
         },


         {
            "polygon"   : self.polygon4,
            "truths" : [
               (5, 5)
            ],
            "falses" : [
               # Points definetely outside
               (11, 5)
            ]
         }
      ]

      for test_polygon in test_data:
         for (x, y) in test_polygon["truths"]:
            polygon_contains(test_polygon["polygon"], x, y)

         for (x, y) in test_polygon["falses"]:
            polygon_not_contains(test_polygon["polygon"], x, y)
Example #5
0
   def _contains_point(self, point):
      """Tests whether or not the current room cointains a specific point

      Return true if this room object contains the supplied object
      Uses the ray casting algorithm:
      http://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm
      For simplicity we assume the ray is casted horizontally to the left
   """

      # We first compare against the bounding box. For most points this will be
      # enough
      min_point, max_point = self.bounding_box

      if (
            (point.x > max_point.x) or
            (point.x < min_point.x) or
            (point.y > max_point.y) or
            (point.y < min_point.y)
         ):
         return False

      # Amount of intersections counted
      match_count = 0

      # Handle some special cases
      counted_vertices = []
      for (a, b) in circular_pairwise(self.points):

         # Is the y coordinate of the point valid? I.e.: is it between
         # the y coordinates of a and b?
         if( a.y <= point.y <= b.y or a.y >= point.y >= b.y ):

            # The following function returns -1 if the point is to the left
            # of the segment, 0 if it is on the same line as the segment,
            # +1 if it is to the right
            comparison = Polygon._compare_line_and_point(a, b, point)

            # If the point is on the same line, we can conclude it belongs
            # to the shape if its x coordinates are between a's and b's
            if(comparison == 0 and
                  max(a.x, b.x) >= point.x >= min(a.x, b.x) and
                  max(a.y, b.y) >= point.y >= min(a.y, b.y)):
               return True # the point is over a border

            # If the point is not over the line, is it to the right?
            # Being to the right means that the ray being cast to the left
            # might actually intersect the segment.
            elif(comparison > 0):

               # Simple case, the ray does not match any vertice, so it
               # intersects inside the segment.
               if ((point.y != a.y) and (point.y != b.y)):
                  match_count = match_count + 1
               else:
                  # Special cases, the ray intersects precisely one of the vertices
                  if a.y == point.y and a.x <= point.x and a not in counted_vertices:
                     counted_vertices.append(a)
                     match_count = match_count + 1
                  if b.y == point.y and b.x <= point.x and (b not in counted_vertices):
                     counted_vertices.append(b)
                     match_count = match_count + 1

      # After analyzing all segments, if we found an even amount of intersections
      # it means the point is outside of the polygon
      return match_count % 2 != 0
Example #6
0
 def as_segment_list(self):
    return [ Segment(a.clone(), b.clone()) for a, b in circular_pairwise(self.points) ]