Runaway
2012-05-14 11:51:40
This is an interesting bit of code I dreamt up after I saw beginner5's function. Also check out function FindTPointCluster(): TPointArray if you're looking for a faster, less precise version.
You can input as many colors as you need and it will only return clusters it finds where ALL colors specified are within the given distance of each other. This is done by looping through each point for every color found and comparing it to every point of the other found colors. A set of points is only stored in the result array if a point from each color is found within the specified distance of every other color's point. This is really useful for areas that require a high color tolerance, as well as objects, npcs, and I'm sure many others.
E1: I've cleaned up the code a bit and done ALOT of testing. so far it's super accurate and can support up to ~6-8 colors before it starts to lose it's speed. Here are some of my tests, as well as the code I used:
MM Walking:

NPC Finding:

Item Finding:

Usage:
It's 100% failsafe'd, and it's got a great debug if you have any problems. It currently takes between 200-450 ms to find and parse all of the colors/points. I'd love to see some people test this out in scripts and see how it goes :)
Descripton:
Function:
Example Debug:
If you want to test it out for yourself, I've attached a testing script with debug, paint, and all sorts of options all set up and ready to go. All you have to do is select the area, colors, etc. :)
function FindTPACluster(Colors: TIntegerArray; Tol: Integer; SortFrom: TPoint; Filter, Trim: Integer; MinDist, MaxDist: Extended; Strict: Boolean; x1, y1, x2, y2: Integer): array of TPointArray;You can input as many colors as you need and it will only return clusters it finds where ALL colors specified are within the given distance of each other. This is done by looping through each point for every color found and comparing it to every point of the other found colors. A set of points is only stored in the result array if a point from each color is found within the specified distance of every other color's point. This is really useful for areas that require a high color tolerance, as well as objects, npcs, and I'm sure many others.
E1: I've cleaned up the code a bit and done ALOT of testing. so far it's super accurate and can support up to ~6-8 colors before it starts to lose it's speed. Here are some of my tests, as well as the code I used:
MM Walking:

NPC Finding:

Item Finding:

Usage:
Arr := FindTPACluster(Colors, Tol, SortFrom, FilterArr, TrimArr, 0, MaxDist, True, Area[0], Area[1], Area[2], Area[3]);
SMART_ClearCanvas;
for a := 0 to High(Arr) do
SMART_DrawCircle(False, MiddleTPA(Arr[a]), MaxDist, False, clred);
It's 100% failsafe'd, and it's got a great debug if you have any problems. It currently takes between 200-450 ms to find and parse all of the colors/points. I'd love to see some people test this out in scripts and see how it goes :)
Descripton:
(*
FindTPACluster
~~~~~~~
.. code-block:: pascal
function FindTPACluster(Colors: TIntegerArray; Tol: Integer; SortFrom: TPoint; Filter, Trim: Integer; MinDist, MaxDist: Extended; Strict: Boolean; x1, y1, x2, y2: Integer): array of TPointArray;
Results an array of TPointArray which holds "clusters" of the specified colors in
each TPointArray. It can search for an unlimited number of colors in x1, y1, x2, y2.
* Colors: The colors to be found and grouped depending on proximity.
* Tol: The tolerance on each color.
* SortFrom: The point to sort each TPoint from.
* Filter: The maximum distance between SortFrom and each TPoint. -1 to not use.
* Trim: The maximum length of each TPointArray. -1 to not use.
* MinDist, MaxDist: The minimum and maximum distances that specify how far apart
each color can be in each cluster.
* Strict: True to exit the function if not all of the specified colors are found.
.. note::
by Runaway
Example:
.. code-block:: pascal
Colors := [16514558, 5062187, 4664874];
Arr := FindTPACluster(Colors, 20, Point(MMCX, MMCY), -1, 200, 0, 30, True, MMX1, MMY1, MMX2, MMY2);
for i := 0 to High(Arr) do
begin
x := MiddleTPA(Arr[i]).x;
y := MiddleTPA(Arr[i]).y;
if (not rs_OnMinimap(x, y)) then
Continue;
Mouse(x, y, 3, 3, mouse_left);
if DidClick(True, RandomRange(750, 1250)) then
Break;
end;
*)
Function:
function FindTPACluster(Colors: TIntegerArray; Tol: Integer; SortFrom: TPoint; Filter, Trim: Integer; MinDist, MaxDist: Extended; Strict: Boolean; x1, y1, x2, y2: Integer): array of TPointArray;
var
TPA, Res: TPointArray;
aPoints: array of TPointArray;
Dist: array of Extended;
Which: array of Integer;
hDist, hPoints, hColors: Integer;
Error, Len: Integer;
r, d, t: Integer;
w, ww: Integer;
i, ii, iii: Integer;
Match, Count: Integer;
Duplicate: Boolean;
begin
MarkTime(t);
SetLength(aPoints, Length(Colors));
hColors := High(Colors);
Error := 0;
r := 0;
for i := 0 to hColors do
begin
if (FindColorsTolerance(TPA, Colors[i], x1, y1, x2, y2, Tol)) then
begin
SortTPAFrom(TPA, SortFrom);
if (Filter <> -1) then
FilterPointsDist(TPA, 0, Filter, SortFrom.x, SortFrom.y);
if (Trim <> -1) and (Length(TPA) > Trim) then
SetLength(TPA, Trim);
aPoints[i - Error] := TPA;
end else
begin
if Strict then
begin
Writeln('Error: not enough colors found!');
Exit;
end;
Len := Length(aPoints) - 1;
SetLength(aPoints, Len);
Inc(Error);
end;
if (Error >= hColors) then
begin
Writeln('Error: not enough colors found!');
Exit;
end;
end;
SetLength(Dist, Length(aPoints) - 1);
SetLength(Which, Length(aPoints) - 1);
hPoints := High(aPoints);
hDist := High(Dist);
for i := 0 to hPoints do
begin
Count := 0;
for w := 0 to hDist do
begin
if (hPoints - w = hPoints - i) or (hPoints - w < hPoints - i) then
Which[w] := w + 1
else
Which[w] := w;
end;
for ii := 0 to High(aPoints[i]) do
begin
Match := 0;
for iii := 0 to hDist do
begin
if (Count > High(aPoints[Which[iii]])) then
begin
Inc(Count);
Break;
end;
Dist[iii] := Distance(aPoints[i][ii].x, aPoints[i][ii].y, aPoints[Which[iii]][Count].x, aPoints[Which[iii]][Count].y);
if (Dist[iii] >= MinDist) and (Dist[iii] <= MaxDist) then
Inc(Match)
else
begin
Inc(Count);
Break;
end;
end;
if (Match >= hPoints) then
begin
SetLength(Res, Length(aPoints));
Res[0] := aPoints[i][ii];
for ww := 0 to hDist do
Res[ww + 1] := aPoints[Which[ww]][Count];
SortTPAByX(Res, True);
if (Length(Result) >= 1) then
begin
Duplicate := False;
for d := 0 to High(Result) do
begin
if (Result[d] = Res) then
Duplicate := True;
end;
if Duplicate then
begin
Inc(Count);
Continue;
end;
end;
SetLength(Result, r + 1);
Result[r] := Res;
Inc(r);
Res := [];
end;
Inc(Count);
end;
end;
Writeln('Took: '+IntToStr(TimeFromMark(t))+' ms, found '+IntToStr(Length(Result))+' unique cluster(s)');
end;
Example Debug:
Searching: color 1 of 4...
Found: 119 point(s) of color 5723995
Using: first 100 point(s) of color 5723995
Searching: color 2 of 4...
Found: 100 point(s) of color 9474455
Using: first 100 point(s) of color 9474455
Searching: color 3 of 4...
Found: 68 point(s) of color 13751003
Using: first 68 point(s) of color 13751003
Searching: color 4 of 4...
Found: 113 point(s) of color 9079440
Using: first 100 point(s) of color 9079440
Searching... done
Sorting: array 1 of 4...
Found: 2 new cluster(s)
Sorting: array 2 of 4...
Found: 0 new cluster(s)
Sorting: array 3 of 4...
Found: 36 new cluster(s)
Sorting: array 4 of 4...
Found: 8 new cluster(s)
Sorting... done
Took: 219 ms, found 46 unique cluster(s)
Successfully executed.
If you want to test it out for yourself, I've attached a testing script with debug, paint, and all sorts of options all set up and ready to go. All you have to do is select the area, colors, etc. :)
