linalg.cpp 17 KB

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