Recent

Author Topic: Vector Drawing - where to start?  (Read 7263 times)

J-G

  • Hero Member
  • *****
  • Posts: 953
Vector Drawing - where to start?
« on: May 30, 2020, 06:27:09 pm »
It's been a while since I needed to amuse myself with FPC & Lazarus but having spent a while researching Reuleaux Polygons and calculating their areas (for fun!),  I'd now like to create a visual program that accepts initially the 'Diameter' and 'Number of sides',  not only Calculates the area but also draws the polygon.

The maths are not an issue and the drawing will be simple 'Arcs' about known points. What I don't know is what component I should use to 'paint' the polygon on. I suspect that it might be a [Panel] and I allredy have the BGRA Controls installed but that may be either overkill or inappropriate.

It's amazing how much one forgets with just a few months of not 'playing' with Lazarus  :-[
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Vector Drawing - where to start?
« Reply #1 on: May 30, 2020, 06:44:44 pm »
The component for drawings by the user is TPaintbox. Simply add your drawing code to the OnPaint event. You could also use a TPanel, or even the form, in the same way, but in my eyes these components are too complex for this simple task.

With BGRAControls you will probably get antialiased lines, but in principle it is not needed (I do not know this library in detail, so I cannot tell you what's the counterpart of TPaintbox).

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: Vector Drawing - where to start?
« Reply #2 on: May 30, 2020, 07:48:41 pm »
Thanks WP  -  I've not been idle whilst awaiting a response (fast as usual  :) )  and the TPaintbox was the next component I added.

I'll have a play to see if I can proceed before coming back with 'silly' questions about how to use that  -  but...

I've already found a problem that I didn't expect in another component.

The number of sides on a Reuleaux Polygon is restricted to Odd Numbers starting at 3 and I have set my top limit to 11. So, I've put these constraints into the properties of a TSpinEdit (Min, Max & Increment) and expected to simply click on the [Up][Down] arrows of the component to change '3' to '5', '7' etc.  The stub program compiles but mouse-clicking on those arrows does nothing - the value remains at the initial [3].  Assuming that I need an 'Event' I thought there might be two 'OnClick's available - one to increase and one to decrease  - but I only see a single [OnClick].

How do I effect a change?
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Vector Drawing - where to start?
« Reply #3 on: May 30, 2020, 07:55:59 pm »
Hi!

If you have installed the BGRAControls yo must have also installed the BGRAbitmap.

The simple solution is:

Draw everything on a BGRAbitmap and finally copy it to an TImage:

Code: Pascal  [Select][+][-]
  1. BGRA.draw(Image1.canvas,0,0);

Polygons and polylines are typically an ArrayOfTPointF - defined in BGRAtypes.

You draw a  polygon width

Code: Pascal  [Select][+][-]
  1. BGRA.DrawPolygonAntialias( MyArrayOfTpointF, OutlineColor, LineWidth, FillColor);

If any questions: ask!

Winni







J-G

  • Hero Member
  • *****
  • Posts: 953
Re: Vector Drawing - where to start?
« Reply #4 on: May 30, 2020, 08:37:46 pm »
Hi Winni  -  thanks for your response

It seems that you missed one very important aspect of my project  -  it is concerned with REULEAUX Polygons.  If the 'attachment' option works (it doesn't show in [Preview]) you should see that these Polygons have curved sides - this gives them their unique property of having a constant diameter.

I also want a VECTOR solution rather than a bitmap  -  that is simply because I have yet to tackle this type of drawing - you may well be aware of my Transparent Clock and Pocket Watch projects of a couple of years back using BGRA components.

I'm hoping that using a vector arc I might be able to 'animate' the drawing as well with simple 'loops' though that is still some time away -  the maths element for calculation of the area is already fully coded.

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

lainz

  • Hero Member
  • *****
  • Posts: 4468
    • https://lainz.github.io/
Re: Vector Drawing - where to start?
« Reply #5 on: May 30, 2020, 08:55:25 pm »
Vectors are just points. Winni give you a good solution. Btw there are other options for bezier curves.

You want to save it to svg or other vector format? Or just display?

Tpaintbox equivalent is tbgragraphiccontrol.
« Last Edit: May 30, 2020, 08:57:02 pm by lainz »

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: Vector Drawing - where to start?
« Reply #6 on: May 30, 2020, 09:26:38 pm »
Vectors are just points. Winni give you a good solution. Btw there are other options for bezier curves.

You want to save it to svg or other vector format? Or just display?

Tpaintbox equivalent is tbgragraphiccontrol.

Thought you might be able to contribute lainz (hope you are well!)

This will just be a display,  I am expecting to be able to pass a [centre of rotation] [radius] and [length of Arc] in degrees or radians --- naturally having previously set line width and colour --- to a 'DrawArc' procedure.

The curves are simply parts of a circle so although they may well also be Bezier curves they are simply a radius.

I've half solved the SpinEdit component change, though I have tried to use the [OnCkick] Event with :
Code: Pascal  [Select][+][-]
  1. procedure TForm1.E_SidesClick(Sender: TObject);
  2. begin
  3.   N_S := N_S + 2;
  4.   if N_S > 11 then
  5.     N_S := 3;
  6.  
  7.   E_Sides.Value:=N_S;
  8.   E_Sides.Caption:=FloatToStr(N_S);
  9.  
  10. end;
  11.  

N_S = Number of sides of course.

Clicking on the 'Spin' buttons does nothing but clicking in the display area does change the value. Not very satisfactory.

I could easily build an 'Edit' with a TLabel and two TArrows of course but I expected the SpinEdit to have that functionality built in.


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

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: Vector Drawing - where to start?
« Reply #7 on: May 30, 2020, 09:49:38 pm »
You always have the Meta format, still supported in windows..  :D
The only true wisdom is knowing you know nothing

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: Vector Drawing - where to start?
« Reply #8 on: May 30, 2020, 09:54:42 pm »
You always have the Meta format, still supported in windows..  :D
I'm sure that would be really useful jamie  -  if I had any idea what Meta format is  :-[

To be clear - yes I only need a 'Windows' solution.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

jamie

  • Hero Member
  • *****
  • Posts: 6130
The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Vector Drawing - where to start?
« Reply #10 on: May 30, 2020, 11:21:35 pm »
There are no "vector" drawings in Lazarus. In the end, everything that you draw is done pixel by pixel.

The difference between "vector" and "bitmap" drawings is only relevant for the way the drawing is stored. In a "vector" file (svg, wmf, PostScript) it consists of drawing commands, e.g. "draw line from (10, 10) to (100, 120)", in a "bitmap" file (bmp, png, jpeg, gif...) the image is essentially a 2D-array of colored pixels. As a consequence, a "vector" drawing can scaled without loss in quality, while a "bitmap" drawing can be scaled only with quality loss because missing pixels must be interpolated, or overlapping pixels must be combined.

----------------

Returning to your question in reply #2:

When you click on the up/down button of the SpinEdit the displayed value is automatically incremented/decremented (unless you set the SpinEdit.Increment to 0). What you need is a handler for the OnChange event of the SpinEdit - as it's name says, it is called whenever the Value of the SpinEdit changes. It gives you the opportunity to react on the new value. In your case you simply call Paintbox1.Invalidate to redraw the Paintbox. The OnPaint event of the Paintbox, on the other hand, must be use the new SpinEdit.value and construct the new polygon from it.

See attached demo which contains a quick implementation of Reubeaux polygon drawing (there is some inaccuracy due to rounding occsionally which should be addressed).
« Last Edit: May 30, 2020, 11:27:30 pm by wp »

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Vector Drawing - where to start?
« Reply #11 on: May 30, 2020, 11:45:25 pm »
Hi!

Reuleux Polygon with some lines of code using BGRAbitmap.

Code: Pascal  [Select][+][-]
  1. function Reuleaux : TBGRABitmap;
  2. const wihi = 300;
  3.       radius = 120; // for pentagon
  4.       Deg2Rad = pi/180;
  5.  
  6. var tmp : TBGRABitmap;
  7. pentagon : array[0..4] of TPointF;
  8. rad,sinus, cosinus : single;
  9. Reu : ArrayOfTPointF;
  10. center : TPointF;
  11. ang : single;
  12. startAngle,i,k : integer;
  13.  
  14.  
  15.      procedure createPentagon;
  16.      var i : integer;
  17.          angle : integer;
  18.      begin
  19.      angle := 270;
  20.      for i := 0 to 4 do
  21.         begin
  22.         math.sincos(deg2rad * angle,sinus,cosinus);
  23.         pentagon[i].x := cosinus*radius + Center.X;
  24.         pentagon[i].y := sinus *radius + Center.Y;
  25.         inc (angle,72);
  26.         end;
  27.      end;  // createPentagon
  28.  
  29. begin // Reuleaux
  30. tmp:= TBGRAbitmap.create (wihi,wihi,CSSSkyBlue);
  31. center := PointF (wihi/2,wihi/2);
  32. createPentagon;
  33. rad  :=  Pentagon[0].Distance(Pentagon[2]);
  34. setLength(Reu,0);
  35. startAngle := 360-72;
  36. for i := 0 to 4 do
  37.   begin
  38.   k := (i+3) mod 5;
  39.   ang := 0;
  40.   while ang <= 36.0 do
  41.     begin
  42.     math.sincoS((startAngle + ang)*Deg2Rad,sinus,cosinus);
  43.     setLength(Reu, length(Reu)+1);
  44.     Reu[high(Reu)] := PointF (cosinus*rad+pentagon[k].x, sinus*rad+pentagon[k].y);
  45.     ang := ang + 0.5;
  46.     end; // while ang
  47.     inc(startAngle,72);
  48.   end; // for i
  49. tmp.DrawPolygonAntialias(Reu,cssBlack,2,cssRed);
  50. for i := 0 to 4 do tmp.EllipseAntialias(pentagon[i].x,pentagon[i].y,5,5,cssBlack,1,cssBlue);
  51. tmp.saveToFile ('Reuleaux.png');
  52. result := tmp;
  53. end;
  54.  
  55. procedure TForm1.Button4Click(Sender: TObject);
  56. var tmp : TBGRABitmap;
  57. begin
  58. tmp := Reuleaux;
  59. tmp.draw(Image1.Canvas,0,0);
  60. tmp.free;
  61. end;
  62.  

Just a quick solution without bezier.
You need an Image1 on Form1.

Example see attachment

Winni

PS: uses ....., BGRABitmap, BGRADefaultbitmap, BGRABitmapTypes;
« Last Edit: May 30, 2020, 11:47:11 pm by winni »

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Vector Drawing - where to start?
« Reply #12 on: May 31, 2020, 12:08:30 am »
Just a quick solution without bezier.
No need for bezier curves, the corner points are connected by circle arcs (https://scipython.com/blog/constructing-reuleaux-polygons/).

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Vector Drawing - where to start?
« Reply #13 on: May 31, 2020, 12:21:00 am »
@wp

If you had looked into my code you would have noticed that I know how to construct a Reuleaux Polygon.

Winni

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Vector Drawing - where to start?
« Reply #14 on: May 31, 2020, 12:25:13 am »
I did not want to express any doubt in your code. But your phrase "a quick solution without bezier" was misleading, it could be misunderstood as "a more complete solution requires bezier curves".

 

TinyPortal © 2005-2018