Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

Author Topic: Drawing a curved 'Arrow'  (Read 668 times)

J-G

• Hero Member
• Posts: 812
Drawing a curved 'Arrow'
« on: June 29, 2022, 11:15:03 am »
Now I can use the EllipseAntialias() proc. I've been looking at what other options might be available - specifically to draw just a part of the Ellipse (Circle) - something like 'from 0° to 90°' - with an arrow-head at one (specified) end. I don't see anything in the BGRA Tutorial covering 'Arrow' or for that matter 'Ellipse' so I know that isn't exhaustive but looking at the BGRADefaultBitmap Unit I noticed a reference to ArrowStart..... and ArrowEnd......  but can't see a means by which I can draw a curved arrow by specifying (say)  Center X&Y, Radius, Start(Angle), Length(Angle), LineWidth, HeadSize . . . . .  It may well be that I need to create such using primitives but that seems beyond my wit at the moment.

I'm sure that elements of BGRA.... are capable - regrettably I can't see how

« Last Edit: June 29, 2022, 12:18:06 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

paweld

• Sr. Member
• Posts: 410
Re: Drawing a curved 'Arrow'
« Reply #1 on: June 29, 2022, 11:59:16 am »
Code: Pascal  [Select][+][-]
1. procedure TForm1.FormPaint(Sender: TObject);
2. var
3.   bmp: TBGRABitmap;
4. begin
5.   bmp := TBGRABitmap.Create(ClientWidth, ClientHeight, clWhite);
6.   bmp.ArrowStartAsTriangle();
7.   bmp.ArrowStartSize := PointF(10, 4);
8.   bmp.ArrowStartOffset:= 0;
9.   bmp.Arc(160, 120, 100, 100, 0, pi/2, clBlack, 1, False, clNone);
10.   bmp.Draw(Canvas, 0, 0);
11.   bmp.Free;
12. end;
Best regards
paweld
---
Lazarus trunk / FPC stable

J-G

• Hero Member
• Posts: 812
Re: Drawing a curved 'Arrow'
« Reply #2 on: June 29, 2022, 12:17:12 pm »
Thanks paweld, I knew there ought to be a (fairly) simple method    I hadn't thought to look for 'Arc' !

I'm just acknowledging your response as I have a busy schedule for the rest of today so won't be in a position to test the solution properly 'til tomorrow at best.

« Last Edit: June 29, 2022, 12:26:57 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

winni

• Hero Member
• Posts: 3121
Re: Drawing a curved 'Arrow'
« Reply #3 on: June 29, 2022, 02:43:42 pm »
Hi!

If you don't like arc you can do the same with 3 points and a spline:

Code: Pascal  [Select][+][-]
1. procedure TForm1.Button1Click(Sender: TObject);
2. const offset = 15;
3.        sin45= 7.01;
4.  var bmp: TBGRABitmap;
5.      poly, spline: ArrayOfTPointF;
6. begin
7.   setLength(poly,3);
8.   poly[0] := PointF(offset+60,offset);
9.   poly[1] := PointF (offset+60-6*sin45,offset+60-6*sin45);
10.   poly[2] := PointF (offset,offset+60);
11.   bmp := TBGRABitmap.create (100,100,cssWhite);
12.   bmp.ArrowStartAsTriangle();
13.   spline := bmp.ComputeOpenedSpline(poly, ssVertexToSide);
14.   bmp.DrawPolyLineAntialias(spline,cssRed,2);
15.   bmp.draw(canvas,0,0);
16.   bmp.free;
17. end;
18.
19.

Winni

J-G

• Hero Member
• Posts: 812
Re: Drawing a curved 'Arrow'
« Reply #4 on: June 29, 2022, 06:06:33 pm »
Thanks Winni but that does look somewhat more complex.  It isn't that I don't like (or dislike) ARC  - I didn't think to look for it !

I suspect that I might find it preferable but I'll create a test project using both to determine the way forward - though not 'til tomorrow (I'm between appointments at the moment).
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

J-G

• Hero Member
• Posts: 812
Re: Drawing a curved 'Arrow'
« Reply #5 on: June 30, 2022, 08:25:30 pm »
'ARC' works very well. I spent a while trying different parameters to better understand what they did but once I added just two lines to my project I was 'up and running'.

I naturally had to add some extra code to determine which direction and could at the same time set a different colour for each.

I had to comment out  bmp.ArrowStartSize := PointF(10, 4);  as I got an error at compile time    Error: Identifier not found "PointF"     so (as yet) I don't understand what that does.   It works without so may well be inconsequential.

I'm currently working on making a general procedure to draw the arrows and hoping that I can pass different TBGRABitmaps to it but thought that I ought to at least report back that I've been successful!  -  and thank paweld again.  -  I  haven't tested Winni's suggestion, that's for another day

ScreenGrab attached.

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

paweld

• Sr. Member
• Posts: 410
Re: Drawing a curved 'Arrow'
« Reply #6 on: June 30, 2022, 09:06:12 pm »
I had to comment out  bmp.ArrowStartSize := PointF(10, 4);  as I got an error at compile time    Error: Identifier not found "PointF"     so (as yet) I don't understand what that does.   It works without so may well be inconsequential.
Add a BGRABitmapTypes unit to uses section.
Best regards
paweld
---
Lazarus trunk / FPC stable

J-G

• Hero Member
• Posts: 812
Re: Drawing a curved 'Arrow'
« Reply #7 on: July 01, 2022, 03:09:51 am »
That does make for a more refined display and I have now incorporated the size of the 'ArrowHead' - even specifying the size dependent upon the Gear size - very effective.

It seems that I still don't fully understand the finer details of drawing BGRABitmaps   The three Gears that I have as yet displayed all work perfectly with curved arrows being dynamically sized, coloured and directed (there will ultimately be up to 6 - never less than 3) but there are four more gears - two of which are static and one of those always rotating clockwise, the other two change direction based upon the position of a lever. I'm sure I can specify the location of each arrow and I have a TImage ready to receive the BGRABitmap. I've attempted to draw an arrow on the static gear that is always clockwise but nothing appears - I have stepped through to make sure the 'Show Arrow' routine is being called. It's the same routine that creates the other arrows which do show.

The calling proc naturally needs to be marginally different though the same elements need to be in place.  This is the code for the Static/CW arrow with a bitmap called [Spindle] and a TImage [Sp_Arrow] :
Code: Pascal  [Select][+][-]
1. procedure ShowSpindleDirection;
2. Var
3.   Spindle : TBGRABitmap;
4. begin
5.   Spindle := TBGRABitmap.Create(60,60);
6.   Spindle.ReplaceTransparent(TrCol);
7.
8.   with Form1.Sp_Arrow do
9.     begin
10.       Canvas.Brush.Color := TrCol;        // set to colour being used as 'transparent'
11.       Canvas.FillRect(0,0,60,60);
12.
13.       Picture.Clear;
14.       Picture.Bitmap.SetSize(60,60);
15.       Picture.Bitmap.TransparentColor:=TrCol;
16.       Transparent:=True;
17.     end;
18.
19.   ShowArrow(Spindle,7,285,105,24);
20.   Spindle.Draw(Form1.Sp_Arrow.Canvas,0,0,false);
21.   application.ProcessMessages;
22.   Spindle.free;
23. end;

Comparing this with the code for the other gears :

Code: Pascal  [Select][+][-]
1. Tmp := TBGRABitmap.Create(Box,Box);
2.     Tmp.ReplaceTransparent(TrCol);
3.
4.     with DestG do
5.       begin
6.         Width  := Box;           // needed to overide the size set at Design time
7.         Height := Box;
8.
9.         Canvas.Brush.Color := TrCol;        // set to colour being used as 'transparent'
10.         Canvas.FillRect(0,0,Box,Box);
11.
12.         Picture.Clear;
13.         Picture.Bitmap.SetSize(Box,Box);
14.         Picture.Bitmap.TransparentColor:=TrCol;
15.         Transparent:=True;
16.
17.         Top    := Round(Y - Boy);
18.         Left   := Round(X - Boy);
19.       end;
20. [...]
21.     ShowArrow(tmp,N,C.x,C.y,R6);
22.     tmp.Draw(DestG.Canvas,0,0,false);
23.     application.ProcessMessages;
24.     tmp.free;

The 'ShowArrow' Proc just determines the Direction, Colour, Size of 'head' and then calls 'ARC' with the specific parameters leaving the actual drawing [ .Draw() ] until after has returned.

I'm sure that you can see that 'Spindle' & 'Tmp' are both TBGRABitmaps, DestG & Sp_Arrow are both TImages.  The subtle difference only being concerned with static rather than dynamic positioning of the TImages.

I'd be grateful for any pointers as to what I've missed
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

paweld

• Sr. Member
• Posts: 410
Re: Drawing a curved 'Arrow'
« Reply #8 on: July 01, 2022, 07:09:02 am »
From what I understand you have several a TImage components - check if the TImage with the arrow is not hidden under the TImage with a gear.
Best regards
paweld
---
Lazarus trunk / FPC stable

J-G

• Hero Member
• Posts: 812
Re: Drawing a curved 'Arrow'
« Reply #9 on: July 01, 2022, 09:27:29 am »
Good call paweld, but no, I had looked for such 'Z-Order' issues     though I was pleased that you didn't suggest some other basic error.

I solved it as I retired!  (but didn't bother to return to test)  Just before falling asleep I had that 'light bulb' moment - - - - the Centre Location I had specified was the main form co-ordinates rather than the TImage co-ordinates

So, it WAS drawing the arrow but well outside the visible area. As soon as I changed the 285,105 to 30, 30 it appeared.  I suspect that that was a good 'lesson' - I seem to learn best by making mistakes!

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

circular

• Hero Member
• Posts: 3835
Re: Drawing a curved 'Arrow'
« Reply #10 on: July 01, 2022, 06:58:19 pm »
Am happy to see a beautiful usage of BGRABitmap
Conscience is the debugger of the mind

J-G

• Hero Member
• Posts: 812
Re: Drawing a curved 'Arrow'
« Reply #11 on: July 01, 2022, 07:06:29 pm »
Am happy to see a beautiful usage of BGRABitmap
I'm not sure I would consider it 'beautiful'     -   practical maybe   -   but thanks for the comment
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64