Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

546 строки
16 KiB

  1. unit ugluMatrixExHelper;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils,
  6. ugluVectorExHelper;
  7. type
  8. generic TgluMatrixHelper<T> = class
  9. public type
  10. TVectorHelper = specialize TgluVectorHelper<T>;
  11. TVectorHelperF = specialize TgluVectorHelperF<T>;
  12. TBaseType = T;
  13. PBaseType = ^T;
  14. TMat2 = array[0..1] of TVectorHelper.TVector2;
  15. TMat3 = array[0..2] of TVectorHelper.TVector3;
  16. TMat4 = array[0..3] of TVectorHelper.TVector4;
  17. PMat2 = ^TMat2;
  18. PMat3 = ^TMat3;
  19. PMat4 = ^TMat4;
  20. public
  21. class function Equals(const m1, m2: TMat2): Boolean; overload; inline;
  22. class function Equals(const m1, m2: TMat3): Boolean; overload; inline;
  23. class function Equals(const m1, m2: TMat4): Boolean; overload; inline;
  24. class function ToString(const m: TMat2; const aRound: Integer = -3): String; overload; inline;
  25. class function ToString(const m: TMat3; const aRound: Integer = -3): String; overload; inline;
  26. class function ToString(const m: TMat4; const aRound: Integer = -3): String; overload; inline;
  27. class function TryFromString(const s: String; out m: TMat2): Boolean; overload; inline;
  28. class function TryFromString(const s: String; out m: TMat3): Boolean; overload; inline;
  29. class function TryFromString(const s: String; out m: TMat4): Boolean; overload; inline;
  30. class function Transpose(const m: TMat2): TMat2; overload; inline;
  31. class function Transpose(const m: TMat3): TMat3; overload; inline;
  32. class function Transpose(const m: TMat4): TMat4; overload; inline;
  33. class function Sub(const m: TMat2; const c, r: Integer): TBaseType; overload; inline;
  34. class function Sub(const m: TMat3; const c, r: Integer): TMat2; overload; inline;
  35. class function Sub(const m: TMat4; const c, r: Integer): TMat3; overload; inline;
  36. class function Determinant(const m: TMat2): Double; overload; inline;
  37. class function Determinant(const m: TMat3): Double; overload; inline;
  38. class function Determinant(const m: TMat4): Double; overload;
  39. class function Adjoint(const m: TMat3): TMat3; overload;
  40. class function Adjoint(const m: TMat4): TMat4; overload;
  41. class function Multiply(const m1, m2: TMat2): TMat2; overload; inline;
  42. class function Multiply(const m1, m2: TMat3): TMat3; overload; inline;
  43. class function Multiply(const m1, m2: TMat4): TMat4; overload; inline;
  44. class function Multiply(const m: TMat2; const v: TVectorHelper.TVector2): TVectorHelper.TVector2; overload; inline;
  45. class function Multiply(const m: TMat3; const v: TVectorHelper.TVector3): TVectorHelper.TVector3; overload; inline;
  46. class function Multiply(const m: TMat4; const v: TVectorHelper.TVector4): TVectorHelper.TVector4; overload; inline;
  47. class function Multiply(const m: TMat2; const v: TBaseType): TMat2; overload; inline;
  48. class function Multiply(const m: TMat3; const v: TBaseType): TMat3; overload; inline;
  49. class function Multiply(const m: TMat4; const v: TBaseType): TMat4; overload; inline;
  50. class function Invert(m: TMat2): TMat2; overload; inline;
  51. class function Invert(m: TMat3): TMat3; overload; inline;
  52. class function Invert(m: TMat4): TMat4; overload; inline;
  53. class function CreateTranslate(const v: TVectorHelper.TVector2): TMat3;
  54. class function CreateTranslate(const v: TVectorHelper.TVector3): TMat4;
  55. class function CreateScale(const v: TVectorHelper.TVector2): TMat3;
  56. class function CreateScale(const v: TVectorHelper.TVector3): TMat4;
  57. class function CreateRotate(a: Double): TMat3;
  58. class function CreateRotate(axis: TVectorHelper.TVector3; a: Double): TMat4;
  59. class function CreateShear(const v: TVectorHelper.TVector2): TMat3;
  60. class function CreateShear(const x, y, z: TVectorHelper.TVector2): TMat4;
  61. private
  62. class function GetElement(p: PBaseType; x, y, sz: Integer): TBaseType; inline;
  63. class procedure SetElement(p: PBaseType; x, y, sz: Integer; v: TBaseType); inline;
  64. class procedure Transpose(src, dst: PBaseType; sz: Integer);
  65. class procedure Sub(src, dst: PBaseType; sz, c, r: Integer);
  66. class procedure Mult(p1, p2, r: PBaseType; c1r2, r1, c2: Integer);
  67. class procedure Mult(src, dst: PBaseType; c, r: Integer; v: TBaseType);
  68. class function TryFromString(const s: String; p: PBaseType; r, c: Integer): Boolean;
  69. end;
  70. TgluMatrixF = specialize TgluMatrixHelper<Single>;
  71. TgluMatrixD = specialize TgluMatrixHelper<Double>;
  72. implementation
  73. uses
  74. Math;
  75. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  76. //TgluMatrixHelper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  77. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  78. class function TgluMatrixHelper.Equals(const m1, m2: TMat2): Boolean;
  79. begin
  80. result :=
  81. TVectorHelper.Equals(m1[0], m2[0]) and
  82. TVectorHelper.Equals(m1[1], m2[1]);
  83. end;
  84. class function TgluMatrixHelper.Equals(const m1, m2: TMat3): Boolean;
  85. begin
  86. result :=
  87. TVectorHelper.Equals(m1[0], m2[0]) and
  88. TVectorHelper.Equals(m1[1], m2[1]) and
  89. TVectorHelper.Equals(m1[2], m2[2]);
  90. end;
  91. class function TgluMatrixHelper.Equals(const m1, m2: TMat4): Boolean;
  92. begin
  93. result :=
  94. TVectorHelper.Equals(m1[0], m2[0]) and
  95. TVectorHelper.Equals(m1[1], m2[1]) and
  96. TVectorHelper.Equals(m1[2], m2[2]) and
  97. TVectorHelper.Equals(m1[3], m2[3]);
  98. end;
  99. class function TgluMatrixHelper.ToString(const m: TMat2; const aRound: Integer): String;
  100. begin
  101. result := format('(%s); (%s)', [
  102. TVectorHelper.ToString(m[0], aRound),
  103. TVectorHelper.ToString(m[1], aRound)]);
  104. end;
  105. class function TgluMatrixHelper.ToString(const m: TMat3; const aRound: Integer): String;
  106. begin
  107. result := format('(%s); (%s); (%s)', [
  108. TVectorHelper.ToString(m[0], aRound),
  109. TVectorHelper.ToString(m[1], aRound),
  110. TVectorHelper.ToString(m[2], aRound)]);
  111. end;
  112. class function TgluMatrixHelper.ToString(const m: TMat4; const aRound: Integer): String;
  113. begin
  114. result := format('(%s); (%s); (%s); (%s)', [
  115. TVectorHelper.ToString(m[0], aRound),
  116. TVectorHelper.ToString(m[1], aRound),
  117. TVectorHelper.ToString(m[2], aRound),
  118. TVectorHelper.ToString(m[3], aRound)]);
  119. end;
  120. class function TgluMatrixHelper.TryFromString(const s: String; out m: TMat2): Boolean;
  121. begin
  122. result := TryFromString(s, @m[0,0], 2, 2);
  123. end;
  124. class function TgluMatrixHelper.TryFromString(const s: String; out m: TMat3): Boolean;
  125. begin
  126. result := TryFromString(s, @m[0,0], 3, 3);
  127. end;
  128. class function TgluMatrixHelper.TryFromString(const s: String; out m: TMat4): Boolean;
  129. begin
  130. result := TryFromString(s, @m[0,0], 4, 4);
  131. end;
  132. class function TgluMatrixHelper.Transpose(const m: TMat2): TMat2;
  133. begin
  134. Transpose(@m[0,0], @result[0,0], Length(m));
  135. end;
  136. class function TgluMatrixHelper.Transpose(const m: TMat3): TMat3;
  137. begin
  138. Transpose(@m[0,0], @result[0,0], Length(m));
  139. end;
  140. class function TgluMatrixHelper.Transpose(const m: TMat4): TMat4;
  141. begin
  142. Transpose(@m[0,0], @result[0,0], Length(m));
  143. end;
  144. class function TgluMatrixHelper.Sub(const m: TMat2; const c, r: Integer): TBaseType;
  145. begin
  146. Sub(@m[0,0], @result, 2, c, r);
  147. end;
  148. class function TgluMatrixHelper.Sub(const m: TMat3; const c, r: Integer): TMat2;
  149. begin
  150. Sub(@m[0,0], @result[0,0], 3, c, r);
  151. end;
  152. class function TgluMatrixHelper.Sub(const m: TMat4; const c, r: Integer): TMat3;
  153. begin
  154. Sub(@m[0,0], @result[0,0], 4, c, r);
  155. end;
  156. class function TgluMatrixHelper.Determinant(const m: TMat2): Double;
  157. begin
  158. result := m[0,0] * m[1,1] - m[1,0] * m[0,1];
  159. end;
  160. class function TgluMatrixHelper.Determinant(const m: TMat3): Double;
  161. begin
  162. result :=
  163. m[0,0] * m[1,1] * m[2,2] +
  164. m[1,0] * m[2,1] * m[0,2] +
  165. m[2,0] * m[0,1] * m[1,2] -
  166. m[2,0] * m[1,1] * m[0,2] -
  167. m[1,0] * m[0,1] * m[2,2] -
  168. m[0,0] * m[2,1] * m[1,2];
  169. end;
  170. class function TgluMatrixHelper.Determinant(const m: TMat4): Double;
  171. var
  172. i: Integer;
  173. begin
  174. result := 0.0;
  175. for i := 0 to 3 do
  176. result := result + power(-1, i) * m[i,0] * Determinant(Sub(m, i, 0));
  177. end;
  178. class function TgluMatrixHelper.Adjoint(const m: TMat3): TMat3;
  179. var
  180. i, j: Integer;
  181. begin
  182. for i := 0 to 2 do
  183. for j := 0 to 2 do
  184. result[i,j] := power(-1, i+j) * Determinant(Sub(m, i, j));
  185. result := Transpose(result{%H-});
  186. end;
  187. class function TgluMatrixHelper.Adjoint(const m: TMat4): TMat4;
  188. var
  189. i, j: Integer;
  190. begin
  191. for i := 0 to 3 do
  192. for j := 0 to 3 do
  193. result[i,j] := power(-1, i+j) * Determinant(Sub(m, i, j));
  194. result := Transpose(result{%H-});
  195. end;
  196. class function TgluMatrixHelper.Multiply(const m1, m2: TMat2): TMat2;
  197. begin
  198. Mult(@m1[0,0], @m2[0,0], @result[0,0], 2, 2, 2);
  199. end;
  200. class function TgluMatrixHelper.Multiply(const m1, m2: TMat3): TMat3;
  201. begin
  202. Mult(@m1[0,0], @m2[0,0], @result[0,0], 3, 3, 3);
  203. end;
  204. class function TgluMatrixHelper.Multiply(const m1, m2: TMat4): TMat4;
  205. begin
  206. Mult(@m1[0,0], @m2[0,0], @result[0,0], 4, 4, 4);
  207. end;
  208. class function TgluMatrixHelper.Multiply(const m: TMat2; const v: TVectorHelper.TVector2): TVectorHelper.TVector2;
  209. begin
  210. Mult(@m[0,0], @v[0], @result[0], 2, 2, 1);
  211. end;
  212. class function TgluMatrixHelper.Multiply(const m: TMat3; const v: TVectorHelper.TVector3): TVectorHelper.TVector3;
  213. begin
  214. Mult(@m[0,0], @v[0], @result[0], 3, 3, 1);
  215. end;
  216. class function TgluMatrixHelper.Multiply(const m: TMat4; const v: TVectorHelper.TVector4): TVectorHelper.TVector4;
  217. begin
  218. Mult(@m[0,0], @v[0], @result[0], 4, 4, 1);
  219. end;
  220. class function TgluMatrixHelper.Multiply(const m: TMat2; const v: TBaseType): TMat2;
  221. begin
  222. Mult(@m[0,0], @result[0,0], 2, 2, v);
  223. end;
  224. class function TgluMatrixHelper.Multiply(const m: TMat3; const v: TBaseType): TMat3;
  225. begin
  226. Mult(@m[0,0], @result[0,0], 3, 3, v);
  227. end;
  228. class function TgluMatrixHelper.Multiply(const m: TMat4; const v: TBaseType): TMat4;
  229. begin
  230. Mult(@m[0,0], @result[0,0], 4, 4, v);
  231. end;
  232. class function TgluMatrixHelper.Invert(m: TMat2): TMat2;
  233. begin
  234. result[0,0] := m[1,1];
  235. result[0,1] := -m[0,1];
  236. result[1,0] := -m[1,0];
  237. result[1,1] := m[0,0];
  238. m := result;
  239. Mult(@m[0,0], @result[0,0], 2, 2, 1 / Determinant(m));
  240. end;
  241. class function TgluMatrixHelper.Invert(m: TMat3): TMat3;
  242. var d: TBaseType;
  243. begin
  244. d := Determinant(m);
  245. m := Adjoint(m);
  246. Mult(@m[0,0], @result[0,0], 3, 3, 1 / d);
  247. end;
  248. class function TgluMatrixHelper.Invert(m: TMat4): TMat4;
  249. var d: TBaseType;
  250. begin
  251. d := Determinant(m);
  252. result := Adjoint(m);
  253. Mult(@m[0,0], @result[0,0], 4, 4, 1 / d);
  254. end;
  255. class function TgluMatrixHelper.CreateTranslate(const v: TVectorHelper.TVector2): TMat3;
  256. begin
  257. result[0, 0] := 1.0;
  258. result[0, 1] := 0.0;
  259. result[0, 2] := 0.0;
  260. result[1, 0] := 0.0;
  261. result[1, 1] := 1.0;
  262. result[1, 2] := 0.0;
  263. result[2, 0] := v[0];
  264. result[2, 1] := v[1];
  265. result[2, 2] := 1.0;
  266. end;
  267. class function TgluMatrixHelper.CreateTranslate(const v: TVectorHelper.TVector3): TMat4;
  268. begin
  269. result[0, 0] := 1.0;
  270. result[0, 1] := 0.0;
  271. result[0, 2] := 0.0;
  272. result[0, 3] := 0.0;
  273. result[1, 0] := 0.0;
  274. result[1, 1] := 1.0;
  275. result[1, 2] := 0.0;
  276. result[1, 3] := 0.0;
  277. result[2, 0] := 0.0;
  278. result[2, 1] := 0.0;
  279. result[2, 2] := 1.0;
  280. result[2, 3] := 0.0;
  281. result[3, 0] := v[0];
  282. result[3, 1] := v[1];
  283. result[3, 2] := v[2];
  284. result[3, 3] := 1.0;
  285. end;
  286. class function TgluMatrixHelper.CreateScale(const v: TVectorHelper.TVector2): TMat3;
  287. begin
  288. result[0, 0] := v[0];
  289. result[0, 1] := 0.0;
  290. result[0, 2] := 0.0;
  291. result[1, 0] := 0.0;
  292. result[1, 1] := v[1];
  293. result[1, 2] := 0.0;
  294. result[2, 0] := 0.0;
  295. result[2, 1] := 0.0;
  296. result[2, 2] := 1.0;
  297. end;
  298. class function TgluMatrixHelper.CreateScale(const v: TVectorHelper.TVector3): TMat4;
  299. begin
  300. result[0, 0] := v[0];
  301. result[0, 1] := 0.0;
  302. result[0, 2] := 0.0;
  303. result[0, 3] := 0.0;
  304. result[1, 0] := 0.0;
  305. result[1, 1] := v[1];
  306. result[1, 2] := 0.0;
  307. result[1, 3] := 0.0;
  308. result[2, 0] := 0.0;
  309. result[2, 1] := 0.0;
  310. result[2, 2] := v[2];
  311. result[2, 3] := 0.0;
  312. result[3, 0] := 0.0;
  313. result[3, 1] := 0.0;
  314. result[3, 2] := 0.0;
  315. result[3, 3] := 1.0;
  316. end;
  317. class function TgluMatrixHelper.CreateRotate(a: Double): TMat3;
  318. begin
  319. a := DegToRad(a);
  320. result[0, 0] := cos(a);
  321. result[0, 1] := -sin(a);
  322. result[0, 2] := 0.0;
  323. result[1, 0] := sin(a);
  324. result[1, 1] := cos(a);
  325. result[1, 2] := 0.0;
  326. result[2, 0] := 0.0;
  327. result[2, 1] := 0.0;
  328. result[2, 2] := 1.0;
  329. end;
  330. class function TgluMatrixHelper.CreateRotate(axis: TVectorHelper.TVector3; a: Double): TMat4;
  331. var
  332. X, Y, Z, s, c: Single;
  333. begin
  334. a := DegToRad(a);
  335. axis := TVectorHelperF.Normalize(axis);
  336. X := axis[0];
  337. Y := axis[1];
  338. Z := axis[2];
  339. s := sin(a);
  340. c := cos(a);
  341. result[0,0] := SQR(X) + (1-SQR(X))*c;
  342. result[0,1] := X*Y*(1-c) + Z*s;
  343. result[0,2] := X*Z*(1-c) - Y*s;
  344. result[0,3] := 0.0;
  345. result[1,0] := X*Y*(1-c) - Z*s;
  346. result[1,1] := SQR(Y) + (1-SQR(Y))*c;
  347. result[1,2] := Y*Z*(1-c) + X*s;
  348. result[1,3] := 0.0;
  349. result[2,0] := X*Z*(1-c) + Y*s;
  350. result[2,1] := Y*Z*(1-c) - X*s;
  351. result[2,2] := SQR(Z) + (1-SQR(Z))*c;
  352. result[2,3] := 0.0;
  353. result[3,0] := 0.0;
  354. result[3,1] := 0.0;
  355. result[3,2] := 0.0;
  356. result[3,3] := 1.0;
  357. end;
  358. class function TgluMatrixHelper.CreateShear(const v: TVectorHelper.TVector2): TMat3;
  359. begin
  360. result[0, 0] := 1.0;
  361. result[0, 1] := v[1];
  362. result[0, 2] := 0.0;
  363. result[1, 0] := v[0];
  364. result[1, 1] := 1.0;
  365. result[1, 2] := 0.0;
  366. result[2, 0] := 0.0;
  367. result[2, 1] := 0.0;
  368. result[2, 2] := 1.0;
  369. end;
  370. class function TgluMatrixHelper.CreateShear(const x, y, z: TVectorHelper.TVector2): TMat4;
  371. begin
  372. result[0,0] := 1.0;
  373. result[0,1] := y[0];
  374. result[0,2] := z[0];
  375. result[0,3] := 0.0;
  376. result[1,0] := x[0];
  377. result[1,1] := 1.0;
  378. result[1,2] := z[1];
  379. result[1,3] := 0.0;
  380. result[2,0] := x[1];
  381. result[2,1] := y[1];
  382. result[2,2] := 1.0;
  383. result[2,3] := 0.0;
  384. result[3,0] := 0.0;
  385. result[3,1] := 0.0;
  386. result[3,2] := 0.0;
  387. result[3,3] := 1.0;
  388. end;
  389. class function TgluMatrixHelper.GetElement(p: PBaseType; x, y, sz: Integer): TBaseType;
  390. begin
  391. result := (p + (x * sz) + y)^;
  392. end;
  393. class procedure TgluMatrixHelper.SetElement(p: PBaseType; x, y, sz: Integer; v: TBaseType);
  394. begin
  395. (p + (x * sz) + y)^ := v;
  396. end;
  397. class procedure TgluMatrixHelper.Transpose(src, dst: PBaseType; sz: Integer);
  398. var
  399. i, j: Integer;
  400. begin
  401. for i := 0 to sz-1 do
  402. for j := 0 to sz-1 do
  403. SetElement(dst, i, j, sz, GetElement(src, j, i, sz));
  404. end;
  405. class procedure TgluMatrixHelper.Sub(src, dst: PBaseType; sz, c, r: Integer);
  406. var
  407. x, y, i, j: Integer;
  408. begin
  409. for i := 0 to sz-1 do begin
  410. for j := 0 to sz-1 do begin
  411. x := i;
  412. y := j;
  413. if (i >= c) then inc(x);
  414. if (j >= r) then inc(y);
  415. SetElement(dst, i, j, sz-1, GetElement(src, x, y, sz));
  416. end;
  417. end;
  418. end;
  419. class procedure TgluMatrixHelper.Mult(p1, p2, r: PBaseType; c1r2, r1, c2: Integer);
  420. var
  421. x, y, i: Integer;
  422. sum: TBaseType;
  423. begin
  424. for x := 0 to c2-1 do begin
  425. for y := 0 to r1-1 do begin
  426. sum := 0;
  427. for i := 0 to c1r2-1 do
  428. sum := sum + GetElement(p1, i, y, c1r2) * GetElement(p2, x, i, c2);
  429. SetElement(r, x, y, c2, sum);
  430. end;
  431. end;
  432. end;
  433. class procedure TgluMatrixHelper.Mult(src, dst: PBaseType; c, r: Integer; v: TBaseType);
  434. var
  435. i, j: Integer;
  436. begin
  437. for i := 0 to c-1 do
  438. for j := 0 to r-1 do
  439. SetElement(dst, i, j, c, v * GetElement(src, i, j, c));
  440. end;
  441. class function TgluMatrixHelper.TryFromString(const s: String; p: PBaseType; r, c: Integer): Boolean;
  442. var
  443. i, j, l: Integer;
  444. begin
  445. result := true;
  446. l := Length(s);
  447. i := 1;
  448. j := l;
  449. while (i <= l) and (c > 0) and result do begin
  450. if (s[i] = '(') then begin
  451. j := i+1;
  452. end else if (s[i] = ')') then begin
  453. result := TVectorHelper.TryFromString(trim(copy(s, j, i-j)), p, r);
  454. j := l;
  455. inc(p, r);
  456. dec(c);
  457. end;
  458. inc(i);
  459. end;
  460. result := (c = 0);
  461. while (c > 0) do begin
  462. for i := 0 to r-1 do begin
  463. p^ := 0;
  464. inc(p);
  465. end;
  466. dec(c);
  467. end;
  468. end;
  469. end.