Solved

# Draw ellipse

Posted on 2002-06-11
616 Views
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 .
0
Question by:ginsonic
• 9
• 4
• 3
• +5

LVL 27

Expert Comment

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

LVL 9

Author Comment

I thinking to this :)
0

LVL 8

Accepted Solution

Cesario earned 100 total points
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

LVL 8

Expert Comment

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

Best Regards

Cesario
0

LVL 3

Expert Comment

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

LVL 11

Expert Comment

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

LVL 11

Expert Comment

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

LVL 7

Expert Comment

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

LVL 11

Expert Comment

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

LVL 9

Author Comment

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

LVL 9

Author Comment

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

LVL 9

Author Comment

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

LVL 9

Author Comment

ups
0

LVL 7

Expert Comment

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

LVL 9

Author Comment

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

LVL 7

Expert Comment

ginsonic,

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

LVL 1

Expert Comment

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

LVL 9

Author Comment

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

LVL 7

Expert Comment

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

LVL 9

Author Comment

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

LVL 4

Expert Comment

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

LVL 9

Author Comment

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

## Featured Post

### Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi projâ€¦
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGridâ€¦
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: â€¦