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