diff --git a/.gitignore b/.gitignore index 3339914..c219973 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ build .coverage .pytest_cache/ htmlcov/ + diff --git a/features/SubdivisionSurface/CatmullClarkSubdivision.py b/features/SubdivisionSurface/CatmullClarkSubdivision.py new file mode 100644 index 0000000..508e09b --- /dev/null +++ b/features/SubdivisionSurface/CatmullClarkSubdivision.py @@ -0,0 +1,132 @@ +''' + This module uses Catmull Clark Subdivision + The interface is CatmullClarkSubdivision function +''' + +from relaxrender.triangle import Triangle,Triangles +from relaxrender.points import Point,Point3D +import numpy as np + +__author__="X-wenhao" + +''' + interface + param: + faces : [face,face,...] + face: [line,line,...] + line: [point,point] + point: Point + num:how many times you want to subdivide + return: + faces +''' +def CatmullClarkSubdivision(faces,num): + lines=[] + points=[] + face_to_lines={} + line_to_points={} + point_to_lines={} + line_to_faces={} + + for i in range(num): + lines,line_to_faces,face_to_lines=_build_index(faces) + #print(line_to_faces,face_to_lines) + points,point_to_lines,line_to_points=_build_index(lines) + #draw(face_to_lines,line_to_points,points) + #print("lines:",lines) + faces=_CatmullClarkSubdivision_in(faces,lines,points,face_to_lines,line_to_points,line_to_faces,point_to_lines) + return faces + +''' + to build index among face line and point + I design this function and try to form index after each division to reduce time,but fail +''' +def _build_index(faces): + lines=[] + face_to_lines={} + line_to_faces={} + for face_i in range(len(faces)): + face=faces[face_i] + face_to_lines[face_i]=[] + for line_i in range(len(faces[face_i])): + line=face[line_i] + if line not in lines: + lines.append(line) + line_to_faces[len(lines)-1]=[] + face_to_lines[face_i].append(lines.index(line)) + line_to_faces[lines.index(line)].append(face_i) + return lines,line_to_faces,face_to_lines + + + +''' + subdivide a model according to its points and faces + return points and faces after subdivision + + param: + faces : [face,face,...] + face: [line,line,...] + line: [point,point] + point: Point + return: + [points,faces] + + PS:this func is not designed as a interface +''' +def _CatmullClarkSubdivision_in(faces,lines,points,face_to_lines,line_to_points,line_to_faces,point_to_lines): + #print("old_points:",list((p.data[0],p.data[1],p.data[2]) for p in points)) + #print("face_to_lines:",face_to_lines) + #print("line_to_points:",line_to_points) + #print("line_to_faces:",line_to_faces) + #print("point_to_lines:",point_to_lines) + face_points=[] + for face in faces: + temp=[] + for l in face: + temp.append(l[0].data) + temp.append(l[1].data) + data=sum(temp)/2/len(face) + face_points.append(Point(p=Point3D.create(data))) + #print("face_points:",len(face_points),list((p.data[0],p.data[1],p.data[2]) for p in face_points)) + + edge_points=[] + + for i in range(len(lines)): + temp=[] + temp.append(face_points[line_to_faces[i][0]].data) + temp.append(face_points[line_to_faces[i][1]].data) + temp.append(points[line_to_points[i][0]].data) + temp.append(points[line_to_points[i][1]].data) + data=sum(temp)/4 + edge_points.append(Point(p=Point3D.create(data))) + #print("edge_points:",list((p.data[0],p.data[1],p.data[2]) for p in edge_points)) + + vertes_points=[] + for i in range(len(points)): + data1=np.array([0.0,0.0,0.0]) + data2=np.array([0.0,0.0,0.0]) + for j in point_to_lines[i]: + data1+=(lines[j][0].data+lines[j][1].data)/2.0/len(point_to_lines[i]) + data2+=(face_points[line_to_faces[j][0]].data+face_points[line_to_faces[j][1]].data)/2/len(point_to_lines[i]) + points[i].data=(data2+2*data1+(len(point_to_lines[i])-3)*points[i].data)/len(point_to_lines[i]) + #print("new_points:",list((p.data[0],p.data[1],p.data[2]) for p in points)) + + re_faces=[] + for i in range(len(face_points)): + tmp=[] + for j in face_to_lines[i]: + for k in line_to_points[j]: + if k not in tmp: + re_faces.append([]) + #print(point_to_lines[k],face_to_lines[i]) + eps=list(edge_points[p_i] for p_i in [m for m in point_to_lines[k] if m in face_to_lines[i]] ) + #print(eps) + for ep in eps: + re_faces[-1].extend([ [face_points[i],ep],[points[k],ep] ]) + tmp.append(k) + #print(len(re_faces),'\n',re_faces[0]) + return re_faces + + + + diff --git a/features/SubdivisionSurface/DOOSabinSubdivision.py b/features/SubdivisionSurface/DOOSabinSubdivision.py new file mode 100644 index 0000000..6487956 --- /dev/null +++ b/features/SubdivisionSurface/DOOSabinSubdivision.py @@ -0,0 +1,207 @@ +import numpy as np +from relaxrender.points import Point3D, Point + +# points_doos=list() +# points_current=list() + +''' +one point for another ones on the faces beside it +''' +# points_doos={} +current_points = [] +current_faces = [] +points_doos = [] + + +class Face: + def __init__(self, points): + self.points = points + + +""" + DOO_Sabin(faces,times): + input:faces(list) , subdivision times + output:new faces(list) + + + + faces :list of face + face : points : list of point +""" + +def DOO_Sabin(faces,times): + new_faces=[] + for f in faces: + n_f=Face(f) + new_faces.append(n_f) + for i in range(0,times): + _DOO_Sabin_single_time(new_faces) + return new_faces + + +# class points_doo: +# def __init__(self,main_point,points): +# self.main_point=main_point +# self.points=points +# def add_point(self,p): +# self.points.append(p) + +''' +def _change_faces(x_faces): + s_faces=[] + for f in x_faces: + new_points=[] + for l in f: + new_points.append(l[0]) + new_points.append(l[1]) + new_f=new_points + s_faces.append(new_f) + return s_faces +''' + + +def _DOO_Sabin_single_time(faces): + for f in faces: + f = _get_new_face(f) + for points_ds in points_doos: + new_face = Face(points_ds) + faces.append(new_face) + return faces + + +def _get_face_point(face): + face_point = _get_average_point(face.points) + return face_point + + +''' +for each point in a face, there would be a new point +''' + + +def _get_new_face(face): + face_point = _get_face_point(face) + new_face_points = [] + for p in face.points: + + ''' + _______global variables_______ + ''' + if p not in current_points: + current_points.append(p) + flag = True + else: + flag=False + + if face.points.index(p) == 0: + tmp1 = len(face.points) - 1 + tmp2 = face.points.index(p) + 1 + + elif face.points.index(p) == len(face.points) - 1: + tmp1 = face.points.index(p) - 1 + tmp2 = 0 + else: + tmp1 = face.points.index(p) - 1 + tmp2 = face.points.index(p) + 1 + + last_average_line = _get_average_point([p, face.points[tmp1]]) + next_average_line = _get_average_point([p, face.points[tmp2]]) + + new_face_point = _get_average_point([p, face_point, last_average_line, next_average_line]) + + new_face_points.append(new_face_point) + + # ''' + # append p's points + # ''' + # if points_doos.has_key(p): + # p_points = points_doos[p] + # p_points.append(new_face_point) + # ''' + # _______global variables_______ + # ''' + # points_doos[p] = p_points + # else: + # p_points=[new_face_point,] + # p_points.append(new_face_point) + # ''' + # _______global variables_______ + # ''' + # points_doos[p]=p_points + if flag: + points_doos.append([new_face_point, ]) + else: + points_doos[current_points.index(p)].append(new_face_point) + + face.points = new_face_points + new_face=Face(new_face_points) + return new_face + + +def _get_average_point(points): + x_sum = 0 + y_sum = 0 + z_sum = 0 + for p in points: + x_sum = x_sum + p.data[0] + y_sum = y_sum + p.data[1] + z_sum = z_sum + p.data[2] + Apoint = Point3D(x_sum / len(points), y_sum / len(points), z_sum / len(points)) + return Apoint + + +''' +def _print_point(p): + tmp = [p.data[0], p.data[1], p.data[2]] + print(tmp) + +def _print_face(f): + for p in f.points: + _print_point(p) + +def _print_points(ps): + for p in ps: + _print_point(p) + +def print_obj(faces): + i=0 + for f in faces: + i=i+1 + print("face",i) + _print_face(f) + +def _change_point(point,color): + new_point=Point(point) + new_point.color=color + return new_point +''' + + +""" +test: +input: cube's faces,6 times +output:new faces +""" +# if __name__ == '__main__': +# point_test_1 = Point3D(4, 4, 4) +# point_test_2 = Point3D(4, 4,0) +# point_test_3 = Point3D(4, 0, 4) +# point_test_4 = Point3D(4, 0, 0) +# point_test_5 = Point3D(0, 4, 4) +# point_test_6 = Point3D(0, 4, 0) +# point_test_7 = Point3D(0, 0, 4) +# point_test_8 = Point3D(0, 0, 0) +# face_test_1 = Face([point_test_1, point_test_2, point_test_3, point_test_4]) +# face_test_2 = Face([point_test_1, point_test_5, point_test_6, point_test_2]) +# face_test_3 = Face([point_test_1, point_test_5, point_test_7, point_test_3]) +# face_test_4 = Face([point_test_3, point_test_4, point_test_8, point_test_7]) +# face_test_5 = Face([point_test_5, point_test_6, point_test_8, point_test_7]) +# face_test_6 = Face([point_test_2, point_test_4, point_test_8, point_test_6]) +# faces_test=[face_test_1,face_test_2,face_test_3,face_test_4,face_test_5,face_test_6] +# _print_obj(DOO_Sabin(faces_test,6)) +# # points_test=[point_test_1,point_test_2,point_test_3,point_test_4] +# # face_test=Face(points_test) +# # _print_face(_get_new_face(face_test)) +# # for ps in points_doos: +# # _print_points(ps) +# diff --git a/features/SubdivisionSurface/LoopSubdivision.py b/features/SubdivisionSurface/LoopSubdivision.py new file mode 100644 index 0000000..83d79b6 --- /dev/null +++ b/features/SubdivisionSurface/LoopSubdivision.py @@ -0,0 +1,105 @@ +from math import * + + +def loop(vertices,faces): + ''' + input:vertices=[[x0,y0,z0],[x1,y1,z1]...],faces=[[index0,index1,index2]...] + output:new_vertices,new_face + + ''' + num_faces=len(faces) + num_vertices=len(vertices) + new_vertices=vertices+[[0,0,0]]*num_faces*3 + new_index_of_ver=num_vertices + edge_vertices=[] + new_faces=[] + + for i in range(num_vertices): + x=[] + for j in range(num_vertices): + x.append([0,0,0]) + edge_vertices.append(x) + + for f_i in range(0,num_faces): + va=faces[f_i][0] + vb=faces[f_i][1] + vc=faces[f_i][2] + vp,va,vb,vc,ev0,ev1,ev2,new_index_of_ver=_add_edge_vertices(va,vb,vc,edge_vertices,new_index_of_ver) + edge_vertices[va][vb][0]=ev0 + edge_vertices[va][vb][1]=ev1 + edge_vertices[va][vb][2]=ev2 + vq,va,vb,vc,ev0,ev1,ev2,new_index_of_ver=_add_edge_vertices(vb,vc,va,edge_vertices,new_index_of_ver) + edge_vertices[va][vb][0]=ev0 + edge_vertices[va][vb][1]=ev1 + edge_vertices[va][vb][2]=ev2 + vr,va,vb,vc,ev0,ev1,ev2,new_index_of_ver=_add_edge_vertices(va,vc,vb,edge_vertices,new_index_of_ver) + edge_vertices[va][vb][0]=ev0 + edge_vertices[va][vb][1]=ev1 + edge_vertices[va][vb][2]=ev2 + four_faces=[[va,vp,vr],[vp,vb,vq],[vr,vq,vc],[vr,vp,vq]] + new_faces=new_faces+four_faces + + + for v_i in range(0,num_vertices-1): + for v_j in range(v_i,num_vertices): + v_index=edge_vertices[v_i][v_j][0] + if(v_index!=0): + first_opposite_index_ver=edge_vertices[v_i][v_j][1] + second_opposite_index_ver=edge_vertices[v_i][v_j][2] + if(first_opposite_index_ver==0 or second_opposite_index_ver==0): + new_vertices[v_index]=[1.0/2*vertices[v_i][i]+1.0/2*vertices[v_j][i] for i in range(3)] + else: + new_vertices[v_index]= [(3/8*vertices[v_i][i]+3/8*vertices[v_j][i] \ + + 1/8*vertices[first_opposite_index_ver][i]+1/8*vertices[second_opposite_index_ver][i]) \ + for i in range(3)] + + adj_ver=[] + for ov_i in range(0,num_vertices): + x=[] + for ov_j in range(0,num_vertices): + if((ov_iov_j and edge_vertices[ov_j][ov_i][0]!=0)): + x.append(ov_j) + adj_ver.append(x) + + for ov in range (0,num_vertices): + k=len(adj_ver[ov]) + adj_boundary_ver=[] + for i in range(0,k): + ov_adj=adj_ver[ov][i] + if((ov_adj>ov and edge_vertices[ov][ov_adj][2]==0) or (ov_adjvb): + v_tmp = va + va = vb + vb = v_tmp + + edge_vertices_va_vb_0=edge_vertices[va][vb][0] + edge_vertices_va_vb_1=edge_vertices[va][vb][1] + edge_vertices_va_vb_2=edge_vertices[va][vb][2] + if (edge_vertices_va_vb_0==0): + edge_vertices_va_vb_0 = new_index_of_ver + edge_vertices_va_vb_1 = vc + new_index_of_ver = new_index_of_ver+1 + else: + edge_vertices_va_vb_2 = vc + + new_ver_index = edge_vertices_va_vb_0 + return new_ver_index,va,vb,vc,edge_vertices_va_vb_0,edge_vertices_va_vb_1,edge_vertices_va_vb_2,new_index_of_ver + + +#vertices = [[10,10,10],[-100,10,-10],[-100,-10,10],[10,-10,-10]] +#faces = [[0,1,2],[0,2,3],[0,3,1],[3,2,1]] + +#print(loop(vertices,faces)) \ No newline at end of file diff --git a/features/SubdivisionSurface/README.md b/features/SubdivisionSurface/README.md new file mode 100644 index 0000000..e956ee3 --- /dev/null +++ b/features/SubdivisionSurface/README.md @@ -0,0 +1,7 @@ +There are three different algorithms of subdivision surface in this package. +Anyone who wants to use it can choose one of them. + +The three algorithms are implemented by different people +and beacuse of this ,they have different interfaces . + +If you want to use them , you may have to read them first. diff --git a/features/SubdivisionSurface/__init__.py b/features/SubdivisionSurface/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/features/SubdivisionSurface/test_CatmullClarkSubdivision.py b/features/SubdivisionSurface/test_CatmullClarkSubdivision.py new file mode 100644 index 0000000..c4c3ee4 --- /dev/null +++ b/features/SubdivisionSurface/test_CatmullClarkSubdivision.py @@ -0,0 +1,94 @@ +""" + this module include function to draw,which is used during test + this module is also used to test CatmullClarkSubdivison +""" +import unittest +#from mpl_toolkits.mplot3d import Axes3D +#from mpl_toolkits.mplot3d.art3d import Poly3DCollection,Line3DCollection +#import matplotlib.pyplot as plt +import numpy as np +from relaxrender.points import Point,Point3D +from SubdivisionSurface.CatmullClarkSubdivision import _CatmullClarkSubdivision_in,_build_index,CatmullClarkSubdivision + +__author__="X-wenhao" + + +class TestCatmullClarkSubdivision(unittest.TestCase): + + + def test_CatmullClarkSubdivision(self): + + verts = [(0, 0, 0), (0, 1, 0), (1, 1, 0), (1, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1), (1, 0, 1)] + points=list(Point.create(np.array(list(v))) for v in verts) + + line_to = [[0,1],[1,2],[2,3],[3,0],[4,5],[5,6],[6,7],[7,4],[0,4],[1,5],[2,6],[3,7]] + face_to = [[0,1,2,3],[4,5,6,7],[0,4,8,9],[1,5,9,10],[2,6,10,11],[3,7,11,8]] + lines=[] + + for lt in line_to: + lines.append([]) + for i in lt: + lines[-1].append(points[i]) + + faces=[] + for ft in face_to: + faces.append([]) + for i in ft: + faces[-1].append(lines[i]) + + lines,line_to_faces,face_to_lines=_build_index(faces) + points,point_to_lines,line_to_points=_build_index(lines) + self.assertTrue(CatmullClarkSubdivision(faces,1)) + ''' + for i in range(4): + lines,line_to_faces,face_to_lines=_build_index(faces) + #print(line_to_faces,face_to_lines) + points,point_to_lines,line_to_points=_build_index(lines) + #draw(face_to_lines,line_to_points,points) + self.assertTrue(_CatmullClarkSubdivision_in(faces,lines,points,face_to_lines,line_to_points,line_to_faces,point_to_lines)) + faces=_CatmullClarkSubdivision_in(faces,lines,points,face_to_lines,line_to_points,line_to_faces,point_to_lines) + print('subdividing {},and there are {} faces now'.format(i+1,len(faces))) + ''' + + +''' +def draw(face_to_lines,line_to_points,points): + verts=list((p.data[0],p.data[1],p.data[2]) for p in points) + faces=[] + #print(face_to_lines,line_to_points) + for ftl in face_to_lines.values(): + faces.append([]) + faces[-1].extend(line_to_points[ftl[0]]) + tmp=[ftl[0]] + for i in range(2): + for ltp in ftl: + #print(ftl,ltp) + if ltp not in tmp and faces[-1][-1] in line_to_points[ltp]: + faces[-1].append(line_to_points[ltp][1-line_to_points[ltp].index(faces[-1][-1])]) + tmp.append(ltp) + #print(verts,'\n',faces) + + + poly3d = [[verts[vert_id] for vert_id in face] for face in faces] + # print(poly3d) + fig = plt.figure() + ax = fig.gca(projection='3d') + # 绘制顶点 + x, y, z = zip(*verts) + ax.scatter(x, y, z) + # 绘制多边形面 + ax.add_collection3d(Poly3DCollection(poly3d, facecolors='w', linewidths=1, alpha=0.3)) + # 绘制对变形的边 + ax.add_collection3d(Line3DCollection(poly3d, colors='k', linewidths=0.5, linestyles=':')) + + # 设置图形坐标范围 + ax.set_xlabel('X') + ax.set_xlim3d(-0.5, 1.5) + ax.set_ylabel('Y') + ax.set_ylim3d(-0.5, 1.5) + ax.set_zlabel('Z') + ax.set_zlim3d(-0.5, 1.5) + plt.show() +''' + + diff --git a/features/SubdivisionSurface/test_DOOSabinSubdivision.py b/features/SubdivisionSurface/test_DOOSabinSubdivision.py new file mode 100644 index 0000000..b99ed1f --- /dev/null +++ b/features/SubdivisionSurface/test_DOOSabinSubdivision.py @@ -0,0 +1,40 @@ +import unittest +from SubdivisionSurface.DOOSabinSubdivision import * + +""" + point_test_*: Point3D + face_test_*: list of point_test + faces_test: list of face_test + +""" + +""" + DOO_Sabin(faces,times): + input:faces(list) , subdivision times + output:new faces(list) + + + + faces :list of face + face : points : list of point +""" +class TestDOOSabinSubdivision(unittest.TestCase): + + #test for cubes + def test_DOOSabin_subdivision(self): + point_test_1 = Point3D(4, 4, 4) + point_test_2 = Point3D(4, 4, 0) + point_test_3 = Point3D(4, 0, 4) + point_test_4 = Point3D(4, 0, 0) + point_test_5 = Point3D(0, 4, 4) + point_test_6 = Point3D(0, 4, 0) + point_test_7 = Point3D(0, 0, 4) + point_test_8 = Point3D(0, 0, 0) + face_test_1 = [point_test_1, point_test_2, point_test_3, point_test_4] + face_test_2 = [point_test_1, point_test_5, point_test_6, point_test_2] + face_test_3 = [point_test_1, point_test_5, point_test_7, point_test_3] + face_test_4 = [point_test_3, point_test_4, point_test_8, point_test_7] + face_test_5 = [point_test_5, point_test_6, point_test_8, point_test_7] + face_test_6 = [point_test_2, point_test_4, point_test_8, point_test_6] + faces_test = [face_test_1, face_test_2, face_test_3, face_test_4, face_test_5, face_test_6] + DOO_Sabin(faces_test, 1) \ No newline at end of file diff --git a/features/SubdivisionSurface/test_LoopSubdivision.py b/features/SubdivisionSurface/test_LoopSubdivision.py new file mode 100644 index 0000000..9d8c9fe --- /dev/null +++ b/features/SubdivisionSurface/test_LoopSubdivision.py @@ -0,0 +1,15 @@ +import unittest +from SubdivisionSurface.LoopSubdivision import * + + +''' + input:vertices=[[x0,y0,z0],[x1,y1,z1]...],faces=[[index0,index1,index2]...] + output:new_vertices,new_face + +''' +class TestLoopSubdivison(unittest.TestCase): + + def test_LoopSubdivison(self): + vertices = [[10,10,10],[-100,10,-10],[-100,-10,10],[10,-10,-10]] + faces = [[0,1,2],[0,2,3],[0,3,1],[3,2,1]] + loop(vertices,faces) \ No newline at end of file diff --git a/nohup.out b/nohup.out new file mode 100644 index 0000000..e69de29