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