fScatterPlot.pas 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. unit fScatterPlot;
  2. interface
  3. {$I GR32.inc}
  4. uses
  5. {$IFDEF FPC}LCLIntf, {$ELSE}Windows, {$ENDIF}
  6. System.SysUtils,
  7. System.Classes,
  8. System.Math,
  9. Vcl.Graphics,
  10. Vcl.Controls,
  11. Vcl.Forms,
  12. Vcl.Dialogs,
  13. GR32,
  14. GR32_Image,
  15. GR32_Polygons;
  16. type
  17. TScatterPoint = record
  18. X, Y, Z: TFloat;
  19. Color: TColor32;
  20. end;
  21. TFmScatterPlot = class(TForm)
  22. Image32: TImage32;
  23. procedure FormCreate(Sender: TObject);
  24. procedure Image32PaintStage(Sender: TObject; Buffer: TBitmap32;
  25. StageNum: Cardinal);
  26. procedure Image32Click(Sender: TObject);
  27. private
  28. FPoints: array of TScatterPoint;
  29. FRadius: TFloat;
  30. FSelection: TFloat;
  31. FCircle: TArrayOfFloatPoint;
  32. FBounds: array [0..1] of TFloat;
  33. FRenderer: TPolygonRenderer32VPR;
  34. procedure Generate;
  35. procedure Draw;
  36. public
  37. procedure ApplicationIdleHandler(Sender: TObject; var Done: Boolean);
  38. end;
  39. var
  40. FmScatterPlot: TFmScatterPlot;
  41. implementation
  42. {$IFDEF FPC}
  43. {$R *.lfm}
  44. {$ELSE}
  45. {$R *.dfm}
  46. {$ENDIF}
  47. uses
  48. GR32_Math,
  49. GR32_LowLevel,
  50. GR32_VectorUtils;
  51. procedure TFmScatterPlot.FormCreate(Sender: TObject);
  52. var
  53. NumPoints: Integer;
  54. begin
  55. Image32.Bitmap.SetSize(Image32.Width, Image32.Height);
  56. FRenderer := TPolygonRenderer32VPR.Create;
  57. FRenderer.Bitmap := Image32.Bitmap;
  58. FRadius := 2;
  59. FSelection := 0.5;
  60. FBounds[0] := 0.1;
  61. FBounds[1] := 0.2;
  62. FCircle := Circle(0, 0, FRadius, 8);
  63. Application.OnIdle := ApplicationIdleHandler;
  64. if TryStrToInt(ParamStr(1), NumPoints) then
  65. NumPoints := EnsureRange(NumPoints, 1, 20000)
  66. else
  67. NumPoints := 10000;
  68. SetLength(FPoints, NumPoints);
  69. Generate;
  70. Draw;
  71. end;
  72. procedure TFmScatterPlot.Generate;
  73. var
  74. Index: Cardinal;
  75. Radius: TFloatPoint;
  76. Z, Dist: TFloat;
  77. ScatterPnt, Pnt: TFloatPoint;
  78. begin
  79. Radius.X := Image32.Width / 3.5;
  80. Radius.Y := Image32.Height / 3.5;
  81. for Index := 0 to Length(FPoints) - 1 do
  82. begin
  83. Z := Random;
  84. FPoints[Index].Z := Z;
  85. GR32_Math.SinCos(2 * Pi * Z, Radius.X, Radius.Y, Pnt.Y, Pnt.X);
  86. Dist := 0.5 * Radius.X * Random;
  87. GR32_Math.SinCos(2 * Pi * Random, ScatterPnt.Y, ScatterPnt.X);
  88. FPoints[Index].X := 0.5 * Image32.Width + Pnt.X + ScatterPnt.X * Dist;
  89. FPoints[Index].Y := 0.5 * Image32.Height + Pnt.Y + ScatterPnt.Y * Dist;
  90. FPoints[Index].Color := HSLtoRGB(Z, 0.7, 0.5);
  91. end;
  92. end;
  93. procedure TFmScatterPlot.Image32Click(Sender: TObject);
  94. begin
  95. Generate;
  96. Draw;
  97. end;
  98. procedure TFmScatterPlot.Image32PaintStage(Sender: TObject; Buffer: TBitmap32;
  99. StageNum: Cardinal);
  100. begin
  101. // Buffer.Clear($FFFFFFFF);
  102. end;
  103. procedure TFmScatterPlot.ApplicationIdleHandler(Sender: TObject;
  104. var Done: Boolean);
  105. var
  106. Index: Cardinal;
  107. begin
  108. for Index := 0 to Length(FPoints) - 1 do
  109. begin
  110. FPoints[Index].X := FPoints[Index].X + FSelection * (Random - 0.5);
  111. FPoints[Index].Y := FPoints[Index].Y + FSelection * (Random - 0.5);
  112. FPoints[Index].Z := FPoints[Index].Z + FSelection * (0.01 * Random - 0.005);
  113. if FPoints[Index].Z < 0.0 then
  114. FPoints[Index].Z := 0.0;
  115. if FPoints[Index].Z > 1.0 then
  116. FPoints[Index].Z := 1.0;
  117. end;
  118. FBounds[0] := FBounds[0] + 0.001 * Random;
  119. FBounds[1] := FBounds[1] + 0.001 * Random;
  120. FSelection := EnsureRange(FSelection + 0.02 * Random - 0.01, 0, 1);
  121. if FBounds[0] > 1 then
  122. FBounds[0] := 0;
  123. if FBounds[1] > 1 then
  124. FBounds[1] := 0;
  125. Draw;
  126. end;
  127. procedure TFmScatterPlot.Draw;
  128. var
  129. Index: Cardinal;
  130. Alpha: TFloat;
  131. begin
  132. Image32.Bitmap.Clear($FFFFFFFF);
  133. for Index := 0 to Length(FPoints) - 1 do
  134. begin
  135. Alpha := 1.0;
  136. if FBounds[1] < FBounds[0] then
  137. begin
  138. if (FPoints[Index].Z < FBounds[0]) and (FPoints[Index].Z > FBounds[1]) then
  139. begin
  140. if FBounds[0] - FPoints[Index].Z < FPoints[Index].Z - FBounds[1] then
  141. Alpha := 1.0 - (FBounds[0] - FPoints[Index].Z) * FSelection * 100.0
  142. else
  143. Alpha := 1.0 - (FPoints[Index].Z - FBounds[1]) * FSelection * 100.0;
  144. end;
  145. end
  146. else
  147. begin
  148. if FPoints[Index].Z < FBounds[0] then
  149. Alpha := 1.0 - (FBounds[0] - FPoints[Index].Z) * FSelection * 100.0;
  150. if FPoints[Index].Z > FBounds[1] then
  151. Alpha := 1.0 - (FPoints[Index].Z - FBounds[1]) * FSelection * 100.0;
  152. end;
  153. if Alpha < 0.0 then
  154. Continue;
  155. if Alpha > 1.0 then
  156. Alpha := 1.0;
  157. FRenderer.Color := SetAlpha(FPoints[Index].Color, Round(Alpha * $FF));
  158. FRenderer.PolygonFS(TranslatePolygon(FCircle, FPoints[Index].X,
  159. FPoints[Index].Y));
  160. end;
  161. end;
  162. end.