Recent

Author Topic: Drawing an 'Arc'  (Read 670 times)

J-G

  • Hero Member
  • *****
  • Posts: 1101
Drawing an 'Arc'
« on: July 05, 2026, 10:11:36 am »
I have addressed this subject previously but no one was able to give me a definitive suggestion as to how I could overcome the 'irritation' that I have.

The 'irritation' is clearly shown in the attached screen grab  -  it is the green line that is drawn from the vertex to the start of the ARC.

After some 'digging' I have eventually found the piece of code that I believe handles the matter.  -  Initially I couldn't fathom why I could not [find] the actual procedure in 'Graphics' Unit where the header for 'AngleArc' is, until I found the 'Inc' section and eventually 'canvas.inc'  -  I only include this to indicate how little i know of the inner workings of Lazarus!

The procedure that handles the drawing of the ARC is at line 683 -
Code: Pascal  [Select][+][-]
  1. procedure TCanvas.AngleArc(X, Y: Integer; Radius: Longword; StartAngle, SweepAngle: Single);
  2. var x1, y1, x2, y2: integer;
  3. begin
  4.   x1:=trunc(x+cos(pi*StartAngle/180)*Radius);
  5.   y1:=trunc(y-sin(pi*StartAngle/180)*Radius);
  6.   x2:=trunc(x+cos(pi*(StartAngle+SweepAngle)/180)*Radius);
  7.   y2:=trunc(y-sin(pi*(StartAngle+SweepAngle)/180)*Radius);
  8.   LineTo(x1,y1);
  9.   if SweepAngle>0 then
  10.     Arc(x-Radius, y-Radius, x+Radius, y+Radius, x1, y1, x2, y2)
  11.   else
  12.     Arc(x-Radius, y-Radius, x+Radius, y+Radius, x2, y2, x1, y1);
  13.   MoveTo(x2,y2);
  14. end;
  15.  

My 'logic' tells me that if I were to modify line 690 (line 8 in the quoted section) from 'LineTo(x1,y1)'  to  'MoveTo(x1,y1)'   it ought to get rid of the 'irritation'.

However, due to my lack of knowledge, I would appreciate advice at to whether this may cause the law of 'unintended consequences' to be invoked   ::)

I could of course simply do the 'mod' and re-compile but, being a 'wimp', I'd rather have the opinion of those 'in the know' before taking that bold step !

ie.  Is there something I've completely mis-understood?

« Last Edit: July 05, 2026, 10:21:10 am by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

simone

  • Hero Member
  • *****
  • Posts: 706
Re: Drawing an 'Arc'
« Reply #1 on: July 05, 2026, 10:50:48 am »
I strongly advise against modifying the LCL source code.

If you need to change AngleArc's behavior, the simplest solution is to introduce a modified version of this method into your code using a class helper for TCanvas, as in the following code:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     procedure FormPaint(Sender: TObject);
  16.   private
  17.  
  18.   public
  19.  
  20.   end;
  21.  
  22.   { TCanvasHelper }
  23.  
  24.   TCanvasHelper=class helper for TCanvas
  25.     procedure AngleArcMod(X, Y: Integer; Radius: Longword; StartAngle, SweepAngle: Single);
  26.   end;
  27.  
  28. var
  29.   Form1: TForm1;
  30.  
  31. implementation
  32.  
  33. {$R *.lfm}
  34.  
  35. { TCanvasHelper }
  36.  
  37. procedure TCanvasHelper.AngleArcMod(X, Y: Integer; Radius: Longword; StartAngle, SweepAngle: Single);
  38. var
  39.   x1, y1, x2, y2: integer;
  40. begin
  41.   x1:=trunc(x+cos(pi*StartAngle/180)*Radius);
  42.   y1:=trunc(y-sin(pi*StartAngle/180)*Radius);
  43.   x2:=trunc(x+cos(pi*(StartAngle+SweepAngle)/180)*Radius);
  44.   y2:=trunc(y-sin(pi*(StartAngle+SweepAngle)/180)*Radius);
  45.   MoveTo(x1,y1);
  46.   if SweepAngle>0 then
  47.     Arc(x-Radius, y-Radius, x+Radius, y+Radius, x1, y1, x2, y2)
  48.   else
  49.     Arc(x-Radius, y-Radius, x+Radius, y+Radius, x2, y2, x1, y1);
  50.   MoveTo(x2,y2);
  51. end;
  52.  
  53. { TForm1 }
  54.  
  55. procedure TForm1.FormPaint(Sender: TObject);
  56. begin
  57.   Canvas.AngleArcMod(500,500,50,100,300);
  58. end;
  59.  
  60. end.
« Last Edit: July 05, 2026, 11:04:33 am by simone »
Microsoft Windows 10/11 64 bit - Lazarus 4.8/4.6 FPC 3.2.2 x86_64-win64-win32/win64

paweld

  • Hero Member
  • *****
  • Posts: 1678
Re: Drawing an 'Arc'
« Reply #2 on: July 05, 2026, 10:58:37 am »
Best regards / Pozdrawiam
paweld

J-G

  • Hero Member
  • *****
  • Posts: 1101
Re: Drawing an 'Arc'
« Reply #3 on: July 05, 2026, 11:41:23 am »
@wp replied in this post: https://forum.lazarus.freepascal.org/index.php/topic,74227.msg584836.html#msg584836
Use Arc instead of AngleArc
I had seen @WP's suggestion but the arguments needed for 'Arc' are not what I have. This would mean further processing of the data to calculate the points x1--y2  - no great hardship really but the 'AngleArc' just seems (to me) a more natural way to declare the parameters.

@simone -  I appreciate and understand your concern over modifying the LCL Source Code but using such a 'Helper' appears to be a very convoluted way of achieving the desired result.  I could just as easily create a totally new proc - with a different name - and simply call that instead of the one provided in the Graphics Unit.

I cannot see any reason that I would ever want the 'spurious' line from the vertex to the start of the arc. The 'Pie', 'RadialPie' and 'Chord' noted by @WP all make sense.

As yet I can see no real downside to modifying the code in 'Canvas.inc' which is essentially what @simone is advocating, so I'll take the bull by the horns - after all it's only one line and I can easily revert - should the 'Law' be invoked :)
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

J-G

  • Hero Member
  • *****
  • Posts: 1101
Re: Drawing an 'Arc'
« Reply #4 on: July 05, 2026, 12:02:03 pm »
! et Viola !

All of my concerns were unfounded - the problem I have (had?) is that - just like @simone - I concider the source code of Lazarus to be sacrosanct.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

wp

  • Hero Member
  • *****
  • Posts: 13628
Re: Drawing an 'Arc'
« Reply #5 on: July 05, 2026, 12:07:37 pm »
the arguments needed for 'Arc' are not what I have. This would mean further processing of the data to calculate the points x1--y2  - no great hardship really but the 'AngleArc' just seems (to me) a more natural way to declare the parameters.
The "Arc" procedure comes in two flavours, with angle arguments and with point arguments:
Code: Pascal  [Select][+][-]
  1.     procedure Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer);
  2.     procedure Arc(ALeft, ATop, ARight, ABottom, SX, SY, EX, EY: Integer);
Compare with:
Code: Pascal  [Select][+][-]
  1.     procedure AngleArc(X, Y: Integer; Radius: Longword; StartAngle, SweepAngle: Single);
The differences to the first Arc method are that it requires the corner points of the enclosing rectangle (rather than center and radius) as well as angles as multiples of 16, i.e. you call Arc with degrees multiplied by 16.

Code: Pascal  [Select][+][-]
  1. procedure CircularArc(ACanvas: TCanvas; X, Y, Radius: Integer; StartAngle, SweepAngle: Single);
  2. begin
  3.   ACanvas.Arc(X-Radius, Y-Radius, X+Radius, Y+Radius, round(StartAngle*16), round(SweepAngle*16));
  4. end;

« Last Edit: July 05, 2026, 12:12:42 pm by wp »

simone

  • Hero Member
  • *****
  • Posts: 706
Re: Drawing an 'Arc'
« Reply #6 on: July 05, 2026, 12:13:30 pm »
! et Viola !

All of my concerns were unfounded - the problem I have (had?) is that - just like @simone - I concider the source code of Lazarus to be sacrosanct.

If you change the LCL code to achieve the desired results, you must modify it every time you update the LCL (for example, by installing a later version of Lazarus). If your source code needs to be compiled by another user, he must also modify its local LCL library.

The source code of Lazarus is not sacrosant. Sarcasm towards those who help you is definitely out of place.
« Last Edit: July 05, 2026, 12:20:06 pm by simone »
Microsoft Windows 10/11 64 bit - Lazarus 4.8/4.6 FPC 3.2.2 x86_64-win64-win32/win64

J-G

  • Hero Member
  • *****
  • Posts: 1101
Re: Drawing an 'Arc'
« Reply #7 on: July 05, 2026, 01:50:00 pm »
The "Arc" procedure comes in two flavours, with angle arguments and with point arguments:
Code: Pascal  [Select][+][-]
  1.     procedure Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer);
  2.     procedure Arc(ALeft, ATop, ARight, ABottom, SX, SY, EX, EY: Integer);
Compare with:
Code: Pascal  [Select][+][-]
  1.     procedure AngleArc(X, Y: Integer; Radius: Longword; StartAngle, SweepAngle: Single);
The differences to the first Arc method are that it requires the corner points of the enclosing rectangle (rather than center and radius) as well as angles as multiples of 16, i.e. you call Arc with degrees multiplied by 16.

Code: Pascal  [Select][+][-]
  1. procedure CircularArc(ACanvas: TCanvas; X, Y, Radius: Integer; StartAngle, SweepAngle: Single);
  2. begin
  3.   ACanvas.Arc(X-Radius, Y-Radius, X+Radius, Y+Radius, round(StartAngle*16), round(SweepAngle*16));
  4. end;
That makes sense @WP - thanks.  I hadn't come across CircularArc and didn't understand what Angle16Deg meant  - I will assume that it has something to do with using Hexadecimal arithmatic - so ignored it (rather than investigate  :-[  life is too short :) )

It still makes more sense - to me - to make the Mod that I have done.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

J-G

  • Hero Member
  • *****
  • Posts: 1101
Re: Drawing an 'Arc'
« Reply #8 on: July 05, 2026, 02:01:58 pm »
If you change the LCL code to achieve the desired results, you must modify it every time you update the LCL (for example, by installing a later version of Lazarus). If your source code needs to be compiled by another user, he must also modify its local LCL library.
I fully understand your stance @simone and your concerns are very valid but the chance that I might update Lazarus is slim to nil and I have only needed others to compile my code less than 5 times in some 20 years.

The source code of Lazarus is not sacrosant. Sarcasm towards those who help you is definitely out of place.
I'm somewhat mortified and sorry that you consider my comment sarcastic  :o  -  that was certainly not my intension.

Perhaps our understanding of the word 'sacrosanct' is different -  I used it to mean 'should not be modified'.
« Last Edit: July 05, 2026, 02:05:55 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

jamie

  • Hero Member
  • *****
  • Posts: 7832
Re: Drawing an 'Arc'
« Reply #9 on: July 05, 2026, 03:44:40 pm »
I just used the one in the WINDOWS which is the API call to the OS with the same parameters and it draw exactly the same results.

Code: Pascal  [Select][+][-]
  1. // canvas.AngleArc(100,100,50,0,90);
  2.   Windows.AngleArc(canvas.handle,100,100,50,0,90);      
  3.  

Both yield the same results.
I believe the function results are correct.

Maybe you should use the ARC function and draw as you wish instead.

Jamie
The only true wisdom is knowing you know nothing

J-G

  • Hero Member
  • *****
  • Posts: 1101
Re: Drawing an 'Arc'
« Reply #10 on: July 05, 2026, 08:34:46 pm »
Thanks for the input @Jamie but I am at a loss to understand what you are proposing.

I wasn't aware (as you may well fathom) that there is also an AngleArc in the Windows Unit.

I've tested that option and do see a very subtle difference in the output - it would need a very keen eye to notice but the attached .PNG image should make it clear. The result when using the Windows Unit version is on the right. This has a clean vertex where the base line (which I don't want) meets the arc whereas the Graphics Unit version (on the left) has a distinct separation.  -  I did say it was subtle!

It took me a while to fathom that the Windows Unit version needs the extra paramerer 'handle' - (rather than canvas.handle) - which is another reason that I find it less comfortable.

I don't doubt that having the line from the vertex to the start of the arc is what is intended - - -  I just don't understand why %)
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

jamie

  • Hero Member
  • *****
  • Posts: 7832
Re: Drawing an 'Arc'
« Reply #11 on: July 05, 2026, 10:50:32 pm »
If you read here
https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-anglearc
scroll down a bit, it explains how the angle arc is being drawn.

As for the two not looking the same, that could be possible, rounding errors can cause one pixel to be off.

In any case, the process starts by drawing a line from the current position, which is currently where the PEN X, Y is on the surface to the calculated starting point which is considered to be the center of a circle. The function then draws a line from that center to the starting of the arc using the radius as the distances, then the arc.

 If you use a MoveTO(Same Parms as the First two) before calling the function, no line is drawn and the function goes from there.

Canvas.MoveTo(100,100);
  Canvas.angleArc(100,100,50,0,45);     

 With that, you will get the lower line and the arc only.

also, there is also the ArcTo function


Jamie



Jamie

The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 7832
Re: Drawing an 'Arc'
« Reply #12 on: July 05, 2026, 11:01:20 pm »
Here is a MS example of using Paths and API.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   P:Tpoint;
  4. begin
  5.   BeginPath(Canvas.Handle);
  6.   MoveToEx(Canvas.Handle,100,100,@p);
  7.   angleArc(Canvas.handle,100,100,100,0,45);
  8.   EndPath(Canvas.handle);
  9.   StrokeAndFillpath(Canvas.Handle);
  10. End;                                    
  11.  
The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 13628
Re: Drawing an 'Arc'
« Reply #13 on: July 06, 2026, 12:37:28 am »
I hadn't come across CircularArc
You wouldn't have, this is just sample code that I wrote for the message.

and didn't understand what Angle16Deg meant  - I will assume that it has something to do with using Hexadecimal arithmatic - so ignored it (rather than investigate  :-[  life is too short :) )
In such a case, put the cursor into the method having this argument (Arc(...)) and press F1 (or Ctrl+F1 if you have the classical keyboard layout, like me), and the IDE will open the help file for the method in the LHelp viewer (provided that you did install the help files). Knowing such little helpers indeed saves a lot of time, and leave you more for your life.

It still makes more sense - to me - to make the Mod that I have done.
You mean the class helper with the MoveTo commands? Moving the cursor is not needed in the Arc method.

J-G

  • Hero Member
  • *****
  • Posts: 1101
Re: Drawing an 'Arc'
« Reply #14 on: July 06, 2026, 12:53:48 pm »
Again I have to thank @WP & @Jamie for their continued interest in my education  :D

I'm sure that I am now very familiar with how an ARC is drawn - but I still cannot for the life of me fathom why whoever wrote the AngleArc Proc thought that drawing a line from the vertex (centre of the 'circle') would be needed.

I do have the help files installed and do (on occasion) use them, but being of a mind that has a 'need to know' temperament that only comes to the fore when something completely new crosses my path, I seldom dig too deeply.

When I come across a function that I don't know about (and do need to know!) I do use the [Alt - UpArrow] which usually takes me to the location of its declaration. From there I can usually determine what I have mis-understood  - - - -  during this particular excercise I've now discovered the structure of Units that use 'Include' files to promote 'clean' (segregated) code (Though I have in the past also used 'Include' files in my own code, so ought to have realized sooner  :-[) and only from that did I eventually find the actual 'working' code, which led me to determine how the spurious (to me) line was being drawn.

Using [f1] on Angle16Deg of course brought up 'No help available' - naturally, since that is simply a parameter being passed to the Proc. On 'Arc' or 'AngleArc' it did open the LHelp Viewer but I had to use the [search] to find any reference to 'Angle16'.  Contrary to my 'hex math' assumption though, it seems '16' is purely arbitrary.

FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

 

TinyPortal © 2005-2018