1from __future__ import print_function 2import numpy as np 3 4 5class Obj: 6 7 def __init__(self, fn): 8 self.ind_v = 0 9 self.ind_vt = 0 10 self.ind_vn = 0 11 self.fn = fn 12 self.out = open(fn + ".tmp", "w") 13 self.out.write("mtllib dinnerware.mtl\n") 14 15 def __del__(self): 16 self.out.close() 17 import shutil 18 shutil.move(self.fn + ".tmp", self.fn) 19 20 def push_v(self, v): 21 self.out.write("v %f %f %f\n" % (v[0], v[1], v[2])) 22 self.ind_v += 1 23 return self.ind_v 24 25 def push_vt(self, vt): 26 self.out.write("vt %f %f\n" % (vt[0], vt[1])) 27 self.ind_vt += 1 28 return self.ind_vt 29 30 def push_vn(self, vn): 31 vn /= np.linalg.norm(vn) 32 self.out.write("vn %f %f %f\n" % (vn[0], vn[1], vn[2])) 33 self.ind_vn += 1 34 return self.ind_vn 35 36 37def convex_hull(points, vind, nind, tind, obj): 38 "super ineffective" 39 cnt = len(points) 40 for a in range(cnt): 41 for b in range(a + 1, cnt): 42 for c in range(b + 1, cnt): 43 vec1 = points[a] - points[b] 44 vec2 = points[a] - points[c] 45 n = np.cross(vec1, vec2) 46 n /= np.linalg.norm(n) 47 C = np.dot(n, points[a]) 48 inner = np.inner(n, points) 49 pos = (inner <= C + 0.0001).all() 50 neg = (inner >= C - 0.0001).all() 51 if not pos and not neg: continue 52 obj.out.write("f %i//%i %i//%i %i//%i\n" % 53 ((vind[a], nind[a], vind[b], nind[b], vind[c], nind[c]) if 54 (inner - C).sum() < 0 else 55 (vind[a], nind[a], vind[c], nind[c], vind[b], nind[b]))) 56 #obj.out.write("f %i/%i/%i %i/%i/%i %i/%i/%i\n" % ( 57 # (vind[a], tind[a], nind[a], vind[b], tind[b], nind[b], vind[c], tind[c], nind[c]) 58 # if (inner - C).sum() < 0 else 59 # (vind[a], tind[a], nind[a], vind[c], tind[c], nind[c], vind[b], tind[b], nind[b]) ) ) 60 61 62def test_convex_hull(): 63 obj = Obj("convex_test.obj") 64 vlist = np.random.uniform(low=-0.1, high=+0.1, size=(100, 3)) 65 nlist = vlist.copy() 66 tlist = np.random.uniform(low=0, high=+1, size=(100, 2)) 67 vind = [obj.push_v(xyz) for xyz in vlist] 68 nind = [obj.push_vn(xyz) for xyz in nlist] 69 tind = [obj.push_vt(uv) for uv in tlist] 70 convex_hull(vlist, vind, nind, tind, obj) 71 72 73class Contour: 74 75 def __init__(self): 76 self.vprev_vind = None 77 78 def f(self, obj, vlist_vind, vlist_tind, vlist_nind): 79 cnt = len(vlist_vind) 80 for i1 in range(cnt): 81 i2 = i1 - 1 82 obj.out.write("f %i/%i/%i %i/%i/%i %i/%i/%i\n" % ( 83 vlist_vind[i2], 84 vlist_tind[i2], 85 vlist_nind[i2], 86 vlist_vind[i1], 87 vlist_tind[i1], 88 vlist_nind[i1], 89 self.vprev_vind[i1], 90 self.vprev_tind[i1], 91 self.vprev_nind[i1], 92 )) 93 obj.out.write("f %i/%i/%i %i/%i/%i %i/%i/%i\n" % ( 94 vlist_vind[i2], 95 vlist_tind[i2], 96 vlist_nind[i2], 97 self.vprev_vind[i1], 98 self.vprev_tind[i1], 99 self.vprev_nind[i1], 100 self.vprev_vind[i2], 101 self.vprev_tind[i2], 102 self.vprev_nind[i2], 103 )) 104 105 def belt(self, obj, vlist, nlist, tlist): 106 vlist_vind = [obj.push_v(xyz) for xyz in vlist] 107 vlist_tind = [obj.push_vt(xyz) for xyz in tlist] 108 vlist_nind = [obj.push_vn(xyz) for xyz in nlist] 109 if self.vprev_vind: 110 self.f(obj, vlist_vind, vlist_tind, vlist_nind) 111 else: 112 self.first_vind = vlist_vind 113 self.first_tind = vlist_tind 114 self.first_nind = vlist_nind 115 self.vprev_vind = vlist_vind 116 self.vprev_tind = vlist_tind 117 self.vprev_nind = vlist_nind 118 119 def finish(self, obj): 120 self.f(obj, self.first_vind, self.first_tind, self.first_nind) 121 122 123def test_contour(): 124 RAD1 = 2.0 125 RAD2 = 1.5 126 obj = Obj("torus.obj") 127 obj.out.write("usemtl porcelain\n") 128 contour = Contour() 129 for step in range(100): 130 angle = step / 100.0 * 2 * np.pi 131 belt_v = [] 132 belt_n = [] 133 belt_t = [] 134 for b in range(50): 135 beta = b / 50.0 * 2 * np.pi 136 r = RAD2 * np.cos(beta) + RAD1 137 z = RAD2 * np.sin(beta) 138 belt_v.append(np.array([np.cos(angle) * r, np.sin(angle) * r, z])) 139 belt_n.append( 140 np.array([np.cos(angle) * np.cos(beta), 141 np.sin(angle) * np.cos(beta), 142 np.sin(beta)])) 143 belt_t.append((0, 0)) 144 contour.belt(obj, belt_v, belt_n, belt_t) 145 contour.finish(obj) 146 147 148#test_convex_hull() 149#test_contour() 150 151 152class RotationFigureParams: 153 pass 154 155 156def generate_plate(p, obj, collision_prefix): 157 contour = Contour() 158 belt_vlist_3d_prev = None 159 160 for step in range(p.N_VIZ + 1): 161 angle = step / float(p.N_VIZ) * 2 * np.pi 162 163 if step % p.COLLISION_EVERY == 0: 164 vlist_3d = [] 165 for x, y in p.belt_simple: 166 vlist_3d.append([np.cos(angle) * x * 1.06, np.sin(angle) * x * 1.06, y]) 167 if belt_vlist_3d_prev: 168 obj2 = Obj(collision_prefix % (step / p.COLLISION_EVERY)) 169 obj2.out.write("usemtl pan_tefal\n") 170 vlist = np.array(vlist_3d + belt_vlist_3d_prev) 171 vlist[len(vlist_3d):] *= 1.01 # break points on one plane 172 vlist[0, 0:2] += 0.01 * vlist[len(vlist_3d), 0:2] 173 vlist[len(vlist_3d), 0:2] += 0.01 * vlist[0, 0:2] 174 nlist = np.random.uniform(low=-1, high=+1, size=vlist.shape) 175 tlist = np.random.uniform(low=0, high=+1, size=(len(vlist), 2)) 176 vind = [obj2.push_v(xyz) for xyz in vlist] 177 nind = [obj2.push_vn(xyz) for xyz in nlist] 178 convex_hull(vlist, vind, nind, None, obj2) 179 belt_vlist_3d_prev = vlist_3d 180 if step == p.N_VIZ: break 181 182 belt_v = [] 183 belt_n = [] 184 belt_t = [] 185 for x, y, nx, ny in p.belt: 186 belt_v.append(np.array([np.cos(angle) * x, np.sin(angle) * x, y])) 187 belt_n.append(np.array([np.cos(angle) * nx, np.sin(angle) * nx, ny])) 188 if ny - nx >= 0: 189 belt_t.append((127.0 / 512 + np.cos(angle) * x / p.RAD_HIGH * 105 / 512, 190 (512 - 135.0) / 512 + np.sin(angle) * x / p.RAD_HIGH * 105 / 512)) 191 else: 192 belt_t.append((382.0 / 512 + np.cos(angle) * x / p.RAD_HIGH * 125 / 512, 193 (512 - 380.0) / 512 + np.sin(angle) * x / p.RAD_HIGH * 125 / 512)) 194 contour.belt(obj, belt_v, belt_n, belt_t) 195 196 contour.finish(obj) 197 198 199def tefal(): 200 p = RotationFigureParams() 201 p.RAD_LOW = 0.240 / 2 202 p.RAD_HIGH = 0.255 / 2 203 p.H = 0.075 204 p.THICK = 0.005 205 p.N_VIZ = 30 206 p.COLLISION_EVERY = 5 207 p.belt = [ 208 (p.RAD_HIGH - p.THICK, p.H, -1, 0), # x y norm 209 (p.RAD_HIGH, p.H, 0, 1), 210 (p.RAD_HIGH + p.THICK, p.H, +1, 0), 211 (p.RAD_LOW + p.THICK, p.THICK, +1, 0), 212 (p.RAD_LOW, 0, 0, -1), 213 (0, 0, 0, -1), 214 (0, p.THICK, 0, 1), 215 (p.RAD_LOW - p.THICK, p.THICK, 0, 1), 216 (p.RAD_LOW - p.THICK, 3 * p.THICK, -1, 0), 217 ] 218 p.belt.reverse() 219 p.belt_simple = [(p.RAD_HIGH - p.THICK, p.H), (p.RAD_HIGH + p.THICK, p.H), (p.RAD_LOW, 0), 220 (p.RAD_LOW - p.THICK, 0)] 221 obj = Obj("pan_tefal.obj") 222 obj.out.write("usemtl pan_tefal\n") 223 generate_plate(p, obj, "pan_tefal-collision%02i.obj") 224 225 226def plate(): 227 p = RotationFigureParams() 228 p.RAD_LOW = 0.110 / 2 229 p.RAD_HIGH = 0.190 / 2 230 p.H = 0.060 231 p.THICK = 0.003 232 p.N_VIZ = 30 233 p.COLLISION_EVERY = 5 234 p.belt = [ 235 (p.RAD_HIGH - p.THICK, p.H, -0.9, 0.5), # x y norm 236 (p.RAD_HIGH, p.H, 0, 1), 237 (p.RAD_HIGH + p.THICK, p.H, +1, 0), 238 (p.RAD_LOW + p.THICK, p.THICK, +1, 0), 239 (p.RAD_LOW, 0, 0, -1), 240 (0, 0, 0, -1), 241 (0, p.THICK, 0, 1), 242 (p.RAD_LOW - 3 * p.THICK, p.THICK, 0, 1), 243 (p.RAD_LOW - p.THICK, 3 * p.THICK, -0.5, 1.0), 244 ] 245 p.belt.reverse() 246 p.belt_simple = [(p.RAD_HIGH - p.THICK, p.H), (p.RAD_HIGH + p.THICK, p.H), (p.RAD_LOW, 0), 247 (p.RAD_LOW - p.THICK, 0)] 248 obj = Obj("plate.obj") 249 obj.out.write("usemtl solid_color\n") 250 generate_plate(p, obj, "plate-collision%02i.obj") 251 252 253plate() 254