linalg.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. #include "pocketpy/linalg.h"
  2. namespace pkpy{
  3. #define BIND_VEC_VEC_OP(D, name, op) \
  4. vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \
  5. Vec##D self = _CAST(Vec##D, _0); \
  6. Vec##D other = CAST(Vec##D, _1); \
  7. return VAR(self op other); \
  8. });
  9. #define BIND_VEC_FLOAT_OP(D, name, op) \
  10. vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \
  11. Vec##D self = _CAST(Vec##D, _0); \
  12. f64 other = CAST(f64, _1); \
  13. return VAR(self op other); \
  14. });
  15. #define BIND_VEC_FUNCTION_0(T, name) \
  16. vm->bind_func(type, #name, 1, [](VM* vm, ArgsView args){ \
  17. T self = _CAST(T, args[0]); \
  18. return VAR(self.name()); \
  19. });
  20. #define BIND_VEC_FUNCTION_1(T, name) \
  21. vm->bind_func(type, #name, 2, [](VM* vm, ArgsView args){ \
  22. T self = _CAST(T, args[0]); \
  23. T other = CAST(T, args[1]); \
  24. return VAR(self.name(other)); \
  25. });
  26. #define BIND_VEC_MUL_OP(D) \
  27. vm->bind__mul__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \
  28. Vec##D self = _CAST(Vec##D, _0); \
  29. if(vm->is_user_type<Vec##D>(_1)){ \
  30. Vec##D other = _CAST(Vec##D, _1); \
  31. return VAR(self * other); \
  32. } \
  33. f64 other = CAST(f64, _1); \
  34. return VAR(self * other); \
  35. }); \
  36. vm->bind_func(type, "__rmul__", 2, [](VM* vm, ArgsView args){ \
  37. Vec##D self = _CAST(Vec##D, args[0]); \
  38. f64 other = CAST(f64, args[1]); \
  39. return VAR(self * other); \
  40. }); \
  41. vm->bind__truediv__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \
  42. Vec##D self = _CAST(Vec##D, _0); \
  43. f64 other = CAST(f64, _1); \
  44. return VAR(self / other); \
  45. });
  46. #define BIND_VEC_GETITEM(D) \
  47. vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj, PyVar index){ \
  48. Vec##D self = _CAST(Vec##D, obj); \
  49. i64 i = CAST(i64, index); \
  50. if(i < 0 || i >= D) vm->IndexError("index out of range"); \
  51. return VAR(self[i]); \
  52. });
  53. #define BIND_SSO_VEC_COMMON(D) \
  54. vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \
  55. Vec##D self = _CAST(Vec##D, _0); \
  56. if(!vm->is_user_type<Vec##D>(_1)) return vm->NotImplemented; \
  57. Vec##D other = _CAST(Vec##D, _1); \
  58. return VAR(self == other); \
  59. }); \
  60. vm->bind_func(type, "__getnewargs__", 1, [](VM* vm, ArgsView args){ \
  61. Vec##D self = _CAST(Vec##D, args[0]); \
  62. Tuple t(D); \
  63. for(int i=0; i<D; i++) t[i] = VAR(self[i]); \
  64. return VAR(std::move(t)); \
  65. });
  66. // https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector2.cs#L289
  67. static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
  68. {
  69. // Based on Game Programming Gems 4 Chapter 1.10
  70. smoothTime = std::max(0.0001F, smoothTime);
  71. float omega = 2.0F / smoothTime;
  72. float x = omega * deltaTime;
  73. float exp = 1.0F / (1.0F + x + 0.48F * x * x + 0.235F * x * x * x);
  74. float change_x = current.x - target.x;
  75. float change_y = current.y - target.y;
  76. Vec2 originalTo = target;
  77. // Clamp maximum speed
  78. float maxChange = maxSpeed * smoothTime;
  79. float maxChangeSq = maxChange * maxChange;
  80. float sqDist = change_x * change_x + change_y * change_y;
  81. if (sqDist > maxChangeSq)
  82. {
  83. float mag = std::sqrt(sqDist);
  84. change_x = change_x / mag * maxChange;
  85. change_y = change_y / mag * maxChange;
  86. }
  87. target.x = current.x - change_x;
  88. target.y = current.y - change_y;
  89. float temp_x = (currentVelocity.x + omega * change_x) * deltaTime;
  90. float temp_y = (currentVelocity.y + omega * change_y) * deltaTime;
  91. currentVelocity.x = (currentVelocity.x - omega * temp_x) * exp;
  92. currentVelocity.y = (currentVelocity.y - omega * temp_y) * exp;
  93. float output_x = target.x + (change_x + temp_x) * exp;
  94. float output_y = target.y + (change_y + temp_y) * exp;
  95. // Prevent overshooting
  96. float origMinusCurrent_x = originalTo.x - current.x;
  97. float origMinusCurrent_y = originalTo.y - current.y;
  98. float outMinusOrig_x = output_x - originalTo.x;
  99. float outMinusOrig_y = output_y - originalTo.y;
  100. if (origMinusCurrent_x * outMinusOrig_x + origMinusCurrent_y * outMinusOrig_y > 0)
  101. {
  102. output_x = originalTo.x;
  103. output_y = originalTo.y;
  104. currentVelocity.x = (output_x - originalTo.x) / deltaTime;
  105. currentVelocity.y = (output_y - originalTo.y) / deltaTime;
  106. }
  107. return Vec2(output_x, output_y);
  108. }
  109. void Vec2::_register(VM* vm, PyVar mod, PyVar type){
  110. type->attr().set("ZERO", vm->new_user_object<Vec2>(0, 0));
  111. type->attr().set("ONE", vm->new_user_object<Vec2>(1, 1));
  112. vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args){
  113. float x = CAST_F(args[1]);
  114. float y = CAST_F(args[2]);
  115. return vm->new_object<Vec2>(PK_OBJ_GET(Type, args[0]), x, y);
  116. });
  117. // @staticmethod
  118. vm->bind(type, "smooth_damp(current: vec2, target: vec2, current_velocity_: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2", [](VM* vm, ArgsView args){
  119. Vec2 current = CAST(Vec2, args[0]);
  120. Vec2 target = CAST(Vec2, args[1]);
  121. Vec2 current_velocity_ = CAST(Vec2, args[2]);
  122. float smooth_time = CAST_F(args[3]);
  123. float max_speed = CAST_F(args[4]);
  124. float delta_time = CAST_F(args[5]);
  125. Vec2 ret = SmoothDamp(current, target, current_velocity_, smooth_time, max_speed, delta_time);
  126. return VAR(Tuple(VAR(ret), VAR(current_velocity_)));
  127. }, {}, BindType::STATICMETHOD);
  128. // @staticmethod
  129. vm->bind(type, "angle(__from: vec2, __to: vec2) -> float", [](VM* vm, ArgsView args){
  130. Vec2 __from = CAST(Vec2, args[0]);
  131. Vec2 __to = CAST(Vec2, args[1]);
  132. float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
  133. const float PI = 3.1415926535897932384f;
  134. if(val > PI) val -= 2*PI;
  135. if(val < -PI) val += 2*PI;
  136. return VAR(val);
  137. }, {}, BindType::STATICMETHOD);
  138. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{
  139. Vec2 self = _CAST(Vec2, obj);
  140. SStream ss;
  141. ss.setprecision(3);
  142. ss << "vec2(" << self.x << ", " << self.y << ")";
  143. return ss.str();
  144. });
  145. vm->bind_func(type, "rotate", 2, [](VM* vm, ArgsView args){
  146. Vec2 self = _CAST(Vec2, args[0]);
  147. float radian = CAST(f64, args[1]);
  148. return vm->new_user_object<Vec2>(self.rotate(radian));
  149. });
  150. PY_READONLY_FIELD(Vec2, "x", x)
  151. PY_READONLY_FIELD(Vec2, "y", y)
  152. BIND_VEC_VEC_OP(2, __add__, +)
  153. BIND_VEC_VEC_OP(2, __sub__, -)
  154. BIND_VEC_MUL_OP(2)
  155. BIND_VEC_FLOAT_OP(2, __truediv__, /)
  156. BIND_VEC_FUNCTION_1(Vec2, dot)
  157. BIND_VEC_FUNCTION_1(Vec2, cross)
  158. BIND_VEC_FUNCTION_0(Vec2, length)
  159. BIND_VEC_FUNCTION_0(Vec2, length_squared)
  160. BIND_VEC_FUNCTION_0(Vec2, normalize)
  161. BIND_VEC_GETITEM(2)
  162. BIND_SSO_VEC_COMMON(2)
  163. }
  164. void Vec3::_register(VM* vm, PyVar mod, PyVar type){
  165. type->attr().set("ZERO", vm->new_user_object<Vec3>(0, 0, 0));
  166. type->attr().set("ONE", vm->new_user_object<Vec3>(1, 1, 1));
  167. vm->bind_func(type, __new__, 4, [](VM* vm, ArgsView args){
  168. float x = CAST_F(args[1]);
  169. float y = CAST_F(args[2]);
  170. float z = CAST_F(args[3]);
  171. return vm->new_object<Vec3>(PK_OBJ_GET(Type, args[0]), x, y, z);
  172. });
  173. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{
  174. Vec3 self = _CAST(Vec3, obj);
  175. SStream ss;
  176. ss.setprecision(3);
  177. ss << "vec3(" << self.x << ", " << self.y << ", " << self.z << ")";
  178. return ss.str();
  179. });
  180. PY_READONLY_FIELD(Vec3, "x", x)
  181. PY_READONLY_FIELD(Vec3, "y", y)
  182. PY_READONLY_FIELD(Vec3, "z", z)
  183. BIND_VEC_VEC_OP(3, __add__, +)
  184. BIND_VEC_VEC_OP(3, __sub__, -)
  185. BIND_VEC_MUL_OP(3)
  186. BIND_VEC_FUNCTION_1(Vec3, dot)
  187. BIND_VEC_FUNCTION_1(Vec3, cross)
  188. BIND_VEC_FUNCTION_0(Vec3, length)
  189. BIND_VEC_FUNCTION_0(Vec3, length_squared)
  190. BIND_VEC_FUNCTION_0(Vec3, normalize)
  191. BIND_VEC_GETITEM(3)
  192. BIND_SSO_VEC_COMMON(3)
  193. }
  194. void Vec4::_register(VM* vm, PyVar mod, PyVar type){
  195. PY_STRUCT_LIKE(Vec4)
  196. type->attr().set("ZERO", vm->new_user_object<Vec4>(0, 0, 0, 0));
  197. type->attr().set("ONE", vm->new_user_object<Vec4>(1, 1, 1, 1));
  198. vm->bind_func(type, __new__, 5, [](VM* vm, ArgsView args){
  199. float x = CAST_F(args[1]);
  200. float y = CAST_F(args[2]);
  201. float z = CAST_F(args[3]);
  202. float w = CAST_F(args[4]);
  203. return vm->new_object<Vec4>(PK_OBJ_GET(Type, args[0]), x, y, z, w);
  204. });
  205. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{
  206. Vec4 self = _CAST(Vec4&, obj);
  207. SStream ss;
  208. ss.setprecision(3);
  209. ss << "vec4(" << self.x << ", " << self.y << ", " << self.z << ", " << self.w << ")";
  210. return ss.str();
  211. });
  212. PY_FIELD(Vec4, "x", x)
  213. PY_FIELD(Vec4, "y", y)
  214. PY_FIELD(Vec4, "z", z)
  215. PY_FIELD(Vec4, "w", w)
  216. BIND_VEC_VEC_OP(4, __add__, +)
  217. BIND_VEC_VEC_OP(4, __sub__, -)
  218. BIND_VEC_MUL_OP(4)
  219. BIND_VEC_FUNCTION_1(Vec4&, dot)
  220. BIND_VEC_FUNCTION_1(Vec4&, copy_)
  221. BIND_VEC_FUNCTION_0(Vec4&, length)
  222. BIND_VEC_FUNCTION_0(Vec4&, length_squared)
  223. BIND_VEC_FUNCTION_0(Vec4&, normalize)
  224. BIND_VEC_FUNCTION_0(Vec4&, normalize_)
  225. BIND_VEC_GETITEM(4)
  226. }
  227. #undef BIND_VEC_VEC_OP
  228. #undef BIND_VEC_MUL_OP
  229. #undef BIND_VEC_FUNCTION_0
  230. #undef BIND_VEC_FUNCTION_1
  231. #undef BIND_VEC_GETITEM
  232. void Mat3x3::_register(VM* vm, PyVar mod, PyVar type){
  233. PY_STRUCT_LIKE(Mat3x3)
  234. vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args){
  235. if(args.size() == 1+0) return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
  236. if(args.size() == 1+1){
  237. const List& list = CAST(List&, args[1]);
  238. if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
  239. Mat3x3 mat;
  240. for(int i=0; i<9; i++) mat.v[i] = CAST_F(list[i]);
  241. return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
  242. }
  243. if(args.size() == 1+9){
  244. Mat3x3 mat;
  245. for(int i=0; i<9; i++) mat.v[i] = CAST_F(args[1+i]);
  246. return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
  247. }
  248. vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size()-1));
  249. return vm->None;
  250. });
  251. vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args){
  252. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  253. const Mat3x3& other = CAST(Mat3x3&, args[1]);
  254. self = other;
  255. return vm->None;
  256. });
  257. vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{
  258. const Mat3x3& self = _CAST(Mat3x3&, obj);
  259. SStream ss;
  260. ss.setprecision(3);
  261. ss << "mat3x3([" << self._11 << ", " << self._12 << ", " << self._13 << ",\n";
  262. ss << " " << self._21 << ", " << self._22 << ", " << self._23 << ",\n";
  263. ss << " " << self._31 << ", " << self._32 << ", " << self._33 << "])";
  264. return ss.str();
  265. });
  266. vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj, PyVar index){
  267. Mat3x3& self = _CAST(Mat3x3&, obj);
  268. Tuple& t = CAST(Tuple&, index);
  269. if(t.size() != 2){
  270. vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers");
  271. }
  272. i64 i = CAST(i64, t[0]);
  273. i64 j = CAST(i64, t[1]);
  274. if(i < 0 || i >= 3 || j < 0 || j >= 3){
  275. vm->IndexError("index out of range");
  276. }
  277. return VAR(self.m[i][j]);
  278. });
  279. vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj, PyVar index, PyVar value){
  280. Mat3x3& self = _CAST(Mat3x3&, obj);
  281. const Tuple& t = CAST(Tuple&, index);
  282. if(t.size() != 2){
  283. vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers");
  284. }
  285. i64 i = CAST(i64, t[0]);
  286. i64 j = CAST(i64, t[1]);
  287. if(i < 0 || i >= 3 || j < 0 || j >= 3){
  288. vm->IndexError("index out of range");
  289. }
  290. self.m[i][j] = CAST_F(value);
  291. });
  292. vm->bind_field(type, "_11", &Mat3x3::_11);
  293. vm->bind_field(type, "_12", &Mat3x3::_12);
  294. vm->bind_field(type, "_13", &Mat3x3::_13);
  295. vm->bind_field(type, "_21", &Mat3x3::_21);
  296. vm->bind_field(type, "_22", &Mat3x3::_22);
  297. vm->bind_field(type, "_23", &Mat3x3::_23);
  298. vm->bind_field(type, "_31", &Mat3x3::_31);
  299. vm->bind_field(type, "_32", &Mat3x3::_32);
  300. vm->bind_field(type, "_33", &Mat3x3::_33);
  301. vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){
  302. Mat3x3& self = _CAST(Mat3x3&, _0);
  303. Mat3x3& other = CAST(Mat3x3&, _1);
  304. return vm->new_user_object<Mat3x3>(self + other);
  305. });
  306. vm->bind__sub__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){
  307. Mat3x3& self = _CAST(Mat3x3&, _0);
  308. Mat3x3& other = CAST(Mat3x3&, _1);
  309. return vm->new_user_object<Mat3x3>(self - other);
  310. });
  311. vm->bind__mul__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){
  312. Mat3x3& self = _CAST(Mat3x3&, _0);
  313. f64 other = CAST_F(_1);
  314. return vm->new_user_object<Mat3x3>(self * other);
  315. });
  316. vm->bind_func(type, "__rmul__", 2, [](VM* vm, ArgsView args){
  317. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  318. f64 other = CAST_F(args[1]);
  319. return vm->new_user_object<Mat3x3>(self * other);
  320. });
  321. vm->bind__truediv__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){
  322. Mat3x3& self = _CAST(Mat3x3&, _0);
  323. f64 other = CAST_F(_1);
  324. return vm->new_user_object<Mat3x3>(self / other);
  325. });
  326. vm->bind__matmul__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){
  327. Mat3x3& self = _CAST(Mat3x3&, _0);
  328. if(vm->is_user_type<Mat3x3>(_1)){
  329. const Mat3x3& other = _CAST(Mat3x3&, _1);
  330. return vm->new_user_object<Mat3x3>(self.matmul(other));
  331. }
  332. if(vm->is_user_type<Vec3>(_1)){
  333. const Vec3 other = _CAST(Vec3, _1);
  334. return vm->new_user_object<Vec3>(self.matmul(other));
  335. }
  336. return vm->NotImplemented;
  337. });
  338. vm->bind(type, "matmul(self, other: mat3x3, out: mat3x3 = None)", [](VM* vm, ArgsView args){
  339. const Mat3x3& self = _CAST(Mat3x3&, args[0]);
  340. const Mat3x3& other = CAST(Mat3x3&, args[1]);
  341. if(args[2] == vm->None){
  342. return vm->new_user_object<Mat3x3>(self.matmul(other));
  343. }else{
  344. Mat3x3& out = CAST(Mat3x3&, args[2]);
  345. out = self.matmul(other);
  346. return vm->None;
  347. }
  348. });
  349. vm->bind_func(type, "determinant", 1, [](VM* vm, ArgsView args){
  350. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  351. return VAR(self.determinant());
  352. });
  353. vm->bind_func(type, "transpose", 1, [](VM* vm, ArgsView args){
  354. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  355. return vm->new_user_object<Mat3x3>(self.transpose());
  356. });
  357. vm->bind__invert__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj){
  358. Mat3x3& self = _CAST(Mat3x3&, obj);
  359. Mat3x3 ret;
  360. if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
  361. return vm->new_user_object<Mat3x3>(ret);
  362. });
  363. vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args){
  364. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  365. Mat3x3 ret;
  366. if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
  367. return vm->new_user_object<Mat3x3>(ret);
  368. });
  369. vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args){
  370. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  371. Mat3x3 ret;
  372. if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
  373. self = ret;
  374. return vm->None;
  375. });
  376. vm->bind_func(type, "transpose_", 1, [](VM* vm, ArgsView args){
  377. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  378. self = self.transpose();
  379. return vm->None;
  380. });
  381. // @staticmethod
  382. vm->bind_func(type, "zeros", 0, [](VM* vm, ArgsView args){
  383. return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
  384. }, {}, BindType::STATICMETHOD);
  385. // @staticmethod
  386. vm->bind_func(type, "ones", 0, [](VM* vm, ArgsView args){
  387. return vm->new_user_object<Mat3x3>(Mat3x3::ones());
  388. }, {}, BindType::STATICMETHOD);
  389. // @staticmethod
  390. vm->bind_func(type, "identity", 0, [](VM* vm, ArgsView args){
  391. return vm->new_user_object<Mat3x3>(Mat3x3::identity());
  392. }, {}, BindType::STATICMETHOD);
  393. /*************** affine transformations ***************/
  394. // @staticmethod
  395. vm->bind(type, "trs(t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args){
  396. Vec2 t = CAST(Vec2, args[0]);
  397. f64 r = CAST_F(args[1]);
  398. Vec2 s = CAST(Vec2, args[2]);
  399. return vm->new_user_object<Mat3x3>(Mat3x3::trs(t, r, s));
  400. }, {}, BindType::STATICMETHOD);
  401. vm->bind(type, "copy_trs_(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args){
  402. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  403. Vec2 t = CAST(Vec2, args[1]);
  404. f64 r = CAST_F(args[2]);
  405. Vec2 s = CAST(Vec2, args[3]);
  406. self = Mat3x3::trs(t, r, s);
  407. return vm->None;
  408. });
  409. vm->bind(type, "copy_t_(self, t: vec2)", [](VM* vm, ArgsView args){
  410. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  411. Vec2 t = CAST(Vec2, args[1]);
  412. self = Mat3x3::trs(t, self._r(), self._s());
  413. return vm->None;
  414. });
  415. vm->bind(type, "copy_r_(self, r: float)", [](VM* vm, ArgsView args){
  416. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  417. f64 r = CAST_F(args[1]);
  418. self = Mat3x3::trs(self._t(), r, self._s());
  419. return vm->None;
  420. });
  421. vm->bind(type, "copy_s_(self, s: vec2)", [](VM* vm, ArgsView args){
  422. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  423. Vec2 s = CAST(Vec2, args[1]);
  424. self = Mat3x3::trs(self._t(), self._r(), s);
  425. return vm->None;
  426. });
  427. vm->bind_func(type, "is_affine", 1, [](VM* vm, ArgsView args){
  428. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  429. return VAR(self.is_affine());
  430. });
  431. vm->bind_func(type, "_t", 1, [](VM* vm, ArgsView args){
  432. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  433. return vm->new_user_object<Vec2>(self._t());
  434. });
  435. vm->bind_func(type, "_r", 1, [](VM* vm, ArgsView args){
  436. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  437. return VAR(self._r());
  438. });
  439. vm->bind_func(type, "_s", 1, [](VM* vm, ArgsView args){
  440. Mat3x3& self = _CAST(Mat3x3&, args[0]);
  441. return vm->new_user_object<Vec2>(self._s());
  442. });
  443. vm->bind_func(type, "transform_point", 2, [](VM* vm, ArgsView args){
  444. const Mat3x3& self = _CAST(Mat3x3&, args[0]);
  445. Vec2 v = CAST(Vec2, args[1]);
  446. Vec2 res(self._11 * v.x + self._12 * v.y + self._13, self._21 * v.x + self._22 * v.y + self._23);
  447. return vm->new_user_object<Vec2>(res);
  448. });
  449. vm->bind_func(type, "inverse_transform_point", 2, [](VM* vm, ArgsView args){
  450. const Mat3x3& self = _CAST(Mat3x3&, args[0]);
  451. Vec2 v = CAST(Vec2, args[1]);
  452. Mat3x3 inv;
  453. if(!self.inverse(inv)) vm->ValueError("matrix is not invertible");
  454. Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23);
  455. return vm->new_user_object<Vec2>(res);
  456. });
  457. vm->bind_func(type, "transform_vector", 2, [](VM* vm, ArgsView args){
  458. const Mat3x3& self = _CAST(Mat3x3&, args[0]);
  459. Vec2 v = CAST(Vec2, args[1]);
  460. Vec2 res(self._11 * v.x + self._12 * v.y, self._21 * v.x + self._22 * v.y);
  461. return vm->new_user_object<Vec2>(res);
  462. });
  463. vm->bind_func(type, "inverse_transform_vector", 2, [](VM* vm, ArgsView args){
  464. const Mat3x3& self = _CAST(Mat3x3&, args[0]);
  465. Vec2 v = CAST(Vec2, args[1]);
  466. Mat3x3 inv;
  467. if(!self.inverse(inv)) vm->ValueError("matrix is not invertible");
  468. Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y);
  469. return vm->new_user_object<Vec2>(res);
  470. });
  471. }
  472. void add_module_linalg(VM* vm){
  473. PyVar linalg = vm->new_module("linalg");
  474. vm->register_user_class<Vec2>(linalg, "vec2", VM::tp_object);
  475. vm->register_user_class<Vec3>(linalg, "vec3", VM::tp_object);
  476. vm->register_user_class<Vec4>(linalg, "vec4", VM::tp_object, true);
  477. vm->register_user_class<Mat3x3>(linalg, "mat3x3", VM::tp_object, true);
  478. PyVar float_p = vm->_modules["c"]->attr("float_p");
  479. linalg->attr().set("vec4_p", float_p);
  480. linalg->attr().set("mat3x3_p", float_p);
  481. }
  482. /////////////// mat3x3 ///////////////
  483. Mat3x3::Mat3x3() {}
  484. Mat3x3::Mat3x3(float _11, float _12, float _13,
  485. float _21, float _22, float _23,
  486. float _31, float _32, float _33)
  487. : _11(_11), _12(_12), _13(_13)
  488. , _21(_21), _22(_22), _23(_23)
  489. , _31(_31), _32(_32), _33(_33) {}
  490. Mat3x3 Mat3x3::zeros(){
  491. return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0);
  492. }
  493. Mat3x3 Mat3x3::ones(){
  494. return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1);
  495. }
  496. Mat3x3 Mat3x3::identity(){
  497. return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
  498. }
  499. Mat3x3 Mat3x3::operator+(const Mat3x3& other) const{
  500. Mat3x3 ret;
  501. for (int i=0; i<9; ++i) ret.v[i] = v[i] + other.v[i];
  502. return ret;
  503. }
  504. Mat3x3 Mat3x3::operator-(const Mat3x3& other) const{
  505. Mat3x3 ret;
  506. for (int i=0; i<9; ++i) ret.v[i] = v[i] - other.v[i];
  507. return ret;
  508. }
  509. Mat3x3 Mat3x3::operator*(float scalar) const{
  510. Mat3x3 ret;
  511. for (int i=0; i<9; ++i) ret.v[i] = v[i] * scalar;
  512. return ret;
  513. }
  514. Mat3x3 Mat3x3::operator/(float scalar) const{
  515. Mat3x3 ret;
  516. for (int i=0; i<9; ++i) ret.v[i] = v[i] / scalar;
  517. return ret;
  518. }
  519. bool Mat3x3::operator==(const Mat3x3& other) const{
  520. for (int i=0; i<9; ++i){
  521. if (!isclose(v[i], other.v[i])) return false;
  522. }
  523. return true;
  524. }
  525. bool Mat3x3::operator!=(const Mat3x3& other) const{
  526. for (int i=0; i<9; ++i){
  527. if (!isclose(v[i], other.v[i])) return true;
  528. }
  529. return false;
  530. }
  531. Mat3x3 Mat3x3::matmul(const Mat3x3& other) const{
  532. Mat3x3 out;
  533. out._11 = _11 * other._11 + _12 * other._21 + _13 * other._31;
  534. out._12 = _11 * other._12 + _12 * other._22 + _13 * other._32;
  535. out._13 = _11 * other._13 + _12 * other._23 + _13 * other._33;
  536. out._21 = _21 * other._11 + _22 * other._21 + _23 * other._31;
  537. out._22 = _21 * other._12 + _22 * other._22 + _23 * other._32;
  538. out._23 = _21 * other._13 + _22 * other._23 + _23 * other._33;
  539. out._31 = _31 * other._11 + _32 * other._21 + _33 * other._31;
  540. out._32 = _31 * other._12 + _32 * other._22 + _33 * other._32;
  541. out._33 = _31 * other._13 + _32 * other._23 + _33 * other._33;
  542. return out;
  543. }
  544. Vec3 Mat3x3::matmul(const Vec3& other) const{
  545. Vec3 out;
  546. out.x = _11 * other.x + _12 * other.y + _13 * other.z;
  547. out.y = _21 * other.x + _22 * other.y + _23 * other.z;
  548. out.z = _31 * other.x + _32 * other.y + _33 * other.z;
  549. return out;
  550. }
  551. float Mat3x3::determinant() const{
  552. return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32
  553. - _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31;
  554. }
  555. Mat3x3 Mat3x3::transpose() const{
  556. Mat3x3 ret;
  557. ret._11 = _11; ret._12 = _21; ret._13 = _31;
  558. ret._21 = _12; ret._22 = _22; ret._23 = _32;
  559. ret._31 = _13; ret._32 = _23; ret._33 = _33;
  560. return ret;
  561. }
  562. bool Mat3x3::inverse(Mat3x3& out) const{
  563. float det = determinant();
  564. if (isclose(det, 0)) return false;
  565. float inv_det = 1.0f / det;
  566. out._11 = (_22 * _33 - _23 * _32) * inv_det;
  567. out._12 = (_13 * _32 - _12 * _33) * inv_det;
  568. out._13 = (_12 * _23 - _13 * _22) * inv_det;
  569. out._21 = (_23 * _31 - _21 * _33) * inv_det;
  570. out._22 = (_11 * _33 - _13 * _31) * inv_det;
  571. out._23 = (_13 * _21 - _11 * _23) * inv_det;
  572. out._31 = (_21 * _32 - _22 * _31) * inv_det;
  573. out._32 = (_12 * _31 - _11 * _32) * inv_det;
  574. out._33 = (_11 * _22 - _12 * _21) * inv_det;
  575. return true;
  576. }
  577. Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s){
  578. float cr = cosf(radian);
  579. float sr = sinf(radian);
  580. return Mat3x3(s.x * cr, -s.y * sr, t.x,
  581. s.x * sr, s.y * cr, t.y,
  582. 0.0f, 0.0f, 1.0f);
  583. }
  584. bool Mat3x3::is_affine() const{
  585. float det = _11 * _22 - _12 * _21;
  586. if(isclose(det, 0)) return false;
  587. return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
  588. }
  589. Vec2 Mat3x3::_t() const { return Vec2(_13, _23); }
  590. float Mat3x3::_r() const { return atan2f(_21, _11); }
  591. Vec2 Mat3x3::_s() const {
  592. return Vec2(
  593. sqrtf(_11 * _11 + _21 * _21),
  594. sqrtf(_12 * _12 + _22 * _22)
  595. );
  596. }
  597. } // namespace pkpy