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_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))
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 is_parallel(*args) -> Optional[bool]: """ Parallel Judgement :param args: Two Vectors or Four Points or Two Segments :return: Optional[bool] """ len_args: int = len(args) if len_args == 2: if isinstance(args[0], Vector): v_1: Vector = args[0] v_2: Vector = args[1] elif isinstance(args[0], Segment): s_1: Segment = args[0] s_2: Segment = args[1] v_1 = Vector((s_1.p1 - s_1.p2).x, (s_1.p1 - s_1.p2).y) v_2 = Vector((s_2.p1 - s_2.p2).x, (s_2.p1 - s_2.p2).y) else: raise TypeError("Error: Argument Type Error") elif len_args == 4: if isinstance(args[0], Point): p_1: Point = args[0] p_2: Point = args[1] p_3: Point = args[2] p_4: Point = args[3] v_1 = Vector((p_1 - p_2).x, (p_1 - p_2).y) v_2 = Vector((p_3 - p_4).x, (p_3 - p_4).y) else: raise TypeError("Error: Argument Type Error") else: raise TypeError("Error: Argument Error") return equals(v_1.cross(v_2), 0.0)
def point_contained_in_polygon(poly: Polygon, p: Point) -> PointContainsInPolygon: """ Calculate Is Point Contained in Polygon :param poly: Polygon :param p: Point :return: PointContainsInPolygon """ n: int = len(poly.p_i) # Number of Nodes of Polygon count_intersect: int = 0 for i in range(n): a: Point = poly.p_i[i] - p b: Point = poly.p_i[(i + 1) % n] - p v_1: Vector = Vector(a.x, a.y) v_2: Vector = Vector(b.x, b.y) if v_1.dot(v_2) < 0 and equals(v_1.cross(v_2), 0): return PointContainsInPolygon.ON_EDGE if a.y > b.y: a, b = b, a v_1 = Vector(a.x, a.y) v_2 = Vector(b.x, b.y) if a.y < EPS < b.y and v_1.cross(v_2) > EPS: count_intersect += 1 return PointContainsInPolygon.IN \ if count_intersect % 2 == 1 else PointContainsInPolygon.OUT
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 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 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 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_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_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)