SRL Archive - SRL Archives

>>> FindColorSector and other functions.... <<<


ZephyrsFury

2007-11-07 07:43:28

Ok this I decide to make this function due to several reasons.

First of all it was because when I was making my Rune Mysteries Runner I was looking for a function similar to FindColorCircle except it would only search a sector of the minimap between to angles and a radius (similar to RadialWalk).

Second was because I was bored studying for my exams in the next two weeks and decided to make SCAR draw random shapes using polar equations.
So I decided to combinded the two together and make a new function that would also prepare me for my exams. :)

So I give you FindColorSectorEx. It gives you many parameters from which ou can make other FindColorSector functions. (ie. FindColorSectorTol, FindColorSectorPolar, FindColorSectorMinimap, etc.)


function FindColourSectorEx(var Sx, Sy, R, Theta: Integer; Colour, CentreX,
CentreY, StartAngle, EndAngle, Radius, RStep, Tol: Integer; Outwards: Boolean): Boolean;
var
j, k, l, m, n, BMP, Handle: Integer;
PP: Array of PPoint;
TP: TPointArray;
Temp: TColor;
begin
Sx := -1; Sy := -1; R := -1; Theta := -1;
if (StartAngle = EndAngle) then
begin
Writeln('StartAngle and EndAngle cannot be the same.');
Exit;
end;
l := 1;
k := 1;
if (Outwards) then l := 0
else k := Radius;
{Handle := GetClientWindowHandle;
BMP := BitmapFromString(2 * Radius, 2 * Radius, '');
CopyClientToBitmap(BMP, CentreX - Radius, CentreY - Radius, CentreX + Radius,
CentreY + Radius);
SetTargetBitmap(BMP);}
repeat
if (Outwards) then PP := CreatePPArray(l, StartAngle, EndAngle, 1)
else PP := CreatePPArray(k, StartAngle, EndAngle, 1);
TP := PolarToCart(PP, CentreX, CentreY);
for j := 0 to Length(TP) - 1 do
begin
//MoveMouse(Tp[j].x, Tp[j].y);
Temp := GetColor(TP[j].x, TP[j].y);
//Temp := FastGetPixel(BMP, TP[j].x, TP[j].y);
if (SimilarColors(Colour, Temp, Tol)) then
begin
Sx := TP[j].x;
Sy := TP[j].y;
if (CentreX < Sx) then
begin
m := 90;
if (CentreY < Sy) then
n := 1
else n := -1;
end else
begin
m := 270;
if (CentreY < Sy) then
n := -1
else n := 1;
end;
Theta := m + n * Round(FixD(Degrees(ArcTan(Abs((CentreY - Sy) / (CentreX - Sx))))));
R := Distance(Sx, Sy, CentreX, CentreY);
{SetClientWindowHandle(Handle);
FreeBitmap(BMP);}
Result := True;
Exit;
end;
end;
if (Outwards) then l := l + RStep
else k := k - RStep;
until (l >= Radius) or (k <= 0);
{SetClientWindowHandle(Handle);
FreeBitmap(BMP);}
end;


To use it you need two other functions that create a PPoint array and then convert Polar coordinates to Cartesian:


function CreatePPArray(Rad, StartAng, EndAng, AngleStep: Integer): Array of PPoint;
var
j, l: Integer;
begin
if (StartAng > EndAng) then l := -1 else l := 1;
for j := 0 to Round(Abs((EndAng - StartAng) / AngleStep)) do
begin
SetLength(Result, j + 1);
Result[j].r := Rad;
Result[j].t := StartAng + j * l * AngleStep;
end;
end;

function PolarToCart(PPointArray: Array of PPoint; CentX, CentY: Integer): TPointArray;
var
k: Integer;
begin
for k := 0 to Length(PPointArray) - 1 do
begin
SetLength(Result, k + 1);
Result[k].x := Round(PPointArray[k].r * Cos(Radians(PPointArray[k].t - 90))) + CentX;
Result[k].y := Round(PPointArray[k].r * Sin(Radians(PPointArray[k].t - 90))) + CentY;
end;
end;

So for an explanation of the parameters for FindColorSectorEx:

  • Sx, Sy - X and Y coordinates of the point found first.
  • R, Theta - R is the radius and Theta is the angle from the positive Y axis of the point found.
  • Colour - The colour to be found.
  • CentreX, CentreY - The centre of the circle in which the function searches in.
  • StartAngle, EndAngle - Pretty self-explanatory (similar to RadialWalk).
  • Radius - Also pretty self-explanatory. (also similar to RadialWalk).
  • RStep - The number of pixels from the centre it adds or subtracts everytime it finishes searching the arc. The smaller the number (1,2) the more accurate but also the slower. The larger the number, the faster. (RadialWalk uses 4).
  • Tol - The tolerance of the colour being searched for.
  • Outwards - True if you want the function to search inside out. False for outside in (RadialWalk is outside in).

As I was saying from this multi-purpose function you could create other functions ie:


function FindColorSectorMiniMap(var x, y: Integer; Colour, StartAngle, EndAngle,
Radius, Tol: Integer): Boolean;
var
R, T: Integer;
begin
Result := FindColorSectorEx(x, y, R, T, Colour, 643, 84, StartAngle, EndAngle, Radius,
3, Tol, True);
end;

or:


function FindColorSectorMMPolar(var R, T: Integer; Colour, StartAngle, EndAngle,
Radius, Tol: Integer): Boolean;
var
x, y: Integer;
begin
Result := FindColorSectorEx(x, y, R, T, Colour, 643, 84, StartAngle, EndAngle,
Radius, 3, Tol, True);
end;

I know this function is pretty slow. I'm trying to speed it up by using bitmaps and stuff (as you can see from my commented out stuff ;) ) but I haven't succeeded. Maybe someone could advise me on how to get it to work. :D

EDIT: Heres the modified function:


function FindColorSectorEx2(var Sx, Sy, R, Theta: Integer; Colour, CentreX,
CentreY, StartAngle, EndAngle, Radius, Tol: Integer; Outwards: Boolean): Boolean;
var
TempTP: TPointArray;
TempPP, TempPts: Array of PPoint;
cx1, cy1, cx2, cy2, i, j, a, Max, MaxNum, m, n: Integer;
begin
if (StartAngle > EndAngle) then
begin
a := StartAngle;
StartAngle := EndAngle;
EndAngle := a;
end;
Sx := -1; Sy := -1; R := -1; Theta := -1; j := 0;
cx1 := CentreX - Radius; cy1 := CentreY - Radius;
cx2 := CentreX + Radius; cy2 := CentreY + Radius;
if (cx1 < 0) then cx1 := 0; if (cy1 < 0) then cy1 := 0;
FindColorsTolerance(TempTP, Colour, cx1, cy1, cx2, cy2, Tol);
if (Length(TempTP) = 0) then Exit;
for i := 0 to Length(TempTp) - 1 do
begin
SetLength(TempPP, i + 1);
if(CentreX < TempTP[i].x) then
begin
m := 90;
if (CentreY < TempTP[i].y) then
n := 1
else n := -1;
end else
begin
m := 270;
if (CentreY < TempTP[i].y) then
n := -1
else n := 1;
end;
TempPP[i].r := Distance(TempTP[i].x, TempTP[i].y, CentreX, CentreY);
TempPP[i].t := m + n * Round(FixD(Degrees(ArcTan(Abs((CentreY - Sy) / (CentreX - Sx))))));
end;
for i := 0 to Length(TempPP) - 1 do
begin
if (TempPP[i].r <= Radius) then
if (TempPP[i].t >= StartAngle) then
if (TempPP[i].t <= EndAngle) then
begin
SetLength(TempPts, j + 1);
TempPts[j].r := TempPP[i].r;
TempPts[j].t := TempPP[i].t;
j := j + 1;
end;
end;
if (Length(TempPts) = 0) then Exit;
if (Outwards) then Max := Radius
else Max := 0;
for i := 0 to Length(TempPts) - 1 do
begin
if (Outwards) then
begin;
if (Round(TempPts[i].r) <= Max) then
begin
Max := Round(TempPts[i].r);
MaxNum := i;
end;
end else
begin
if (Round(TempPts[i].r) >= Max) then
begin
Max := Round(TempPts[i].r);
MaxNum := i;
end;
end;
end;
Sx := Round(TempPts[MaxNum].r * Cos(Radians(TempPts[MaxNum].t - 90))) + CentreX;
Sy := Round(TempPts[MaxNum].r * Sin(Radians(TempPts[MaxNum].t - 90))) + CentreY;
R := Round(TempPts[MaxNum].r);
Theta := Round(TempPts[MaxNum].t);
Result := True;
end;

Its parameters are the same except I've removed RStep.

Wizzup?

2007-11-07 07:58:27

You can speed it up by first using a FindColorsTolerance, then take out points in that TPA that are not in the degrees and distance. Then sort it by distance. :)

n3ss3s

2007-11-07 08:00:25

That looks pretty nice!

Rofl, Wizzy is viewing, prepare for shortened version, or a thousand lines long uberturboleet code lol…

Btw, if you want ever to do it in a less leet way, just do a FindColors and then a for loop, and have a function that checks if a coord is in a sector (Yes wizzup I remember InDegreeEx) and then sort the ones that were in a new TPA :p

EDIT: -.- Wizzy….

EDIT EDIT:

Then sort it by distance.


Okay, I escape the situation by mentioning wizzy's SortTPAFrom :p

R0b0t1

2007-11-07 17:14:37

Fuck! I got my ass kicked!


Ok. I'm of to learn Trig now.

Miitchyy

2007-11-07 19:11:49

RadialWalkEx?

Also;
Why Theta if you have an end angle?

ZephyrsFury

2007-11-08 02:22:28

From: Wizzup?
You can speed it up by first using a FindColorsTolerance, then take out points in that TPA that are not in the degrees and distance. Then sort it by distance. :)


I suppose that would be better. Thanks for the advise.

From: Kevin Wolf
RadialWalkEx?

Also;
Why Theta if you have an end angle?


Theta is the variable in which it saves the angle of the point its found. EndAngle is just the end of the search area.

EDIT: Modified the function using Wizzup?'s idea. It now works a bit faster.

Miitchyy

2007-11-08 07:42:08

Ah, Very nice;
I can't deny I haven't wish for more hmm "Indepth"? procedure,
Ones which return more stuff xP

ZephyrsFury

2007-11-08 08:23:12

From: Kevin Wolf
Ah, Very nice;
I can't deny I haven't wish for more hmm "Indepth"? procedure,
Ones which return more stuff xP


Yes that was one of the reasons why I made this function. :) BTW Wizzup?, since your method works so much better, maybe you could alter RadialWalk or make a FastRadialWalk or something.

@R0b0t, Good luck… G & T (Geometry and Trigonometry) is the most advance maths course available for my year at school. ;)