SRL Archive - Research & Development Lounge

TPAFromOval


mixster

2009-07-04 18:59:10

Generates a TPA of an oval at location specified, like TPAFromBox.

mx and my are the center of the oval, with maxx being the max width and maxy being max height of the oval from the center point, so maxx would actually give an oval with double the number specified.


function TPAFromOval(mx, my, maxx, maxy: Integer): TPointArray;
var
x, y, i, ii, d, h: Integer;
r: Extended;
begin
r := maxx / maxy; // ratio that sets "fatness" of oval
h := -1; // Handles high of the result array
SetLength(Result, maxx * maxy * 4); // Ensure result array is long enough to hold all points
for i := -maxy to maxy do // loop through y axis
begin
y := my + i; // Set the y position
d := Round(Sqrt(Sqr(maxy) - Sqr(i)) * r); // Get the distance from centre to outside of oval using b^2 = c^2 - a^2 then multiplying by ratio to alter thickness
x := mx - d; // Get the left most x position
d := d + d; // Double radius to turn it into the diameter
h := h + 1; // Increase the height
for ii := 0 to d do // Loop through the current row
Result[h + ii] := Point(x + ii, y); // Add the point in the row
h := h + d; // Increment the high by the amount added
end;
SetLength(Result, h + d + 1); // Set the length so it only stores set points
end;

One use is a M/Mouse that performs what it would normally do in an ovular area specified.


procedure MouseOval(x, y, rx, ry, click: Integer);
var
tp: TPointArray;
i: Integer;
begin
tp := TPAFromOval(x, y, rx, ry);
i := Random(Length(tp));
case click of
1,2: Mouse(tp[i].x, tp[i].y, 0, 0, click = 1);
3: MMouse(tp[i].x, tp[i].y, 0, 0);
else
srl_Warn('MouseOval', 'ClickType is NOT a valid number!', warn_AllVersions);
end;
end;
(I stole the click bit from MouseBox, but it doesn't act like MouseBox since it is passed a point and a random x and y like M/Mouse rather than the two sets of points MouseBox uses)

Of course, it can also be used for drawing etc.
I do also have a very good reason for using Pythagoras over Trigonometry for this.

Edit: It is very inefficient to use TPAFromOval in a M/Mouse thingy like that as it could be made much faster by only generating one point, but it's a nice example of what you could do with it. Something like

function TPFromOval(cx, cy, mx, my: Integer): TPoint;
var
m: Integer;
r: Extended;
begin
r := mx / my; // Get the ratio of mx per my
m := Random(my - 1); // Get random y axis offset
if (Random(2) = 0) then // If 50/50 chance is true
m := -m - 1; // Set to minus with an additional -1
Result.y := cy + m; // Add the offset to the centre point
m := Random(Round(Sqrt(Sqr(my) - Sqr(m)) * r) - 1); // Get random x offset
if (Random(2) = 0) then // If 50/50 chance is true
m := -m - 1; // Set to minus with an additional -1
Result.x := cx + m; // Add the offset to the centre point
end;
Would be better suited to being using in a time critical function/procedure :)

Cazax

2009-07-05 05:43:55

Nice :) So this works like Canvas.Circle() right? I was thinking on converting canvas functions drawing them and then finding the white points. But this seems faster though. Something hard to reproduce is the shortest path algorithm(Dijkstra's algorithm, Floyd-Warshall algorithm, etc).

Richard

2009-07-05 05:47:46

So this is why you were talking about the difficulty of ovals in SCAR.

Nice job, how efficient is it normally?

Naum

2009-07-05 11:59:19

From: Cazax
Nice :) So this works like Canvas.Circle() right? I was thinking on converting canvas functions drawing them and then finding the white points. But this seems faster though. Something hard to reproduce is the shortest path algorithm(Dijkstra's algorithm, Floyd-Warshall algorithm, etc).


Although Dijkstra's algorithm could be done, as all you do is trial paths store the values then eliminate them.

Good work mixster, this can be handy for things such as DoEmote :)

mixster

2009-07-05 13:24:22

I think Raymond did Dijkstra's algorithm - I definitely know someone was at least attempting it :)

Richard: TPAFromOval is nearly as efficient as it could be. The only real way would be to swap over the height iteration to a width iteration when it's thinner than it is higher. Otherwise, it only performs 'height' complicated-ish operations and then a little loop for the width. I could possibly also make it more efficient by seeing if I can accurately preset the length of the array or set it higher than it could be and then set to a lower length at the end. Overall, I'm certain it's very efficient, though in most cases when you use it the little TPFromOval would be more useful :)

Cazax: I have no idea. I haven't compared the shapes that Canvas's draw oval method produces compared to mine, but I would assume that they would both generate ovalish shapes :)

The only problem I have with it right now is rotating the oval. I've been looking into a couple of things, but the only reasonable way would be to make an initial TPA with the outline then use trig/RotatePoints to rotate them and then loop through and find the matching y co-ords and loop through the x's, but this seems pretty inefficient to me but can do it if anyone wanted rotated ovals.

mastaraymond

2009-07-05 13:54:34

Ah! Nice stuff :-). x^2 / a^2 + y^2 / b^2 = 1. La oval formula ^_^.

Rotating shouldn't be hard, just some extra unwanted lines maybe :-p.

@Caxaz: http://www.villavu.com/forum/showthread.php?t=36548

Wizzup?

2009-07-05 14:06:05

From: Cazax
Nice :) So this works like Canvas.Circle() right? I was thinking on converting canvas functions drawing them and then finding the white points. But this seems faster though. Something hard to reproduce is the shortest path algorithm(Dijkstra's algorithm, Floyd-Warshall algorithm, etc).


AFAIK Raymond already made it, a long time ago. :)

Shuttleu

2009-07-05 14:15:57

with a width of 50 and hieght of 100 it has 15975 points in it :O
i thought it would just be the outline not the whole oval :p

~shut

Da 0wner

2009-07-05 14:25:28


Your function drew it :).

And Thomas, it is the whole oval so you can just pick a random point from the TPA and it will be inside the oval.

mixster

2009-07-05 17:45:52

Raymond: Would be more than just a few lines and would probably slow it down quite a bit. If there's a demand for rotated ovals then I could stretch to it I guess
Shuttleu: I could make it just generate the outline for an oval, but that wouldn't be as cool as having some few hundred tpoint's :)

Shuttleu

2009-07-05 21:08:17

From: mixster
Raymond: Would be more than just a few lines and would probably slow it down quite a bit. If there's a demand for rotated ovals then I could stretch to it I guess
Shuttleu: I could make it just generate the outline for an oval, but that wouldn't be as cool as having some few hundred tpoint's :)


or a few thousand…
@ Da 0wner - i used paint to test it
i done a height of 100 and width of 50 which is acctualy a height of 200 and width of 100

~shut