linalg.cpp 17 KB

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