| 1 | # Color selected surface pieces by mean curvature.
|
|---|
| 2 | #
|
|---|
| 3 | # Gray at the average curvature value over the surface, and blue and red
|
|---|
| 4 | # at +/- 3 standard deviations of curvature values across the surface.
|
|---|
| 5 | #
|
|---|
| 6 | # The curvature is estimated from the vertices and normals of the triangulated
|
|---|
| 7 | # surface in simple way which will show artifacts from non-isotropic meshes.
|
|---|
| 8 | # For each triangle edge it computes the normal vector rotation from one vertex
|
|---|
| 9 | # to the other divided by the edge length. The vertex mean curvature is the
|
|---|
| 10 | # mean of the curvatures computed for each edge.
|
|---|
| 11 | #
|
|---|
| 12 |
|
|---|
| 13 | def color_by_curvature(p):
|
|---|
| 14 | k = vertex_mean_curvatures(p)
|
|---|
| 15 | r = 1.0/k
|
|---|
| 16 | print ('radius min %.4g, max %.4g, mean %.4g, std %.4g'
|
|---|
| 17 | % (r.min(), r.max(), r.mean(), r.std()))
|
|---|
| 18 |
|
|---|
| 19 | km = k.mean()
|
|---|
| 20 | cval = (km - 3*k.std(), km, km + 3*k.std())
|
|---|
| 21 | # Colors are red, green, blue, opacity in range 0 to 1.
|
|---|
| 22 | low_color, mean_color, high_color = (0,0,1,1),(.7,.7,.7,1),(1,0,0,1) # blue, gray, red
|
|---|
| 23 | colors = (low_color, mean_color, high_color)
|
|---|
| 24 | above_color = below_color = (1,1,0,1)
|
|---|
| 25 | import SurfaceColor
|
|---|
| 26 | rgba = SurfaceColor.interpolate_colormap(k, cval, colors, low_color, high_color)
|
|---|
| 27 | p.vertexColors = rgba
|
|---|
| 28 |
|
|---|
| 29 | def vertex_mean_curvatures(p):
|
|---|
| 30 | va, ta = p.geometry # Vertices and triangles
|
|---|
| 31 | na = p.normals
|
|---|
| 32 | nv, nt = len(va), len(ta)
|
|---|
| 33 | from numpy import zeros, float64
|
|---|
| 34 | k = zeros((nv,), float64) # Vertex curvatures
|
|---|
| 35 | c = zeros((nv,), float64) # Count of edges per vertex
|
|---|
| 36 | from math import acos, sqrt
|
|---|
| 37 | for t in range(nt):
|
|---|
| 38 | j0, j1, j2 = ta[t]
|
|---|
| 39 | for i0,i1 in ((j0,j1),(j1,j2),(j2,j0)):
|
|---|
| 40 | v0,v1 = va[i0],va[i1]
|
|---|
| 41 | n0,n1 = na[i0],na[i1]
|
|---|
| 42 | e = v1-v0 # vector between two vertices
|
|---|
| 43 | elen = sqrt((e*e).sum())
|
|---|
| 44 | e /= elen # Normalize edge length.
|
|---|
| 45 | da = acos((n0*e).sum()) - acos((n1*e).sum())
|
|---|
| 46 | k01 = da / elen
|
|---|
| 47 | k[i0] += k01
|
|---|
| 48 | k[i1] += k01
|
|---|
| 49 | c[i0] += 1
|
|---|
| 50 | c[i1] += 1
|
|---|
| 51 | k /= c
|
|---|
| 52 | return k
|
|---|
| 53 |
|
|---|
| 54 | import Surface
|
|---|
| 55 | plist = Surface.selected_surface_pieces()
|
|---|
| 56 | for p in plist:
|
|---|
| 57 | color_by_curvature(p)
|
|---|