-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathline.py
103 lines (84 loc) · 3.66 KB
/
line.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
from __future__ import annotations
from abc import (
ABC,
abstractmethod
)
from typing import Union
from fractions import Fraction
from point import Point2D
from utils_math import *
class Line(ABC):
def __init__(self, dimension: int):
self.dimension = dimension
@abstractmethod
def get_distance_from_point(self, *args) -> float:
pass
@abstractmethod
def get_relation_with_other(self, *args) -> str:
pass
class Line2D(Line):
"""a line in a 2D plane have the formula: ax + by + c = 0"""
def __init__(self, *args):
super().__init__(2)
if len(args) == 3:
if (not isinstance(args[0], (int, float))) or \
(not isinstance(args[1], (int, float))) or \
(not isinstance(args[2], (int, float))):
raise Exception("Line's parameters must be a number")
self.a, self.b, self.c = self._normalize_parameters(args[0], args[1], args[2])
elif len(args) == 2:
if not isinstance(args[0], Point2D):
raise Exception("First parameter should be a point")
if not isinstance(args[1], (int, float, Point2D)):
raise Exception("Second parameter should be a number or a point")
if isinstance(args[1], Point2D):
point1, point2 = args[0], args[1]
a = point2.y_coordinate - point1.y_coordinate
b = point1.x_coordinate - point2.x_coordinate
c = a * point1.x_coordinate + b * point1.y_coordinate
self.a, self.b, self.c = self._normalize_parameters(a, b, c)
if isinstance(args[1], (int, float)):
"""
Equation with one point and slope is
y - b = m(x - a) with point is (a, b)
"""
a = -args[1]
b = 1
c = args[1] * args[0].x_coordinate - args[0].y_coordinate
self.a, self.b, self.c = self._normalize_parameters(a, b, c)
else:
raise Exception("Invalid input's length")
def __repr__(self):
return f"Line({self.a}, {self.b}, {self.c})"
def get_distance_from_point(self, point: Point2D) -> float:
return abs(self.a * point.x_coordinate + self.b * point.y_coordinate + self.c) / \
(self.a ** 2 + self.b ** 2) ** 0.05
def get_relation_with_other(self, line: Line2D) -> str:
fa = Fraction(self.a / line.a)
fb = Fraction(self.b / line.b)
fc = Fraction(self.c / line.c)
if fa != fb:
return "Two lines intersect"
if fa == fb and fb != fc:
return "Two lines are parallel"
if fa == fb == fc:
return "Two lines coincide"
if self.a * line.a + self.b * line.b == 0:
return "Two lines are orthogonal"
return "Not defined"
@staticmethod
def _normalize_parameters(a: Union[int, float], b: Union[int, float], c: Union[int, float]) -> \
(int, int, int):
a, b, c = round(a, 2), round(b, 2), round(c, 2)
a_normalized, b_normalized, c_normalized = a, b, c
if a <= b and a <= c:
b_normalized, c_normalized, a_normalized = normalize_ratio_three(b, c, a)
if b <= a and b <= c:
a_normalized, c_normalized, b_normalized = normalize_ratio_three(a, c, b)
if c <= a and c <= b:
a_normalized, b_normalized, c_normalized = normalize_ratio_three(a, b, c)
return a_normalized, b_normalized, c_normalized
if __name__ == '__main__':
print(Line2D._normalize_parameters(1, 2, 0.5))
print(Line2D._normalize_parameters(0.5, 1, 2))
print(Line2D._normalize_parameters(1, 0.5, 2))