GLS.CurvesAndSurfaces.pas 7.7 KB

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