linalg.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. #include "pocketpy/linalg.h"
  2. namespace pkpy{
  3. #define BIND_VEC_ADDR(D) \
  4. vm->bind_method<0>(type, "addr", [](VM* vm, ArgsView args){ \
  5. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  6. return VAR_T(VoidP, &self.x); \
  7. });
  8. #define BIND_VEC_VEC_OP(D, name, op) \
  9. vm->bind_method<1>(type, #name, [](VM* vm, ArgsView args){ \
  10. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  11. PyVec##D& other = CAST(PyVec##D&, args[1]); \
  12. return VAR(self op other); \
  13. });
  14. #define BIND_VEC_FLOAT_OP(D, name, op) \
  15. vm->bind_method<1>(type, #name, [](VM* vm, ArgsView args){ \
  16. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  17. f64 other = CAST(f64, args[1]); \
  18. return VAR(self op other); \
  19. });
  20. #define BIND_VEC_FUNCTION_0(D, name) \
  21. vm->bind_method<0>(type, #name, [](VM* vm, ArgsView args){ \
  22. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  23. return VAR(self.name()); \
  24. });
  25. #define BIND_VEC_FUNCTION_1(D, name) \
  26. vm->bind_method<0>(type, #name, [](VM* vm, ArgsView args){ \
  27. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  28. PyVec##D& other = CAST(PyVec##D&, args[1]); \
  29. return VAR(self.name(other)); \
  30. });
  31. #define BIND_VEC_FIELD(D, name) \
  32. vm->bind_property(type, #name, \
  33. [](VM* vm, ArgsView args){ \
  34. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  35. return VAR(self.name); \
  36. }, [](VM* vm, ArgsView args){ \
  37. PyVec##D& self = _CAST(PyVec##D&, args[0]); \
  38. self.name = CAST(f64, args[1]); \
  39. return vm->None; \
  40. });
  41. void PyVec2::_register(VM* vm, PyObject* mod, PyObject* type){
  42. vm->bind_constructor<3>(type, [](VM* vm, ArgsView args){
  43. float x = CAST_F(args[1]);
  44. float y = CAST_F(args[2]);
  45. return VAR(Vec2(x, y));
  46. });
  47. vm->bind_method<0>(type, "__getnewargs__", [](VM* vm, ArgsView args){
  48. PyVec2& self = _CAST(PyVec2&, args[0]);
  49. return VAR(Tuple({ VAR(self.x), VAR(self.y) }));
  50. });
  51. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  52. PyVec2& self = _CAST(PyVec2&, obj);
  53. std::stringstream ss;
  54. ss << "vec2(" << self.x << ", " << self.y << ")";
  55. return VAR(ss.str());
  56. });
  57. vm->bind_method<0>(type, "copy", [](VM* vm, ArgsView args){
  58. PyVec2& self = _CAST(PyVec2&, args[0]);
  59. return VAR_T(PyVec2, self);
  60. });
  61. vm->bind_method<1>(type, "rotate", [](VM* vm, ArgsView args){
  62. Vec2 self = _CAST(PyVec2&, args[0]);
  63. float radian = CAST(f64, args[1]);
  64. float cr = cosf(radian);
  65. float sr = sinf(radian);
  66. Mat3x3 rotate(cr, -sr, 0.0f,
  67. sr, cr, 0.0f,
  68. 0.0f, 0.0f, 1.0f);
  69. self = rotate.transform_vector(self);
  70. return VAR(self);
  71. });
  72. vm->bind_method<1>(type, "rotate_", [](VM* vm, ArgsView args){
  73. Vec2& self = _CAST(PyVec2&, args[0]);
  74. float radian = CAST(f64, args[1]);
  75. float cr = cosf(radian);
  76. float sr = sinf(radian);
  77. Mat3x3 rotate(cr, -sr, 0.0f,
  78. sr, cr, 0.0f,
  79. 0.0f, 0.0f, 1.0f);
  80. self = rotate.transform_vector(self);
  81. return vm->None;
  82. });
  83. BIND_VEC_ADDR(2)
  84. BIND_VEC_VEC_OP(2, __add__, +)
  85. BIND_VEC_VEC_OP(2, __sub__, -)
  86. BIND_VEC_FLOAT_OP(2, __mul__, *)
  87. BIND_VEC_FLOAT_OP(2, __rmul__, *)
  88. BIND_VEC_FLOAT_OP(2, __truediv__, /)
  89. BIND_VEC_VEC_OP(2, __eq__, ==)
  90. BIND_VEC_FIELD(2, x)
  91. BIND_VEC_FIELD(2, y)
  92. BIND_VEC_FUNCTION_1(2, dot)
  93. BIND_VEC_FUNCTION_1(2, cross)
  94. BIND_VEC_FUNCTION_0(2, length)
  95. BIND_VEC_FUNCTION_0(2, length_squared)
  96. BIND_VEC_FUNCTION_0(2, normalize)
  97. }
  98. void PyVec3::_register(VM* vm, PyObject* mod, PyObject* type){
  99. vm->bind_constructor<4>(type, [](VM* vm, ArgsView args){
  100. float x = CAST_F(args[1]);
  101. float y = CAST_F(args[2]);
  102. float z = CAST_F(args[3]);
  103. return VAR(Vec3(x, y, z));
  104. });
  105. vm->bind_method<0>(type, "__getnewargs__", [](VM* vm, ArgsView args){
  106. PyVec3& self = _CAST(PyVec3&, args[0]);
  107. return VAR(Tuple({ VAR(self.x), VAR(self.y), VAR(self.z) }));
  108. });
  109. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  110. PyVec3& self = _CAST(PyVec3&, obj);
  111. std::stringstream ss;
  112. ss << "vec3(" << self.x << ", " << self.y << ", " << self.z << ")";
  113. return VAR(ss.str());
  114. });
  115. vm->bind_method<0>(type, "copy", [](VM* vm, ArgsView args){
  116. PyVec3& self = _CAST(PyVec3&, args[0]);
  117. return VAR_T(PyVec3, self);
  118. });
  119. BIND_VEC_ADDR(3)
  120. BIND_VEC_VEC_OP(3, __add__, +)
  121. BIND_VEC_VEC_OP(3, __sub__, -)
  122. BIND_VEC_FLOAT_OP(3, __mul__, *)
  123. BIND_VEC_FLOAT_OP(3, __rmul__, *)
  124. BIND_VEC_FLOAT_OP(3, __truediv__, /)
  125. BIND_VEC_VEC_OP(3, __eq__, ==)
  126. BIND_VEC_FIELD(3, x)
  127. BIND_VEC_FIELD(3, y)
  128. BIND_VEC_FIELD(3, z)
  129. BIND_VEC_FUNCTION_1(3, dot)
  130. BIND_VEC_FUNCTION_1(3, cross)
  131. BIND_VEC_FUNCTION_0(3, length)
  132. BIND_VEC_FUNCTION_0(3, length_squared)
  133. BIND_VEC_FUNCTION_0(3, normalize)
  134. }
  135. void PyVec4::_register(VM* vm, PyObject* mod, PyObject* type){
  136. vm->bind_constructor<1+4>(type, [](VM* vm, ArgsView args){
  137. float x = CAST_F(args[1]);
  138. float y = CAST_F(args[2]);
  139. float z = CAST_F(args[3]);
  140. float w = CAST_F(args[4]);
  141. return VAR(Vec4(x, y, z, w));
  142. });
  143. vm->bind_method<0>(type, "__getnewargs__", [](VM* vm, ArgsView args){
  144. PyVec4& self = _CAST(PyVec4&, args[0]);
  145. return VAR(Tuple({ VAR(self.x), VAR(self.y), VAR(self.z), VAR(self.w) }));
  146. });
  147. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  148. PyVec4& self = _CAST(PyVec4&, obj);
  149. std::stringstream ss;
  150. ss << "vec4(" << self.x << ", " << self.y << ", " << self.z << ", " << self.w << ")";
  151. return VAR(ss.str());
  152. });
  153. vm->bind_method<0>(type, "copy", [](VM* vm, ArgsView args){
  154. PyVec4& self = _CAST(PyVec4&, args[0]);
  155. return VAR_T(PyVec4, self);
  156. });
  157. BIND_VEC_ADDR(4)
  158. BIND_VEC_VEC_OP(4, __add__, +)
  159. BIND_VEC_VEC_OP(4, __sub__, -)
  160. BIND_VEC_FLOAT_OP(4, __mul__, *)
  161. BIND_VEC_FLOAT_OP(4, __rmul__, *)
  162. BIND_VEC_FLOAT_OP(4, __truediv__, /)
  163. BIND_VEC_VEC_OP(4, __eq__, ==)
  164. BIND_VEC_FIELD(4, x)
  165. BIND_VEC_FIELD(4, y)
  166. BIND_VEC_FIELD(4, z)
  167. BIND_VEC_FIELD(4, w)
  168. BIND_VEC_FUNCTION_1(4, dot)
  169. BIND_VEC_FUNCTION_0(4, length)
  170. BIND_VEC_FUNCTION_0(4, length_squared)
  171. BIND_VEC_FUNCTION_0(4, normalize)
  172. }
  173. #undef BIND_VEC_ADDR
  174. #undef BIND_VEC_VEC_OP
  175. #undef BIND_VEC_FLOAT_OP
  176. #undef BIND_VEC_FIELD
  177. #undef BIND_VEC_FUNCTION_0
  178. #undef BIND_VEC_FUNCTION_1
  179. void PyMat3x3::_register(VM* vm, PyObject* mod, PyObject* type){
  180. vm->bind_constructor<-1>(type, [](VM* vm, ArgsView args){
  181. if(args.size() == 1+0) return VAR_T(PyMat3x3, Mat3x3::zeros());
  182. if(args.size() == 1+9){
  183. Mat3x3 mat;
  184. for(int i=0; i<9; i++) mat.v[i] = CAST_F(args[1+i]);
  185. return VAR_T(PyMat3x3, mat);
  186. }
  187. if(args.size() == 1+1){
  188. List& a = CAST(List&, args[1]);
  189. if(a.size() != 3) vm->ValueError("Mat3x3.__new__ takes 3x3 list");
  190. Mat3x3 mat;
  191. for(int i=0; i<3; i++){
  192. List& b = CAST(List&, a[i]);
  193. if(b.size() != 3) vm->ValueError("Mat3x3.__new__ takes 3x3 list");
  194. for(int j=0; j<3; j++){
  195. mat.m[i][j] = CAST_F(b[j]);
  196. }
  197. }
  198. return VAR_T(PyMat3x3, mat);
  199. }
  200. vm->TypeError(fmt("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size()-1));
  201. return vm->None;
  202. });
  203. vm->bind_method<0>(type, "__getnewargs__", [](VM* vm, ArgsView args){
  204. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  205. Tuple t(9);
  206. for(int i=0; i<9; i++) t[i] = VAR(self.v[i]);
  207. return VAR(std::move(t));
  208. });
  209. #define METHOD_PROXY_NONE(name) \
  210. vm->bind_method<0>(type, #name, [](VM* vm, ArgsView args){ \
  211. PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
  212. self.name(); \
  213. return vm->None; \
  214. });
  215. METHOD_PROXY_NONE(set_zeros)
  216. METHOD_PROXY_NONE(set_ones)
  217. METHOD_PROXY_NONE(set_identity)
  218. #undef METHOD_PROXY_NONE
  219. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  220. PyMat3x3& self = _CAST(PyMat3x3&, obj);
  221. std::stringstream ss;
  222. ss << std::fixed << std::setprecision(4);
  223. ss << "mat3x3([[" << self._11 << ", " << self._12 << ", " << self._13 << "],\n";
  224. ss << " [" << self._21 << ", " << self._22 << ", " << self._23 << "],\n";
  225. ss << " [" << self._31 << ", " << self._32 << ", " << self._33 << "]])";
  226. return VAR(ss.str());
  227. });
  228. vm->bind_method<0>(type, "copy", [](VM* vm, ArgsView args){
  229. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  230. return VAR_T(PyMat3x3, self);
  231. });
  232. vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* index){
  233. PyMat3x3& self = _CAST(PyMat3x3&, obj);
  234. Tuple& t = CAST(Tuple&, index);
  235. if(t.size() != 2){
  236. vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers");
  237. return vm->None;
  238. }
  239. i64 i = CAST(i64, t[0]);
  240. i64 j = CAST(i64, t[1]);
  241. if(i < 0 || i >= 3 || j < 0 || j >= 3){
  242. vm->IndexError("index out of range");
  243. return vm->None;
  244. }
  245. return VAR(self.m[i][j]);
  246. });
  247. vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj, PyObject* index, PyObject* value){
  248. PyMat3x3& self = _CAST(PyMat3x3&, obj);
  249. Tuple& t = CAST(Tuple&, index);
  250. if(t.size() != 2){
  251. vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers");
  252. return;
  253. }
  254. i64 i = CAST(i64, t[0]);
  255. i64 j = CAST(i64, t[1]);
  256. if(i < 0 || i >= 3 || j < 0 || j >= 3){
  257. vm->IndexError("index out of range");
  258. return;
  259. }
  260. self.m[i][j] = CAST_F(value);
  261. });
  262. #define PROPERTY_FIELD(field) \
  263. vm->bind_property(type, #field ": float", \
  264. [](VM* vm, ArgsView args){ \
  265. PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
  266. return VAR(self.field); \
  267. }, [](VM* vm, ArgsView args){ \
  268. PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
  269. self.field = CAST(f64, args[1]); \
  270. return vm->None; \
  271. });
  272. PROPERTY_FIELD(_11)
  273. PROPERTY_FIELD(_12)
  274. PROPERTY_FIELD(_13)
  275. PROPERTY_FIELD(_21)
  276. PROPERTY_FIELD(_22)
  277. PROPERTY_FIELD(_23)
  278. PROPERTY_FIELD(_31)
  279. PROPERTY_FIELD(_32)
  280. PROPERTY_FIELD(_33)
  281. #undef PROPERTY_FIELD
  282. vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  283. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  284. PyMat3x3& other = CAST(PyMat3x3&, _1);
  285. return VAR_T(PyMat3x3, self + other);
  286. });
  287. vm->bind__sub__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  288. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  289. PyMat3x3& other = CAST(PyMat3x3&, _1);
  290. return VAR_T(PyMat3x3, self - other);
  291. });
  292. vm->bind__mul__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  293. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  294. f64 other = CAST_F(_1);
  295. return VAR_T(PyMat3x3, self * other);
  296. });
  297. vm->bind_method<1>(type, "__rmul__", [](VM* vm, ArgsView args){
  298. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  299. f64 other = CAST_F(args[1]);
  300. return VAR_T(PyMat3x3, self * other);
  301. });
  302. vm->bind__truediv__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  303. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  304. f64 other = CAST_F(_1);
  305. return VAR_T(PyMat3x3, self / other);
  306. });
  307. vm->bind__matmul__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  308. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  309. if(is_non_tagged_type(_1, PyMat3x3::_type(vm))){
  310. PyMat3x3& other = _CAST(PyMat3x3&, _1);
  311. return VAR_T(PyMat3x3, self.matmul(other));
  312. }
  313. if(is_non_tagged_type(_1, PyVec3::_type(vm))){
  314. PyVec3& other = _CAST(PyVec3&, _1);
  315. return VAR_T(PyVec3, self.matmul(other));
  316. }
  317. return vm->NotImplemented;
  318. });
  319. vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){
  320. PyMat3x3& self = _CAST(PyMat3x3&, _0);
  321. if(is_non_tagged_type(_1, PyMat3x3::_type(vm))){
  322. PyMat3x3& other = _CAST(PyMat3x3&, _1);
  323. return VAR(self == other);
  324. }
  325. return vm->NotImplemented;
  326. });
  327. vm->bind_method<0>(type, "determinant", [](VM* vm, ArgsView args){
  328. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  329. return VAR(self.determinant());
  330. });
  331. vm->bind_method<0>(type, "transpose", [](VM* vm, ArgsView args){
  332. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  333. return VAR_T(PyMat3x3, self.transpose());
  334. });
  335. vm->bind__invert__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
  336. PyMat3x3& self = _CAST(PyMat3x3&, obj);
  337. Mat3x3 ret;
  338. bool ok = self.inverse(ret);
  339. if(!ok) vm->ValueError("matrix is not invertible");
  340. return VAR_T(PyMat3x3, ret);
  341. });
  342. vm->bind_func<0>(type, "zeros", [](VM* vm, ArgsView args){
  343. PK_UNUSED(args);
  344. return VAR_T(PyMat3x3, Mat3x3::zeros());
  345. });
  346. vm->bind_func<0>(type, "ones", [](VM* vm, ArgsView args){
  347. PK_UNUSED(args);
  348. return VAR_T(PyMat3x3, Mat3x3::ones());
  349. });
  350. vm->bind_func<0>(type, "identity", [](VM* vm, ArgsView args){
  351. PK_UNUSED(args);
  352. return VAR_T(PyMat3x3, Mat3x3::identity());
  353. });
  354. /*************** affine transformations ***************/
  355. vm->bind_func<3>(type, "trs", [](VM* vm, ArgsView args){
  356. PyVec2& t = CAST(PyVec2&, args[0]);
  357. f64 r = CAST_F(args[1]);
  358. PyVec2& s = CAST(PyVec2&, args[2]);
  359. return VAR_T(PyMat3x3, Mat3x3::trs(t, r, s));
  360. });
  361. vm->bind_method<0>(type, "is_affine", [](VM* vm, ArgsView args){
  362. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  363. return VAR(self.is_affine());
  364. });
  365. vm->bind_method<0>(type, "_t", [](VM* vm, ArgsView args){
  366. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  367. return VAR_T(PyVec2, self._t());
  368. });
  369. vm->bind_method<0>(type, "_r", [](VM* vm, ArgsView args){
  370. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  371. return VAR(self._r());
  372. });
  373. vm->bind_method<0>(type, "_s", [](VM* vm, ArgsView args){
  374. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  375. return VAR_T(PyVec2, self._s());
  376. });
  377. vm->bind_method<1>(type, "transform_point", [](VM* vm, ArgsView args){
  378. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  379. PyVec2& v = CAST(PyVec2&, args[1]);
  380. return VAR_T(PyVec2, self.transform_point(v));
  381. });
  382. vm->bind_method<1>(type, "transform_vector", [](VM* vm, ArgsView args){
  383. PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
  384. PyVec2& v = CAST(PyVec2&, args[1]);
  385. return VAR_T(PyVec2, self.transform_vector(v));
  386. });
  387. }
  388. } // namespace pkpy