2
0

GXS.CurvesAndSurfaces.pas 7.7 KB

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