You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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