The blob is a polyhedron whose faces are called ‘facets’ here.
This code subdivides each of the 20 faces of an icosahedron into n2 triangles.
This results in VN = 10n2+2 vertices whose coordinates are recorded in array q, and SN = 20n2 triangles each terminating its own sliver.
q[j] holds coordinates for vertex j.
Q[j] holds indices for the 3 vertices that bound sliver j.
L[3j], L[3j+1] & L[3j+2] provide link space for sliver j.
Chain flows thru L.
m[j] is the mass of sliver j.
For each vertex v we often need to visit each sliver that v bounds. Each chain link is an index into L, or –1 which ends the chain. The head of the chain for vertex k is in h[k]. The link following k is in L[k]. If the chain rooted in h[i] includes 3k+j and 0⩽j<3 then sliver k includes vertex i. The chain provides each sliver index by following the chain rooted in h and linked thru L. This requires a bit of combinatorial topology.
det(p, q, r) returns the determinant of three P vectors.
sph() initializes a Bucky ball and returns n.
nv takes an integer identifying a facet and returns the vector which is the normal to that facet.
centr(j, q) returns the location of the center of facet j.
add & sub return the sum and difference of two vectors.
ip returns the inner (dot) product of two vectors (Pt’s).
R det(Pt a, Pt b, Pt c) returns the determinant of the three vectors.
rf() returns a random float distributed uniformly between 0 and 1.
len(Pt x) returns the length of its argument.
sm(R s, Pt b) returns the product of scalar s and vector b.
cp returns the cross product of two vectors.
prP prints an annotated vector.
R moments(R m1[3], R m2[3][3]) returns moment 0 (the mass) and puts moments 1 and 2 into the two arguments.
puff takes a vertex index and returns the vector sum of the impinging faces. This routine illustrates how the information in h and L may be used to find the facets about a vertex. If that information is needed elsewhere we may abstract this logic.
There is now code in main of fac.c to compute moments of the blob, m0, m1 & m2. This code can be moved to a routine when we learn when we want to compute these moments.
This code is awkward because C does not pass an array of three R’s by value so I must use type Pt. But I can’t get the math right without tensor notation. Pt a2Pt(R m[3]) turns an array into a Pt and void Pt2a(R a[3], Pt p) stores a Pt into the array a.
This version tries to be cache savvy and keep k*6 floats in cache to avoid 20*n4 cache misses each evaluation of surface potentials.
The constant k affects cache efficiency but not the results.
I chose k as 10 for my Mac.
rm(char *, m0, m1, m2) merely prints moments 0, 1 and 2.
matrot(m) rotates the vertices about the origin by matrix m.
a2Pt and Pt2a convert between structure Pt and an array of 3 reals.
A performance hack?