|
1 | 1 | (* |
2 | 2 | # ColorFinder |
3 | | -Methods to interact with the mainscreen. |
| 3 | +Methods to find and interact with complex color objects. |
4 | 4 | *) |
5 | 5 |
|
6 | 6 | {$DEFINE SRLT_COLORFINDER_INCLUDED} |
7 | 7 | {$INCLUDE_ONCE SRLT/osrs.simba} |
8 | 8 |
|
9 | 9 | 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 |
12 | 17 | Distance, Erode, Grow: Integer; |
13 | | - LongSide, ShortSide: record Min, Max: Integer; end; |
| 18 | + LongSide, ShortSide: record |
| 19 | + Min, Max: Integer; |
| 20 | + end; |
14 | 21 | end; |
15 | 22 |
|
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; |
17 | 61 | var |
18 | | - tpa: TPointArray; |
19 | 62 | i, l, s: Integer; |
20 | | - finder: TColorFinder; |
21 | | - tmp: T2DPointArray; |
| 63 | + weights: TIntegerArray; |
22 | 64 | 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; |
27 | 66 |
|
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); |
30 | 70 |
|
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; |
35 | 72 |
|
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); |
40 | 74 |
|
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 |
44 | 77 |
|
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; |
47 | 86 |
|
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; |
52 | 92 |
|
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; |
54 | 105 |
|
55 | | - Result := True; |
56 | | - tmp := tpa.Cluster(finder.Distance); |
57 | 106 |
|
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 |
60 | 148 | 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 |
62 | 153 | begin |
63 | | - with tmp[i].Edges().MinAreaRect() do |
| 154 | + if Self.ColorClusters[i].Distance <= 0 then |
64 | 155 | 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; |
67 | 158 | end; |
68 | 159 |
|
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); |
70 | 200 | 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); |
72 | 246 | 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; |
73 | 253 |
|
74 | | - atpa += tmp[I]; |
| 254 | + tmp += primary.PointsNearby(secondary, 0, MainScreen.NormalizeDistance(Self.ColorClusters[i].Distance)); |
75 | 255 | end; |
76 | | - end else |
77 | | - atpa := tmp; |
78 | 256 |
|
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]); |
80 | 274 | end; |
81 | 275 |
|
0 commit comments