GLS.CurvesAndSurfaces.pas 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.CurvesAndSurfaces;
  5. (* Bezier and B-Spline Curve and Surface Routines *)
  6. interface
  7. uses
  8. System.SysUtils,
  9. GLS.VectorTypes,
  10. GLS.VectorGeometry,
  11. GLS.VectorLists;
  12. type
  13. TBSplineContinuity = (bscUniformNonPeriodic, bscUniformPeriodic);
  14. function BezierCurvePoint(t: single; n: integer; cp: PAffineVectorArray): TAffineVector;
  15. function BezierSurfacePoint(s, t: single; m, n: integer; cp: PAffineVectorArray): TAffineVector;
  16. procedure GenerateBezierCurve(Steps: integer; ControlPoints, Vertices: TGLAffineVectorList);
  17. procedure GenerateBezierSurface(Steps, Width, Height: integer; ControlPoints, Vertices: TGLAffineVectorList);
  18. function BSplinePoint(t: single; n, k: integer; knots: PSingleArray;
  19. cp: PAffineVectorArray): TAffineVector;
  20. function BSplineSurfacePoint(s, t: single; m, n, k1, k2: integer;
  21. uknots, vknots: PSingleArray; cp: PAffineVectorArray): TAffineVector;
  22. procedure GenerateBSpline(Steps, Order: integer; KnotVector: TGLSingleList;
  23. ControlPoints, Vertices: TGLAffineVectorList);
  24. procedure GenerateBSplineSurface(Steps, UOrder, VOrder, Width, Height: integer;
  25. UKnotVector, VKnotVector: TGLSingleList;
  26. ControlPoints, Vertices: TGLAffineVectorList);
  27. procedure GenerateKnotVector(KnotVector: TGLSingleList;
  28. NumberOfPoints, Order: integer; Continuity: TBSplineContinuity);
  29. // --------------------------------------------------------------------------
  30. implementation
  31. // --------------------------------------------------------------------------
  32. function Factorial(n: integer): single;
  33. var
  34. i: integer;
  35. begin
  36. if (n < 0) or (n > 32) then
  37. Exception.Create('Invalid factorial parameter: n = ' + IntToStr(n));
  38. Result := 1;
  39. for i := 2 to n do
  40. Result := Result * i;
  41. end;
  42. // ------------------------------------------------------------
  43. // Bezier routines
  44. // ------------------------------------------------------------
  45. function BernsteinBasis(n, i: integer; t: single): single;
  46. var
  47. ti, tni: single;
  48. begin
  49. if (t = 0) and (i = 0) then
  50. ti := 1
  51. else
  52. ti := PowerInteger(t, i);
  53. if (n = i) and (t = 1) then
  54. tni := 1
  55. else
  56. tni := PowerInteger(1 - t, integer(n - i));
  57. Result := (Factorial(n) / (Factorial(i) * Factorial(n - i))) * ti * tni;
  58. end;
  59. function BezierCurvePoint(t: single; n: integer; cp: PAffineVectorArray)
  60. : TAffineVector;
  61. var
  62. i: integer;
  63. b: single;
  64. begin
  65. Result := NullVector;
  66. for i := 0 to n - 1 do
  67. begin
  68. b := BernsteinBasis(n - 1, i, t);
  69. Result.X := Result.X + cp[i].X * b;
  70. Result.Y := Result.Y + cp[i].Y * b;
  71. Result.Z := Result.Z + cp[i].Z * b;
  72. end;
  73. end;
  74. function BezierSurfacePoint(s, t: single; m, n: integer; cp: PAffineVectorArray)
  75. : TAffineVector;
  76. var
  77. i, j: integer;
  78. b1, b2: single;
  79. begin
  80. Result := NullVector;
  81. for j := 0 to n - 1 do
  82. for i := 0 to m - 1 do
  83. begin
  84. b1 := BernsteinBasis(m - 1, i, s);
  85. b2 := BernsteinBasis(n - 1, j, t);
  86. Result.X := Result.X + cp[j * m + i].X * b1 * b2;
  87. Result.Y := Result.Y + cp[j * m + i].Y * b1 * b2;
  88. Result.Z := Result.Z + cp[j * m + i].Z * b1 * b2;
  89. end;
  90. end;
  91. procedure GenerateBezierCurve(Steps: integer;
  92. ControlPoints, Vertices: TGLAffineVectorList);
  93. var
  94. i: integer;
  95. begin
  96. Vertices.Count := Steps;
  97. for i := 0 to Steps - 1 do
  98. Vertices[i] := BezierCurvePoint(i / (Steps - 1), ControlPoints.Count,
  99. ControlPoints.List);
  100. end;
  101. procedure GenerateBezierSurface(Steps, Width, Height: integer;
  102. ControlPoints, Vertices: TGLAffineVectorList);
  103. var
  104. i, j: integer;
  105. begin
  106. Vertices.Count := Steps * Steps;
  107. for j := 0 to Steps - 1 do
  108. for i := 0 to Steps - 1 do
  109. Vertices[i + j * Steps] := BezierSurfacePoint(i / (Steps - 1),
  110. j / (Steps - 1), Width, Height, ControlPoints.List);
  111. end;
  112. // ------------------------------------------------------------
  113. // B-Spline routines
  114. // ------------------------------------------------------------
  115. function BSplineBasis(i, k, n: integer; u: single; knots: PSingleArray): single;
  116. var
  117. v1, v2: single;
  118. begin
  119. if (u < knots[i]) or (u > knots[i + k]) then
  120. begin
  121. Result := 0;
  122. end
  123. else if k = 1 then
  124. begin
  125. Result := 0;
  126. if (u >= knots[i]) and (u < knots[i + 1]) then
  127. Result := 1;
  128. end
  129. else if (i = n - 1) and (u = knots[i + k]) then
  130. begin
  131. Result := 1;
  132. end
  133. else
  134. begin
  135. v1 := (knots[i + k - 1] - knots[i]);
  136. v2 := (knots[i + k] - knots[i + 1]);
  137. if v1 <> 0 then
  138. v1 := (u - knots[i]) / v1 * BSplineBasis(i, k - 1, n, u, knots);
  139. if v2 <> 0 then
  140. v2 := (knots[i + k] - u) / v2 * BSplineBasis(i + 1, k - 1, n, u, knots);
  141. Result := v1 + v2;
  142. end;
  143. end;
  144. function BSplinePoint(t: single; n, k: integer; knots: PSingleArray;
  145. cp: PAffineVectorArray): TAffineVector;
  146. var
  147. i: integer;
  148. b: array of single;
  149. det: single;
  150. begin
  151. SetLength(b, n);
  152. for i := 0 to n - 1 do
  153. b[i] := BSplineBasis(i, k, n, t, knots);
  154. det := 0;
  155. for i := 0 to n - 1 do
  156. det := det + b[i];
  157. Result := NullVector;
  158. for i := 0 to n - 1 do
  159. begin
  160. if det <> 0 then
  161. b[i] := b[i] / det
  162. else
  163. b[i] := 0;
  164. Result.X := Result.X + cp[i].X * b[i];
  165. Result.Y := Result.Y + cp[i].Y * b[i];
  166. Result.Z := Result.Z + cp[i].Z * b[i];
  167. end;
  168. SetLength(b, 0);
  169. end;
  170. function BSplineSurfacePoint(s, t: single; m, n, k1, k2: integer;
  171. uknots, vknots: PSingleArray; cp: PAffineVectorArray): TAffineVector;
  172. var
  173. i, j: integer;
  174. b1, b2: array of single;
  175. det1, det2: single;
  176. begin
  177. SetLength(b1, m);
  178. SetLength(b2, n);
  179. det1 := 0;
  180. det2 := 0;
  181. for i := 0 to m - 1 do
  182. b1[i] := BSplineBasis(i, k1, m, s, uknots);
  183. for i := 0 to n - 1 do
  184. b2[i] := BSplineBasis(i, k2, n, t, vknots);
  185. for i := 0 to m - 1 do
  186. det1 := det1 + b1[i];
  187. for i := 0 to n - 1 do
  188. det2 := det2 + b2[i];
  189. Result := NullVector;
  190. for j := 0 to n - 1 do
  191. begin
  192. if det2 <> 0 then
  193. b2[j] := b2[j] / det2
  194. else
  195. b2[j] := 0;
  196. for i := 0 to m - 1 do
  197. begin
  198. if det1 <> 0 then
  199. b1[i] := b1[i] / det1
  200. else
  201. b1[i] := 0;
  202. Result.X := Result.X + cp[j * m + i].X * b1[i] * b2[j];
  203. Result.Y := Result.Y + cp[j * m + i].Y * b1[i] * b2[j];
  204. Result.Z := Result.Z + cp[j * m + i].Z * b1[i] * b2[j];
  205. end;
  206. end;
  207. end;
  208. procedure GenerateBSpline(Steps, Order: integer; KnotVector: TGLSingleList;
  209. ControlPoints, Vertices: TGLAffineVectorList);
  210. var
  211. i: integer;
  212. begin
  213. Vertices.Clear;
  214. Vertices.Count := Steps;
  215. for i := 0 to Steps - 1 do
  216. Vertices[i] := BSplinePoint(i / (Steps - 1), ControlPoints.Count, Order + 1,
  217. @KnotVector.List[0], ControlPoints.List);
  218. end;
  219. procedure GenerateBSplineSurface(Steps, UOrder, VOrder, Width, Height: integer;
  220. UKnotVector, VKnotVector: TGLSingleList; ControlPoints, Vertices: TGLAffineVectorList);
  221. var
  222. i, j: integer;
  223. begin
  224. Vertices.Clear;
  225. Vertices.Count := Steps * Steps;
  226. for j := 0 to Steps - 1 do
  227. for i := 0 to Steps - 1 do
  228. Vertices[i + j * Steps] := BSplineSurfacePoint(i / (Steps - 1),
  229. j / (Steps - 1), Width, Height, UOrder + 1, VOrder + 1,
  230. @UKnotVector.List[0], @VKnotVector.List[0], ControlPoints.List);
  231. end;
  232. procedure GenerateKnotVector(KnotVector: TGLSingleList;
  233. NumberOfPoints, Order: integer; Continuity: TBSplineContinuity);
  234. var
  235. i, n, k: integer;
  236. begin
  237. KnotVector.Clear;
  238. k := Order + 1;
  239. n := NumberOfPoints - 1;
  240. case Continuity of
  241. // Open curve
  242. bscUniformNonPeriodic:
  243. begin
  244. for i := 0 to n + k do
  245. begin
  246. if i < k then
  247. KnotVector.Add(0)
  248. else if i > n then
  249. KnotVector.Add(n - k + 2)
  250. else
  251. KnotVector.Add(i - k + 1);
  252. end;
  253. end;
  254. // Closed curve
  255. bscUniformPeriodic:
  256. begin
  257. for i := 0 to n + k do
  258. begin
  259. KnotVector.Add(i);
  260. end;
  261. KnotVector.Scale(1 / KnotVector.Sum);
  262. end;
  263. end;
  264. end;
  265. end.