Skip to content

Commit 96adf1c

Browse files
committed
feat: finished TColorFinder the successor of TRSObjectFinder`
1 parent 97d7a2e commit 96adf1c

File tree

1 file changed

+240
-46
lines changed

1 file changed

+240
-46
lines changed

osrs/colorfinder.simba

Lines changed: 240 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,275 @@
11
(*
22
# ColorFinder
3-
Methods to interact with the mainscreen.
3+
Methods to find and interact with complex color objects.
44
*)
55

66
{$DEFINE SRLT_COLORFINDER_INCLUDED}
77
{$INCLUDE_ONCE SRLT/osrs.simba}
88

99
type
10-
TColorFinder = record
11-
Colors: array of TColorTolerance;
10+
(*
11+
(TColorFinderTransformer)=
12+
## type TColorFinderTransformer
13+
Helper record that helps transforming a {ref}`TColorFinder` after finding it's
14+
colors and/or colors clusters.
15+
*)
16+
TColorFinderTransformer = record
1217
Distance, Erode, Grow: Integer;
13-
LongSide, ShortSide: record Min, Max: Integer; end;
18+
LongSide, ShortSide: record
19+
Min, Max: Integer;
20+
end;
1421
end;
1522

16-
function TColorFinder.Find(area: TBox; atpa: T2DPointArray): Boolean;
23+
(*
24+
## TColorFinderTransformer.Normalize
25+
```pascal
26+
function TColorFinderTransformer.Normalize(): TColorFinder;
27+
```
28+
Helper method to normalize a {ref}`TColorFinderTransformer` from 50% zoom values
29+
to our current one with the help of {ref}`MainScreen.NormalizeDistance`.
30+
This is important to do so we have consistent values at any zoom value.
31+
*)
32+
function TColorFinderTransformer.Normalize(): TColorFinderTransformer;
33+
begin
34+
if Self.Distance > 0 then
35+
Result.Distance := MainScreen.NormalizeDistance(Self.Distance);
36+
if Self.Erode > 0 then
37+
Result.Erode := MainScreen.NormalizeDistance(Self.Erode);
38+
if Self.Grow > 0 then
39+
Result.Grow := MainScreen.NormalizeDistance(Self.Grow);
40+
41+
if Self.LongSide.Min > 0 then
42+
Result.LongSide.Min := MainScreen.NormalizeDistance(Self.LongSide.Min);
43+
if Self.ShortSide.Min > 0 then
44+
Result.ShortSide.Min := MainScreen.NormalizeDistance(Self.ShortSide.Min);
45+
46+
if Self.LongSide.Max > 0 then
47+
Result.LongSide.Max := MainScreen.NormalizeDistance(Self.LongSide.Max);
48+
if Self.ShortSide.Max > 0 then
49+
Result.ShortSide.Max := MainScreen.NormalizeDistance(Self.ShortSide.Max);
50+
end;
51+
52+
(*
53+
## TColorFinderTransformer.Process
54+
```pascal
55+
function TColorFinderTransformer.Process(tpa: TPointArray): T2DPointArray;
56+
```
57+
Helper method to transform a TPA with the current {ref}`TColorFinderTransformer`
58+
into an ATPA.
59+
*)
60+
function TColorFinderTransformer.Process(tpa: TPointArray): T2DPointArray;
1761
var
18-
tpa: TPointArray;
1962
i, l, s: Integer;
20-
finder: TColorFinder;
21-
tmp: T2DPointArray;
63+
weights: TIntegerArray;
2264
begin
23-
// Translate distances
24-
finder.Distance := MainScreen.NormalizeDistance(Self.Distance);
25-
finder.Erode := MainScreen.NormalizeDistance(Self.Erode);
26-
finder.Grow := MainScreen.NormalizeDistance(Self.Grow);
65+
if tpa <> [] then Exit;
2766

28-
finder.LongSide.Min := MainScreen.NormalizeDistance(Self.LongSide.Min);
29-
finder.ShortSide.Min := MainScreen.NormalizeDistance(Self.ShortSide.Min);
67+
// Transform the TPA
68+
if Self.Grow > 0 then tpa := tpa.Grow(Self.Grow);
69+
if Self.Erode > 0 then tpa := tpa.Erode(Self.Erode);
3070

31-
if Self.LongSide.Max = 0 then
32-
finder.LongSide.Max := $FFFFFF
33-
else
34-
finder.LongSide.Max := MainScreen.NormalizeDistance(Self.LongSide.Max);
71+
if tpa = [] then Exit;
3572

36-
if Self.ShortSide.Max = 0 then
37-
finder.ShortSide.Max := $FFFFFF
38-
else
39-
finder.ShortSide.Max := MainScreen.NormalizeDistance(Self.ShortSide.Max);
73+
Result := tpa.Cluster(Self.Distance);
4074

41-
// Find colors
42-
for i := 0 to High(Self.Colors) do
43-
tpa += Target.FindColor(Self.Colors[i], area);
75+
if (Self.ShortSide.Max <= 0) and (Self.LongSide.Max <= 0) then
76+
Exit(Result.SortBySize(True)); //sort by size
4477

45-
// Process TPA
46-
if tpa <> [] then Exit;
78+
//filter the TPA by ShortSide and LongSide
79+
for i := High(Result) downto 0 do
80+
begin
81+
with Result[i].MinAreaRect() do
82+
begin
83+
l := LongSideLen;
84+
s := ShortSideLen;
85+
end;
4786

48-
if finder.Grow > 0 then
49-
tpa := tpa.Grow(finder.Grow);
50-
if finder.Erode > 0 then
51-
tpa := tpa.Erode(finder.Erode);
87+
if not InRange(s, Self.ShortSide.Min, Self.ShortSide.Max) then
88+
begin
89+
Delete(Result, i, 1);
90+
Continue;
91+
end;
5292

53-
if tpa = [] then Exit;
93+
if not InRange(l, Self.LongSide.Min, Self.LongSide.Max) then
94+
begin
95+
Delete(Result, i, 1);
96+
Continue;
97+
end;
98+
99+
weights += Length(Result[i]);
100+
end;
101+
102+
if Result = [] then Exit;
103+
Result := Result.Sort(weights); //Sort by size making use of the prev loop.
104+
end;
54105

55-
Result := True;
56-
tmp := tpa.Cluster(finder.Distance);
57106

58-
if (finder.ShortSide.Min > 0) or (finder.ShortSide.Max > 0) or
59-
(finder.LongSide.Min > 0) or (finder.LongSide.Max > 0) then
107+
type
108+
(*
109+
(TColorFinder)=
110+
## type TColorFinder
111+
Main record used to find and interact with complex color objects.
112+
*)
113+
TColorFinder = record
114+
Colors: array of TColorTolerance;
115+
ColorClusters: array of record
116+
Primary, Secondary: TColorTolerance;
117+
Distance: Integer;
118+
end;
119+
Transformer: TColorFinderTransformer;
120+
end;
121+
122+
(*
123+
## TColorFinder.Find
124+
```pascal
125+
function TColorFinder.Find(out atpa: T2DPointArray; areas: TBoxArray): Boolean;
126+
function TColorFinder.Find(out atpa: T2DPointArray; area: TBox): Boolean; overload;
127+
function TColorFinder.Find(out atpa: T2DPointArray; areas: TPolygonArray): Boolean; overload;
128+
function TColorFinder.Find(out atpa: T2DPointArray; area: TPolygon): Boolean; overload;
129+
function TColorFinder.Find(out atpa: T2DPointArray; areas: TCuboidArray): Boolean; overload;
130+
function TColorFinder.Find(out atpa: T2DPointArray; area: TCuboid): Boolean; overload;
131+
```
132+
Attempts to find on the given `area` a {ref}`TColorFinder`.
133+
If `area` is not specified, {ref}`MainScreen` Bounds are used.
134+
The function returns true if we find anything and the coordinates containing
135+
what was found are returned through `atpa`.
136+
137+
*)
138+
function TColorFinder.Find(out atpa: T2DPointArray; areas: TBoxArray): Boolean;
139+
var
140+
transformer: TColorFinderTransformer;
141+
area: TBox;
142+
i: Integer;
143+
tpa, primary, secondary: TPointArray;
144+
begin
145+
transformer := Self.Transformer.Normalize();
146+
147+
for area in areas do
60148
begin
61-
for i := 0 to High(tmp) do
149+
for i := 0 to High(Self.Colors) do // Find TColorFinder.Colors
150+
tpa += Target.FindColor(Self.Colors[i], area);
151+
152+
for i := 0 to High(Self.ColorClusters) do // Find TColorFinder.ColorClusters
62153
begin
63-
with tmp[i].Edges().MinAreaRect() do
154+
if Self.ColorClusters[i].Distance <= 0 then
64155
begin
65-
l := LongSideLen;
66-
s := ShortSideLen;
156+
WriteLn GetDebugLn('TColorFinder', 'Skipping cluster with 0 distance, make it higher than 0!', EErrorLevel.WARN);
157+
Continue;
67158
end;
68159

69-
if ((finder.ShortSide.Min > 0) or (finder.ShortSide.Max > 0)) and (not InRange(s, finder.ShortSide.Min, finder.ShortSide.Max)) then
160+
primary := Target.FindColor(Self.ColorClusters[i].Primary, area);
161+
if primary = [] then Continue;
162+
secondary := Target.FindColor(Self.ColorClusters[i].Secondary, area);
163+
if secondary = [] then Continue;
164+
165+
tpa += primary.PointsNearby(secondary, 0, MainScreen.NormalizeDistance(Self.ColorClusters[i].Distance));
166+
end;
167+
end;
168+
169+
atpa := transformer.Process(tpa);
170+
Result := atpa <> [];
171+
end;
172+
173+
function TColorFinder.Find(out atpa: T2DPointArray; area: TBox): Boolean; overload;
174+
begin
175+
Result := Self.Find(atpa, [area]);
176+
end;
177+
178+
179+
function TColorFinder.Find(out atpa: T2DPointArray; areas: TPolygonArray): Boolean; overload;
180+
var
181+
transformer: TColorFinderTransformer;
182+
area: TPolygon;
183+
bounds: TBox;
184+
i: Integer;
185+
tpa, primary, secondary, tmp: TPointArray;
186+
begin
187+
transformer := Self.Transformer.Normalize();
188+
189+
for area in areas do
190+
begin
191+
bounds := area.Bounds();
192+
for i := 0 to High(Self.Colors) do // Find TColorFinder.Colors
193+
tmp += Target.FindColor(Self.Colors[i], bounds);
194+
195+
for i := 0 to High(Self.ColorClusters) do // Find TColorFinder.ColorClusters
196+
begin
197+
if Self.ColorClusters[i].Distance <= 0 then
198+
begin
199+
WriteLn GetDebugLn('TColorFinder', 'Skipping cluster with 0 distance, make it higher than 0!', EErrorLevel.WARN);
70200
Continue;
71-
if ((finder.LongSide.Min > 0) or (finder.LongSide.Max > 0)) and (not InRange(l, finder.LongSide.Min, finder.LongSide.Max)) then
201+
end;
202+
203+
primary := Target.FindColor(Self.ColorClusters[i].Primary, bounds);
204+
if primary = [] then Continue;
205+
secondary := Target.FindColor(Self.ColorClusters[i].Secondary, bounds);
206+
if secondary = [] then Continue;
207+
208+
tmp += primary.PointsNearby(secondary, 0, MainScreen.NormalizeDistance(Self.ColorClusters[i].Distance));
209+
end;
210+
211+
tpa += tmp.ExtractPolygon(area);
212+
tmp := [];
213+
end;
214+
215+
atpa := transformer.Process(tpa);
216+
Result := atpa <> [];
217+
end;
218+
219+
function TColorFinder.Find(out atpa: T2DPointArray; area: TPolygon): Boolean; overload;
220+
begin
221+
Result := Self.Find(atpa, [area]);
222+
end;
223+
224+
225+
function TColorFinder.Find(out atpa: T2DPointArray; areas: TCuboidArray): Boolean; overload;
226+
var
227+
transformer: TColorFinderTransformer;
228+
area: TCuboid;
229+
bounds: TBox;
230+
i: Integer;
231+
tpa, primary, secondary, tmp: TPointArray;
232+
begin
233+
transformer := Self.Transformer.Normalize();
234+
235+
for area in areas do
236+
begin
237+
bounds := area.Bounds();
238+
for i := 0 to High(Self.Colors) do // Find TColorFinder.Colors
239+
tmp += Target.FindColor(Self.Colors[i], bounds);
240+
241+
for i := 0 to High(Self.ColorClusters) do // Find TColorFinder.ColorClusters
242+
begin
243+
if Self.ColorClusters[i].Distance <= 0 then
244+
begin
245+
WriteLn GetDebugLn('TColorFinder', 'Skipping cluster with 0 distance, make it higher than 0!', EErrorLevel.WARN);
72246
Continue;
247+
end;
248+
249+
primary := Target.FindColor(Self.ColorClusters[i].Primary, bounds);
250+
if primary = [] then Continue;
251+
secondary := Target.FindColor(Self.ColorClusters[i].Secondary, bounds);
252+
if secondary = [] then Continue;
73253

74-
atpa += tmp[I];
254+
tmp += primary.PointsNearby(secondary, 0, MainScreen.NormalizeDistance(Self.ColorClusters[i].Distance));
75255
end;
76-
end else
77-
atpa := tmp;
78256

79-
atpa := atpa.SortBySize(True);
257+
tpa += tmp.ExtractPolygon(area.Polygon());
258+
tmp := [];
259+
end;
260+
261+
atpa := transformer.Process(tpa);
262+
Result := atpa <> [];
263+
end;
264+
265+
function TColorFinder.Find(out atpa: T2DPointArray; area: TCuboid): Boolean; overload;
266+
begin
267+
Result := Self.Find(atpa, [area]);
268+
end;
269+
270+
271+
function TColorFinder.Find(out atpa: T2DPointArray): Boolean; overload;
272+
begin
273+
Result := Self.Find(atpa, [MainScreen.Bounds]);
80274
end;
81275

0 commit comments

Comments
 (0)