Am trying to compute the midpoints of each triangle edges of an icosahedron to get an icosphere which is the composion of an icosahedron subdivided in 6 or more levels. i tried to calculate the newly created vertices of each edges but some points wore missing. I tried to normalize each mid point but still the points woren't evenly spread out and some points wore missing.
import matplotlib.pyplot as plt
import numpy as np
num_points = 12
indices = np.arange(0, num_points, dtype='float')
r = 1
vertices = [ [0.0, 0.0, -1.0], [0.0, 0.0, 1.0] ] # poles
# icosahedron
for i in range(num_points):
theta = np.arctan(1 / 2) * (180 / np.pi) # angle 26 degrees
phi = np.deg2rad(i * 72)
if i >= (num_points / 2):
theta = -theta
phi = np.deg2rad(36 + i * 72)
x = r * np.cos(np.deg2rad(theta)) * np.cos(phi)
y = r * np.cos(np.deg2rad(theta)) * np.sin(phi)
z = r * np.sin(np.deg2rad(theta))
vertices.append([x, y, z])
vertices = np.array(vertices)
Icosahedron:

# Triangle Subdivision
for _ in range(2):
for j in range(0, len(vertices), 3):
v1 = vertices[j]
v2 = vertices[j + 1]
v3 = vertices[j + 2]
m1_2 = ((v1 + v2) / 2)
m2_3 = ((v2 + v3) / 2)
m1_3 = ((v1 + v3) / 2)
m1_2 /= np.linalg.norm(m1_2)
m2_3 /= np.linalg.norm(m2_3)
m1_3 /= np.linalg.norm(m1_3)
vertices = np.vstack([vertices, m1_2, m2_3, m1_3,])
print(vertices)
plt.figure().add_subplot(projection='3d').scatter(vertices[:, 0], vertices[:, 1], vertices[:, 2])
plt.show()
icosphere attempt:

I used this as reference to create an icosahedron https://www.songho.ca/opengl/gl_sphere.html
and what am expecting to achive is this:
Geodesic polyhedro:

I tried debugging the subdivision of each edges and it performed well:
import numpy as np
import matplotlib.pyplot as plt
vertices = [[1, 1], [2, 3], [3, 1]]
vertices = np.array(vertices)
for j in range(2):
for i in range(0, len(vertices), 3):
v1 = vertices[i]
v2 = vertices[i + 1]
v3 = vertices[i + 2]
m1_2 = (v1 + v2) / 2
m1_3 = (v1 + v3) / 2
m2_3 = (v2 + v3) / 2
vertices = np.vstack([vertices, m1_2, m1_3, m2_3])
plt.figure().add_subplot().scatter(vertices[:, 0], vertices[:, 1])
plt.plot(vertices[:, 0], vertices[:, 1], '-ok')
plt.show()
Midpoints of each edgeL


Pardon the JavaScripty answer (because that's easier for showing things off in the answer itself =), and the "cabinet projection", which is a dead simple way to turn 3D into 2D but it'll look "strangly squished" (unless you're playing an isometric platformer =)
Icosahedrons are basically fully defined by their edge length, so once you've decided on that one value, everything else is locked in, and you can generate your 12 icosahedron points pretty easily. In your case, if we stand the icosahedron on a "pole" at
(0,0,0), then its height is defined by the edge length as:(Or if we want maximum fives,
h = edge * ((5 + 5 ** 0.5) * 0.5) ** 0.5)And we can generate two rings of 5 vertices each, one ring at height
h1 = edge * sqrt(1/2 - 1 / (2 * sqrt(5)));, spaced at 2π/5 angular intervals, and then the other at heighth2 = h - h1(no need to do additional "real" math!) with the same angular intervals, but offset by π/5.That gives us this:
(mouse-over that graphic for more precise 3D rotational control)
To then find all the midpoints, we could do a lot of maths, but why bother: we can just linearly interpolate between points:
So adding that to the previous graphic:
(And again, mouse-over that graphic to get a better 3D feel)
That still leaves "normalizing" each newly derived vertex so that it lies on the same sphere that the original icosahedral vertices, by scaling it relative to the center as the icosahedron, with a new length equal to half the distance to our poles (i.e., the same as every vertex in our original icosahedron):
So that really only leaves the "tedious" job of linking up all our edges... let's add
scaleToSphereto the previous code, with a newdrawIcosaspheronfunction that draws all our edges:Of course, if you want to keep going, the manual edge-building is silly, but since we're building rings of vertices, we (and by "we" of course I mean "you" ;) can write our point generation to be a little smarter and automatically "merge" all new points on a ring into that same ring, so that edge building is a matter of starting with "five edges from the bottom pole to first ring", then iterating over each higher ring so that it cross-connects all points to the previous ring (as well as adding all edges of the ring itself, of course) until we reach the top pole, which just needs five edges to the ring below it.