예제 #1
0
 def test_defined_segment_correctly(self) -> None:
     """
     Segment Data Structure Normal Case Test
     :return: None
     """
     segment: Segment = Segment(Point(0.1, 0.2), Point(0.3, 0.4))
     self.assertEqual(segment.p1.x, 0.1)
     self.assertEqual(segment.p1.y, 0.2)
     self.assertEqual(segment.p2.x, 0.3)
     self.assertEqual(segment.p2.y, 0.4)
 def test_get_distance_sp_normal(self):
     p_l: Point = Point(-1, -1)
     p_r: Point = Point(1, 1)
     s: Segment = Segment(p_l, p_r)
     p_1: Point = Point(-2, -2)
     p_2: Point = Point(0, 1)
     p_3: Point = Point(2, 2)
     self.assertEqual(equals(get_distance_sp(s, p_1), (p_1 - p_l).abs()),
                      True)
     self.assertEqual(equals(get_distance_sp(s, p_2), 1.0 / math.sqrt(2)),
                      True)
     self.assertEqual(equals(get_distance_sp(s, p_3), (p_3 - p_r).abs()),
                      True)
 def test_intersect_normal(self):
     s_1: Segment = Segment(Point(0, 0), Point(3, 0))
     s_2: Segment = Segment(Point(1, 1), Point(2, -1))
     s_3: Segment = Segment(Point(3, 1), Point(3, -1))
     s_4: Segment = Segment(Point(3, -2), Point(5, 0))
     self.assertEqual(intersect(s_1, s_2), True)
     self.assertEqual(intersect(s_1, s_3), True)
     self.assertEqual(intersect(s_1, s_4), False)
 def test_get_distance_ss_normal(self):
     s_0: Segment = Segment(Point(0, 0), Point(2, 2))
     s_1: Segment = Segment(Point(-3, -3), Point(-1, -1))
     s_2: Segment = Segment(Point(0, -3), Point(1, -2))
     s_3: Segment = Segment(Point(0, 2), Point(2, 0))
     self.assertEqual(equals(get_distance_ss(s_0, s_1), math.sqrt(2)), True)
     self.assertEqual(equals(get_distance_ss(s_0, s_2), math.sqrt(5)), True)
     self.assertEqual(equals(get_distance_ss(s_0, s_3), 0), True)
 def test_is_parallel_normal(self):
     # Vector
     v_1: Vector = Vector(1.0, 1.0)
     v_2: Vector = Vector(2.0, 2.0)
     self.assertEqual(is_parallel(v_1, v_2), True)
     # Points
     p_1: Point = Point(1.0, 1.0)
     p_2: Point = Point(2.0, 2.0)
     p_3: Point = Point(-1.0, -1.0)
     p_4: Point = Point(-2.0, -2.0)
     self.assertEqual(is_parallel(p_1, p_2, p_3, p_4), True)
     # Segments
     s_1: Segment = Segment(p_1, p_2)
     s_2: Segment = Segment(p_3, p_4)
     self.assertEqual(is_parallel(s_1, s_2), True)
예제 #6
0
 def test_defined_point_correctly(self) -> None:
     """
     Point Data Structure Normal Case Test
     :return: None
     """
     for i in range(-1, 2):
         for j in range(-1, 2):
             point: Point = Point(i * 1.0, j * 1.0)
             self.assertEqual(point.x, i * 1.0)
             self.assertEqual(point.y, j * 1.0)
             if i == -1:
                 self.assertEqual(point < Point(0, 0), True)
             elif i == 0:
                 self.assertEqual(point < Point(0, 0), j == -1)
             else:
                 self.assertEqual(point < Point(0, 0), False)
def get_num_of_segment_intersections(segments: List[Segment]) -> int:
    """
    Get Number of Segment Intersections (Manhattan Geometry)
    :param segments: Segment List
    :return: Number of Segment Intersections
    """
    n: int = len(segments)
    k: int = 0
    ep: List[EndPoint] = [
        EndPoint(Point(i, i), i, EndPointType.BOTTOM) for i in range(2 * n)
    ]
    for i in range(n):
        if segments[i].p1.y == segments[i].p2.y:
            if segments[i].p1.x > segments[i].p2.x:
                segments[i].p1, segments[i].p2 = segments[i].p2, segments[i].p1
        elif segments[i].p1.y > segments[i].p2.y:
            segments[i].p1, segments[i].p2 = segments[i].p2, segments[i].p1

        if segments[i].p1.y == segments[i].p2.y:
            ep[k] = EndPoint(Point(segments[i].p1.x, segments[i].p1.y), i,
                             EndPointType.LEFT)
            k += 1
            ep[k] = EndPoint(Point(segments[i].p2.x, segments[i].p2.y), i,
                             EndPointType.RIGHT)
            k += 1
        else:
            ep[k] = EndPoint(Point(segments[i].p1.x, segments[i].p1.y), i,
                             EndPointType.BOTTOM)
            k += 1
            ep[k] = EndPoint(Point(segments[i].p2.x, segments[i].p2.y), i,
                             EndPointType.TOP)
            k += 1
    ep.sort()

    bt: List[int] = []  # Binary Tree of Intersect Point x-coordinate value
    cnt: int = 0
    for j in range(2 * n):
        if ep[j].st == EndPointType.TOP:
            bt.remove(ep[j].p.x)
        elif ep[j].st == EndPointType.BOTTOM:
            bisect.insort(bt, ep[j].p.x)
        elif ep[j].st == EndPointType.LEFT:
            left: int = bisect.bisect_left(bt, segments[ep[j].seg].p1.x)
            right: int = bisect.bisect_right(bt, segments[ep[j].seg].p2.x)
            cnt += right - left
    return cnt
 def test_get_cross_point_normal(self):
     s_1: Segment = Segment(Point(0, 0), Point(1, 1))
     s_2: Segment = Segment(Point(0, 1), Point(1, 0))
     s_3: Segment = Segment(Point(1, 0), Point(0, 1))
     s_4: Segment = Segment(Point(0, 1), Point(1, 2))
     self.assertEqual(equals(get_cross_point(s_1, s_2).x, 0.5), True)
     self.assertEqual(equals(get_cross_point(s_1, s_2).y, 0.5), True)
     self.assertEqual(equals(get_cross_point(s_1, s_3).x, 0.5), True)
     self.assertEqual(equals(get_cross_point(s_1, s_3).y, 0.5), True)
     self.assertIsNone(get_cross_point(s_1, s_4))
예제 #9
0
 def test_defined_circle_correctly(self) -> None:
     """
     Circle Data Structure Normal Case Test
     :return: None
     """
     circle: Circle = Circle(Point(0.5, 0.7), 3.5)
     self.assertEqual(circle.c.x, 0.5)
     self.assertEqual(circle.c.y, 0.7)
     self.assertEqual(circle.r, 3.5)
def get_cross_points_circle_and_line(circle: Circle,
                                     line: Line) -> Optional[List[Point]]:
    """
    Calculate Line and Circle Cross Point Coordinate Values
    :param circle: Circle
    :param line: Line
    :return: Cross Point or Contact Point
    """
    res: List[Point] = []
    d: float = get_distance_lp(line, circle.c)
    if circle.r - d > EPS:
        p: Point = project(line, circle.c)
        e: float = math.sqrt(math.pow(circle.r, 2.0) - math.pow(d, 2.0))
        v_base: Vector = Vector((line.p2 - line.p1).x, (line.p2 - line.p1).y)
        x_1: Vector = Vector(p.x, p.y) + v_base * e / v_base.abs()
        x_2: Vector = Vector(p.x, p.y) - v_base * e / v_base.abs()
        res.append(Point(x_1.x, x_1.y))
        res.append(Point(x_2.x, x_2.y))
        return res
    elif equals(circle.r, d):
        res.append(project(line, circle.c))
        return res
    return None
def get_common_points_circle_and_circle(c_1: Circle,
                                        c_2: Circle) -> Optional[List[Point]]:
    """
    Calculate Two Circle Common Points
    :param c_1: One Circle
    :param c_2: The Other Circle
    :return: None: Not Intersect or Duplicate, List[Point] : Contacts or Intersects
    """
    d: float = (c_1.c - c_2.c).abs()  # Distance Between Circle Centers
    res: List[Point] = []
    if c_1.c == c_2.c and equals(c_1.r, c_2.r) \
            or c_1.r + c_2.r < d or abs(c_1.r - c_2.r) > d:
        # Completely Duplicates or Not Contacts and Intersects
        return None
    if equals(c_1.r + c_2.r, d) or equals(abs(c_1.r - c_2.r), d):
        # Contacts Each Other
        c_larger: Circle = c_1 if c_1.r >= c_2.r else c_2
        c_smaller: Circle = c_1 if c_1.r < c_2.r else c_2
        v_c1_c2: Vector = Vector((c_smaller.c - c_larger.c).x,
                                 (c_smaller.c - c_larger.c).y)
        x_c: Vector = Vector(c_larger.c.x,
                             c_larger.c.y) + v_c1_c2 * (c_larger.r / d)
        res.append(Point(x_c.x, x_c.y))
    if abs(c_1.r - c_2.r) < d < c_1.r + c_2.r:
        # Intersects
        t: float = (math.pi / 2.0 if c_1.c.y < c_2.c.y else -math.pi / 2.0)\
            if c_1.c.x == c_2.c.x \
            else math.atan(abs((c_2.c - c_1.c).y / (c_2.c - c_1.c).x))
        alpha: float = \
            math.acos((c_1.r * c_1.r + d * d - c_2.r * c_2.r) / (2 * c_1.r * d))
        v_1: Vector = Vector(c_1.c.x, c_1.c.y) + \
            Vector(c_1.r * math.cos(t + alpha), c_1.r * math.sin(t + alpha))
        v_2: Vector = Vector(c_1.c.x, c_1.c.y) + \
            Vector(c_1.r * math.cos(t - alpha), c_1.r * math.sin(t - alpha))
        res.append(Point(v_1.x, v_1.y))
        res.append(Point(v_2.x, v_2.y))
    return res
 def test_get_point_relative_position_normal(self):
     p_0: Point = Point(0, 0)
     p_1: Point = Point(2, 0)
     self.assertEqual(get_point_relative_position(p_0, p_1, Point(-1, 1)),
                      PointRelativePosition.COUNTER_CLOCK_WISE)
     self.assertEqual(get_point_relative_position(p_0, p_1, Point(-1, -1)),
                      PointRelativePosition.CLOCK_WISE)
     self.assertEqual(get_point_relative_position(p_0, p_1, Point(-1, 0)),
                      PointRelativePosition.ON_LINE_BACK)
     self.assertEqual(get_point_relative_position(p_0, p_1, Point(3, 0)),
                      PointRelativePosition.ON_LINE_FRONT)
     self.assertEqual(get_point_relative_position(p_0, p_1, Point(1, 0)),
                      PointRelativePosition.ON_SEGMENT)
 def test_point_contained_in_polygon(self):
     poly: Polygon = Polygon(
         [Point(0, 0), Point(3, 1),
          Point(2, 3), Point(0, 3)])
     p_1: Point = Point(2, 1)
     self.assertEqual(point_contained_in_polygon(poly, p_1),
                      PointContainsInPolygon.IN)
     p_2: Point = Point(0, 2)
     self.assertEqual(point_contained_in_polygon(poly, p_2),
                      PointContainsInPolygon.ON_EDGE)
     p_3: Point = Point(3, 2)
     self.assertEqual(point_contained_in_polygon(poly, p_3),
                      PointContainsInPolygon.OUT)
def get_cross_point(s_1: Segment, s_2: Segment) -> Optional[Point]:
    """
    Calculate Segment Cross Point
    :param s_1: One Segment
    :param s_2: The Other Segment
    :return: Cross Point Coordinate Value if intersects
    """
    if intersect(s_1, s_2):
        v_base: Vector = Vector((s_2.p2 - s_2.p1).x, (s_2.p2 - s_2.p1).y)
        v_hypo1: Vector = Vector((s_1.p1 - s_2.p1).x, (s_1.p1 - s_2.p1).y)
        v_hypo2: Vector = Vector((s_1.p2 - s_2.p1).x, (s_1.p2 - s_2.p1).y)
        v: Vector = Vector((s_1.p2 - s_1.p1).x, (s_1.p2 - s_1.p1).y)
        d1: float = abs(v_base.cross(v_hypo1))
        d2: float = abs(v_base.cross(v_hypo2))
        p: Vector = Vector(s_1.p1.x, s_1.p1.y) + v * (d1 / (d1 + d2))
        return Point(p.x, p.y)
    return None
 def test_get_convex_hull_normal(self):
     poly: Polygon = Polygon([
         Point(2, 1),
         Point(0, 0),
         Point(1, 2),
         Point(2, 2),
         Point(4, 2),
         Point(1, 3),
         Point(3, 3)
     ])
     res: Polygon = get_convex_hull(poly)
     self.assertEqual(5, len(res.p_i))
     x_expected: List[float] = [0, 2, 4, 3, 1]
     y_expected: List[float] = [0, 1, 2, 3, 3]
     for i in range(5):
         self.assertTrue(equals(res.p_i[i].x, x_expected[i]))
         self.assertTrue(equals(res.p_i[i].y, y_expected[i]))
 def test_get_cross_point_line_and_circle(self):
     c_0: Circle = Circle(Point(1, 1), 2)
     l_1: Line = Line(Point(0, -2), Point(1, -2))
     l_2: Line = Line(Point(0, -1), Point(1, -1))
     l_3: Line = Line(Point(0, 0), Point(1, 0))
     self.assertIsNone(get_cross_points_circle_and_line(c_0, l_1))
     self.assertEqual(len(get_cross_points_circle_and_line(c_0, l_2)), 1)
     self.assertTrue(
         equals(get_cross_points_circle_and_line(c_0, l_2)[0].x, 1.0))
     self.assertTrue(
         equals(get_cross_points_circle_and_line(c_0, l_2)[0].y, -1.0))
     self.assertEqual(len(get_cross_points_circle_and_line(c_0, l_3)), 2)
     self.assertTrue(
         equals(
             get_cross_points_circle_and_line(c_0, l_3)[0].x,
             1 + math.sqrt(3)))
     self.assertTrue(
         equals(
             get_cross_points_circle_and_line(c_0, l_3)[1].x,
             1 - math.sqrt(3)))
 def test_get_common_points_circle_and_circle_normal(self):
     c_1: Circle = Circle(Point(0, 0), 2.0)
     c_2: Circle = Circle(Point(2.0, 0), 2.0)
     # Intersects Case
     res: List[Point] = get_common_points_circle_and_circle(c_1, c_2)
     self.assertEqual(len(res), 2)
     self.assertTrue(equals(res[0].x, 2.0 * 1.0 / 2.0))
     self.assertTrue(equals(res[0].y, 2.0 * math.sqrt(3.0) / 2.0))
     self.assertTrue(equals(res[1].x, 2.0 * 1.0 / 2.0))
     self.assertTrue(equals(res[1].y, -2.0 * math.sqrt(3.0) / 2.0))
     c_2_1: Circle = Circle(Point(0, 2.0), 2.0)
     res = get_common_points_circle_and_circle(c_1, c_2_1)
     self.assertEqual(len(res), 2)
     self.assertTrue(equals(res[0].x, -2.0 * math.sqrt(3.0) / 2.0))
     self.assertTrue(equals(res[0].y, 2.0 * 1.0 / 2.0))
     self.assertTrue(equals(res[1].x, 2.0 * math.sqrt(3.0) / 2.0))
     self.assertTrue(equals(res[1].y, 2.0 * 1.0 / 2.0))
     c_2_2: Circle = Circle(Point(2.0, 2.0), 2.0)
     res = get_common_points_circle_and_circle(c_1, c_2_2)
     self.assertEqual(len(res), 2)
     self.assertTrue(equals(res[0].x, 0))
     self.assertTrue(equals(res[0].y, 2.0))
     self.assertTrue(equals(res[1].x, 2.0))
     self.assertTrue(equals(res[1].y, 0))
     # Contacts Case
     c_3: Circle = Circle(Point(4.0, 0), 2.0)
     res = get_common_points_circle_and_circle(c_1, c_3)
     self.assertEqual(len(res), 1)
     self.assertTrue(equals(res[0].x, 2.0))
     self.assertTrue(equals(res[0].y, 0))
     # Not Intersects and Contacts Case
     c_4: Circle = Circle(Point(5.0, 0), 2.0)
     res = get_common_points_circle_and_circle(c_1, c_4)
     self.assertIsNone(res)
     c_5: Circle = Circle(Point(1.0, 0), 0.5)
     res = get_common_points_circle_and_circle(c_1, c_5)
     self.assertIsNone(res)
     # Completely Duplicates Case
     res = get_common_points_circle_and_circle(c_1, c_1)
     self.assertIsNone(res)
 def test_project_normal(self):
     seg: Segment = Segment(Point(0, 0), Point(3, 4))
     p: Point = Point(2, 5)
     self.assertEqual(equals(project(seg, p).x, 3.12), True)
     self.assertEqual(equals(project(seg, p).y, 4.16), True)
 def test_get_distance_lp_normal(self):
     l: Line = Line(Point(0, 0), Point(1, 1))
     p: Point = Point(0.5, 0)
     self.assertEqual(equals(get_distance_lp(l, p), 0.5 / math.sqrt(2)),
                      True)
 def test_get_distance_normal(self):
     p_1: Point = Point(0, 0)
     p_2: Point = Point(1, 1)
     self.assertEqual(equals(get_distance(p_1, p_2), math.sqrt(2.0)), True)
 def test_reflect_normal(self):
     seg: Segment = Segment(Point(0, 0), Point(3, 4))
     p: Point = Point(2, 5)
     self.assertEqual(equals(reflect(seg, p).x, 4.24), True)
     self.assertEqual(equals(reflect(seg, p).y, 3.32), True)
 def test_get_num_of_segment_intersections_normal(self):
     segments: List[Segment] = [
         Segment(Point(2, 2), Point(2, 5)),
         Segment(Point(1, 3), Point(5, 3)),
         Segment(Point(4, 1), Point(4, 4)),
         Segment(Point(5, 2), Point(7, 2)),
         Segment(Point(6, 1), Point(6, 3)),
         Segment(Point(6, 5), Point(6, 7))
     ]
     self.assertEqual(3, get_num_of_segment_intersections(segments))