Rose Curve Conversion from CSharp lazarus / 39-Graphics ---------------------------------------------------------------------- Boleeman · 2023-11-03 08:04 Trying to convert a Maurer Rose Curve Code from CSharp, but stuck on implementing Image1 into code. Also TList ? Dzandaa, could you possibly help or other Graphics Gurus? Here is what I have so far: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, Math; type   { TForm1 }   TForm1 = class(TForm)    btnDraw: TButton;    Edit1: TEdit;    Edit2: TEdit;    Edit3: TEdit;    Image1: TImage;    Label1: TLabel;  Label2: TLabel;    Label3: TLabel;    Panel1: TPanel;    procedure btnDrawClick(Sender: TObject);  private   public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure DrawAxes(gr: Graphics; wxmax: Single);var  xmax: Integer;  pen: Pen;  tic: Single;  x: Integer;begin  xmax := Trunc(wxmax);  pen := Pen.Create(Color.Black, 0);  try    // Draw the X and Y axes.    gr.DrawLine(pen, -wxmax, 0, wxmax, 0);    gr.DrawLine(pen, 0, -wxmax, 0, wxmax);    tic := 0.1;    for x := -xmax to xmax do    begin      gr.DrawLine(pen, x, -tic, x, tic);      gr.DrawLine(pen, -tic, x, tic, x);    end;  finally    pen.Free;  end;end; procedure DrawCurve(gr: Graphics; A: Single; n: Integer; d: Integer);const  num_points: Integer = 1000;var  period: Double;  dtheta: Double;  points: TList;  k: Double;  i: Integer;  theta: Double;  r: Double;  x: Single;  y: Single;  pen: TPen;begin  period := Math.PI * d;  if (n mod 2 = 0) or (d mod 2 = 0) then    period := period * 2;  dtheta := period / num_points;  points := TList.Create;  k := n / d;  for i := 0 to num_points - 1 do  begin    theta := i * dtheta;    r := A * Cos(k * theta);    x := r * Cos(theta);    y := r * Sin(theta);  points.Add(PointF(x, y));  end;  gr.FillPolygon(Brushes.LightBlue, points.ToArray);  pen := TPen.Create(Color.Red, 0);  try    gr.DrawLines(pen, points.ToArray);  finally    pen.Free;  end;  points.Free;end; procedure TForm1.btnDrawClick(Sender: TObject);var  A: Single;  n, d: Integer;  bmp: TBitmap;  gr: TGraphic;  rect: TRectF;  pts: array[0..2] of TPointF;begin  A := StrToFloat(Edit1.Text);  n := StrToInt(Edit2.Text);  d := StrToInt(Edit3.Text);   bmp := TBitmap.Create;  try    bmp.SetSize(300, 300);    gr := bmp.Canvas;    gr.Clear(clWhite);    gr.SmoothingMode := SmoothingModeAntiAlias;     rect := TRectF.Create(-A - 0.1, -A - 0.1, 2 * A + 0.2, 2 * A + 0.2);    pts[0] := TPointF.Create(0, bmp.Height);    pts[1] := TPointF.Create(bmp.Width, bmp.Height);    pts[2] := TPointF.Create(0, 0);    gr.Transform := TMatrix.Create(rect, pts);     DrawCurve(gr, A, n, d);    DrawAxes(gr, rect.Right);     picCurve.Picture.Assign(bmp);    picCurve.AutoSize := True;    ClientWidth := picCurve.Right + picCurve.Top;    ClientHeight := picCurve.Bottom + picCurve.Top;  finally    bmp.Free;  end;end; end. ---------------------------------------------------------------------- cdbc · 2023-11-03 11:56 Hi Regarding QuoteTList ? translation to fpc/laz would be something like this:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses ..., Generics.Collections;...type  TPointFList = specialize TList;...// then use:  TTestCls = class  private  fPoints: TPointFList;...  end;...begin  fPoints:= TPoinFList.Create;... etc...  fPoints.Free;...end; Regards Benny ---------------------------------------------------------------------- Boleeman · 2023-11-03 16:14 Now I have: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, Generics.Collections, Math, Types; type   TPointFList = specialize TList;   { TForm1 }   TForm1 = class(TForm)    btnDraw: TButton;    Edit1: TEdit;    Edit2: TEdit;    Edit3: TEdit;    Image1: TImage;    Label1: TLabel;    Label2: TLabel;    Label3: TLabel;    Panel1: TPanel;    procedure btnDrawClick(Sender: TObject);  private       fPoints: TPointFList;  public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure DrawAxes(Image1: TImage; wxmax: LongInt);var  xmax: Integer;  //pen: Pen;  tic: LongInt;  x: Integer;begin  xmax := Trunc(wxmax);  //pen := Pen.Create(Color.Black, 0);  Image1.Canvas.Pen.Color:= clBlack;  //Image1.Canvas.Pen.Width := 2;  Image1.Canvas.Pen.Style := psSolid;  try    // Draw the X and Y axes.    //gr.DrawLine(pen, -wxmax, 0, wxmax, 0);    //gr.DrawLine(pen, 0, -wxmax, 0, wxmax);    //gr.DrawLine(pen, -wxmax, 0, wxmax, 0);    //gr.DrawLine(pen, 0, -wxmax, 0, wxmax);    Image1.Canvas.Line(-wxmax, 0, wxmax, 0);    Image1.Canvas.Line(0, -wxmax, 0, wxmax);    tic := 1;    for x := -xmax to xmax do    begin      //gr.DrawLine(pen, x, -tic, x, tic);      //gr.DrawLine(pen, -tic, x, tic, x);    Image1.Canvas.Line(x, -tic, x, tic);    Image1.Canvas.Line(-tic, x, tic, x);    end;  finally    //pen.Free;  end;end; procedure DrawCurve(Image1: TImage; A: LongInt; n: Integer; d: Integer);const  num_points: Integer = 1000;var  period: Double;  dtheta: Double;  //points: TList;  fPoints: TPointFList;  k: Double;  i: Integer;  theta: Double;  r: LongInt;  x: LongInt;  y: LongInt;  //pen: TPen;begin  period := PI * d;  if (n mod 2 = 0) or (d mod 2 = 0) then    period := period * 2;  dtheta := period / num_points;  fPoints:= TPointFList.Create;  //points := TList.Create;  k := n / d;  for i := 0 to num_points - 1 do  begin    theta := i * dtheta;    r := round(A * Cos(k * theta));    x := round(r * Cos(theta));    y := round(r * Sin(theta));    fPoints[i].Create(x, y);    //fPoints[i]:= TPointF(fPoints[i].x, fPoints[i].y);    //fPoints.Add(PointF(x, y));    //fPoints.Add(TPointF(x, y));    fPoints.Add(fPoints[i]);  end;   //gr.FillPolygon(Brushes.LightBlue, fPoints.ToArray);  Image1.canvas.brush.color := clBlue;  Image1.canvas.brush.style := bsclear;  //Image1.Canvas.Polygon(fPoints.ToArray);  Image1.Canvas.Polygon(fPoints);  //pen := TPen.Create(Color.Red, 0);  Image1.Canvas.Pen.Color:= clRed;  try    //gr.DrawLines(pen, fPoints.ToArray);    Image1.Canvas.Polygon(fPoints);  finally    //pen.Free;  end;  //points.Free;  fPoints.Freeend; procedure TForm1.btnDrawClick(Sender: TObject);var  A: Single;  n, d: Integer;  bmp: TBitmap;  //gr: TGraphic;  Image1: TImage;  rect: TRectF;  pts: array[0..2] of TPointF;begin  A := StrToFloat(Edit1.Text);  n := StrToInt(Edit2.Text);  d := StrToInt(Edit3.Text);   bmp := TBitmap.Create;  try    bmp.SetSize(300, 300);    //gr := bmp.Canvas;    //gr.Clear(clWhite);    Image1 := bmp.Canvas;    Image1.Canvas.Clear;    //gr.SmoothingMode := SmoothingModeAntiAlias;    Image1.Canvas.AntialiasingMode := AntialiasingMode[cbAntialiasing.State];     rect := TRectF.Create(-A - 0.1, -A - 0.1, 2 * A + 0.2, 2 * A + 0.2);    pts[0] := TPointF.Create(0, bmp.Height);    pts[1] := TPointF.Create(bmp.Width, bmp.Height);    pts[2] := TPointF.Create(0, 0);    Image1.Transform := TMatrix.Create(rect, pts);    DrawCurve(Image1, A, n, d);    DrawAxes(Image1, rect.Right);     picCurve.Picture.Assign(bmp);    picCurve.AutoSize := True;    ClientWidth := picCurve.Right + picCurve.Top;    ClientHeight := picCurve.Bottom + picCurve.Top;  finally    bmp.Free;  end;end; end. ---------------------------------------------------------------------- cdbc · 2023-11-03 18:26 Hi I think this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   private       fPoints: TPointFList;  public is superfluous, you only need the local one in "DrawCurve" Regards Benny ---------------------------------------------------------------------- Boleeman · 2023-11-03 19:36 Thanks Benny. so If it IS broke, then fix it Still got too many errors. Giving up for now. Errors here   Image1.Canvas.Polygon(fPoints);   How to go set this properly? ---------------------------------------------------------------------- cdbc · 2023-11-03 20:45 Hi I see this:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     procedure Polygon(const Points: array of TPoint;                      Winding: Boolean;                      StartIndex: Integer = 0;                    NumPts: Integer = -1);    procedure Polygon(Points: PPoint; NumPts: Integer;                      Winding: boolean = False); virtual;    procedure Polygon(const Points: array of TPoint); {$IFDEF HasFPCanvas1}reintroduce;{$ENDIF} when I look in TCanvas in graphics.pp.... No mention of taking /any/ lists as parameters, only arrays and blocks of memory. ...and the Item-type is "TPoint"  -> edit: maybe:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i image.canvas.polygon(fPoints.ToArray); but you may have to define your list with ... You might also need someone sharper in generics than me  Regards Benny ---------------------------------------------------------------------- paweld · 2023-11-04 06:03 still needs some work, but the basis is:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses  BGRABitmap, BGRABitmapTypes, Math, LCLIntf; procedure TForm1.DrawRoseBGRA(img_size: Integer; n, d: Integer; num_points: Integer = 1000; acanvas: TCanvas = nil; x: Integer = 0; y: Integer = 0);var  bmp: TBGRABitmap;  halfsize: Single;  margin: Integer;  fn: String;   procedure DrawAxes;  var    i: Integer;  begin    bmp.DrawLineAntialias(0, halfsize + margin, bmp.Width, halfsize + margin, clBlack, 1);    bmp.DrawLineAntialias(halfsize + margin, 0, halfsize + margin, bmp.Width, clBlack, 1);    for i := 0 to 4 do    begin      bmp.DrawLineAntialias(margin + i * img_size / 4, halfsize, margin + i * img_size / 4, halfsize + 2 * margin, clBlack, 1);      bmp.DrawLineAntialias(halfsize, margin + i * img_size / 4, halfsize + 2 * margin, margin + i * img_size / 4, clBlack, 1);    end;  end;   procedure DrawCurve;  var    period, dtheta, k, theta, r: Single;    nparr: array of TPointF;    i: Integer;  begin    SetLength(nparr, num_points);    period := pi * d;    if ((n mod 2) = 0) or ((d mod 2) = 0) then      period := period * 2;    dtheta := period / num_points;    k := n / d;    for i := 0 to num_points - 1 do    begin      theta := i * dtheta;      r := halfsize * cos(k * theta);    nparr[i].x := margin + r * cos(theta) + halfsize;      nparr[i].y := margin + r * sin(theta) + halfsize;    end;    bmp.FillPolyAntialias(nparr, clSkyBlue);    for i := 1 to High(nparr) do      bmp.DrawLineAntialias(nparr[i - 1].x, nparr[i - 1].y, nparr[i].x, nparr[i].y, clRed, 1);    bmp.DrawLineAntialias(nparr[High(nparr)].x, nparr[High(nparr)].y, nparr[0].x, nparr[0].y, clRed, 1, True);   end; begin  margin := img_size div 75;  halfsize := img_size / 2;  bmp := TBGRABitmap.Create(img_size + 2 * margin, img_size + 2 * margin, clWhite);  DrawCurve;  DrawAxes;  if acanvas <> nil then    bmp.Draw(acanvas, x, y)  else  begin    fn := TGUID.NewGuid.ToString(True) + '.png';    bmp.SaveToFile(fn);    OpenDocument(fn);  end;  bmp.Free;end;   run: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i DrawRoseBGRA(300, 3, 4, 1000, Form1.Canvas, 100, 100);        Edit: added line closure ---------------------------------------------------------------------- Boleeman · 2023-11-04 06:50 Turns out that I came to a dark dead end .... and then  I SAW THE LIGHT. Just kidding. Just amazing ! I am not getting the saved png, but I am seeing the picture on the form. Thanks so much Paweld Coloured it in manually and realised that perhaps the axes are not needed. ---------------------------------------------------------------------- paweld · 2023-11-04 08:34 if you want to save to png instead of canvas specify nil ---------------------------------------------------------------------- Boleeman · 2023-11-04 09:05 Ah now I see what you mean Paweld,  DrawRoseBGRA(600, 5, 4, 1000, nil, 100, 100); Never seen this done like this before. Kinda cool. Thanks Paweld. Changing the HSL gives nice colour effects. Check out the attached animated gif below. ---------------------------------------------------------------------- paweld · 2023-11-04 12:00 great ---------------------------------------------------------------------- Dzandaa · 2023-11-04 15:26 Hi, Just for the fun, a different approach. B-> ---------------------------------------------------------------------- wp · 2023-11-04 17:30 Nice application of TAChart, Dzandaa. But the same can be achieved without the overhead of TAChart by simply drawing the polygon with the corresponding canvas method. The only important thing is to set the Winding argument to false (https://wiki.freepascal.org/Graphics_- _Working_with_TCanvas#Self-overlapping_polygons). (There is an inconsistency in the 1-parameter overload of polygon ("Polygon(const Points: array of TPoint)") which sets Winding to true, while it is false by default in "Polygon(Points: PPoint; NumPts: Integer; Winding: boolean = False)") ---------------------------------------------------------------------- Boleeman · 2023-11-04 22:53 Thanks to Paweld, Dzandaa and WP for the great Rose Curve Generators. Discovered that when D value is one more than N value then we get perfect colouring of shapes in wp version. I was "Playing Around" and achieved a fractal like curve I made a VB6 program years ago that rotates a fractal fern like leaf and it achieved a similar result, but not as good in quality. https://github.com/BoleeMan/Looped-Fern-Fractal Attached a DZandaa triple rose. Also changed wp's save to jpg to png and removed the gradient to fill in manually. ---------------------------------------------------------------------- Dzandaa · 2023-11-05 12:40 Hi, Another one based on CCurve  Have an excellent Week End. B-> ---------------------------------------------------------------------- Josh · 2023-11-05 14:59 Had to have a play Can change N D and P (number of points), can render in lineart. the save re-renders at 6000x6000 for good printing. Requires BGRABitmap and BGRAControls.  Download Deleted  See Latest Post ---------------------------------------------------------------------- Boleeman · 2023-11-05 21:39 Josh, thanks for the lines version that you created. I compiled it and it asked for uEConntrols. I installed that using OPM and then compiled again. I also reinstalled to the newest version of BGRABitmap and BGRAControls using OPM. Your program worked for both coloured and line modes. Love that coloured mode (works beautifully) Attached below is what I get. Brilliant. Also DZandaa, thank you for the C-Fractal curve. ---------------------------------------------------------------------- Josh · 2023-11-05 21:59 Ooops removed uecontrols dependency, not needed. QuoteYour program worked for coloured mode, but not for Lines mode in which way is it not working? attached image showing params for one. ---------------------------------------------------------------------- Boleeman · 2023-11-05 22:05 I tried on FCPDeluxe version and now it works with those settings. Wow. That is so GREAT. Ah, so the method is ... make D one more than N  and then vary P until you get a Nice Pattern. BINGO Very impressed. I see why you made the saved picture big. .... so that you see the extra detail. ---------------------------------------------------------------------- Josh · 2023-11-05 23:06 hi simpe way would be to add params to saved file; so filename becomes N83-D87-P1000-xxxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxxxx.png proj attached Download Deleted  See Latest Post ---------------------------------------------------------------------- Boleeman · 2023-11-06 03:27 That's a good idea for remembering the settings. Attached is one pattern that I found quite interesting with the settings in the filename (almost like some ancient pattern). ---------------------------------------------------------------------- Josh · 2023-11-06 12:16 Just for fun Added in "Animation", ie it cyles through the parameters, you can adust the speed, clicking the rose panel stops the anim, and returns values back to original. you can pause, then adjust NDP and resume if required, you can also anim on 1 2 or 3 params at the same time. To start click one of the Triangle by the sliders, then it starts and the control params then appear. Brain Warning :- Can be a bit psychedelic, if run at 50ms  Download Deleted  See Latest Post ---------------------------------------------------------------------- Josh · 2023-11-06 15:13 Couple Little fixes. Generated exe is now rose_curve_generator Download Deleted  See Latest Post ---------------------------------------------------------------------- Boleeman · 2023-11-06 21:12 Looking good Josh. I like the animated mode. I like how more than one side arrow can be clicked to allow for multiple changes in the values of N, D, P at the same time. Like all the added features. Little 50ms button: The 50ms button is slightly moved. In animation mode: In animation mode the even N values (bring up just red) so possibly could a checkbox be used for a user to select to skip even values of N? Also is there a way to set/change the opacity of the whole image to say 80% opacity? A nice effect may be to overlay on top of another image. Lastly another design I like with seregated edges. ---------------------------------------------------------------------- Josh · 2023-11-06 23:17 i'm not seeing the odd button placement. Added a skip evens version 1.01 Download Deleted  See Latest Post ---------------------------------------------------------------------- Boleeman · 2023-11-07 00:18 Thanks Josh A D change animation linked to freehosting image website: https://iili.io/JqpKav1.gif and higher res. https://iili.io/JqpqmYB.gif Right click an saveAs And some links to some interesting thumbnailed patterns that I discovered: https://iili.io/JqpM3ns.md.gif https://iili.io/JqpMhKv.md.png The png is higher resolution. Attached is just a tiny sample. Better to download the png. ---------------------------------------------------------------------- Josh · 2023-11-07 08:22 One more tweak You can set the colors version 1.02 Download Deleted  See Latest Post ---------------------------------------------------------------------- Josh · 2023-11-07 12:16 oops introduced a bug where repeat was always true. fix attached Noticed a non complete or black line Version attached to try to correct. ********** Removed all my older versions from previous posts to tidy things up a bit. ********** ---------------------------------------------------------------------- Boleeman · 2023-11-08 07:07 Noticed those extra lines as well in some patterns produced by your code. Also in WP version there was a stray straight line (not sure if at the start or end of the pattern). Could it be related to your program as well? Maybe a start from center flaw or end at center flaw? where to curved line is not finishing at the center. Also wondered about the color blend modes then I found a thread explaining them. For drawing from one BGRAbitmap to another you use:     MainBGRAbitmap.putImage (x,y, SourceBGRAbitmap, TDrawMode);     where TDrawMode is defined in bgrapixel.inc as:         TDrawMode = (         {** The pixel is replaced }         dmSet,         {** The pixel is replaced if the pixel over has an alpha value of 255 }         dmSetExceptTransparent,         {** The pixel is blend over the other one according to alpha values,             however no gamma correction is applied. In other words, the color             space is assumed to be linear }         dmLinearBlend,         {** The pixel is blend over the other one according to alpha values,             and a gamma correction is applied. In other word, the color             space is assumed to be sRGB }         dmDrawWithTransparency,         {** Values of all channels are combined with Xor. This is useful to             compute the binary difference, however it is not something that makes             much sense to display on the screen }         dmXor); Is there a way of making a gradient colouring within each polygon? I saw an example where processing makes radial gradients at: https://processing.org/examples/radialgradient.html Also DZandaa made an animated spiral using HSL to add vivid colors. Anyhow, I like the feature you made to add different colours (storing a favourite palette of colour might be nice) I am amazed how the program produces these amazing shapes and patterns. Quite addictive to play around with. ---------------------------------------------------------------------- Boleeman · 2023-11-08 20:19 A couple of interesting patterns in contrasting Black and White. 1st pattern is a bit hypnotic/psychedelic and 2nd a bit like fracture art. Could possibly be rotated to make some groovy animations.