# Copyright Tony Kaap 2008 # regularSphere.py # This script can be used for any legal purpose as long as this attribution # remains intact. #example usages: #import geodesic #reload(geodesic) #geodesic.checkFaceDistribution() #import maya.cmds as m #import geodesic #reload(geodesic) #for n in range(5): # smoothing iterations # for i in range(5): # types # print "I: " + str(i) # o2 = geodesic.geodesicSolid(n,i) # m.move(3*i,0,3*n,o2) import maya.cmds as m # n - number of division steps to take # type - which type of platonic solid to start with. (only types 1 and 2 are # effective here.) # # 0 - Dodecahedron -- poke faces # 1 - Icosahedron (already works) # 2 - Octahedon ( already works) # 3 - Tetrahedron (move +y 0.354*radius) UnitSphere scaled up to 1.061 circumscribes this. # 4 - Cube def geodesicSolid(n,type=1,obj=None): if (type < 0 or type > 4): print "Error: Select a type value between 0 and 4:" return if(type < 4): obj = m.polyPlatonicSolid( r=1, st=type)[0] #tetrahedron -- needs extra work to get it centered properly if type == 3: # since Maya does not start the tetrahedron with its true center at the # origin, and since the calculated bounding box for it is based off of # the axes, and not well suited for its singular shape, I move the # object to the world origin, then combine it with a large sphere # with the same center, will forces the sculpt deformer to accurately # deform the tetrahedral points into a true geodesic shape. m.move(0, 0.354,0, obj, r=1) tObj = m.polyCube(w=n*2, d=n*2, h=n*2)[0] obj = m.polyUnite(obj,tObj)[0] else: #cube! obj = m.polyCube(w=1,d=1,h=1)[0] if(type ==0 or type ==4): m.polyPoke(obj, ws=1, tx=0, ty=0, tz=0, ch=1) print "using " +obj m.select(obj) # preparation steps to make the various solids easier to "geodesize" for i in range(n): print i # This is an alternate method to smoothing. I'm not sure which is better, # since the results are very close. I'll keep it here in case it # becomes clearly better later. #numEdges = m.polyEvaluate(obj,e=1) #m.select(obj+".e[0:"+str(numEdges-1)+"]") #m.polySubdivideEdge(obj+".e[0:"+str(numEdges-1)+"]", ws=0, s=0, dv=1) #numEdges *=2 #m.polyTriangulate (obj+".e[0:"+str(numEdges-1)+"]"); #m.select(obj) m.polySmooth(obj,mth=1,dv=1,c=1, suv=1,peh=0,sl=1,dpe=1, ps=0.1, ro=1,ch=1) m.sculpt(obj,mode="stretch", insideMode="even", maxDisplacement=0, dropoffType="linear", dropoffDistance=1, groupWithLocator=0, objectCentered=1) m.delete(obj,ch=1) # shink the non-final steps, so that the subsequent sculpt deformer # will stretch the shape properly if i != n-1: m.scale(0.75, 0.75, 0.75,obj) m.makeIdentity(obj, apply=1, t=1,r=1,s=1,n=0) if (type == 3): # clean-up tetrahedron objList = m.polySeparate(obj) #print objList m.delete(objList[1:2]) obj = objList[0] m.delete(obj,ch=1) return obj # this is a more general case if you want to perform the geodesic operation # on some non-standard geometry. # def geodesize(n=1,obj=None): if not obj: obj = m.ls(sl=1)[0] for i in xrange(n): m.polySmooth(obj,mth=1,dv=1,c=1, suv=1,peh=0,sl=1,dpe=1, ps=0.1, ro=1,ch=1) m.sculpt(obj,mode="stretch", insideMode="even", maxDisplacement=0, dropoffType="linear", dropoffDistance=1, groupWithLocator=0, objectCentered=1) m.delete(obj,ch=1) if i != n-1: m.scale(0.75, 0.75, 0.75,obj) m.makeIdentity(obj, apply=1, t=1,r=1,s=1,n=0) m.select(obj) return obj # This is a script to check how regular of an object is created. It starts with # the surface area of each face, then finds the average, min, and max face size. # The closer the avg, min, and max are together, the more regular the surface is. # Because the polyEvaluate -area command only works on separate mesh objects, # you need to run 'extract' with 'keep faces together turned off', then select the resulting individual objects. before running this. def checkFaceDistribution(): list = m.ls(sl=1) print "number of objects selected: " + str(len(list)) if len(list) == 0: print "checkFaceDistribution: select some face-objects to check!" return sum = 0 min = 1000 minIndex = -1 max = 0; maxIndex = -1 index = 0 for face in list: area = m.polyEvaluate(face, area=1) sum += area if area > max: max = area maxIndex = index if area < min: min = area minIndex = index index += 1 avg = sum / len(list) maxPercent = max / avg minPercent = min / avg print "total= %(sumNum)1.5f" % {'sumNum':sum} print 'max = %(maxNum)1.5f - %(maxIndexNum)d - %(maxPercentNum)1.2f%%' %{'maxNum':max, 'maxIndexNum':maxIndex, 'maxPercentNum':maxPercent} print 'min = %(minNum)1.5f - %(minIndexNum)d - %(minPercentNum)1.2f%%' %{'minNum':min, 'minIndexNum':minIndex, 'minPercentNum':minPercent} print "average = %(avgNum)1.5f"% {'avgNum':avg} # # 0: # number of objects selected: 20 # total= 9.57454 # max = 0.47873 - 3 - 1.00% # min = 0.47873 - 8 - 1.00% # average = 0.47873 # # 1: # number of objects selected: 80 # total= 14.11578 # max = 0.20013 - 18 - 1.13% # min = 0.16855 - 55 - 0.96% # average = 0.17645 # # 2: # number of objects selected: 320 # total= 14.91912 # max = 0.05531 - 250 - 1.19% # min = 0.04360 - 318 - 0.94% # average = 0.04662 # # 3: # number of objects selected: 1280 # total= 15.13286 # max = 0.01420 - 42 - 1.20% # min = 0.01099 - 1034 - 0.93% # average = 0.01182 # # 4: # number of objects selected: 5120 # total= 15.18714 # max = 0.00358 - 426 - 1.21% # min = 0.00275 - 298 - 0.93% # average = 0.00297 # # 5: # number of objects selected: 20480 # total= 15.20076 # max = 0.00090 - 10922 - 1.21% # min = 0.00069 - 16554 - 0.93% # average = 0.00074 # #