-
Notifications
You must be signed in to change notification settings - Fork 1
/
plane.py
130 lines (102 loc) · 4.06 KB
/
plane.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
from decimal import Decimal, getcontext
from line import MyDecimal
from vector import Vector
getcontext().prec = 30
class Plane(object):
def __init__(self, normal_vector=None, constant_term=None):
if not normal_vector:
all_zeros = ['0'] * 2
normal_vector = Vector(all_zeros)
self.normal_vector = Vector([Decimal(x) for x in normal_vector])
self.dimension = self.normal_vector.dimension
if not constant_term:
constant_term = Decimal('0')
self.constant_term = Decimal(constant_term)
self.basepoint = None
self.set_basepoint()
def set_basepoint(self):
n = self.normal_vector
c = self.constant_term
basepoint_coordinates = ['0'] * self.dimension
initial_index = Plane.first_nonzero_index(n)
if initial_index is None:
self.basepoint = None
else:
initial_coefficient = n[initial_index]
basepoint_coordinates[initial_index] = c / Decimal(initial_coefficient)
self.basepoint = Vector(basepoint_coordinates)
def __eq__(self, other):
"""
Are planes equal?
:param Plane other: The other plane
:return Bool: True if planes are equal otherwise false
"""
are_zero_vectors = self.normal_vector.is_zero_vector() and other.normal_vector.is_zero_vector()
if are_zero_vectors:
return self.constant_term == other.constant_term
return self.normal_vector == other.normal_vector and self.constant_term == other.constant_term
def __str__(self):
num_decimal_places = 3
def write_coefficient(coefficient, is_initial_term=False):
coefficient = round(coefficient, num_decimal_places)
if coefficient % 1 == 0:
coefficient = int(coefficient)
result = ''
if coefficient < 0:
result += '-'
if coefficient > 0 and not is_initial_term:
result += '+'
if not is_initial_term:
result += ' '
if abs(coefficient) != 1:
result += '{}'.format(abs(coefficient))
return result
n = self.normal_vector
initial_index = Plane.first_nonzero_index(n)
if initial_index is None:
output='0'
else:
terms = [write_coefficient(n[i], is_initial_term=(i == initial_index)) + 'x_{}'.format(i + 1)
for i in range(self.dimension) if round(n[i], num_decimal_places) != 0]
output = ' '.join(terms)
constant = round(self.constant_term, num_decimal_places)
if constant % 1 == 0:
constant = int(constant)
output += ' = {}'.format(constant)
return output
def are_parallel(self, other):
"""
Are the 2 Planes parallel?
:param Plane other:
:return Bool: True if the Planes are parallel
"""
return self.normal_vector.are_parallel(other.normal_vector)
def are_equal(self, other):
"""
Are the 2 Planes equal?
:param Plane other:
:return Boolean: True if the Planes are equal
"""
if not self.are_parallel(other):
return False
p1 = self.get_point_on_plane()
p2 = other.get_point_on_plane()
vp = Vector([p1[0] - p2[0], p1[1] - p2[1]])
return vp.are_orthogonal(self.normal_vector) and vp.are_orthogonal(other.normal_vector)
@staticmethod
def first_nonzero_index(iterable):
for k, item in enumerate(iterable):
if not MyDecimal(item).is_near_zero():
return k
return None
def get_point_on_plane(self):
first_nonzero_index = Plane.first_nonzero_index(self.normal_vector)
if first_nonzero_index is None:
return 0, 0, 0
result = []
for k, item in enumerate(self.normal_vector):
if k == first_nonzero_index:
result.append(self.constant_term / item)
else:
result.append(0)
return tuple(result)