import numbers
import math
#all interior are less than 180 degree
#all sides have equal length
#apothem: goes from the center of the polygon to the middle of the edge
#circumradius: goes from the midpoint of the polygon to the edge of the circle
#n edges (= n vettices)
#R circumradius
#formula
#interior angle: (n - 2)*180/n
#edge length: S = 2R sin(pi/n)
#apothem: a = R cos(pi/n)
#area: 1/2nsa
#perimeter: ns
#Goal 1: Create a Polygon class
#Initializer: number of edges/vertices, circumradius
#Properties: edges, vertices; calculated properties: interior angle, edge length, apothem, area, perimeter
#Functionality: a proper representation (__repr__), implements equality (==) based on vertices and circumradius(__eq__),
# implements > based on number of vertices only (__gt__)
#Goal 2: Implement a Polygon sequence type
#Initializer: number of vertices for largest polygon in the sequence
# common circumradius for all polygons
#Properties: max efficiency polygon: returns the polygon with the highest area:perimeter ration
#Functionality: functions as a sequence type(__getitem__), supports the len() function(__len__)
class Polygon:
def __init__(self, n, R):
if isinstance(n, numbers.Real) and isinstance(R, numbers.Real):
self._R = R
self._n = n
def __repr__(self):
return f'Polygon(n={self._n}, R={self._R})'
@property
def count_vertices(self):
return self._n
@property
def count_edges(self):
return self._n
@property
def circumradius(self):
return self._R
@property
def interior_angle(self):
return (self._n - 2) * 180 / self._n
@property
def side_length(self):
return 2* self._R * math.sin(math.pi / self._n)
@property
def apothem(self):
return self._R * math.cos(math.pi / self._n)
@property
def area(self):
return self._n / 2 * self.side_length * self.apothem
@property
def perimeter(self):
return self._n * self.side_length
def test_polygon():
n = 4
R = 1
p = Polygon(n, R)
assert str(p) == f'Polygon(n=4, R=1)', f'actual: {str(p)}'
assert p.count_vertices == n, (f'actual: {p.count_vertices}, '
f'expected: {n}' )
assert p.count_edges == n
assert p.circumradius == R
assert p.interior_angle == 90
assert p.area == 2.0, (f'actual: {p.area}, '
f'expexted: {2.0}')
test_polygon()
don’t ever compare floats.
1.0 + 1.0 + 1.0 == 3.0
#False
#The resolution: math.iscolse
!!! Be careful for Polygon at least needs 3 sides as a triangle.
p = Polygon(1, 10)
# No Error!!!
Goal 2
import math
class Polygon:
def __init__(self, n, R):
if n < 3:
raise ValueError('Polygon must have at lease 3 sides.')
self._R = R
self._n = n
def __repr__(self):
return f'Polygon(n={self._n}, R={self._R})'
@property
def count_vertices(self):
return self._n
@property
def count_edges(self):
return self._n
@property
def circumradius(self):
return self._R
@property
def interior_angle(self):
return (self._n - 2) * 180 / self._n
@property
def side_length(self):
return 2 * self._R * math.sin(math.pi / self._n)
@property
def apothem(self):
return self._R * math.cos(math.pi / self._n)
@property
def area(self):
return self._n / 2 * self.side_length * self.apothem
@property
def perimeter(self):
return self._n * self.side_length
def __eq__(self, other):
if isinstance(other, self.__class__): #if isinstance(other, Polygon) this way works fine
return (self.count_edges == other.count_edges
and self.circumradius == other.circumradius) #self._n == other._n is this way works fine
else:
return NotImplemented
def __gt__(self, other):
if isinstance(other, Polygon):
return self.count_vertices > other.count_vertices
else:
return NotImplemented
#---------------------Goal 2 start line----------------------------
class Polygons:
def __init__(self, m, R):
if m < 3:
raise ValueError('m must be greater than 3')
self._m = m
self._R = R
self._polygons = [Polygon(i, R) for i in range(3, m+1)]
def __len__(self):
return self._m - 2
def __repr__(self):
return f'Polygons(m={self._m}, R={self._R})'
def __getitem__(self, s):
return self._polygons[s]
@property
def max_efficiency_polygon(self):
sorted_polygons = sorted(self._polygons,
key=lambda p: p.area / p.perimeter,
reverse=True)
return sorted_polygons[0]
# for p in polygons:
# print(p)
# for p in polygons[2:5]:
# print(p)
# for p in polygons[::-1]:
# print(p)
# print(polygons.max_efficiency_polygon)
# print([(p, p.area/p.perimeter) for p in polygons])
polygons = Polygons(500, 1)
p = polygons.max_efficiency_polygon
print(p.area)
assert math.isclose(p.area, math.pi, rel_tol= 0.001, abs_tol=0.001)
#True