def line_segment_intersection(self, segment: Segment) -> int: """ Method that checks for polygon-line segment intersection. We look at the polygon sides as line segments. We for intersection for each of the sides. If segment intersects any of the polygon sides, the answer is affirmative. If the line segment is completely in- side of outside of polygon, the answer is negative. Args: segment: Segment object Returns: 1 if there is intersection, 0 otherwise """ for i in range(len(self.points)): edge = Segment(self.points[i], self.points[(i + 1) % len(self.points)]) if segment.check_for_intersection(edge) == 1: return 1 return 0
class TestSegment(unittest.TestCase): @classmethod def setUpClass(cls): pass @classmethod def tearDownClass(cls): pass def setUp(self): self.segment1 = Segment(Point(0, 0), Point(5, 5)) self.segment_intersects1 = Segment(Point(0, 5), Point(5, 0)) self.segment_does_not_intersect1 = Segment(Point(-5, -8), Point(9, -3)) self.segment_single_common_endpoint = Segment(Point(5, 5), Point(9, 3)) self.segment_coincident = Segment(Point(0, 0), Point(5, 5)) self.segment_contains1 = Segment(Point(0, 0), Point(6, 6)) self.segment_deg = Segment(Point(3, 3), Point(3, 3)) self.segment_deg2 = Segment(Point(9, 5), Point(9, 5)) def tearDown(self): pass def test_intersection(self): self.assertEqual( self.segment1.check_for_intersection(self.segment_intersects1), 1) self.assertEqual( self.segment1.check_for_intersection( self.segment_does_not_intersect1), 0) self.assertEqual( self.segment1.check_for_intersection( self.segment_single_common_endpoint), 1) self.assertEqual( self.segment1.check_for_intersection(self.segment_coincident), 1) self.assertEqual( self.segment1.check_for_intersection(self.segment_contains1), 1) self.assertEqual( self.segment_contains1.check_for_intersection(self.segment1), 1) self.assertEqual( self.segment1.check_for_intersection(self.segment_deg), 1) self.assertEqual( self.segment_deg.check_for_intersection(self.segment_deg2), 0)
def point_in_polygon(self, point: Point) -> int: """ Idea - Ray Casting. We check if the point belongs to any of the line segments coincident to polygon sides. Point is considered to be an empty line segment in that case. If there exists at least a single intersection, the point is on the edge of polygon. The ray - We create a line segment determined by point passed through parameter and a (Tx, miny-1) point. It takes O(n) to find miny - we are looking for the polygon vertex with the smallest value on y axis. We then go through all polygon vertices and check if there are any points with same value on x axis and smaller value on y axis than T. When there are not, we return number of intersections modulo 2. Otherwise, we form the list L of neighbour vertices with same x value on x axis, and we also memorize point index. Special case: if the first and list point of polygons are containt in the ray, they need to be merged. If the ray goest through the edge of the polygon, number of intersections is 3. If the ray contains the side of polygon, number of intersections is 3. We subtract the length of all elements of L reduced for 1. For elements in L, we take predecessor point from a first point in list and successor point from a last element in the list and we check if they are on the opposite sides of the ray. If they are, we reduce by one the number of intersections. We return the number of intersections modulo 2. Args: point: Returns: """ index_minimum = 0 no_of_intersections = 0 neighbours_list = [] for i in range(len(self.points)): if self.points[i].return_y() < self.points[index_minimum].return_y( ): index_minimum = i point2 = Point(point.return_x(), self.points[index_minimum].return_y() - 1) segment = Segment(point, point2) segment_point = Segment(point, point) for i in range(len(self.points)): edge_ = Segment(self.points[i], self.points[(i + 1) % len(self.points)]) if edge_.check_for_intersection(segment_point) == 1: return 1 elif segment.check_for_intersection(edge_) == 1: no_of_intersections += 1 neighbour_ = 0 for i in range(len(self.points)): if self.points[i].return_x() == point.return_x() and \ self.points[i].return_y() <= point.return_y() and neighbour_ != 1: neighbours_list.append([(self.points[i], i)]) neighbour_ = 1 elif self.points[i].return_x() == point.return_x() and \ self.points[i].return_y() <= point.return_y() and neighbour_ == 1: neighbours_list[len(neighbours_list) - 1].append( (self.points[i], i)) neighbour_ = 1 else: neighbour_ = 0 if not neighbours_list: return no_of_intersections % 2 if neighbours_list[0][0][1] == 0 and neighbours_list[-1][-1][1] == len( self.points) - 1: neighbours_list[0] = neighbours_list[-1] + neighbours_list[0] neighbours_list.pop(-1) for i in range(len(neighbours_list)): no_of_intersections -= len(neighbours_list[i]) - 1 for i in range(len(neighbours_list)): first_point = self.points[neighbours_list[i][0][1] - 1] second_point = self.points[(neighbours_list[i][ (len(neighbours_list[i]) - 1)][1] + 1) % len(self.points)] if (point.return_x() - first_point.return_x()) * ( second_point.return_x() - point.return_x()) > 0: no_of_intersections -= 1 return no_of_intersections % 2