# Draw ellipse

I wish to follow an eliptic route .
For example I wish to go from a point (100,100) and to draw an ellipse ( with next dimensions for example : 100 and 75 ), point by point, to my canvas.

Attention, POINT BY POINT .
LVL 9
###### Who is Participating?

Commented:
try this code ;-)

procedure TForm1.Button1Click(Sender: TObject);
var
mx,my,x,y,cnt :Integer;
begin
With Canvas Do
Begin
moveTo ( 400,200);
mx :=  100;
my :=  75;
For cnt := 0 to 360 do
begin
x := 400 + trunc(mx * sin ( cnt*pi/180 ));
y := 200 + Trunc(my * cos ( cnt*pi/180 ));
Pixels[x,y] := clBlack;
End;
End;
end;
0

Commented:
would be a nice qow, nick :-))
0

Author Commented:
I thinking to this :)
0

Commented:
to ginsonic:
sorry, for delay but I was last 2 weeks offline.
You can contact me  C_Lababidi@hotmail.com

Best Regards

Cesario
0

Commented:
Hi Ginsonic
Do you mean with a time delay in the drawing from point to point?
T.
0

Commented:
Yes i know not POINT by POINT, but Win32 AngleArc function is not well known and needs mentioning.
0

Commented:
I recall that it is possible to tweak Bresenham algoritm to draw ellipses.
0

Commented:
ginsonic,

Cesario provided you with correct answer. You could tweek it a little by replacing Trunc with Round (more accurate curve) and using precalculated trigonometric table (much more speed).

0

Commented:
After a fast Google search i found this algorithm in a newsgroup message which i translated to Pascal. It is completely untested. The text is from the message.

: I am looking an algorithm for drawing an ellipse .
: The input shall be the midpoint and the two axes .

Here is one implementation in C of the algorithm...

Remark : Only one quarter of the ellipse is computated, the rest
is set by symmetry.

a  and  b  are the half-axes (I hope this is the right
word for it) of the ellipse in  x- and y-direction.
If you like a circle set  a=b=radius  .

--------------------------------- cut ---------------------------------
procedure symmetry(x, y: Integer);
begin
PUT_PIXEL( x, y);  // This would obviously be inlined!
PUT_PIXEL(-x, y);  // and offset by a constant amount
PUT_PIXEL(-x,-y);
PUT_PIXEL( x,-y);
end;

procedure bresenham_ellipse(a, b: Integer);
var
x, y, a2, b2, S, T: Integer;
begin
a2 := a*a;
b2 := b*b;
x  := 0;
y  := b;
S  := a2*(1-2*b) + 2*b2;
T  := b2 - 2*a2*(2*b-1);
symmetry(x, y);
repeat
if S < 0 then
begin
S := S + 2*b2*(2*x+3);
T =  T + 4*b2*(x+1);
Inc(x);
end
else
if T < 0 then
begin
S := S + 2*b2*(2*x+3) - 4*a2*(y-1);
T := T + 4*b2*(x+1) - 2*a2*(2*y-3);
Inc(x);
Dec(y);
end
else
begin
S := S - 4*a2*(y-1);
T := T - 2*a2*(2*y-3);
Dec(y);
end;
symmetry(x, y);
until y <= 0;
end;
0

Author Commented:
I realise that Cesario solution solve my question , so I will give the points to him.

But I wait anothers working solutions for anothers points . Alike kretzschmar's Q.O.W.

If you have solution or can improve proposed one the put a comment and take new points :)
0

Author Commented:
I realise that Cesario solution solve my question , so I will give the points to him.

But I wait anothers working solutions for anothers points . Alike kretzschmar's Q.O.W.

If you have solution or can improve proposed one the put a comment and take new points :)
0

Author Commented:
I realise that Cesario solution solve my question , so I will give the points to him.

But I wait anothers working solutions for anothers points . Alike kretzschmar's Q.O.W.

If you have solution or can improve proposed one the put a comment and take new points :)
0

Author Commented:
ups
0

Commented:
ginsonic,

This are optimized versions (DrawEllipse() and even faster, DrawEllipse2()):

const RESOLUTION = 100; // larger=better but slower

// Requires global vars (trig. tables)
var
Form1: TForm1;
SinTable, CosTable: Array [0..360*RESOLUTION] of Double;

......

procedure BuildTrigTable;
// Precalculation of sin and cos. Resolution is 1/RESOLUTION degree.
var i: Integer;
begin
for i:= 0 to 360*RESOLUTION do begin
end;
end;

procedure DrawEllipse(Where: TCanvas; Center, R: TPoint);
// Draws ellipse, centered around Center, with halfaxes: a=R.X , b=R.Y
var i,x,y, xold, yold: Integer;
begin
for i:= 0 to 360*RESOLUTION do begin
x:=Center.X+Round(R.X*CosTable[i]);
y:=Center.Y+Round(R.Y*SinTable[i]);
if (xold<>x) or (yold<>y) then Where.Pixels[x,y]:=Where.Pen.Color;
xold:=x; yold:=y;
end;
end;

procedure DrawEllipse2(Where: TCanvas; Center, R: TPoint);
// Draws ellipse, centered around Center, with halfaxes: a=R.X , b=R.Y
var i,x,y, xold, yold: Integer;
begin
for i:= 0 to 360*RESOLUTION do begin
x:=Center.X+Round(R.X*CosTable[i]);
y:=Center.Y+Round(R.Y*SinTable[i]);
if i=0 then begin
Where.Pixels[x,y]:=Where.Pen.Color;
Where.MoveTo(x,y);
end
else if (xold<>x) or (yold<>y) then Where.LineTo(x,y);
xold:=x; yold:=y;
end;
end;

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

1. DrawEllipse() uses precalculated trig. table instead of slow trig. functions. On the down-side, you must call BuildTrigTable before using DrawEllipse().

2. BuildTrigTable is called only once. After that, tables are built, and we can use them instead of real sin,cos.
It is usually called at the execution start (for example, initialization section, OnCreate event of the main form etc.)

3. RESOLUTION defines granulation of real functions. This shouldn't be below 10 for DrawEllipse().

4. DrawEllipse2() is good for very low RESOLUTION (even for RESOLUTION=1 !!). But, it uses LineTo to aproximate ellipse segments.
If you want real speed, and are willing to live without Pixels (that is, use LineTo), it's better to use DrawEllipse2() with RESOLUTION of 1..10, which is *very* fast.

EXAMPLE OF USE (place TButton on the form)
----------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var i: Integer;
begin
BuildTrigTable; // Call it *ONLY* once (OnForm1Create is good place)
Randomize;
for i:=1 to 100 do
DrawEllipse(Form1.Canvas,
Point(100+Random(100),100+Random(100)),
Point(50+Random(100) , 10+Random(100)));
end;
0

Author Commented:
Add a sleep(1) and see what slow is it.
0

Commented:
ginsonic,

Why should you put sleep(1) (inside DrawEllipse() loop I assume) ?
0

Commented:
Add a sleep(10) and it's really slow ;-)
0

Author Commented:
Just to create a nice slide draw ellipse. Try with Cesario sample and see what I wish to say.
0

Commented:
ginsonic,

If you want to create animation effect, you can regulate delay in my code by changing RESOLUTION const. Decrease it and you'll get faster animation if that's what you want. Set it to 1 and see what happens.

But, I don't quite understand what you want:

> If you have solution or can improve proposed one the put a comment and take new points :)

Could you tell us what you mean by improved solution? What should be improved in accepted answer?
0

Author Commented:
I talk about a slow animation when draw step by step . Draw a point , sleep a while , draw next ....

About improvement ... any proposed solution not just the accepted one . Just to be a better way alike accepted .
0

Commented:
a comment only:

unit EllipseUnit1;
{This is an illustration of an ellipse that starts at
point (100,100) and fits in a rectangle of 100,75. Continues
until back again to point (100,100)}

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Math;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{\$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
mx, my, x, y, cnt: Integer;
y1: Real;
begin
Canvas.Pen.Color := clGreen;
//first a bit of a container
//100 Width, 75 Height; 1/2 width = 50; 1/2 height = 38
Canvas.MoveTo(100, 100); // Start point for request
Canvas.LineTo(150, 100);
Canvas.LineTo(150, 175);
Canvas.LineTo(50, 175);
Canvas.LineTo(50, 100);
Canvas.LineTo(100, 100);
Canvas.Pen.Color := clBlue;
Canvas.LineTo(100, 175); // Axis line
Canvas.Pen.Color := clBlack;
Canvas.MoveTo(50, 138); // Axis line
//Center is located at (100,138)
Canvas.LineTo(100, 138);
Canvas.Pen.Color := clWhite;
Canvas.LineTo(150, 138);// Axis line

{ A bit of Standard Algebra:

Draw an Ellipse
Center of the ellipse is located at h,k and the
major axis is 'a' the minor axis is 'b'

the equation is:

(((x-h)^2)/a^2) + (((y-k)^2)/b^2) = 1

Eventual substitutions:
a = 50; b = 38 ; h = 100; k = 100;

Algebraic equivalents
(((y-k)^2)/b^2) = 1 - (((x-h)^2)/a^2)

(y-k)^2)  = (1- (((x-h)^2)/a^2))* b^2

and solving for y

y-k = + square root ((1- (((x-h)^2)/a^2))* b^2)
y-k = - square root ((1- (((x-h)^2)/a^2))* b^2)
y = k + square root ((1- (((x-h)^2)/a^2))* b^2)
y = k - square root ((1- (((x-h)^2)/a^2))* b^2)

substitution of values

y = 100 + square root ((1- (((x-100)^2)/50^2))* 38^2)
y = 100 - square root ((1- (((x-100)^2)/50^2))* 38^2)
square root = power raised to the 0.5
y = 100 - power(((1- ((power(x-100),2)/(power,50,2))* (power,38,2),0.5)
}

Canvas.TextOut(100,80, 'Starts Here at (100,100)');
Canvas.Pen.Color := clRed;
Canvas.MoveTo(100, 138);
for x := 100 to 150 do
begin
Sleep(5);
y := Round(137.5 - (power((1 - (power(x - 100, 2)) / (power(50, 2))) * power(38, 2), 0.5)));
Canvas.LineTo(X, Y);
end;
Canvas.Pen.Color := clYellow;
for x := 150 downto 50 do
begin
Sleep(5);
y := Round(137.5 + (power((1 - (power(x - 100, 2)) / (power(50, 2))) * power(38, 2), 0.5)));
Canvas.LineTo(X, Y);
end;
Canvas.Pen.Color := clBlack;
for x := 51 to 100 do
begin
Sleep(5);
y := Round(137.5 - (power((1 - (power(x - 100, 2)) / (power(50, 2))) * power(38, 2), 0.5)));
Canvas.LineTo(X, Y);
end;
Canvas.TextOut(100,80, 'Ends Here at (100,100)    ');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Application.Terminate;
end;

end.
// Form as text
object Form1: TForm1
Left = 456
Top = 182
Width = 258
Height = 368
Caption = 'Ellipse'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -13
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 120
TextHeight = 16
object Button1: TButton
Left = 64
Top = 232
Width = 115
Height = 25
Caption = 'Show Ellipse'
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 64
Top = 272
Width = 115
Height = 25
Caption = 'Close'
TabOrder = 1
OnClick = Button2Click
end
end

Goal :

From: ginsonic
Status: Waiting for Answer Points: 100
Email A Friend
I wish to follow an eliptic route.
for example I wish to go from a point(100, 100) and to draw an ellipse(with next dimensions for example
: 100 and 75), point by point, to my canvas.

0

Author Commented:
I will stop the topic now. Don't have enough time , sorry .
But not before accept the delphi3 comments , too.
Take a look for your points in questions list .

Thanks to all for support,
Nick
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.