OSDN Git Service

refactoring pmd.writer
[meshio/pymeshio.git] / pymeshio / common.py
1 # coding: utf-8\r
2 """\r
3 common utilities.\r
4 """\r
5 import math\r
6 import struct\r
7 \r
8 \r
9 """\r
10 common structures.\r
11 """\r
12 class Vector2(object):\r
13     """\r
14     2D coordinate for uv value\r
15     """\r
16     __slots__=['x', 'y']\r
17     def __init__(self, x=0, y=0):\r
18         self.x=x\r
19         self.y=y\r
20 \r
21     def __str__(self):\r
22         return "<%f %f>" % (self.x, self.y)\r
23 \r
24     def __eq__(self, rhs):\r
25         return self.x==rhs.x and self.y==rhs.y\r
26 \r
27     def __getitem__(self, key):\r
28         if key==0:\r
29             return self.x\r
30         elif key==1:\r
31             return self.y\r
32         else:\r
33             assert(False)\r
34 \r
35     def to_tuple(self):\r
36         return (self.x, self.y)\r
37 \r
38     def cross(self, rhs):\r
39         """cross(outer) product"""\r
40         return self.x*rhs.y-self.y*rhs.x\r
41 \r
42 \r
43 class Vector3(object):\r
44     """\r
45     3D coordinate for vertex position, normal direction\r
46     """\r
47     __slots__=['x', 'y', 'z']\r
48     def __init__(self, x=0, y=0, z=0):\r
49         self.x=x\r
50         self.y=y\r
51         self.z=z\r
52 \r
53     def __str__(self):\r
54         return "<%f %f %f>" % (self.x, self.y, self.z)\r
55 \r
56     def __eq__(self, rhs):\r
57         return self.x==rhs.x and self.y==rhs.y and self.z==rhs.z\r
58 \r
59     def __getitem__(self, key):\r
60         if key==0:\r
61             return self.x\r
62         elif key==1:\r
63             return self.y\r
64         elif key==2:\r
65             return self.z\r
66         else:\r
67             assert(False)\r
68 \r
69     def to_tuple(self):\r
70         return (self.x, self.y, self.z)\r
71 \r
72     def __add__(self, r):\r
73         return Vector3(self.x+r.x, self.y+r.y, self.z+r.z)\r
74 \r
75     def __sub__(self, rhs):\r
76         return Vector3(self.x-rhs.x, self.y-rhs.y, self.z-rhs.z)\r
77 \r
78     def getSqNorm(self):\r
79         return self.x*self.x + self.y*self.y + self.z*self.z\r
80 \r
81     def getNorm(self):\r
82         return math.sqrt(self.getSqNorm())\r
83 \r
84     def normalize(self):\r
85         factor=1.0/self.getNorm()\r
86         self.x*=factor\r
87         self.y*=factor\r
88         self.z*=factor\r
89         return self\r
90 \r
91     def to_a(self):\r
92         return [self.x, self.y, self.z]\r
93 \r
94     def dot(self, rhs):\r
95         """dot(inner) product"""\r
96         return self.x*rhs.x + self.y*rhs.y + self.z*rhs.z\r
97 \r
98     def cross(self, rhs):\r
99         """cross(outer) product"""\r
100         return Vector3(\r
101                 self.y*rhs.z - rhs.y*self.z,\r
102                 self.z*rhs.x - rhs.z*self.x,\r
103                 self.x*rhs.y - rhs.x*self.y,\r
104                 )\r
105 \r
106 \r
107 class Quaternion(object):\r
108     """\r
109     rotation representation in vmd motion\r
110     """\r
111     __slots__=['x', 'y', 'z', 'w']\r
112     def __init__(self, x=0, y=0, z=0, w=1):\r
113         self.x=x\r
114         self.y=y\r
115         self.z=z\r
116         self.w=w\r
117 \r
118     def __str__(self):\r
119         return "<%f %f %f %f>" % (self.x, self.y, self.z, self.w)\r
120 \r
121     def __mul__(self, rhs):\r
122         u=numpy.array([self.x, self.y, self.z], 'f')\r
123         v=numpy.array([rhs.x, rhs.y, rhs.z], 'f')\r
124         xyz=self.w*v+rhs.w*u+numpy.cross(u, v)\r
125         q=Quaternion(xyz[0], xyz[1], xyz[2], self.w*rhs.w-numpy.dot(u, v))\r
126         return q\r
127 \r
128     def dot(self, rhs):\r
129         return self.x*rhs.x+self.y*rhs.y+self.z*rhs.z+self.w*rhs.w\r
130 \r
131     def getMatrix(self):\r
132         sqX=self.x*self.x\r
133         sqY=self.y*self.y\r
134         sqZ=self.z*self.z\r
135         xy=self.x*self.y\r
136         xz=self.x*self.z\r
137         yz=self.y*self.z\r
138         wx=self.w*self.x\r
139         wy=self.w*self.y\r
140         wz=self.w*self.z\r
141         return numpy.array([\r
142                 # 1\r
143                 [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],\r
144                 # 2\r
145                 [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],\r
146                 # 3\r
147                 [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],\r
148                 # 4\r
149                 [0, 0, 0, 1]],\r
150                 'f')\r
151 \r
152     def getRHMatrix(self):\r
153         x=-self.x\r
154         y=-self.y\r
155         z=self.z\r
156         w=self.w\r
157         sqX=x*x\r
158         sqY=y*y\r
159         sqZ=z*z\r
160         xy=x*y\r
161         xz=x*z\r
162         yz=y*z\r
163         wx=w*x\r
164         wy=w*y\r
165         wz=w*z\r
166         return numpy.array([\r
167                 # 1\r
168                 [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],\r
169                 # 2\r
170                 [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],\r
171                 # 3\r
172                 [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],\r
173                 # 4\r
174                 [0, 0, 0, 1]],\r
175                 'f')\r
176 \r
177     def getRollPitchYaw(self):\r
178         m=self.getMatrix()\r
179 \r
180         roll = math.atan2(m[0, 1], m[1, 1])\r
181         pitch = math.asin(-m[2, 1])\r
182         yaw = math.atan2(m[2, 0], m[2, 2])\r
183 \r
184         if math.fabs(math.cos(pitch)) < 1.0e-6:\r
185             roll += m[0, 1] > math.pi if 0.0 else -math.pi\r
186             yaw += m[2, 0] > math.pi if 0.0 else -math.pi\r
187 \r
188         return roll, pitch, yaw\r
189 \r
190     def getSqNorm(self):\r
191         return self.x*self.x+self.y*self.y+self.z*self.z+self.w*self.w\r
192 \r
193     def getNormalized(self):\r
194         f=1.0/self.getSqNorm()\r
195         q=Quaternion(self.x*f, self.y*f, self.z*f, self.w*f)\r
196         return q\r
197 \r
198     def getRightHanded(self):\r
199         "swap y and z axis"\r
200         return Quaternion(-self.x, -self.z, -self.y, self.w)\r
201 \r
202     @staticmethod\r
203     def createFromAxisAngle(axis, rad):\r
204         q=Quaternion()\r
205         half_rad=rad/2.0\r
206         c=math.cos(half_rad)\r
207         s=math.sin(half_rad)\r
208         return Quaternion(axis[0]*s, axis[1]*s, axis[2]*s, c)\r
209 \r
210 \r
211 class RGB(object):\r
212     """\r
213     material color\r
214     """\r
215     __slots__=['r', 'g', 'b']\r
216     def __init__(self, r=0, g=0, b=0):\r
217         self.r=r\r
218         self.g=g\r
219         self.b=b\r
220 \r
221     def __eq__(self, rhs):\r
222         return self.r==rhs.r and self.g==rhs.g and self.b==rhs.b\r
223 \r
224     def __getitem__(self, key):\r
225         if key==0:\r
226             return self.r\r
227         elif key==1:\r
228             return self.g\r
229         elif key==2:\r
230             return self.b\r
231         else:\r
232             assert(False)\r
233 \r
234 \r
235 class RGBA(object):\r
236     """\r
237     material color\r
238     """\r
239     __slots__=['r', 'g', 'b', 'a']\r
240     def __init__(self, r=0, g=0, b=0, a=1):\r
241         self.r=r\r
242         self.g=g\r
243         self.b=b\r
244         self.a=a\r
245 \r
246     def __getitem__(self, key):\r
247         if key==0:\r
248             return self.r\r
249         elif key==1:\r
250             return self.g\r
251         elif key==2:\r
252             return self.b\r
253         elif key==3:\r
254             return self.a\r
255         else:\r
256             assert(False)\r
257 \r
258 \r
259 """\r
260 utilities\r
261 """\r
262 def radian_to_degree(x):\r
263     """darian to deglee"""\r
264 \r
265     return x/math.pi * 180.0\r
266 \r
267 \r
268 class ParseException(Exception):\r
269     pass\r
270 \r
271 \r
272 def readall(path):\r
273     """read all bytes from path\r
274     """\r
275     with open(path, "rb") as f:\r
276         return f.read()\r
277 \r
278 \r
279 class BinaryLoader(object):\r
280     """general BinaryLoader\r
281     """\r
282     def __init__(self, ios):\r
283         self.ios=ios\r
284 \r
285     def is_end(self):\r
286         return not self.ios.readable()\r
287 \r
288     def unpack(self, fmt, size):\r
289         result=struct.unpack(fmt, self.ios.read(size))\r
290         return result[0]\r
291 \r
292     def read_uint(self, size):\r
293         if size==1:\r
294             return self.unpack("B", size)\r
295         if size==2:\r
296             return self.unpack("H", size)\r
297         if size==4:\r
298             return self.unpack("I", size)\r
299         print("not reach here")\r
300         raise ParseException("invalid int size: "+size)\r
301 \r
302     def read_float(self):\r
303         return self.unpack("f", 4)\r
304 \r
305     def read_vector2(self):\r
306         return Vector2(\r
307                 self.read_float(), \r
308                 self.read_float()\r
309                 )\r
310 \r
311     def read_vector3(self):\r
312         return Vector3(\r
313                 self.read_float(), \r
314                 self.read_float(), \r
315                 self.read_float()\r
316                 )\r
317 \r
318     def read_rgba(self):\r
319         return RGBA(\r
320                 self.read_float(), \r
321                 self.read_float(), \r
322                 self.read_float(),\r
323                 self.read_float()\r
324                 )\r
325 \r
326     def read_rgb(self):\r
327         return RGB(\r
328                 self.read_float(), \r
329                 self.read_float(), \r
330                 self.read_float()\r
331                 )\r
332 \r
333 \r
334 class BinaryWriter(object):\r
335     def __init__(self, ios):\r
336         self.ios=ios\r
337 \r
338     def write_text(self, v, size=None):\r
339         if size:\r
340             self.ios.write(struct.pack("={0}s".format(size), v))\r
341         else:\r
342             self.ios.write(v)\r
343 \r
344     def write_float(self, v):\r
345         self.ios.write(struct.pack("f", v))\r
346 \r
347     def write_uint(self, v, size):\r
348         if size==1:\r
349             self.ios.write(struct.pack("B", v))\r
350         elif size==2:\r
351             self.ios.write(struct.pack("H", v))\r
352         elif size==4:\r
353             self.ios.write(struct.pack("I", v))\r
354         else:\r
355             raise WriteError("invalid int uint size")\r
356 \r
357     def write_vector2(self, v):\r
358         self.ios.write(struct.pack("=2f", v.x, v.y))\r
359 \r
360     def write_vector3(self, v):\r
361         self.ios.write(struct.pack("=3f", v.x, v.y, v.z))\r
362 \r
363     def write_rgb(self, v):\r
364         self.ios.write(struct.pack("=3f", v.r, v.g, v.b))\r
365 \r
366 \r