Ridley5 opened this issue on Jul 26, 2010 · 1724 posts
odf posted Wed, 11 August 2010 at 4:33 AM
Now this is getting silly. Thanks to the puzzler that kawecki gave me, I've been massaging the normal computation code even further, and this is the result:
def
compute_normals(self):<br></br>
verts = self.verts<br></br>
polys =
self.geom.Polygons()<br></br>
sets =
self.geom.Sets()<br></br><br></br>
normals =
num.zeros([self.nr_verts, 3], "double")<br></br><br></br>
for i, p in
enumerate(polys):<br></br>
start = p.Start()<br></br>
indices = sets[start : start + p.NumVertices()]<br></br><br></br>
p = num.take(verts, indices)<br></br>
q = rotate_rows(p, -1)<br></br>
n = num.sum(p * rotate_columns(q, -1) - q * rotate_columns(p,
-1))<br></br>
n = n / num.sqrt(num.dot(n, n))<br></br><br></br>
for v in indices:<br></br>
normals[v] += n<br></br><br></br>
self.normals =
normalize_rows(rotate_columns(normals, -1))<br></br>
What kawecki reminded me of is that instead of summing up over the cross products of consecutive edge vectors, one can just use consecutive vertex positions. I've never really understood why that worked, but now I do. Also, all the adding and normalizing doesn't care whether I have the columns in the wrong order (as long as they are all in the same wrong order, obviously), so I could simply pull the outer rotate_columns() call in the line that computes the cross product (hint: it's that really long one) out of the loop.
This also seems quite a bit faster than the previous version.
For completeness, here are the necessary imports and helper methods:
import Numeric as
num<br></br><br></br>
def rotate_rows(a, i):<br></br>
indices = range(len(a))<br></br>
return num.take(a, indices[-i:] +
indices[:-i])<br></br><br></br>
def rotate_columns(a, i):<br></br>
indices = range(len(a[0]))<br></br>
return num.take(a, indices[-i:] + indices[:-i],
1)<br></br><br></br>
def normalize_rows(a):<br></br>
norms = num.sqrt(num.sum(num.transpose(a *
a)))<br></br>
return a /
num.transpose([norms])<br></br>
Come to think of it, I might just as well inline those methods now, since rotate_columns() is the only one that's called more than once, and I always have three columns, anyway.
-- I'm not mad at you, just Westphalian.