''' Module for regular icosahedron.
.. codeauthor:: Yoshifumi Futaana
Regular icosahedron is is a regular polyhedron with 20
idenical equilateral triangle.
Thre are 30 edges with 12 vertices.
'''
import math
import numpy as np
from irfpy.util import triangle
[docs]class RegularIcosahedron():
''' Class of regular icosahedron.
'''
def __init__(self, radius=None, edgeLength=None):
''' Instance the regular icosahedron.
Instances the regular icosahedron.
Parameter radius specifies the raidus of a circumsribed sphere.
>>> ic = RegularIcosahedron()
>>> print(ic.radius)
1.0
>>> print('%.5f' % ic.edgeLength)
1.05146
>>> ic = RegularIcosahedron(radius = 3.5)
>>> edgeLen = ic.edgeLength
>>> ic = RegularIcosahedron(edgeLength = edgeLen)
>>> print('%.1f' % ic.radius)
3.5
'''
if edgeLength is None:
if radius is None:
radius = 1.0
self.radius = radius
self.edgeLength = self.radius * 4 / math.sqrt(
10 + 2 * math.sqrt(5))
else:
if radius is None:
self.radius = edgeLength * math.sqrt(
10 + 2 * math.sqrt(5)) / 4.
self.edgeLength = edgeLength
else:
raise RuntimeError("RegularIcosahedron::__init__() can have " +
"only one keyword either radius or edgeLength.")
[docs] def numberEdges(self):
''' Get the number of edges, i.e. 30.
>>> ico = RegularIcosahedron()
>>> print(ico.numberEdges())
30
'''
return 30
[docs] def numberVertices(self):
''' Return the number of vertices, i.e. 12.
>>> ico = RegularIcosahedron()
>>> print(ico.numberVertices())
12
'''
return 12
[docs] def getArea(self):
r''' Get the surface area (in total of 20 faces).
The surface area is calculated as 5\sqrt(3)a^2 where
a is the edge length.
>>> ico = RegularIcosahedron(radius=5)
>>> print('%.2f' % ico.getArea())
239.36
>>> print('%.3f' % (ico.getArea() / ( 4. * math.pi * 5 * 5)))
0.762
'''
return 5 * math.sqrt(3) * (self.edgeLength ** 2)
[docs] def getVolume(self):
r''' Get the volume.
The volume is calculated as (3+\sqrt(5)) * 5/12 * a^3
where a is the edge length.
>>> ico = RegularIcosahedron(radius=3)
>>> print('%.2f' % ico.getVolume())
68.48
>>> sphere = 4. / 3. * math.pi * 3 * 3 * 3
>>> print('%.3f' % (ico.getVolume() / sphere))
0.605
'''
return (3 + math.sqrt(5)) * 5. / 12. * (self.edgeLength ** 3)
[docs] def getVertices(self):
''' Returns the 12 coordinates for vertices and the indexes to connect.
Vertices have 12 elements.
Connection has 20 elements.
>>> ic = RegularIcosahedron()
>>> v, p = ic.getVertices()
>>> len(v)
12
>>> len(p)
20
'''
from math import cos, sin
r = 2 / math.sqrt(5)
h = 1 / math.sqrt(5)
rad36 = 36. * math.pi / 180.
v = []
v.append(np.array([0, 0, 1]) * self.radius)
for ang in range(5):
v.append(np.array([r * cos(rad36 * 2 * ang),
r * sin(rad36 * 2 * ang), h]) * self.radius)
for ang in range(5):
v.append(np.array([r * cos(rad36 * (1 + 2 * ang)),
r * sin(rad36 * (1 + 2 * ang)), -h]) * self.radius)
v.append(np.array([0, 0, -1]) * self.radius)
### Connection is the pair of indexes to be connected.
pair = (
(0, 1, 2),
(0, 2, 3),
(0, 3, 4),
(0, 4, 5),
(0, 5, 1),
(1, 6, 2),
(2, 6, 7),
(2, 7, 3),
(3, 7, 8),
(3, 8, 4),
(4, 8, 9),
(4, 9, 5),
(5, 9, 10),
(5, 10, 1),
(1, 10, 6),
(6, 11, 7),
(7, 11, 8),
(8, 11, 9),
(9, 11, 10),
(10, 11, 6),
)
return v, pair
[docs] def getTriangles(self):
''' Returns the instance of :class:`irfpy.util.triangle.Triangle`.
All the triangles will have normal vectors pointing outward.
'''
vert, pair = self.getVertices()
tris = []
for v0, v1, v2 in pair:
tris.append(triangle.Triangle(vert[v0], vert[v1], vert[v2]))
return tuple(tris)
[docs] def getNpTriangles(self):
''' Returns the instance of :class:`irfpy.util.triangle.NpTriangle`.
All the triangles will have normal vectors pointing outward.
'''
vert, pair = self.getVertices()
tris = []
for v0, v1, v2 in pair:
tris.append(triangle.NpTriangle(vert[v0], vert[v1], vert[v2]))
return tuple(tris)
[docs] def getTriangleLinks(self):
''' Returns a link of triangles.
'''
link = ((1, 4, 5), #0
(2, 0, 7),
(3, 1, 9),
(4, 2, 11),
(0, 3, 13),
(6, 0, 14), #5
(7, 5, 15),
(8, 1, 6),
(9, 7, 16),
(10, 2, 8),
(11, 9, 17), #10
(12, 3, 10),
(13, 11, 18),
(14, 4, 12),
(5, 13, 19),
(6, 19, 16), #15
(8, 15, 17),
(10, 16, 18),
(12, 17, 19),
(14, 18, 15))
return np.array(link)
import unittest
import doctest
[docs]def doctests():
return unittest.TestSuite((
doctest.DocTestSuite(),
))
if __name__ == '__main__':
unittest.main(defaultTest='doctests')