0

I am trying to map surface curvature (mean, gaussian and principle curvature) values to surface faces. I have computed the curvature values for an artificially generated 3D surface (eg. cylinder). The resulting 3D surface that I am trying to get is something like this mean curvature mapped to surface. Can somebody guide me in how to get this?

The code for the surface I am creating is:

import math
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

xindex = []
yindex = []
zindex = []
x = []
y = []
z = []
count = 1
surfaceSt = []
import numpy
numpy.set_printoptions(threshold=numpy.nan)
#surfaceStX = numpy.empty((10,36))
#surfaceStY = numpy.empty((10,36))
#surfaceStZ = numpy.empty((10,36))
surfaceStZ  = []
surfaceStX = []
surfaceStY = []
for i in range(1,21):
    if i < 11:
        x = []
        y = []
        z = []
        pt = []
        ptX = []
        ptY = []
        ptZ = []
        for t in range(0,360,10):
            x = i*math.sin(math.radians(t))
            y = i*math.cos(math.radians(t))
            z = i-1
            ptX.append(x)
            ptY.append(y)
            ptZ.append(z)
            pt.append([x,y,z])
        ptX.append(ptX[0])
        ptY.append(ptY[0])
        ptZ.append(ptZ[0])
        surfaceStX.append(ptX)
        surfaceStY.append(ptY)
        surfaceStZ.append(ptZ)
#        numpy.append(surfaceStX,ptX)
#        numpy.append(surfaceStY,ptY)
#        numpy.append(surfaceStZ,ptZ)
    

        #ax.scatter(x,y,z)
    elif i >= 11:
        x = []
        y = []
        z = []
        pt = []
        ptX = []
        ptY = []
        ptZ = []
        for t in range(0,360,10):
            x = (i-count)*math.sin(math.radians(t))
            y = (i-count)*math.cos(math.radians(t))
            z = i-1
            ptX.append(x)
            ptY.append(y)
            ptZ.append(z)
            pt.append([x,y,z])
        ptX.append(ptX[0])
        ptY.append(ptY[0])
        ptZ.append(ptZ[0])
        surfaceStX.append(ptX)
        surfaceStY.append(ptY)
        surfaceStZ.append(ptZ)
        count +=2
        
        

X = numpy.array(surfaceStX)
Y = numpy.array(surfaceStY)
Z = numpy.array(surfaceStZ)

ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,shade = 'True' )
from surfaceCurvature import surface_curvature
Pcurvature,Gcurvature,Mcurvature = surface_curvature(X,Y,Z)
plt.show()

My surface curvature computation is given below (courtesy: https://github.com/sujithTSR/surface-curvature):

    def surface_curvature(X,Y,Z):

 (lr,lb)=X.shape

 #print lr
 #print "awfshss-------------"
 #print lb
#First Derivatives
 Xv,Xu=np.gradient(X)
 Yv,Yu=np.gradient(Y)
 Zv,Zu=np.gradient(Z)

#Second Derivatives
 Xuv,Xuu=np.gradient(Xu)
 Yuv,Yuu=np.gradient(Yu)
 Zuv,Zuu=np.gradient(Zu)   

 Xvv,Xuv=np.gradient(Xv)
 Yvv,Yuv=np.gradient(Yv)
 Zvv,Zuv=np.gradient(Zv) 

#2D to 1D conversion 
#Reshape to 1D vectors
 Xu=np.reshape(Xu,lr*lb)
 Yu=np.reshape(Yu,lr*lb)
 Zu=np.reshape(Zu,lr*lb)
 Xv=np.reshape(Xv,lr*lb)
 Yv=np.reshape(Yv,lr*lb)
 Zv=np.reshape(Zv,lr*lb)
 Xuu=np.reshape(Xuu,lr*lb)
 Yuu=np.reshape(Yuu,lr*lb)
 Zuu=np.reshape(Zuu,lr*lb)
 Xuv=np.reshape(Xuv,lr*lb)
 Yuv=np.reshape(Yuv,lr*lb)
 Zuv=np.reshape(Zuv,lr*lb)
 Xvv=np.reshape(Xvv,lr*lb)
 Yvv=np.reshape(Yvv,lr*lb)
 Zvv=np.reshape(Zvv,lr*lb)

 Xu=np.c_[Xu, Yu, Zu]
 Xv=np.c_[Xv, Yv, Zv]
 Xuu=np.c_[Xuu, Yuu, Zuu]
 Xuv=np.c_[Xuv, Yuv, Zuv]
 Xvv=np.c_[Xvv, Yvv, Zvv]

# First fundamental Coeffecients of the surface (E,F,G)
 
 E=np.einsum('ij,ij->i', Xu, Xu) 
 F=np.einsum('ij,ij->i', Xu, Xv) 
 G=np.einsum('ij,ij->i', Xv, Xv) 

 m=np.cross(Xu,Xv,axisa=1, axisb=1) 
 p=np.sqrt(np.einsum('ij,ij->i', m, m)) 
 n=m/np.c_[p,p,p]

# Second fundamental Coeffecients of the surface (L,M,N), (e,f,g)
 L= np.einsum('ij,ij->i', Xuu, n) #e
 M= np.einsum('ij,ij->i', Xuv, n) #f
 N= np.einsum('ij,ij->i', Xvv, n) #g


# Gaussian Curvature
 K=(L*N-M**2)/(E*G-F**2)
 K=np.reshape(K,lr*lb)

# Mean Curvature
 H = (E*N + G*L - 2*F*M)/((E*G - F**2))
 H = np.reshape(H,lr*lb)

# Principle Curvatures
 Pmax = H + np.sqrt(H**2 - K)
 Pmin = H - np.sqrt(H**2 - K)
#[Pmax, Pmin]
 Principle = [Pmax,Pmin]
 return Principle,K,H

EDIT 1:

I tried a few things based on the link provided by armatita. Following is my code:

    '''
    Creat half cylinder
    '''
    import numpy
    import matplotlib.pyplot as plt
    import math
    ptX= []
    ptY = []
    ptZ = []
    ptX1 = []
    ptY1 = []
    ptZ1 = []
    for i in range(0,10):
        x = []
        y = []
        z = []
        for t in range(0,200,20):
            x.append(10*math.cos(math.radians(t)))
            y.append(10*math.sin(math.radians(t)))
            z.append(i)
            x1= 5*math.cos(math.radians(t))
            y1 = 5*math.sin(math.radians(t))
            z1 = i
            ptX1.append(x1)
            ptY1.append(y1)
            ptZ1.append(z1)
        ptX.append(x)
        ptY.append(y)
        ptZ.append(z)

    X = numpy.array(ptX)
    Y = numpy.array(ptY)
    Z = numpy.array(ptZ)     

    fig = plt.figure()
    ax = fig.add_subplot(111,projection = '3d')
    from surfaceCurvature import surface_curvature
    p,g,m= surface_curvature(X,Y,Z)
    n = numpy.reshape(m,numpy.shape(X))
    ax.plot_surface(X,Y,Z, rstride=1, cstride=1)
    plt.show()

    '''
    Map mean curvature to color
    '''
    import numpy as np
    X1 = X.ravel()
    Y1 = Y.ravel()
    Z1 = Z.ravel()

    from scipy.interpolate import RectBivariateSpline
    

    # Define the points at the centers of the faces:
    y_coords, x_coords = np.unique(Y1), np.unique(X1)
    y_centers, x_centers = [ arr[:-1] + np.diff(arr)/2 for arr in (y_coords,      x_coords)]

    # Convert back to a 2D grid, required for plot_surface:
    #Y1 = Y.reshape(y_coords.size, -1)
    #X1 = X.reshape(-1, x_coords.size)
    #Z1 = Z.reshape(X.shape)
    C = m.reshape(X.shape)

    C -= C.min()
    C /= C.max()
    interp_func = RectBivariateSpline(x_coords, y_coords, C.T, kx=1, ky=1)
I get the following error:
raise TypeError('y dimension of z must have same number of y')
TypeError: y dimension of z must have same number of elements as y

All the dimensions are same. Can anybody tell what's going wrong with my implementation?

  • You can map a variable to color (your function is returning at least 3). Check this link: http://stackoverflow.com/questions/36614456/how-do-i-color-individual-sections-of-a-3d-sphere-in-python/36616730#36616730 – armatita Apr 28 '16 at 13:12
  • thanks for the comment. I tried what you suggested and edited the post. I still can't get it to work. Anymore help is much appreciated. – Gaurav Kaila May 01 '16 at 10:43

1 Answers1

0

I think you need to figure out exactly what you need. Looking at your code I notice you are producing variables that have no use. Also you seem to have a function to calculate the surface curvature but than you try to make some calculations using the np.unique function for which I cannot see the purpose here (and that is why that error appears).

So let's assume this:

  • You have a function that returns the curvature value for each cell.
  • You have the X,Y and Z meshes to plot that surface.

Using your code, and assuming you m variable is the curvature (again this is in your code), if I do this:

import numpy
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import math

# Here would be the surface_curvature function

X = numpy.array(ptX)
Y = numpy.array(ptY)
Z = numpy.array(ptZ)   
p,g,m= surface_curvature(X,Y,Z)
C = m.reshape(X.shape)

C -= C.min()
C /= C.max() 

fig = plt.figure()
ax = fig.add_subplot(111,projection = '3d')
n = numpy.reshape(m,numpy.shape(X))
ax.plot_surface(X,Y,Z,facecolors = cm.jet(C), rstride=1, cstride=1)
plt.show()

, I obtain this:

Value mapped to color in matpotlib surface

Which is a value mapped to color in a matplotlib surface. If that C you've built is not the actual curvature you need to replace it by the one that is.

armatita
  • 12,825
  • 8
  • 48
  • 49