Tuesday, April 24, 2012

surface subdivision adjusted by curvature




this script does all we were shown in class+ a little extra something
it caculates the curvatures of the surface and shifts all the points closer to the point with the highest curvature. 


import rhinoscriptsyntax as rs
import math

### get the surface, filter =8 ensures that only surfaces can be selected
base =rs.GetObject(message = "please select surface", filter= 8)

### find out the UV domains in order to scale later
uDom= rs.SurfaceDomain(base,0)
vDom= rs.SurfaceDomain(base,1)
uScale = uDom[1]-uDom[0]
vScale = vDom[1]-vDom[0]

### number if subdivisions
uDiv=10
vDiv=10


points = []
curvatures = []
UVs= []

for u in range(uDiv+1):
    ### we store the data in three matrixes with the same structure
    ### that way we can use the u and v indexes to find the right elements
    uPoints =[]
    uCurvatures = []
    uUVs=[]
    ###u/uDiv provides a number between 0 to 1,
    ###multiplying it by uScale fits it to the surface domain, this works similiarly to the frange, but in  a different way
    uP = u/uDiv*uScale
    for v in range (vDiv+1):
        vP = v/vDiv*vScale
        pt = rs.EvaluateSurface(base,uP,vP)
        uPoints.append(pt)
        curv=rs.SurfaceCurvature(base,(uP,vP))
        maxCurv = curv[2]
        ### max curvature should always be a positive value
        if maxCurv<0 : maxCurv=maxCurv*(-1)
        uCurvatures.append(maxCurv)
        uUVs.append((uP,vP))
    ### now we have all three matrixs assembeled
    points.append(uPoints)
    curvatures.append(uCurvatures)
    UVs.append(uUVs)


tempMax =0
maxX=0
maxY=0
### this loop finds the indexes of the point with the maximum curvature
for x in range(1,uDiv):
    for y in range(1,vDiv):
        if curvatures[x][y]>tempMax:
            tempMax = curvatures[x][y]
            maxX=x
            maxY=y

maxPoint= points[maxX][maxY]
### new matrix, again with the same structre, with the distance between all
### points and the point with the maximum curvature
distances =[]
for u in range (uDiv+1):
    uDist=rs.Distance(maxPoint, points[u])
    distances.append(uDist)


###parameters for the amount of shifting
moveDist = 3
power=.2

### in this loop we first change the UV values of the points (so they will always
### remain on the surface) and then we recalculate the points xyz values
for u in range(1,uDiv):
    for v in range(1,vDiv):
        if distances[u][v] > 0:
            ### uDir shows if the point is below or above the center point
            ### so we can tell which direction to shift the points
            uDir = 0
            vDir = 0
            if maxX < u : uDir=(-1)
            if maxX > u : uDir=1
            if maxY < v : vDir = (-1)
            if maxY >v : vDir = 1
            ### by using a combination of the moveDist and pow parameters the amount of move can be
            ### adjusted to fit the size of the surface and the sensitivity to the distance
            newU = UVs[u][v][0]+uDir*(moveDist/math.pow(distances[u][v],power))
            newV = UVs[u][v][1]+vDir*(moveDist/math.pow(distances[u][v],power))
            UVs[u][v] = (newU,newV)
            points[u][v] = rs.EvaluateSurface(base,newU,newV)

rs.EnableRedraw(False)

for i in range(uDiv):
    for j in range(vDiv):
        rs.AddSrfPt([points[i][j],points[i+1][j],points[i+1][j+1],points[i][j+1]])

rs.EnableRedraw(True)

No comments:

Post a Comment