2010-01-25 08:59:44 -05:00
{
This file is part of the Mufasa Macro Library ( MML)
Copyright ( c) 2 0 0 9 by Raymond van Venetië and Merlijn Wajer
MML is free software: you can redistribute it and/ or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
( at your option) any later version.
MML is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MML. If not , see < http: //www.gnu.org/licenses/>.
See the file COPYING, included in this distribution,
for details about the copyright.
Finder class for the Mufasa Macro Library
}
unit finder;
{$mode objfpc} {$H+}
2010-02-28 08:21:30 -05:00
{$INLINE ON}
2010-01-25 08:59:44 -05:00
interface
{$define CheckAllBackground} //Undefine this to only check the first white point against the background (in masks).
uses
2011-06-13 14:21:23 -04:00
colour_conv, Classes, SysUtils, bitmaps, DTM, MufasaTypes; // Types
2010-01-25 08:59:44 -05:00
{ TMFinder Class }
{
2011-06-13 14:21:23 -04:00
Should be 1 0 0 % OS independant, as all OS dependant code is in the IO Manager.
2010-01-25 08:59:44 -05:00
Let' s try not to use any OS- specific defines here? ; )
2011-06-16 08:26:20 -04:00
2011-08-01 10:16:19 -04:00
TODO: Check that each procedure calling Create_CTSInfo also calls
Free_CTSInfo( ) .
2010-01-25 08:59:44 -05:00
}
type
2010-04-02 11:55:54 -04:00
TMFinder = class( TObject)
private
Client: TObject;
Percentage : array [ 0 .. 2 5 5 ] of Extended ; //We store all the possible RGB / 255 divisions.
CachedWidth, CachedHeight : integer ;
ClientTPA : TPointArray;
hueMod, satMod: Extended ;
CTS: Integer ;
Procedure UpdateCachedValues( NewWidth, NewHeight : integer ) ;
//Loads the Spiral into ClientTPA (Will not cause problems)
procedure LoadSpiralPath( startX, startY, x1, y1, x2, y2: Integer ) ;
public
WarnOnly : boolean ;
2010-04-21 11:10:40 -04:00
procedure DefaultOperations( var xs, ys, xe, ye : integer ) ;
2010-04-02 11:55:54 -04:00
function FindColorsToleranceOptimised( out Points: TPointArray; Color, xs, ys, xe, ye, Tol: Integer ) : Boolean ;
function FindColorToleranceOptimised( out x, y: Integer ; Color, xs, ys, xe, ye, tol: Integer ) : Boolean ;
function CountColorTolerance( Color, xs, ys, xe, ye, Tolerance: Integer ) : Integer ;
function CountColor( Color, xs, ys, xe, ye: Integer ) : Integer ;
function SimilarColors( Color1, Color2, Tolerance : Integer ) : boolean ;
// Possibly turn x, y into a TPoint var.
function FindColor( out x, y: Integer ; Color, xs, ys, xe, ye: Integer ) : Boolean ;
function FindColorSpiral( var x, y: Integer ; color, xs, ys, xe, ye: Integer ) : Boolean ;
function FindColorSpiralTolerance( var x, y: Integer ; color, xs, ys, xe, ye, Tol: Integer ) : Boolean ;
function FindColorTolerance( out x, y: Integer ; Color, xs, ys, xe, ye, tol: Integer ) : Boolean ;
function FindColorsTolerance( out Points: TPointArray; Color, xs, ys, xe, ye, Tol: Integer ) : Boolean ;
2011-07-07 05:59:15 -04:00
function FindColorsSpiralTolerance( x, y: Integer ; out Points: TPointArray; color, xs, ys, xe, ye: Integer ; Tol: Integer ) : boolean ;
2010-04-18 11:14:19 -04:00
function FindColors( var TPA: TPointArray; Color, xs, ys, xe, ye: Integer ) : Boolean ;
2010-04-02 11:55:54 -04:00
function FindColoredArea( var x, y: Integer ; color, xs, ys, xe, ye: Integer ; MinArea: Integer ) : Boolean ;
function FindColoredAreaTolerance( var x, y: Integer ; color, xs, ys, xe, ye: Integer ; MinArea, tol: Integer ) : Boolean ;
//Mask
function FindMaskTolerance( const mask: TMask; out x, y: Integer ; xs, ys, xe, ye: Integer ; Tolerance, ContourTolerance: Integer ) : Boolean ;
procedure CheckMask( const Mask : TMask) ;
//Bitmap functions
function FindBitmap( bitmap: TMufasaBitmap; out x, y: Integer ) : Boolean ;
function FindBitmapIn( bitmap: TMufasaBitmap; out x, y: Integer ; xs, ys, xe, ye: Integer ) : Boolean ;
function FindBitmapToleranceIn( bitmap: TMufasaBitmap; out x, y: Integer ; xs, ys, xe, ye: Integer ; tolerance: Integer ) : Boolean ;
function FindBitmapSpiral( bitmap: TMufasaBitmap; var x, y: Integer ; xs, ys, xe, ye: Integer ) : Boolean ;
function FindBitmapSpiralTolerance( bitmap: TMufasaBitmap; var x, y: Integer ; xs, ys, xe, ye, tolerance : integer ) : Boolean ;
function FindBitmapsSpiralTolerance( bitmap: TMufasaBitmap; x, y: Integer ; out Points : TPointArray; xs, ys, xe, ye, tolerance: Integer ) : Boolean ;
function FindDeformedBitmapToleranceIn( bitmap: TMufasaBitmap; out x, y: Integer ; xs, ys, xe, ye: Integer ; tolerance: Integer ; Range: Integer ; AllowPartialAccuracy: Boolean ; out accuracy: Extended ) : Boolean ;
2010-05-19 10:01:01 -04:00
function FindDTM( DTM: TMDTM; out x, y: Integer ; x1, y1, x2, y2: Integer ) : Boolean ;
function FindDTMs( DTM: TMDTM; out Points: TPointArray; x1, y1, x2, y2 : integer ; maxToFind: Integer = 0 ) : Boolean ;
function FindDTMRotated( DTM: TMDTM; out x, y: Integer ; x1, y1, x2, y2: Integer ; sAngle, eAngle, aStep: Extended ; out aFound: Extended ; Alternating : boolean ) : Boolean ;
function FindDTMsRotated( DTM: TMDTM; out Points: TPointArray; x1, y1, x2, y2: Integer ; sAngle, eAngle, aStep: Extended ; out aFound: T2DExtendedArray; Alternating : boolean ; maxToFind: Integer = 0 ) : Boolean ;
2010-04-02 11:55:54 -04:00
//Donno
function GetColors( const Coords: TPointArray) : TIntegerArray;
// tol speeds
procedure SetToleranceSpeed( nCTS: Integer ) ;
function GetToleranceSpeed: Integer ;
procedure SetToleranceSpeed2Modifiers( const nHue, nSat: Extended ) ;
procedure GetToleranceSpeed2Modifiers( out hMod, sMod: Extended ) ;
constructor Create( aClient: TObject) ;
destructor Destroy; override ;
end ;
2010-01-25 08:59:44 -05:00
implementation
uses
2011-06-13 14:21:23 -04:00
Client, // For the Client casting.
math, // min/max
tpa, //TPABounds
dtmutil;
2010-01-25 08:59:44 -05:00
2011-07-06 12:15:33 -04:00
type
2011-07-06 15:06:17 -04:00
TCTS0Info = record
B, G, R, A: byte ;
Tol: Integer ;
end ;
PCTS0Info = ^ TCTS0Info;
TCTS1Info = record
B, G, R, A: byte ;
Tol: Integer ; { Squared }
end ;
PCTS1Info = ^ TCTS1Info;
2011-07-06 12:15:33 -04:00
TCTS2Info = record
H, S, L: extended ;
hueMod, satMod: extended ;
2011-07-06 15:06:17 -04:00
Tol: Integer ;
2011-07-06 12:15:33 -04:00
end ;
PCTS2Info = ^ TCTS2Info;
2011-07-30 07:12:21 -04:00
TCTSInfo = Pointer ;
TCTSInfoArray = Array of TCTSInfo;
TCTSInfo2DArray = Array of TCTSInfoArray;
2011-07-06 15:06:17 -04:00
TCTSCompareFunction = function ( ctsInfo: Pointer ; C2: PRGB32) : boolean ;
2011-07-06 12:15:33 -04:00
2010-01-25 08:59:44 -05:00
procedure TMFinder. LoadSpiralPath( startX, startY, x1, y1, x2, y2: Integer ) ;
var
i, c, Ring : integer ;
CurrBox : TBox;
2011-06-13 14:21:23 -04:00
begin
2010-01-25 08:59:44 -05:00
i : = 0 ;
Ring : = 1 ;
c : = 0 ;
CurrBox. x1 : = Startx- 1 ;
CurrBox. y1 : = Starty- 1 ;
CurrBox. x2 : = Startx+ 1 ;
CurrBox. y2 : = Starty+ 1 ;
if ( startx > = x1) and ( startx < = x2) and ( starty > = y1) and ( starty < = y2) then
begin ;
ClientTPA[ c] : = Point( Startx, StartY) ;
2011-06-13 11:41:06 -04:00
Inc( c) ;
2010-01-25 08:59:44 -05:00
end ;
2011-06-13 14:21:23 -04:00
repeat
2010-01-25 08:59:44 -05:00
if ( CurrBox. x2 > = x1) and ( CurrBox. x1 < = x2) and ( Currbox. y1 > = y1) and ( Currbox. y1 < = y2) then
for i : = CurrBox. x1 + 1 to CurrBox. x2 do
if ( I > = x1) and ( I < = x2) then
begin ;
ClientTPA[ c] : = Point( i, CurrBox. y1) ;
2011-06-13 11:41:06 -04:00
Inc( c) ;
2010-01-25 08:59:44 -05:00
end ;
if ( CurrBox. x2 > = x1) and ( CurrBox. x2 < = x2) and ( Currbox. y2 > = y1) and ( Currbox. y1 < = y2) then
for i : = CurrBox. y1 + 1 to CurrBox. y2 do
if ( I > = y1) and ( I < = y2) then
begin ;
ClientTPA[ c] : = Point( Currbox. x2, I) ;
2011-06-13 11:41:06 -04:00
Inc( c) ;
2010-01-25 08:59:44 -05:00
end ;
if ( CurrBox. x2 > = x1) and ( CurrBox. x1 < = x2) and ( Currbox. y2 > = y1) and ( Currbox. y2 < = y2) then
for i : = CurrBox. x2 - 1 downto CurrBox. x1 do
if ( I > = x1) and ( I < = x2) then
begin ;
ClientTPA[ c] : = Point( i, CurrBox. y2) ;
2011-06-13 11:41:06 -04:00
Inc( c) ;
2010-01-25 08:59:44 -05:00
end ;
if ( CurrBox. x1 > = x1) and ( CurrBox. x1 < = x2) and ( Currbox. y2 > = y1) and ( Currbox. y1 < = y2) then
for i : = CurrBox. y2 - 1 downto CurrBox. y1 do
if ( I > = y1) and ( I < = y2) then
begin ;
ClientTPA[ c] : = Point( Currbox. x1, I) ;
2011-06-13 11:41:06 -04:00
Inc( c) ;
2010-01-25 08:59:44 -05:00
end ;
2011-06-13 11:41:06 -04:00
Inc( ring) ;
2010-01-25 08:59:44 -05:00
CurrBox. x1 : = Startx- ring;
CurrBox. y1 : = Starty- Ring;
CurrBox. x2 : = Startx+ Ring;
CurrBox. y2 : = Starty+ Ring;
2011-06-13 11:41:06 -04:00
until ( Currbox. x1 < x1) and ( Currbox. x2 > x2) and ( currbox. y1 < y1)
and ( currbox. y2 > y2) ;
2010-01-25 08:59:44 -05:00
end ;
2011-06-13 14:21:23 -04:00
function CalculateRowPtrs( ReturnData: TRetData; RowCount: integer ) : TPRGB32Array; overload ;
2010-01-25 08:59:44 -05:00
var
I : integer ;
begin ;
2011-06-13 14:21:23 -04:00
SetLength( result , RowCount) ;
2010-01-25 08:59:44 -05:00
for i : = 0 to RowCount - 1 do
result [ i] : = ReturnData. Ptr + ReturnData. RowLen * i;
end ;
2011-06-13 14:21:23 -04:00
function CalculateRowPtrs( Bitmap : TMufasaBitmap) : TPRGB32Array; overload ;
2011-02-06 13:54:29 -05:00
begin
Result : = Bitmap. RowPtrs;
2010-01-25 08:59:44 -05:00
end ;
2011-06-13 11:41:06 -04:00
2010-01-25 08:59:44 -05:00
//SkipCoords[y][x] = False/True; True means its "transparent" and therefore not needed to be checked.
procedure CalculateBitmapSkipCoords( Bitmap : TMufasaBitmap; out SkipCoords : T2DBoolArray) ;
var
x, y : integer ;
R, G, B : byte ;
Ptr : PRGB32;
begin ;
r : = 0 ;
g : = 0 ;
b : = 0 ;
if Bitmap. TransparentColorSet then
ColorToRGB( Bitmap. GetTransparentColor, r, g, b) ;
Ptr : = Bitmap. FData;
SetLength( SkipCoords, Bitmap. Height, Bitmap. Width) ;
for y : = 0 to Bitmap. Height - 1 do
for x : = 0 to Bitmap. Width - 1 do
begin ;
if ( Ptr^ . r = r) and ( Ptr^ . g = g) and ( Ptr^ . b = b) then
SkipCoords[ y] [ x] : = True
else
SkipCoords[ y] [ x] : = false ;
inc( ptr) ;
end ;
end ;
2011-06-13 11:41:06 -04:00
{ Points left holds the amount of points that are "left" to be checked
( Including the point itself.. So for example Pointsleft[ 0 ] [ 0 ] would
hold the total amount of pixels that are to be checked. }
2010-01-25 08:59:44 -05:00
procedure CalculateBitmapSkipCoordsEx( Bitmap : TMufasaBitmap; out SkipCoords : T2DBoolArray; out TotalPoints : integer ; out PointsLeft : T2DIntArray) ;
var
x, y : integer ;
R, G, B : byte ;
Ptr : PRGB32;
TotalC : integer ;
begin ;
r : = 0 ;
g : = 0 ;
b : = 0 ;
TotalC : = 0 ;
if Bitmap. TransparentColorSet then
ColorToRGB( Bitmap. GetTransparentColor, r, g, b) ;
Ptr : = Bitmap. FData;
SetLength( SkipCoords, Bitmap. Height, Bitmap. Width) ;
SetLength( PointsLeft, Bitmap. Height, Bitmap. Width) ;
for y : = 0 to Bitmap. Height - 1 do
for x : = 0 to Bitmap. Width - 1 do
begin ;
if ( Ptr^ . r = r) and ( Ptr^ . g = g) and ( Ptr^ . b = b) then
SkipCoords[ y] [ x] : = True
else
begin ;
SkipCoords[ y] [ x] : = false ;
inc( TotalC) ;
end ;
inc( ptr) ;
end ;
TotalPoints: = TotalC;
for y : = 0 to Bitmap. Height - 1 do
for x : = 0 to Bitmap. Width - 1 do
begin ;
PointsLeft[ y] [ x] : = TotalC;
if not SkipCoords[ y] [ x] then
Dec( TotalC) ;
end ;
end ;
2011-06-13 11:41:06 -04:00
{ Initialise the variables for TMFinder }
2010-01-25 08:59:44 -05:00
constructor TMFinder. Create( aClient: TObject) ;
var
I : integer ;
begin
inherited Create;
2010-04-02 11:55:54 -04:00
WarnOnly : = False ;
2010-01-25 08:59:44 -05:00
Self. Client : = aClient;
Self. CTS : = 1 ;
Self. hueMod : = 0.2 ;
Self. satMod : = 0.2 ;
for i : = 0 to 2 5 5 do
Percentage[ i] : = i / 2 5 5 ;
end ;
destructor TMFinder. Destroy;
begin
2010-04-18 12:09:23 -04:00
{ We don' t really have to free stuff here.
The array is managed, so that is automatically freed.
The rest is either references to objects we may not destroy
}
2010-01-25 08:59:44 -05:00
inherited ;
end ;
procedure TMFinder. SetToleranceSpeed( nCTS: Integer ) ;
begin
2011-06-05 13:44:52 -04:00
if ( nCTS < 0 ) or ( nCTS > 3 ) then
2010-01-25 08:59:44 -05:00
raise Exception. CreateFmt( 'The given CTS ([%d]) is invalid.' , [ nCTS] ) ;
Self. CTS : = nCTS;
end ;
function TMFinder. GetToleranceSpeed: Integer ;
begin
Result : = Self. CTS;
end ;
2010-04-02 11:55:54 -04:00
procedure TMFinder. SetToleranceSpeed2Modifiers( const nHue, nSat: Extended ) ;
2010-01-25 08:59:44 -05:00
begin
Self. hueMod : = nHue;
Self. satMod : = nSat;
end ;
procedure TMFinder. GetToleranceSpeed2Modifiers( out hMod, sMod: Extended ) ;
begin
hMod : = Self. hueMod;
sMod : = Self. satMod;
end ;
function TMFinder. SimilarColors( Color1, Color2, Tolerance: Integer ) : boolean ;
var
R1, G1, B1, R2, G2, B2 : Byte ;
H1, S1, L1, H2, S2, L2 : extended ;
2011-06-05 13:44:52 -04:00
L_1, a_1, b_1, L_2, a_2 , b_2, X, Y, Z: extended ;
2010-01-25 08:59:44 -05:00
begin
Result : = False ;
ColorToRGB( Color1, R1, G1, B1) ;
ColorToRGB( Color2, R2, G2, B2) ;
if Color1 = Color2 then
Result : = true
else
case CTS of
0 : Result : = ( ( Abs( R1- R2) < = Tolerance) and ( Abs( G1- G2) < = Tolerance) and ( Abs( B1- B2) < = Tolerance) ) ;
1 : Result : = ( Sqrt( sqr( R1- R2) + sqr( G1- G2) + sqr( B1- B2) ) < = Tolerance) ;
2 : begin
RGBToHSL( R1, g1, b1, H1, S1, L1) ;
RGBToHSL( R2, g2, b2, H2, S2, L2) ;
Result : = ( ( abs( H1 - H2) < = ( hueMod * Tolerance) ) and ( abs( S2- S1) < = ( satMod * Tolerance) ) and ( abs( L1- L2) < = Tolerance) ) ;
end ;
2011-06-05 13:44:52 -04:00
3 :
begin
RGBToXYZ( R1, G1, B1, X, Y, Z) ;
XYZtoCIELab( X, Y, Z, L_1, a_1, b_1) ;
RGBToXYZ( R2, G2, B2, X, Y, Z) ;
XYZtoCIELab( X, Y, Z, L_2, a_2, b_2) ;
Result : = ( abs( L_1 - L_2) < Tolerance)
and ( abs( a_1 - a_2) < Tolerance)
and ( abs( b_1 - b_2) < Tolerance) ;
end ;
2010-01-25 08:59:44 -05:00
end ;
end ;
2011-06-05 13:44:52 -04:00
{
2011-07-06 12:15:33 -04:00
TODO: Remove this
2011-06-05 13:44:52 -04:00
}
2010-01-25 08:59:44 -05:00
function ColorSame( var CTS, Tolerance : Integer ; var R1, G1, B1, R2, G2, B2 : byte ; var H1, S1, L1, huemod, satmod : extended ) : boolean ; inline ;
var
H2, S2, L2 : extended ;
2011-06-05 13:44:52 -04:00
L_1, a_1, b_1, L_2, a_2 , b_2, X, Y, Z: extended ;
2010-01-25 08:59:44 -05:00
begin
Result : = False ;
case CTS of
0 : Result : = ( ( Abs( R1- R2) < = Tolerance) and ( Abs( G1- G2) < = Tolerance) and ( Abs( B1- B2) < = Tolerance) ) ;
1 : Result : = ( Sqrt( sqr( R1- R2) + sqr( G1- G2) + sqr( B1- B2) ) < = Tolerance) ;
2 : begin
RGBToHSL( R2, g2, b2, H2, S2, L2) ;
Result : = ( ( abs( H1 - H2) < = ( hueMod * Tolerance) ) and ( abs( S2- S1) < = ( satMod * Tolerance) ) and ( abs( L1- L2) < = Tolerance) ) ;
end ;
2011-06-05 13:44:52 -04:00
3 : begin
RGBToXYZ( R1, G1, B1, X, Y, Z) ;
XYZtoCIELab( X, Y, Z, L_1, a_1, b_1) ;
RGBToXYZ( R2, G2, B2, X, Y, Z) ;
XYZtoCIELab( X, Y, Z, L_2, a_2, b_2) ;
2011-06-06 10:06:17 -04:00
Result : = Sqrt( sqr( L_1 - L_2) + sqr( a_1 - a_2) +
2011-06-16 10:33:25 -04:00
sqr( b_1 - b_2) ) < = Tolerance;
2011-06-05 13:44:52 -04:00
end ;
2010-01-25 08:59:44 -05:00
end ;
end ;
2011-06-16 06:52:10 -04:00
2011-07-06 12:15:33 -04:00
{ Colour Same functions }
2011-07-06 15:06:17 -04:00
function ColorSame_cts0( ctsInfo: Pointer ; C2: PRGB32) : boolean ;
2011-06-16 08:26:20 -04:00
2011-07-06 12:15:33 -04:00
var
2011-07-06 15:06:17 -04:00
C1: TCTS0Info;
2011-06-16 08:26:20 -04:00
begin
2011-07-06 15:06:17 -04:00
C1 : = PCTS0Info( ctsInfo) ^ ;
Result : = ( Abs( C1. B - C2^ . B) < = C1. Tol)
and ( Abs( C1. G - C2^ . G) < = C1. Tol)
and ( Abs( C1. R - C2^ . R) < = C1. Tol) ;
2011-06-16 08:26:20 -04:00
end ;
2011-07-06 15:06:17 -04:00
function ColorSame_cts1( ctsInfo: Pointer ; C2: PRGB32) : boolean ;
2011-06-16 08:26:20 -04:00
2011-07-06 12:15:33 -04:00
var
2011-07-06 15:06:17 -04:00
C1: TCTS1Info;
2011-07-06 12:15:33 -04:00
r, g, b: integer ;
2011-06-16 08:26:20 -04:00
begin
2011-07-06 15:06:17 -04:00
C1 : = PCTS1Info( ctsInfo) ^ ;
2011-07-06 12:15:33 -04:00
b : = C1. B - C2^ . B;
g : = C1. G - C2^ . G;
r : = C1. R - C2^ . R;
2011-07-06 15:06:17 -04:00
Result : = ( b* b + g* g + r* r) < = C1. Tol;
2011-06-16 08:26:20 -04:00
end ;
2011-07-06 15:06:17 -04:00
function ColorSame_cts2( ctsInfo: Pointer ; C2: PRGB32) : boolean ;
2011-07-06 12:15:33 -04:00
var
h, s, l: extended ;
i: TCTS2Info;
2011-06-13 12:16:59 -04:00
begin
2011-07-06 12:15:33 -04:00
i : = PCTS2Info( ctsInfo) ^ ;
RGBToHSL( C2^ . R, C2^ . G, C2^ . B, h, s, l) ; // Inline this later.
2011-07-06 14:39:44 -04:00
Result : = ( abs( h - i. H) < = ( i. hueMod) )
and ( abs( s - i. S) < = ( i. satMod) )
2011-07-06 15:06:17 -04:00
and ( abs( l - i. L) < = i. Tol) ;
2011-07-06 12:15:33 -04:00
end ;
{ }
function Create_CTSInfo( cts: integer ; Color, Tol: Integer ;
2011-07-30 13:10:10 -04:00
hueMod, satMod: extended ) : Pointer ; overload ;
2011-07-06 12:15:33 -04:00
var
R, G, B: Integer ;
begin
case cts of
2011-07-06 15:06:17 -04:00
0 :
2011-07-06 12:15:33 -04:00
begin
2011-08-01 07:58:49 -04:00
Result : = AllocMem( SizeOf( TCTS0Info) ) ;
ColorToRGB( Color, PCTS0Info( Result ) ^ . R, PCTS0Info( Result ) ^ . G,
PCTS0Info( Result ) ^ . B) ;
PCTS0Info( Result ) ^ . Tol : = Tol;
2011-07-06 15:06:17 -04:00
end ;
1 :
begin
2011-08-01 07:58:49 -04:00
Result : = AllocMem( SizeOf( TCTS1Info) ) ;
ColorToRGB( Color, PCTS1Info( Result ) ^ . R, PCTS1Info( Result ) ^ . G,
PCTS1Info( Result ) ^ . B) ;
2011-07-30 14:08:17 -04:00
2011-08-01 07:58:49 -04:00
PCTS1Info( Result ) ^ . Tol : = Tol * Tol;
2011-07-06 12:15:33 -04:00
end ;
2 :
begin
2011-08-01 07:58:49 -04:00
Result : = AllocMem( SizeOf( TCTS2Info) ) ;
ColorToRGB( Color, R, G, B) ;
RGBToHSL( R, G, B, PCTS2Info( Result ) ^ . H, PCTS2Info( Result ) ^ . S,
PCTS2Info( Result ) ^ . L) ;
PCTS2Info( Result ) ^ . hueMod : = Tol * hueMod;
PCTS2Info( Result ) ^ . satMod : = Tol * satMod;
PCTS2Info( Result ) ^ . Tol : = Tol;
2011-07-06 12:15:33 -04:00
end ;
end ;
end ;
2011-07-30 13:10:10 -04:00
function Create_CTSInfo( cts: integer ; R, G, B, Tol: Integer ;
hueMod, satMod: extended ) : Pointer ; overload ;
var Color: Integer ;
begin
Color : = RGBToColor( R, G, B) ;
Result : = Create_CTSInfo( cts, Color, Tol, hueMod, satMod) ;
end ;
2011-07-30 14:08:17 -04:00
2011-07-06 12:15:33 -04:00
procedure Free_CTSInfo( i: Pointer ) ;
begin
if assigned( i) then
FreeMem( i)
else
raise Exception. Create( 'Free_CTSInfo: Invalid TCTSInfo passed' ) ;
end ;
2011-08-01 12:13:36 -04:00
{ TODO: Not universal, mainly for DTM }
function Create_CTSInfoArray( cts: integer ; color, tolerance: array of integer ;
hueMod, satMod: extended ) : TCTSInfoArray;
2011-07-30 07:12:21 -04:00
2011-08-01 12:13:36 -04:00
var
i: integer ;
begin
if length( color) < > length( tolerance) then
raise Exception. Create( 'Create_CTSInfoArray: Length(Color) <>'
+ ' Length(Tolerance' ) ;
SetLength( Result , Length( color) ) ;
for i : = High( result ) downto 0 do
result : = Create_CTSInfo( cts, color[ i] , tolerance[ i] , hueMod, satMod) ;
end ;
{ TODO: Not universal, mainly for Bitmap }
2011-07-30 14:08:17 -04:00
function Create_CTSInfo2DArray( cts, w, h: integer ; data: TPRGB32Array;
2011-07-30 07:12:21 -04:00
Tolerance: Integer ; hueMod, satMod: Extended ) : TCTSInfo2DArray;
var
2011-07-30 09:53:48 -04:00
x, y: integer ;
2011-07-30 07:12:21 -04:00
begin
2011-07-30 14:08:17 -04:00
SetLength( Result , h+ 1 , w+ 1 ) ;
2011-07-30 09:53:48 -04:00
for y : = 0 to h do
for x : = 0 to w do
2011-07-30 14:08:17 -04:00
Result [ y] [ x] : = Create_CTSInfo( cts,
data[ y] [ x] . R, data[ y] [ x] . G, data[ y] [ x] . B,
2011-07-30 07:12:21 -04:00
Tolerance, hueMod, satMod) ;
end ;
procedure Free_CTSInfoArray( i: TCTSInfoArray) ;
var
c: integer ;
begin
for c : = high( i) downto 0 do
2011-08-01 12:13:36 -04:00
Free_CTSInfo( i[ c] ) ;
2011-07-30 07:12:21 -04:00
SetLength( i, 0 ) ;
end ;
procedure Free_CTSInfo2DArray( i: TCTSInfo2DArray) ;
var
x, y: integer ;
begin
for y : = high( i) downto 0 do
for x : = high( i[ y] ) downto 0 do
Free_CTSInfo( i[ y] [ x] ) ;
SetLength( i, 0 ) ;
end ;
2011-07-06 12:15:33 -04:00
function Get_CTSCompare( cts: Integer ) : TCTSCompareFunction;
begin
case cts of
0 : Result : = @ ColorSame_cts0;
1 : Result : = @ ColorSame_cts1;
2 : Result : = @ ColorSame_cts2;
end ;
2011-06-13 12:16:59 -04:00
end ;
2010-01-25 08:59:44 -05:00
procedure TMFinder. UpdateCachedValues( NewWidth, NewHeight: integer ) ;
begin
CachedWidth : = NewWidth;
CachedHeight : = NewHeight;
SetLength( ClientTPA, NewWidth * NewHeight) ;
end ;
2010-04-02 11:55:54 -04:00
procedure Swap( var A, B : integer ) ;
var
c : integer ;
begin
c : = a;
a : = b;
b : = c;
end ;
2010-01-25 08:59:44 -05:00
procedure TMFinder. DefaultOperations( var xs, ys, xe, ye: integer ) ;
var
w, h : integer ;
begin
2010-04-02 11:55:54 -04:00
if ( xs > xe) then
if WarnOnly then
begin
TClient( Client) . WriteLn( Format( 'Warning! You passed wrong values to a finder function: xs > xe (%d,%d). Swapping the values for now.' , [ xs, xe] ) ) ;
swap( xs, xe) ;
end else
raise Exception. CreateFMT( 'You passed wrong values to a finder function: xs > xe (%d,%d).' , [ xs, xe] ) ;
2010-01-25 08:59:44 -05:00
if ys > ye then
2010-04-02 11:55:54 -04:00
if WarnOnly then
begin
TClient( Client) . WriteLn( Format( 'Warning! You passed wrong values to a finder function: ys > ye (%d,%d). Swapping the values for now.' , [ ys, ye] ) ) ;
swap( ys, ye) ;
end else
raise Exception. CreateFMT( 'You passed wrong values to a finder function: ys > ye (%d,%d).' , [ ys, ye] ) ;
2010-01-25 08:59:44 -05:00
if xs < 0 then
2010-04-02 11:55:54 -04:00
if WarnOnly then
begin
TClient( Client) . WriteLn( Format( 'Warning! You passed a wrong xs to a finder function: %d. That is below 0, thus out of bounds. Setting the value to 0 for now.' , [ xs] ) ) ;
xs : = 0 ;
end else
raise Exception. createFMT( 'You passed a wrong xs to a finder function: %d. That is below 0, thus out of bounds.' , [ xs] ) ;
2010-01-25 08:59:44 -05:00
if ys < 0 then
2010-04-02 11:55:54 -04:00
if WarnOnly then
begin
TClient( Client) . WriteLn( Format( 'Warning! You passed a wrong ys to a finder function: %d. That is below 0, thus out of bounds. Setting the value to 0 for now.' , [ ys] ) ) ;
ys : = 0 ;
end else
raise Exception. createFMT( 'You passed a wrong ys to a finder function: %d. That is below 0, thus out of bounds.' , [ ys] ) ;
2010-01-25 08:59:44 -05:00
TClient( Self. Client) . IOManager. GetDimensions( w, h) ;
if ( w < > CachedWidth) or ( h < > CachedHeight) then
UpdateCachedValues( w, h) ;
if xe > = w then
2010-04-02 11:55:54 -04:00
if WarnOnly then
begin
TClient( Client) . WriteLn( Format( 'Warning! You passed a wrong xe to a finder function: %d. The client has a width of %d, thus the xe is out of bounds. Setting the value to %d (w-1) for now.' , [ xe, w, w- 1 ] ) ) ;
xe : = w- 1 ;
end else
raise Exception. createFMT( 'You passed a wrong xe to a finder function: %d. The client has a width of %d, thus the xe is out of bounds.' , [ xe, w] ) ;
2010-01-25 08:59:44 -05:00
if ye > = h then
2010-04-02 11:55:54 -04:00
if WarnOnly then
begin
TClient( Client) . WriteLn( Format( 'Warning! You passed a wrong ye to a finder function: %d. The client has a height of %d, thus the ye is out of bounds. Setting the value to %d (h-1) for now.' , [ ye, h, h- 1 ] ) ) ;
ye : = h- 1 ;
end else
raise Exception. createFMT( 'You passed a wrong ye to a finder function: %d. The client has a height of %d, thus the ye is out of bounds.' , [ ye, h] ) ;
2010-01-25 08:59:44 -05:00
end ;
function TMFinder. CountColorTolerance( Color, xs, ys, xe, ye, Tolerance: Integer ) : Integer ;
var
PtrData: TRetData;
Ptr: PRGB32;
PtrInc: Integer ;
dX, dY, xx, yy: Integer ;
2011-07-30 07:12:21 -04:00
compare: TCTSCompareFunction;
ctsinfo: TCTSInfo;
2010-01-25 08:59:44 -05:00
begin
Result : = 0 ;
DefaultOperations( xs, ys, xe, ye) ;
2011-07-30 07:12:21 -04:00
2010-01-25 08:59:44 -05:00
dX : = xe - xs;
dY : = ye - ys;
2011-07-30 07:12:21 -04:00
2010-01-25 08:59:44 -05:00
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
result : = 0 ;
2011-07-30 07:12:21 -04:00
ctsinfo : = Create_CTSInfo( Self. CTS, Color, Tolerance, hueMod, satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
2010-01-25 08:59:44 -05:00
for yy : = ys to ye do
begin ;
for xx : = xs to xe do
2011-07-30 07:12:21 -04:00
begin
if compare( ctsinfo, Ptr) then
2010-01-25 08:59:44 -05:00
inc( result ) ;
Inc( Ptr) ;
end ;
Inc( Ptr, PtrInc)
end ;
2011-08-01 10:16:19 -04:00
Free_CTSInfo( ctsinfo) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. CountColor( Color, xs, ys, xe, ye: Integer ) : Integer ;
var
PtrData: TRetData;
Ptr: PRGB32;
PtrInc: Integer ;
dX, dY, clR, clG, clB, xx, yy: Integer ;
begin
Result : = 0 ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
//next, convert the color to r,g,b
ColorToRGB( Color, clR, clG, clB) ;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
// Do we want to "cache" these vars?
// We will, for now. Easier to type.
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
for yy : = ys to ye do
begin ;
for xx : = xs to xe do
begin ;
// Colour comparison here. Possibly with tolerance? ;)
if ( Ptr^ . R = clR) and ( Ptr^ . G = clG) and ( Ptr^ . B = clB) then
inc( result ) ;
Inc( Ptr) ;
end ;
2010-10-06 10:51:38 -04:00
Inc( Ptr, PtrInc) ;
2010-01-25 08:59:44 -05:00
end ;
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindColor( out x, y: Integer ; Color, xs, ys, xe, ye: Integer ) : Boolean ;
var
PtrData: TRetData;
Ptr: PRGB32;
PtrInc: Integer ;
dX, dY, clR, clG, clB, xx, yy: Integer ;
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
//next, convert the color to r,g,b
ColorToRGB( Color, clR, clG, clB) ;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
// Do we want to "cache" these vars?
// We will, for now. Easier to type.
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
for yy : = ys to ye do
begin ;
for xx : = xs to xe do
begin ;
// Colour comparison here. Possibly with tolerance? ;)
if ( Ptr^ . R = clR) and ( Ptr^ . G = clG) and ( Ptr^ . B = clB) then
begin
Result : = True ;
x : = xx;
y : = yy;
TClient( Client) . IOManager. FreeReturnData;
Exit;
end ;
Inc( Ptr) ;
end ;
Inc( Ptr, PtrInc)
end ;
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindColorSpiral( var x, y: Integer ; color, xs, ys, xe,
ye: Integer ) : Boolean ;
var
PtrData: TRetData;
RowData : TPRGB32Array;
dX, dY, clR, clG, clB, i, HiSpiral: Integer ;
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
//next, convert the color to r,g,b
ColorToRGB( Color, clR, clG, clB) ;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
//Load rowdata
RowData: = CalculateRowPtrs( ptrdata, dy+ 1 ) ;
//Load the spiral path
LoadSpiralPath( x- xs, y- ys, 0 , 0 , dx, dy) ;
HiSpiral : = ( dy+ 1 ) * ( dx + 1 ) - 1 ;
for i : = 0 to HiSpiral do
if ( RowData[ ClientTPA[ i] . y] [ ClientTPA[ i] . x] . R = clR) and ( RowData[ ClientTPA[ i] . y] [ ClientTPA[ i] . x] . G = clG)
and ( RowData[ ClientTPA[ i] . y] [ ClientTPA[ i] . x] . B = clB) then
begin
Result : = True ;
x : = ClientTPA[ i] . x + xs;
y : = ClientTPA[ i] . y + ys;
TClient( Client) . IOManager. FreeReturnData;
Exit;
end ;
TClient( Client) . IOManager. FreeReturnData;
end ;
2010-01-28 18:34:03 -05:00
function TMFinder. FindColorSpiralTolerance( var x, y: Integer ; color, xs, ys,
xe, ye, Tol: Integer ) : Boolean ;
var
PtrData: TRetData;
RowData : TPRGB32Array;
dX, dY, clR, clG, clB, i, Hispiral: Integer ;
2011-08-01 10:16:19 -04:00
var
j: integer ;
compare: TCTSCompareFunction;
ctsinfo: TCTSInfo;
2011-06-13 11:41:06 -04:00
2010-01-28 18:34:03 -05:00
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
//next, convert the color to r,g,b
ColorToRGB( Color, clR, clG, clB) ;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
//Load rowdata
RowData: = CalculateRowPtrs( ptrdata, dy+ 1 ) ;
//Load the spiral path
LoadSpiralPath( x- xs, y- ys, 0 , 0 , dx, dy) ;
HiSpiral : = ( dy+ 1 ) * ( dx + 1 ) - 1 ;
2011-08-01 10:16:19 -04:00
ctsinfo : = Create_CTSInfo( Self. CTS, Color, Tol, hueMod, satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
i : = - 1 ;
for j : = 0 to HiSpiral do
begin
if compare( ctsinfo, @ RowData[ ClientTPA[ j] . y] [ ClientTPA[ j] . x] ) then
begin
i : = j;
break;
end ;
2010-01-28 18:34:03 -05:00
end ;
2011-08-01 10:16:19 -04:00
Free_CTSInfo( ctsinfo) ;
2011-06-13 12:16:59 -04:00
if i = - 1 then
begin
Result : = False ;
TClient( Client) . IOManager. FreeReturnData;
Exit;
end else
begin
2010-01-28 18:34:03 -05:00
Result : = True ;
x : = ClientTPA[ i] . x + xs;
y : = ClientTPA[ i] . y + ys;
TClient( Client) . IOManager. FreeReturnData;
2011-06-13 12:16:59 -04:00
end ;
2010-01-28 18:34:03 -05:00
end ;
2010-01-25 08:59:44 -05:00
function TMFinder. FindColoredArea( var x, y: Integer ; Color, xs, ys, xe, ye, MinArea: Integer ) : Boolean ;
var
PtrData: TRetData;
Ptr, Before: PRGB32;
PtrInc: Integer ;
dX, dY, clR, clG, clB, xx, yy, fx, fy, Count : Integer ;
NotFound : Boolean ;
begin
Result : = false ;
Count : = 0 ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
//next, convert the color to r,g,b
ColorToRGB( Color, clR, clG, clB) ;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
// Do we want to "cache" these vars?
// We will, for now. Easier to type.
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
for yy : = ys to ye do
begin ;
for xx : = xs to xe do
begin ;
NotFound : = False ;
// Colour comparison here. Possibly with tolerance? ;)
if ( Ptr^ . R = clR) and ( Ptr^ . G = clG) and ( Ptr^ . B = clB) then
begin
Before : = Ptr;
for fy : = yy to ye do
begin
for fx : = xx to xe do
begin
Inc( Ptr) ;
if not ( ( Ptr^ . R = clR) and ( Ptr^ . G = clG) and ( Ptr^ . B = clB) ) then
begin
NotFound : = True ;
Break;
end ;
Inc( Count) ;
if Count > = MinArea then
Begin
Result : = True ;
x : = xx;
y : = yy;
TClient( Client) . IOManager. FreeReturnData;
Exit;
end ;
end ;
if NotFound then
begin
Ptr : = Before;
Break;
end ;
end ;
end ;
Inc( Ptr) ;
end ;
Inc( Ptr, PtrInc) ;
end ;
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindColorToleranceOptimised( out x, y: Integer ; Color, xs, ys, xe, ye, tol: Integer ) : Boolean ;
var
PtrData: TRetData;
Ptr: PRGB32;
PtrInc: Integer ;
dX, dY, clR, clG, clB, xx, yy: Integer ;
H1, S1, L1, H2, S2, L2: Extended ;
R, G, B : extended ; //percentage R,G,B.. (Needed for HSL).
D : Extended ; //CMax - Cmin
HueTol, SatTol, LumTol : extended ;
CMax, CMin : extended ;
label Hit;
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
//next, convert the color to r,g,b
ColorToRGB( Color, clR, clG, clB) ;
if Cts = 2 then
RGBToHSLNonFixed( clR, clG, clB, H1, S1, L1) ;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
// Do we want to "cache" these vars?
// We will, for now. Easier to type.
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
case CTS of
0 :
for yy : = ys to ye do
begin
for xx : = xs to xe do
begin
if ( ( abs( clB- Ptr^ . B) < = Tol) and ( abs( clG- Ptr^ . G) < = Tol) and ( Abs( clR- Ptr^ . R) < = Tol) ) then
goto Hit;
inc( Ptr) ;
end ;
Inc( Ptr, PtrInc) ;
end ;
1 :
begin
Tol : = Sqr( Tol) ;
for yy : = ys to ye do
begin
for xx : = xs to xe do
begin
if ( sqr( clB - Ptr^ . B) + sqr( clG - Ptr^ . G) + sqr( clR- Ptr^ . R) ) < = Tol then
goto Hit;
inc( ptr) ;
end ;
Inc( Ptr, PtrInc) ;
end ;
end ;
2 :
begin
//Since we don't make (real) percentages of the HSL-values we need to change the tolerance..
HueTol : = hueMod * Tol / 1 0 0 ;
SatTol : = satMod * Tol / 1 0 0 ;
LumTol : = Tol / 1 0 0 ;
for yy : = ys to ye do
begin
for xx : = xs to xe do
begin
R : = Percentage[ Ptr^ . r] ;
G : = Percentage[ Ptr^ . g] ;
B : = Percentage[ Ptr^ . b] ;
//We increase the Ptr already, since we do Continue in loops..
inc( Ptr) ;
CMin : = R;
CMax : = R;
if G < Cmin then CMin : = G;
if B < Cmin then CMin : = B;
if G > Cmax then CMax : = G;
if B > Cmax then CMax : = B;
L2 : = 0.5 * ( Cmax + Cmin) ;
//The L-value is already calculated, lets see if the current point meats the requirements!
if Abs( L2- L1) > LumTol then //if not (Abs(L2 - L1) <= LumTol) then
Continue;
if Cmax = Cmin then
begin
//S and H are both zero, lets check if we need found a point!
if ( H1 < = HueTol) and ( S1 < = SatTol) then
goto Hit
else
Continue;
end ;
D : = Cmax - Cmin;
if L2 < 0.5 then
S2 : = D / ( Cmax + Cmin)
else
S2 : = D / ( 2 - Cmax - Cmin) ;
//We've Calculated the S. Lets see if we need to continue.
if Abs( S2 - S1) > SatTol then //if not (abs(S1 - S2) <= SatXTol) then
Continue;
if R = Cmax then
H2 : = ( G - B) / D
else
if G = Cmax then
H2 : = 2 + ( B - R) / D
else
H2 : = 4 + ( R - G) / D;
H2 : = H2 / 6 ;
if H2 < 0 then
H2 : = H2 + 1 ;
//Finally lets test H2
if Abs( H2 - H1) < = HueTol then
goto hit;
end ;
Inc( Ptr, PtrInc) ;
end ;
end ;
end ;
Result : = False ;
TClient( Client) . IOManager. FreeReturnData;
Exit;
Hit:
Result : = True ;
x : = xx;
y : = yy;
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindColorTolerance( out x, y: Integer ; Color, xs, ys, xe, ye, tol: Integer ) : Boolean ;
var
PtrData: TRetData;
Ptr: PRGB32;
PtrInc: Integer ;
2011-08-01 13:08:23 -04:00
dX, dY: Integer ;
2011-07-06 15:06:17 -04:00
xx, yy: integer ;
compare: TCTSCompareFunction;
2011-07-30 07:12:21 -04:00
ctsinfo: TCTSInfo;
2011-07-06 15:06:17 -04:00
label Hit;
2011-06-13 14:38:00 -04:00
2010-01-25 08:59:44 -05:00
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
// Do we want to "cache" these vars?
// We will, for now. Easier to type.
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
2011-07-06 15:06:17 -04:00
ctsinfo : = Create_CTSInfo( Self. CTS, Color, Tol, hueMod, satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
for yy : = ys to ye do
2011-06-13 14:38:00 -04:00
begin
2011-07-06 15:06:17 -04:00
for xx : = xs to xe do
begin
if compare( ctsinfo, Ptr) then
goto Hit;
inc( Ptr) ;
end ;
Inc( Ptr, PtrInc) ;
end ;
Result : = False ;
2011-08-01 10:16:19 -04:00
Free_CTSInfo( ctsinfo) ;
2011-07-06 15:06:17 -04:00
TClient( Client) . IOManager. FreeReturnData;
Exit;
Hit:
2010-01-25 08:59:44 -05:00
Result : = True ;
2011-07-06 15:06:17 -04:00
x : = xx;
y : = yy;
2011-08-01 10:16:19 -04:00
Free_CTSInfo( ctsinfo) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindColoredAreaTolerance( var x, y: Integer ; Color, xs, ys, xe, ye, MinArea, tol: Integer ) : Boolean ;
var
PtrData: TRetData;
Ptr, Before: PRGB32;
PtrInc: Integer ;
dX, dY, xx, yy, fx, fy, Count: Integer ;
clR, clG, clB : Byte ;
H1, S1, L1: Extended ;
NotFound : Boolean ;
2011-08-01 10:16:19 -04:00
compare: TCTSCompareFunction;
ctsinfo: TCTSInfo;
2010-01-25 08:59:44 -05:00
label Hit;
2011-08-01 10:16:19 -04:00
2010-01-25 08:59:44 -05:00
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
//next, convert the color to r,g,b
ColorToRGB( Color, clR, clG, clB) ;
if Cts = 2 then
RGBToHSL( clR, clG, clB, H1, S1, L1) ;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
// Do we want to "cache" these vars?
// We will, for now. Easier to type.
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
2010-02-27 21:01:18 -05:00
Count : = 0 ;
2011-08-01 10:16:19 -04:00
ctsinfo : = Create_CTSInfo( Self. CTS, Color, Tol, hueMod, satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
2010-01-25 08:59:44 -05:00
for yy : = ys to ye do
begin ;
for xx : = xs to xe do
begin ;
NotFound : = False ;
// Colour comparison here.
2011-08-01 10:16:19 -04:00
if compare( ctsinfo, Ptr) then
2010-01-25 08:59:44 -05:00
begin
Before : = Ptr;
for fy : = yy to ye do
begin
for fx : = xx to xe do
begin
Inc( Ptr) ;
2011-08-01 10:16:19 -04:00
if compare( ctsinfo, Ptr) then
2010-01-25 08:59:44 -05:00
begin
NotFound : = True ;
Break;
end ;
Inc( Count) ;
if Count > = MinArea then
goto Hit;
end ;
if NotFound then
begin
Ptr : = Before;
Break;
end ;
Inc( Ptr, PtrInc) ;
end ;
end ;
Inc( Ptr) ;
end ;
Inc( Ptr, PtrInc) ;
end ;
Result : = False ;
2011-08-01 10:16:19 -04:00
Free_CTSInfo( ctsinfo) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
Exit;
Hit:
Result : = True ;
x : = xx;
y : = yy;
2011-08-01 10:16:19 -04:00
Free_CTSInfo( ctsinfo) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindColorsTolerance( out Points: TPointArray; Color, xs, ys,
xe, ye, Tol: Integer ) : Boolean ;
var
2011-06-13 14:21:23 -04:00
PtrData: TRetData;
Ptr: PRGB32;
PtrInc, C: Integer ;
2011-08-01 13:08:23 -04:00
dX, dY: Integer ;
2011-06-13 12:16:59 -04:00
2011-07-06 12:15:33 -04:00
xx, yy: integer ;
compare: TCTSCompareFunction;
2011-07-30 07:12:21 -04:00
ctsinfo: TCTSInfo;
2011-06-13 12:16:59 -04:00
2010-01-25 08:59:44 -05:00
begin
Result : = false ;
DefaultOperations( xs, ys, xe, ye) ;
dX : = xe - xs;
dY : = ye - ys;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
// Do we want to "cache" these vars?
// We will, for now. Easier to type.
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
c : = 0 ;
2011-07-06 12:15:33 -04:00
ctsinfo : = Create_CTSInfo( Self. CTS, Color, Tol, hueMod, satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
for yy : = ys to ye do
begin
for xx : = xs to xe do
begin
2011-07-06 15:06:17 -04:00
if compare( ctsinfo, Ptr) then
2011-07-06 12:15:33 -04:00
begin
ClientTPA[ c] . x : = xx;
ClientTPA[ c] . y : = yy;
inc( c) ;
end ;
inc( Ptr) ;
end ;
Inc( Ptr, PtrInc) ;
2010-01-25 08:59:44 -05:00
end ;
2011-07-06 12:15:33 -04:00
2010-01-25 08:59:44 -05:00
SetLength( Points, C) ;
Move( ClientTPA[ 0 ] , Points[ 0 ] , C * SizeOf( TPoint) ) ;
Result : = C > 0 ;
2011-07-07 05:59:15 -04:00
2011-07-06 12:34:49 -04:00
Free_CTSInfo( ctsinfo) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
end ;
2011-06-13 12:16:59 -04:00
2010-01-25 08:59:44 -05:00
function TMFinder. FindColorsToleranceOptimised( out Points: TPointArray; Color, xs, ys,
xe, ye, Tol: Integer ) : Boolean ;
var
PtrData: TRetData;
Ptr: PRGB32;
PtrInc, C: Integer ;
dX, dY, clR, clG, clB, xx, yy: Integer ;
H1, S1, L1, H2, S2, L2, hueTol, satTol, LumTol, R, G, B, D, Cmin, Cmax: Extended ;
label
hit;
begin
Result : = false ;
DefaultOperations( xs, ys, xe, ye) ;
dX : = xe - xs;
dY : = ye - ys;
//next, convert the color to r,g,b
ColorToRGB( Color, clR, clG, clB) ;
if CTS = 2 then
RGBToHSLNonFixed( clR, clG, clB, H1, S1, L1) ;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
// Do we want to "cache" these vars?
// We will, for now. Easier to type.
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
c : = 0 ;
case CTS of
0 :
for yy : = ys to ye do
begin
for xx : = xs to xe do
begin
if ( ( abs( clB- Ptr^ . B) < = Tol) and ( abs( clG- Ptr^ . G) < = Tol) and ( Abs( clR- Ptr^ . R) < = Tol) ) then
begin ;
ClientTPA[ c] . x : = xx;
ClientTPA[ c] . y : = yy;
inc( c) ;
end ;
inc( Ptr) ;
end ;
Inc( Ptr, PtrInc) ;
end ;
1 :
for yy : = ys to ye do
begin
for xx : = xs to xe do
begin
if ( Sqrt( sqr( clR- Ptr^ . R) + sqr( clG - Ptr^ . G) + sqr( clB - Ptr^ . B) ) < = Tol) then
begin ;
ClientTPA[ c] . x : = xx;
ClientTPA[ c] . y : = yy;
inc( c) ;
end ;
inc( ptr) ;
end ;
Inc( Ptr, PtrInc) ;
end ;
2 :
begin
HueTol : = hueMod * Tol / 1 0 0 ;
SatTol : = satMod * Tol / 1 0 0 ;
LumTol : = Tol / 1 0 0 ;
for yy : = ys to ye do
begin
for xx : = xs to xe do
begin
R : = Percentage[ Ptr^ . r] ;
G : = Percentage[ Ptr^ . g] ;
B : = Percentage[ Ptr^ . b] ;
//We increase the Ptr already, since we use Continue;
inc( Ptr) ;
CMin : = R;
CMax : = R;
if G < Cmin then CMin : = G;
if B < Cmin then CMin : = B;
if G > Cmax then CMax : = G;
if B > Cmax then CMax : = B;
L2 : = 0.5 * ( Cmax + Cmin) ;
//The L-value is already calculated, lets see if the current point meats the requirements!
if Abs( L2- L1) > LumTol then //if not (Abs(L2 - L1) <= LumTol) then
Continue;
if Cmax = Cmin then
begin
//S and H are both zero, lets check if we need found a point!
if ( H1 < = HueTol) and ( S1 < = SatTol) then
goto Hit
else
Continue;
end ;
D : = Cmax - Cmin;
if L2 < 0.5 then
S2 : = D / ( Cmax + Cmin)
else
S2 : = D / ( 2 - Cmax - Cmin) ;
{ We've Calculated the S. Lets see if we need to continue. }
if Abs( S2 - S1) > SatTol then //if not (abs(S1 - S2) <= SatXTol) then
Continue;
if R = Cmax then
H2 : = ( G - B) / D
else
if G = Cmax then
H2 : = 2 + ( B - R) / D
else
H2 : = 4 + ( R - G) / D;
H2 : = H2 / 6 ;
if H2 < 0 then
H2 : = H2 + 1 ;
//Finally lets test H2
if Abs( H2 - H1) > HueTol then
continue;
2010-04-02 11:55:54 -04:00
//We survived the checks, this point is a match!
2010-01-25 08:59:44 -05:00
hit:
ClientTPA[ c] . x : = xx;
ClientTPA[ c] . y : = yy;
Inc( c) ;
end ;
Inc( Ptr, PtrInc) ;
end ;
end ;
end ;
SetLength( Points, C) ;
Move( ClientTPA[ 0 ] , Points[ 0 ] , C * SizeOf( TPoint) ) ;
Result : = C > 0 ;
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindColorsSpiralTolerance( x, y: Integer ;
2011-07-07 05:59:15 -04:00
out Points: TPointArray; color, xs, ys, xe, ye: Integer ; Tol: Integer
2010-01-25 08:59:44 -05:00
) : boolean ;
var
2011-06-16 06:52:10 -04:00
PtrData: TRetData;
c : integer ;
RowData : TPRGB32Array;
2011-07-07 05:59:15 -04:00
dX, dY, SpiralHi, i: Integer ;
2010-01-25 08:59:44 -05:00
2011-07-07 05:59:15 -04:00
compare: TCTSCompareFunction;
2011-07-30 07:12:21 -04:00
ctsinfo: TCTSInfo;
2010-01-25 08:59:44 -05:00
2011-06-16 06:52:10 -04:00
begin
Result : = false ;
DefaultOperations( xs, ys, xe, ye) ;
dX : = xe - xs;
dY : = ye - ys;
//next, convert the color to r,g,b
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
c : = 0 ;
2011-07-07 05:59:15 -04:00
ctsinfo : = Create_CTSInfo( Self. CTS, Color, Tol, hueMod, satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
2011-06-16 06:52:10 -04:00
//Load rowdata
RowData: = CalculateRowPtrs( ptrdata, dy+ 1 ) ;
//Load the spiral path
2011-07-07 05:59:15 -04:00
LoadSpiralPath( x- xs, y- ys, 0 , 0 , dx, dy) ; { Fills ClientTPA with Spiral path }
2011-06-16 06:52:10 -04:00
SpiralHi : = ( dx + 1 ) * ( dy + 1 ) - 1 ;
2011-07-07 05:59:15 -04:00
for i : = 0 to SpiralHi do
if compare( ctsinfo, @ RowData[ ClientTPA[ i] . y] [ ClientTPA[ i] . x] ) then
begin ;
{ We can re-use the ClientTPA to store results. }
ClientTPA[ c] . x : = ClientTPA[ i] . x + xs;
ClientTPA[ c] . y : = ClientTPA[ i] . y + ys;
inc( c) ;
end ;
2010-01-25 08:59:44 -05:00
SetLength( Points, C) ;
Move( ClientTPA[ 0 ] , Points[ 0 ] , C * SizeOf( TPoint) ) ;
Result : = C > 0 ;
2011-07-07 05:59:15 -04:00
Free_CTSInfo( ctsinfo) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
end ;
2010-04-18 11:14:19 -04:00
function TMFinder. FindColors( var TPA: TPointArray; Color, xs, ys, xe, ye: Integer ) : Boolean ;
2010-01-25 08:59:44 -05:00
var
PtrData: TRetData;
Ptr: PRGB32;
PtrInc: Integer ;
dX, dY, clR, clG, clB, xx, yy, i: Integer ;
begin
Result : = false ;
DefaultOperations( xs, ys, xe, ye) ;
dX : = xe - xs;
dY : = ye - ys;
I : = 0 ;
ColorToRGB( Color, clR, clG, clB) ;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
Ptr : = PtrData. Ptr;
PtrInc : = PtrData. IncPtrWith;
for yy : = ys to ye do
begin ;
for xx : = xs to xe do
begin ;
if ( Ptr^ . R = clR) and ( Ptr^ . G = clG) and ( Ptr^ . B = clB) then
begin
Self. ClientTPA[ I] . x : = xx;
Self. ClientTPA[ i] . y : = yy;
Inc( I) ;
end ;
Inc( Ptr) ;
end ;
Inc( Ptr, PtrInc) ;
end ;
SetLength( TPA, I) ;
Move( ClientTPA[ 0 ] , TPA[ 0 ] , i * SizeOf( TPoint) ) ;
Result : = I > 0 ;
TClient( Client) . IOManager. FreeReturnData;
end ;
{ Only works with CTS 1 for now.. Since Colorsame doesn't return a boolean :-( }
//We do not check whether every white pixel is in tol range with every other white pixel..
2010-04-02 11:55:54 -04:00
function TMFinder. FindMaskTolerance( const mask: TMask; out x, y: Integer ; xs,
2010-01-25 08:59:44 -05:00
ys, xe, ye: Integer ; Tolerance, ContourTolerance: Integer ) : Boolean ;
var
MainRowdata : TPRGB32Array;
PtrData : TRetData;
MaskW, MaskH : integer ;
CheckerWhite, CheckerBlack, CurrWhite, CurrBlack: TRGB32;
i, ii : integer ;
dX, dY, xx, yy: Integer ;
label NotFoundMask;
{ Don't know if the compiler has any speed-troubles with goto jumping in nested for loops. }
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
//Check the mask.
CheckMask( Mask) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
//Caculate the row ptrs
MainRowdata: = CalculateRowPtrs( PtrData, dy+ 1 ) ;
//Get the 'fixed' mask size
MaskW : = Mask. W;
MaskH : = Mask. H;
//Heck our mask cannot be outside the search area
dX : = dX - MaskW;
dY : = dY - MaskH;
for yy : = 0 to dY do
for xx : = 0 to dX do
begin ;
CheckerWhite : = MainRowdata[ yy + mask. White[ 0 ] . y] [ xx + mask. white[ 0 ] . x] ;
CheckerBlack : = MainRowdata[ yy + mask. Black[ 0 ] . y] [ xx + mask. Black[ 0 ] . x] ;
//Just check two 'random' points against eachother, might be a time saver in some circumstances.
if ( Sqrt( sqr( CheckerWhite. r- CheckerBlack. r) + sqr( CheckerWhite. G- CheckerBlack. G) + sqr( CheckerWhite. b- CheckerBlack. B) )
< = ContourTolerance) then //The Tol between the white and black is lower than the minimum difference, so continue with looking!
continue;
for i : = 0 to mask. WhiteHi do
begin ;
CurrWhite : = MainRowdata[ yy + mask. White[ i] . y] [ xx + mask. white[ i] . x] ;
if ( Sqrt( sqr( CheckerWhite. r- CurrWhite. r) + sqr( CheckerWhite. G- CurrWhite. G) + sqr( CheckerWhite. b- CurrWhite. B) )
> Tolerance) then //The white checkpoint n' this point aren't in the same tol range -> goto nomatch;
goto NotFoundMask;
{$ifdef CheckAllBackground}
for ii : = 0 to mask. BlackHi do
begin
CurrBlack : = MainRowdata[ yy + mask. Black[ ii] . y] [ xx + mask. Black[ ii] . x] ;
if ( Sqrt( sqr( CurrWhite. r- CurrBlack. r) + sqr( CurrWhite. G- CurrBlack. G) + sqr( CurrWhite. b- CurrBlack. B) )
< = ContourTolerance) then //The Tol between the white and black is lower than the minimum difference -> goto nomatch;
goto NotFoundMask;
end ;
{$endif}
end ;
{$ifndef CheckAllBackground}
for ii : = 0 to mask. BlackHi do
begin
CurrBlack : = MainRowdata[ yy + mask. Black[ ii] . y] [ xx + mask. Black[ ii] . x] ;
if ( Sqrt( sqr( CheckerWhite. r- CurrBlack. r) + sqr( CheckerWhite. G- CurrBlack. G) + sqr( CheckerWhite. b- CurrBlack. B) )
< = ContourTolerance) then //The Tol between the white and black is lower than the minimum difference -> goto nomatch;
goto NotFoundMask;
end ;
{$endif}
//We have found the mask appearntly, otherwise we would have jumped! Gna Gna.
x : = xx + xs;
y : = yy + ys;
TClient( Client) . IOManager. FreeReturnData;
Exit( true ) ;
//Bah not found the mask, lets do nothing and continue!
NotFoundMask:
end ;
TClient( Client) . IOManager. FreeReturnData;
end ;
2010-04-02 11:55:54 -04:00
procedure TMFinder. CheckMask( const Mask: TMask) ;
2010-01-25 08:59:44 -05:00
begin
if ( Mask. W < 1 ) or ( Mask. H < 1 ) or ( Mask. WhiteHi < 0 ) or ( Mask. BlackHi < 0 ) then
raise exception. CreateFMT( 'Mask is invalid. Width/Height: (%d,%d). WhiteHi/BlackHi: (%d,%d)' , [ Mask. W, Mask. H, Mask. WhiteHi, Mask. BlackHi] ) ;
end ;
function TMFinder. FindBitmap( bitmap: TMufasaBitmap; out x, y: Integer ) : Boolean ;
var
w, h : integer ;
begin
TClient( Client) . IOManager. GetDimensions( w, h) ;
result : = Self. FindBitmapIn( bitmap, x, y, 0 , 0 , w- 1 , h- 1 ) ;
end ;
function TMFinder. FindBitmapIn( bitmap: TMufasaBitmap; out x, y: Integer ; xs,
ys, xe, ye: Integer ) : Boolean ;
var
MainRowdata : TPRGB32Array;
BmpRowData : TPRGB32Array;
PtrData : TRetData;
BmpW, BmpH : integer ;
xBmp, yBmp : integer ;
tmpY : integer ;
dX, dY, xx, yy: Integer ;
SkipCoords : T2DBoolArray;
label NotFoundBmp;
{ Don't know if the compiler has any speed-troubles with goto jumping in nested for loops. }
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
//Caculate the row ptrs
MainRowdata: = CalculateRowPtrs( PtrData, dy+ 1 ) ;
BmpRowData: = CalculateRowPtrs( bitmap) ;
//Get the 'fixed' bmp size
BmpW : = bitmap. Width - 1 ;
BmpH : = bitmap. Height - 1 ;
//Heck our bitmap cannot be outside the search area
dX : = dX - bmpW;
dY : = dY - bmpH;
//Get the "skip coords".
CalculateBitmapSkipCoords( Bitmap, SkipCoords) ;
for yy : = 0 to dY do
for xx : = 0 to dX do
begin ;
for yBmp: = 0 to BmpH do
begin ;
tmpY : = yBmp + yy;
for xBmp : = 0 to BmpW do
if not SkipCoords[ yBmp] [ xBmp] then
if ( BmpRowData[ yBmp] [ xBmp] . R < > MainRowdata[ tmpY] [ xBmp + xx] . R) or
( BmpRowData[ yBmp] [ xBmp] . G < > MainRowdata[ tmpY] [ xBmp + xx] . G) or
( BmpRowData[ yBmp] [ xBmp] . B < > MainRowdata[ tmpY] [ xBmp + xx] . B) then
goto NotFoundBmp;
end ;
//We did find the Bmp, otherwise we would be at the part below
TClient( Client) . IOManager. FreeReturnData;
x : = xx + xs;
y : = yy + ys;
result : = true ;
exit;
NotFoundBmp:
end ;
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindBitmapToleranceIn( bitmap: TMufasaBitmap; out x, y: Integer ; xs,
ys, xe, ye: Integer ; tolerance: Integer ) : Boolean ;
var
2011-07-06 12:15:33 -04:00
MainRowdata : TPRGB32Array;
BmpRowData : TPRGB32Array;
PtrData : TRetData;
BmpW, BmpH : integer ;
xBmp, yBmp : integer ;
tmpY : integer ;
dX, dY, xx, yy: Integer ;
SkipCoords : T2DBoolArray;
2011-07-30 07:12:21 -04:00
ctsinfoarray: TCTSInfo2DArray;
compare: TCTSCompareFunction;
2011-07-06 12:15:33 -04:00
label NotFoundBmp;
2011-07-30 14:08:17 -04:00
{ Don't know if the compiler has any speed-troubles with goto jumping in nested for loops. }
2010-01-25 08:59:44 -05:00
begin
2011-07-06 12:15:33 -04:00
Result : = false ;
2010-01-25 08:59:44 -05:00
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
//Caculate the row ptrs
MainRowdata: = CalculateRowPtrs( PtrData, dy+ 1 ) ;
2011-07-06 12:15:33 -04:00
BmpRowData: = CalculateRowPtrs( bitmap) ;
2010-01-25 08:59:44 -05:00
//Get the 'fixed' bmp size
BmpW : = bitmap. Width - 1 ;
BmpH : = bitmap. Height - 1 ;
//Heck our bitmap cannot be outside the search area
dX : = dX - bmpW;
dY : = dY - bmpH;
2011-07-06 12:15:33 -04:00
2011-07-30 14:08:17 -04:00
ctsinfoarray : = Create_CTSInfo2DArray( Self. CTS, bmpW, bmpH, BmpRowData,
2011-07-30 07:12:21 -04:00
Tolerance, self. hueMod, self. satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
2011-04-10 05:51:32 -04:00
2010-01-25 08:59:44 -05:00
//Get the "skip coords".
CalculateBitmapSkipCoords( Bitmap, SkipCoords) ;
2011-07-06 12:15:33 -04:00
for yy : = 0 to dY do
for xx : = 0 to dX do
begin ;
for yBmp: = 0 to BmpH do
begin ;
tmpY : = yBmp + yy;
for xBmp : = 0 to BmpW do
if not SkipCoords[ yBmp] [ xBmp] then
2011-07-30 07:12:21 -04:00
if not compare( ctsinfoarray[ yBmp] [ xBmp] ,
@ MainRowData[ tmpY] [ xBmp + xx] ) then
2011-07-06 12:15:33 -04:00
goto NotFoundBmp;
end ;
2011-07-30 07:12:21 -04:00
2011-07-06 12:15:33 -04:00
//We did find the Bmp, otherwise we would be at the part below
2011-07-30 07:12:21 -04:00
Free_CTSInfo2DArray( ctsinfoarray) ;
2011-07-06 12:15:33 -04:00
TClient( Client) . IOManager. FreeReturnData;
2011-07-30 07:12:21 -04:00
2011-07-06 12:15:33 -04:00
x : = xx + xs;
y : = yy + ys;
result : = true ;
2011-08-01 10:16:19 -04:00
Exit;
2011-07-06 12:15:33 -04:00
NotFoundBmp:
end ;
2011-07-30 07:12:21 -04:00
Free_CTSInfo2DArray( ctsinfoarray) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindBitmapSpiral( bitmap: TMufasaBitmap; var x, y: Integer ;
xs, ys, xe, ye: Integer ) : Boolean ;
var
MainRowdata : TPRGB32Array;
BmpRowData : TPRGB32Array;
PtrData : TRetData;
BmpW, BmpH : integer ;
xBmp, yBmp : integer ;
tmpY : integer ;
dX, dY, i, HiSpiral: Integer ;
SkipCoords : T2DBoolArray;
label NotFoundBmp;
{ Don't know if the compiler has any speed-troubles with goto jumping in nested for loops }
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
//Caculate the row ptrs
MainRowdata: = CalculateRowPtrs( PtrData, dy+ 1 ) ;
BmpRowData: = CalculateRowPtrs( bitmap) ;
//Get the 'fixed' bmp size
BmpW : = bitmap. Width - 1 ;
BmpH : = bitmap. Height - 1 ;
//Heck, our bitmap cannot be outside the search area
dX : = dX - bmpW;
dY : = dY - bmpH;
//Load the spiral into memory
LoadSpiralPath( x- xs, y- ys, 0 , 0 , dX, dY) ;
HiSpiral : = ( dx+ 1 ) * ( dy+ 1 ) - 1 ;
//Get the "skip coords".
CalculateBitmapSkipCoords( Bitmap, SkipCoords) ;
for i : = 0 to HiSpiral do
begin ;
for yBmp: = 0 to BmpH do
begin ;
tmpY : = yBmp + ClientTPA[ i] . y;
for xBmp : = 0 to BmpW do
if not SkipCoords[ yBmp] [ xBmp] then
if ( BmpRowData[ yBmp] [ xBmp] . R < > MainRowdata[ tmpY] [ xBmp + ClientTPA[ i] . x] . R) or
( BmpRowData[ yBmp] [ xBmp] . G < > MainRowdata[ tmpY] [ xBmp + ClientTPA[ i] . x] . G) or
( BmpRowData[ yBmp] [ xBmp] . B < > MainRowdata[ tmpY] [ xBmp + ClientTPA[ i] . x] . B) then
goto NotFoundBmp;
end ;
//We did find the Bmp, otherwise we would be at the part below
TClient( Client) . IOManager. FreeReturnData;
x : = ClientTPA[ i] . x + xs;
y : = ClientTPA[ i] . y + ys;
result : = true ;
exit;
NotFoundBmp:
end ;
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindBitmapSpiralTolerance( bitmap: TMufasaBitmap; var x,
y: Integer ; xs, ys, xe, ye, tolerance: integer ) : Boolean ;
var
MainRowdata : TPRGB32Array;
BmpRowData : TPRGB32Array;
PtrData : TRetData;
BmpW, BmpH : integer ;
xBmp, yBmp : integer ;
tmpY : integer ;
dX, dY, i, HiSpiral: Integer ;
SkipCoords : T2DBoolArray;
2011-08-01 10:16:19 -04:00
ctsinfoarray: TCTSInfo2DArray;
compare: TCTSCompareFunction;
2010-01-25 08:59:44 -05:00
label NotFoundBmp;
{ Don't know if the compiler has any speed-troubles with goto jumping in nested for loops. }
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
//Caculate the row ptrs
MainRowdata: = CalculateRowPtrs( PtrData, dy+ 1 ) ;
BmpRowData: = CalculateRowPtrs( bitmap) ;
//Get the 'fixed' bmp size
BmpW : = bitmap. Width - 1 ;
BmpH : = bitmap. Height - 1 ;
//Heck, our bitmap cannot be outside the search area
dX : = dX - bmpW;
dY : = dY - bmpH;
//Load the spiral into memory
LoadSpiralPath( x- xs, y- ys, 0 , 0 , dX, dY) ;
HiSpiral : = ( dx+ 1 ) * ( dy+ 1 ) - 1 ;
2011-08-01 10:16:19 -04:00
ctsinfoarray : = Create_CTSInfo2DArray( Self. CTS, bmpW, bmpH, BmpRowData,
Tolerance, self. hueMod, self. satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
2011-04-10 05:51:32 -04:00
2010-01-25 08:59:44 -05:00
//Get the "skip coords".
CalculateBitmapSkipCoords( Bitmap, SkipCoords) ;
for i : = 0 to HiSpiral do
begin ;
for yBmp: = 0 to BmpH do
begin ;
tmpY : = yBmp + ClientTPA[ i] . y;
for xBmp : = 0 to BmpW do
if not SkipCoords[ yBmp] [ xBmp] then
2011-08-01 10:16:19 -04:00
if not compare( ctsinfoarray[ yBmp] [ xBmp] ,
@ MainRowData[ tmpY] [ xBmp + ClientTPA[ i] . x] ) then
2010-01-25 08:59:44 -05:00
goto NotFoundBmp;
end ;
//We did find the Bmp, otherwise we would be at the part below
2011-08-01 10:16:19 -04:00
Free_CTSInfo2DArray( ctsinfoarray) ;
TClient( Client) . IOManager. FreeReturnData;
2010-01-25 08:59:44 -05:00
x : = ClientTPA[ i] . x + xs;
y : = ClientTPA[ i] . y + ys;
result : = true ;
exit;
NotFoundBmp:
end ;
2011-08-01 10:16:19 -04:00
Free_CTSInfo2DArray( ctsinfoarray) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindBitmapsSpiralTolerance( bitmap: TMufasaBitmap; x,
y: Integer ; out Points: TPointArray; xs, ys, xe, ye, tolerance: Integer ) : Boolean ;
var
MainRowdata : TPRGB32Array;
BmpRowData : TPRGB32Array;
PtrData : TRetData;
BmpW, BmpH : integer ;
xBmp, yBmp : integer ;
tmpY : integer ;
dX, dY, i, HiSpiral: Integer ;
FoundC : integer ;
SkipCoords : T2DBoolArray;
2011-08-01 10:16:19 -04:00
ctsinfoarray: TCTSInfo2DArray;
compare: TCTSCompareFunction;
2010-01-25 08:59:44 -05:00
label NotFoundBmp;
{ Don't know if the compiler has any speed-troubles with goto jumping in nested for loops. }
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
//Caculate the row ptrs
MainRowdata: = CalculateRowPtrs( PtrData, dy+ 1 ) ;
BmpRowData: = CalculateRowPtrs( bitmap) ;
//Get the 'fixed' bmp size
BmpW : = bitmap. Width - 1 ;
BmpH : = bitmap. Height - 1 ;
//Heck, our bitmap cannot be outside the search area
dX : = dX - bmpW;
dY : = dY - bmpH;
//Load the spiral into memory
LoadSpiralPath( x- xs, y- ys, 0 , 0 , dX, dY) ;
HiSpiral : = ( dx+ 1 ) * ( dy+ 1 ) - 1 ;
FoundC : = 0 ;
2011-08-01 10:16:19 -04:00
ctsinfoarray : = Create_CTSInfo2DArray( Self. CTS, bmpW, bmpH, BmpRowData,
Tolerance, self. hueMod, self. satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
2010-01-25 08:59:44 -05:00
//Get the "skip coords".
CalculateBitmapSkipCoords( Bitmap, SkipCoords) ;
for i : = 0 to HiSpiral do
begin ;
for yBmp: = 0 to BmpH do
begin ;
tmpY : = yBmp + ClientTPA[ i] . y;
for xBmp : = 0 to BmpW do
if not SkipCoords[ yBmp] [ xBmp] then
2011-08-01 10:16:19 -04:00
if not compare( ctsinfoarray[ yBmp] [ xBmp] ,
@ MainRowData[ tmpY] [ xBmp + ClientTPA[ i] . x] ) then
2010-01-25 08:59:44 -05:00
goto NotFoundBmp;
end ;
//We did find the Bmp, otherwise we would be at the part below
ClientTPA[ FoundC] . x : = ClientTPA[ i] . x + xs;
ClientTPA[ FoundC] . y : = ClientTPA[ i] . y + ys;
inc( FoundC) ;
NotFoundBmp:
end ;
if FoundC > 0 then
begin ;
result : = true ;
SetLength( Points, FoundC) ;
Move( ClientTPA[ 0 ] , Points[ 0 ] , FoundC * SizeOf( TPoint) ) ;
end ;
2011-08-01 10:16:19 -04:00
Free_CTSInfo2DArray( ctsinfoarray) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
end ;
function TMFinder. FindDeformedBitmapToleranceIn( bitmap: TMufasaBitmap; out x,
y: Integer ; xs, ys, xe, ye: Integer ; tolerance: Integer ; Range: Integer ;
2010-03-02 16:27:49 -05:00
AllowPartialAccuracy: Boolean ; out accuracy: Extended ) : Boolean ;
2010-01-25 08:59:44 -05:00
var
MainRowdata : TPRGB32Array;
BmpRowData : TPRGB32Array;
PtrData : TRetData;
BmpW, BmpH : integer ;
xBmp, yBmp : integer ;
dX, dY, xx, yy: Integer ;
SearchdX, SearchdY : integer ;
GoodCount : integer ; //Save the amount of pixels who have found a correspondening pixel
BestCount : integer ; //The best amount of pixels till now..
BestPT : TPoint; //The point where it found the most pixels.
RangeX, RangeY : Integer ;
yStart, yEnd, xStart, xEnd : integer ;
TotalC : integer ;
SkipCoords : T2DBoolArray;
PointsLeft : T2DIntArray;
2011-08-01 10:16:19 -04:00
ctsinfoarray: TCTSInfo2DArray;
compare: TCTSCompareFunction;
2010-01-25 08:59:44 -05:00
label FoundBMPPoint, Madness;
{ Don't know if the compiler has any speed-troubles with goto jumping in nested for loops. }
begin
Result : = false ;
// checks for valid xs,ys,xe,ye? (may involve GetDimensions)
DefaultOperations( xs, ys, xe, ye) ;
// calculate delta x and y
dX : = xe - xs;
dY : = ye - ys;
SearchDx : = dX;
SearchDy : = dY;
PtrData : = TClient( Client) . IOManager. ReturnData( xs, ys, dX + 1 , dY + 1 ) ;
//Caculate the row ptrs
MainRowdata: = CalculateRowPtrs( PtrData, dy+ 1 ) ;
BmpRowData: = CalculateRowPtrs( bitmap) ;
//Get the 'fixed' bmp size
BmpW : = bitmap. Width - 1 ;
BmpH : = bitmap. Height - 1 ;
//Heck our bitmap cannot be outside the search area
dX : = dX - bmpW;
dY : = dY - bmpH;
//Reset the accuracy :-)
Accuracy : = 0 ;
BestCount : = - 1 ;
BestPT : = Point( - 1 , - 1 ) ;
2011-08-01 10:16:19 -04:00
ctsinfoarray : = Create_CTSInfo2DArray( Self. CTS, bmpW, bmpH, BmpRowData,
Tolerance, self. hueMod, self. satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
2010-01-25 08:59:44 -05:00
//Get the "skip coords". and PointsLeft (so we can calc whether we should stop searching or not ;-).
CalculateBitmapSkipCoordsEx( Bitmap, SkipCoords, TotalC, PointsLeft) ;
for yy : = 0 to dY do
for xx : = 0 to dX do
begin ;
GoodCount : = 0 ;
for yBmp: = 0 to BmpH do
begin ;
for xBmp : = 0 to BmpW do
begin ;
//We do not have to check this point, win win win <--- triple win <-- JACKPOT!
if SkipCoords[ yBmp] [ xBmp] then
Continue;
//Calculate points of the BMP left against Goodcount (if it cannot possibly get more points skip this x,y?
if bestCount > ( GoodCount + PointsLeft[ yBmp] [ xBmp] ) then
goto Madness;
//The point on the bitmap + the the coordinate we are on at the "screen" minus the range.
yStart : = max( yBmp + yy- Range, 0 ) ;
yEnd : = Min( yBmp + yy+ range, SearchdY) ;
for RangeY : = yStart to yEnd do
begin ;
xStart : = max( xx- Range + xBmp, 0 ) ;
xEnd : = Min( xx+ range + xBmp, SearchdX) ;
for RangeX : = xStart to xEnd do
begin ;
2011-08-01 10:16:19 -04:00
if not compare( ctsinfoarray[ yBmp] [ xBmp] ,
@ MainRowData[ rangeY] [ rangeX] ) then
2010-01-25 08:59:44 -05:00
goto FoundBMPPoint;
end ;
end ;
//We did not find a good point so were continueing!
Continue;
FoundBMPPoint:
//We found a pooint woot!
inc( GoodCount) ;
end ;
end ;
//If we jumped to Madness it means we did not have enuf points left to beat tha fu-king score.
Madness:
if GoodCount > BestCount then //This x,y has the best Acc so far!
begin ;
BestCount : = GoodCount;
BestPT : = Point( xx+ xs, yy+ ys) ;
if GoodCount = TotalC then
2011-08-01 10:16:19 -04:00
begin
Free_CTSInfo2DArray( ctsinfoarray) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
x : = BestPT. x;
y : = BestPT. y;
accuracy: = 1 ;
Exit( true ) ;
end ;
end ;
end ;
2011-08-01 10:16:19 -04:00
Free_CTSInfo2DArray( ctsinfoarray) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
if BestCount = 0 then
Exit;
accuracy : = BestCount / TotalC;
if ( accuracy = 1 ) or AllowPartialAccuracy then
begin
x : = BestPT. x;
y : = BestPT. y;
Exit( true ) ;
end ;
end ;
2010-04-02 11:55:54 -04:00
{
Tries to find the given DTM. If found will put the point the dtm has
been found at in x, y and result to true .
}
2010-01-25 08:59:44 -05:00
2010-05-19 10:01:01 -04:00
function TMFinder. FindDTM( DTM: TMDTM; out x, y: Integer ; x1, y1, x2, y2: Integer ) : Boolean ;
2010-01-25 08:59:44 -05:00
var
P: TPointArray;
begin
Self. FindDTMs( DTM, P, x1, y1, x2, y2, 1 ) ;
if( Length( p) > 0 ) then
begin
x : = p[ 0 ] . x;
y : = p[ 0 ] . y;
Exit( True ) ;
end ;
Exit( False ) ;
end ;
2010-04-03 08:05:15 -04:00
//MaxToFind, if it's < 1 it won't stop looking
2010-05-19 10:01:01 -04:00
function TMFinder. FindDTMs( DTM: TMDTM; out Points: TPointArray; x1, y1, x2, y2, maxToFind: Integer ) : Boolean ;
2010-01-25 08:59:44 -05:00
var
2011-08-01 12:13:36 -04:00
//Cache DTM stuff
Len : integer ; //Len of the points
DPoints : PMDTMPoint; //DTM Points
2010-01-25 08:59:44 -05:00
// Bitwise
b: Array of Array of Integer ;
2010-02-25 09:54:14 -05:00
ch: array of array of integer ;
2010-01-25 08:59:44 -05:00
// bounds
W, H: integer ;
MA: TBox;
2010-04-13 14:10:30 -04:00
MaxX, MaxY : integer ; //The maximum value X/Y can take (for subpoints)
2010-01-25 08:59:44 -05:00
// for loops, etc
xx, yy: integer ;
i, xxx, yyy: Integer ;
2010-02-27 21:01:18 -05:00
StartX, StartY, EndX, EndY : integer ;
2010-01-25 08:59:44 -05:00
//clientdata
cd: TPRGB32Array;
PtrData: TRetData;
// point count
pc: Integer = 0 ;
2010-02-27 21:01:18 -05:00
Found : boolean ;
2010-01-25 08:59:44 -05:00
goodPoints: Array of Boolean ;
2011-08-01 12:13:36 -04:00
col_arr, tol_arr: Array of Integer ;
ctsinfoarray: TCTSInfoArray;
compare: TCTSCompareFunction;
2010-01-25 08:59:44 -05:00
label theEnd;
label AnotherLoopEnd;
begin
2010-02-27 21:01:18 -05:00
// Is the area valid?
DefaultOperations( x1, y1, x2, y2) ;
2010-05-19 10:01:01 -04:00
if not DTM. Valid then
raise Exception. CreateFmt( 'FindDTMs: DTM[%s] is not valid.' , [ DTM. name ] ) ;
2010-01-25 08:59:44 -05:00
// Get the area we should search in for the Main Point.
MA : = ValidMainPointBox( DTM, x1, y1, x2, y2) ;
2010-05-19 10:01:01 -04:00
//Load the DTM-cache variables
Len : = dtm. Count;
DPoints: = dtm. PPoints;
2010-02-25 09:54:14 -05:00
// Turn the bp into a more usable array.
2010-05-19 10:01:01 -04:00
setlength( goodPoints, Len) ;
for i : = 0 to Len - 1 do
goodPoints[ i] : = not DPoints[ i] . bp;
2010-01-25 08:59:44 -05:00
2010-02-25 09:54:14 -05:00
// Init data structure b and ch.
2010-01-25 08:59:44 -05:00
W : = x2 - x1;
H : = y2 - y1;
2010-02-25 09:54:14 -05:00
2010-02-06 16:01:35 -05:00
setlength( b, ( W + 1 ) ) ;
2010-02-25 09:54:14 -05:00
setlength( ch, ( W + 1 ) ) ;
2010-01-25 08:59:44 -05:00
for i : = 0 to W do
begin
2010-02-25 09:54:14 -05:00
setlength( ch[ i] , ( H + 1 ) ) ;
FillChar( ch[ i] [ 0 ] , SizeOf( Integer ) * ( H+ 1 ) , 0 ) ;
2010-02-06 16:01:35 -05:00
setlength( b[ i] , ( H + 1 ) ) ;
FillChar( b[ i] [ 0 ] , SizeOf( Integer ) * ( H+ 1 ) , 0 ) ;
2010-01-25 08:59:44 -05:00
end ;
2011-08-01 13:04:16 -04:00
// Retreive Client Data.
PtrData : = TClient( Client) . IOManager. ReturnData( x1, y1, W + 1 , H + 1 ) ;
2011-08-01 13:08:23 -04:00
SetLength( col_arr, Len) ;
SetLength( tol_arr, Len) ;
2010-01-25 08:59:44 -05:00
// C = DTM.C
2010-05-19 10:01:01 -04:00
for i : = 0 to Len - 1 do
2011-08-01 12:13:36 -04:00
begin
col_arr[ i] : = DPoints[ i] . c;
tol_arr[ i] : = DPoints[ i] . t;
end ;
2010-02-28 08:03:16 -05:00
2011-08-01 12:13:36 -04:00
ctsinfoarray : = Create_CTSInfoArray( Self. CTS,
col_arr, tol_arr, self. hueMod, self. satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
2010-01-25 08:59:44 -05:00
cd : = CalculateRowPtrs( PtrData, h + 1 ) ;
2010-02-27 21:01:18 -05:00
//CD starts at 0,0.. We must adjust the MA, since this is still based on the xs,ys,xe,ye box.
MA. x1 : = MA. x1 - x1;
MA. y1 : = MA. y1 - y1;
MA. x2 : = MA. x2 - x1;
MA. y2 : = MA. y2 - y1;
2010-04-13 14:10:30 -04:00
2010-04-25 12:53:33 -04:00
MaxX : = x2- x1;
MaxY : = y2- y1;
2010-02-27 21:01:18 -05:00
//MA is now fixed to the new (0,0) box...
for yy : = MA. y1 to MA. y2 do //Coord of the mainpoint in the search area
for xx : = MA. x1 to MA. x2 do
2010-01-25 08:59:44 -05:00
begin
2010-02-27 21:01:18 -05:00
//Mainpoint can have area size as well, so we must check that just like any subpoint.
2010-05-19 10:01:01 -04:00
for i : = 0 to Len - 1 do
2010-01-25 08:59:44 -05:00
begin //change to use other areashapes too.
2010-02-27 21:01:18 -05:00
Found : = false ;
//With area it can go out of bounds, therefore this max/min check
2010-05-19 10:01:01 -04:00
StartX : = max( 0 , xx - DPoints[ i] . asz + DPoints[ i] . x) ;
StartY : = max( 0 , yy - DPoints[ i] . asz + DPoints[ i] . y) ;
EndX : = Min( MaxX, xx + DPoints[ i] . asz + DPoints[ i] . x) ;
EndY : = Min( MaxY, yy + DPoints[ i] . asz + DPoints[ i] . y) ;
2010-02-27 21:01:18 -05:00
for xxx : = StartX to EndX do //The search area for the subpoint
begin
for yyy : = StartY to EndY do
2010-01-25 08:59:44 -05:00
begin
2010-02-25 09:54:14 -05:00
// If we have not checked this point, check it now.
2010-02-25 10:23:41 -05:00
if ch[ xxx] [ yyy] and ( 1 shl i) = 0 then
2010-01-25 08:59:44 -05:00
begin
// Checking point i now. (Store that we matched it)
2010-02-25 09:54:14 -05:00
ch[ xxx] [ yyy] : = ch[ xxx] [ yyy] or ( 1 shl i) ;
2010-05-19 10:01:01 -04:00
// if SimilarColors(dtm.c[i], rgbtocolor(cd[yyy][xxx].R, cd[yyy][xxx].G, cd[yyy][xxx].B), DPoints[i].t) then
2011-08-01 12:13:36 -04:00
if compare( ctsinfoarray[ i] , @ cd[ yyy] [ xxx] ) then
2010-02-27 21:01:18 -05:00
b[ xxx] [ yyy] : = b[ xxx] [ yyy] or ( 1 shl i) ;
2010-01-25 08:59:44 -05:00
end ;
2010-02-27 21:01:18 -05:00
//Check if the point matches the subpoint
if ( b[ xxx] [ yyy] and ( 1 shl i) < > 0 ) then
begin
//Check if it was supposed to be a goodpoint..
if GoodPoints[ i] then
begin
Found : = true ;
break;
end else //It was not supposed to match!!
goto AnotherLoopEnd;
end ;
2010-01-25 08:59:44 -05:00
end ;
2010-02-27 21:01:18 -05:00
if Found then Break; //Optimalisation, we must break out of this second for loop, since we already found the subpoint
end ;
if ( not found) and ( GoodPoints[ i] ) then //This sub-point wasn't found, while it should.. Exit this mainpoint search
goto AnotherLoopEnd;
2010-01-25 08:59:44 -05:00
end ;
2010-02-27 21:01:18 -05:00
//We survived the sub-point search, add this mainpoint to the results.
2010-02-06 16:01:35 -05:00
ClientTPA[ pc] : = Point( xx + x1, yy + y1) ;
2010-01-25 08:59:44 -05:00
Inc( pc) ;
if( pc = maxToFind) then
goto theEnd;
AnotherLoopEnd:
end ;
TheEnd:
2011-08-01 12:13:36 -04:00
Free_CTSInfoArray( ctsinfoarray) ;
2010-01-25 08:59:44 -05:00
TClient( Client) . IOManager. FreeReturnData;
SetLength( Points, pc) ;
if pc > 0 then
Move( ClientTPA[ 0 ] , Points[ 0 ] , pc * SizeOf( TPoint) ) ;
2010-02-27 21:01:18 -05:00
Result : = ( pc > 0 ) ;
2010-01-25 08:59:44 -05:00
end ;
2010-05-19 10:01:01 -04:00
function TMFinder. FindDTMRotated( DTM: TMDTM; out x, y: Integer ; x1, y1, x2, y2: Integer ; sAngle, eAngle, aStep: Extended ; out aFound: Extended ; Alternating : boolean ) : Boolean ;
2010-01-25 08:59:44 -05:00
2010-02-25 18:53:31 -05:00
var
P: TPointArray;
F: T2DExtendedArray;
2010-01-25 08:59:44 -05:00
begin
2010-04-03 08:05:15 -04:00
FindDTMsRotated( dtm, P, x1, y1, x2, y2, sAngle, eAngle, aStep, F, Alternating, 1 ) ;
2010-02-25 18:53:31 -05:00
if Length( P) = 0 then
2011-08-01 13:04:16 -04:00
exit( False ) ;
2010-02-25 18:53:31 -05:00
aFound : = F[ 0 ] [ 0 ] ;
x : = P[ 0 ] . x;
y : = P[ 0 ] . y;
Exit( True ) ;
2010-01-25 08:59:44 -05:00
end ;
2011-08-01 13:04:16 -04:00
procedure RotPoints_DTM( const P: TPointArray; var RotTPA : TPointArray; const A:
Extended ) ; inline ;
2010-01-25 08:59:44 -05:00
var
2010-05-19 10:01:01 -04:00
I, L: Integer ;
begin
L : = High( P) ;
for I : = 0 to L do
begin
RotTPA[ I] . X : = Round( cos( A) * p[ i] . x - sin( A) * p[ i] . y) ;
RotTPA[ I] . Y : = Round( sin( A) * p[ i] . x + cos( A) * p[ i] . y) ;
end ;
end ;
function TMFinder. FindDTMsRotated( DTM: TMDTM; out Points: TPointArray; x1, y1, x2, y2: Integer ; sAngle, eAngle, aStep: Extended ; out aFound: T2DExtendedArray; Alternating : boolean ; maxToFind: Integer ) : Boolean ;
var
2011-08-01 13:04:16 -04:00
//Cached variables
Len : integer ;
DPoints : PMDTMPoint;
DTPA : TPointArray;
RotTPA: TPointArray;
2010-01-25 08:59:44 -05:00
// Bitwise
b: Array of Array of Integer ;
2010-02-25 09:54:14 -05:00
ch: Array of Array of Integer ;
2010-01-25 08:59:44 -05:00
// bounds
W, H: integer ;
MA: TBox;
2010-04-13 14:10:30 -04:00
MaxX, MaxY : integer ; //The maximum value a (subpoint) can have!
2010-01-25 08:59:44 -05:00
// for loops, etc
xx, yy: integer ;
i, xxx, yyy: Integer ;
2010-02-27 21:01:18 -05:00
StartX, StartY, EndX, EndY : integer ;
2010-01-25 08:59:44 -05:00
2010-02-27 21:01:18 -05:00
Found : boolean ;
2010-01-25 08:59:44 -05:00
//clientdata
cd: TPRGB32Array;
PtrData: TRetData;
2010-02-28 14:21:15 -05:00
//If we search alternating, we start in the middle and then +,-,+,- the angle step outwars
MiddleAngle : extended ;
//Count the amount of anglesteps, mod 2 determines whether it's a + or a - search, and div 2 determines the amount of steps
//you have to take.
AngleSteps : integer ;
2010-01-25 08:59:44 -05:00
// point count
pc: Integer = 0 ;
goodPoints: Array of Boolean ;
2010-02-25 09:54:14 -05:00
s: extended ;
2010-01-25 08:59:44 -05:00
2011-08-01 13:04:16 -04:00
col_arr, tol_arr: Array of Integer ;
ctsinfoarray: TCTSInfoArray;
compare: TCTSCompareFunction;
2010-01-25 08:59:44 -05:00
label theEnd;
label AnotherLoopEnd;
begin
2010-02-27 21:01:18 -05:00
// Is the area valid?
DefaultOperations( x1, y1, x2, y2) ;
2010-05-19 10:01:01 -04:00
if not dtm. Valid then
raise Exception. CreateFmt( 'FindDTMs: DTM[%s] is not consistent.' , [ DTM. name ] ) ;
2010-01-25 08:59:44 -05:00
2010-05-20 05:12:20 -04:00
dtm. Normalize; ;
2010-01-25 08:59:44 -05:00
2010-05-19 10:01:01 -04:00
Len : = DTM. Count;
DPoints: = DTM. PPoints;
setlength( goodPoints, Len) ;
for i : = 0 to Len - 1 do
goodPoints[ i] : = not DPoints[ i] . bp;
2010-02-25 09:54:14 -05:00
2010-04-13 14:10:30 -04:00
MaxX : = x2 - x1;
2010-04-18 17:26:21 -04:00
MaxY : = y2 - y1;
2010-04-13 14:10:30 -04:00
2010-02-25 09:54:14 -05:00
// Init data structure B.
W : = x2 - x1;
H : = y2 - y1;
setlength( b, ( W + 1 ) ) ;
setlength( ch, ( W + 1 ) ) ;
for i : = 0 to W do
begin
setlength( b[ i] , ( H + 1 ) ) ;
FillChar( b[ i] [ 0 ] , SizeOf( Integer ) * ( H+ 1 ) , 0 ) ;
setlength( ch[ i] , ( H + 1 ) ) ;
FillChar( ch[ i] [ 0 ] , SizeOf( Integer ) * ( H+ 1 ) , 0 ) ;
end ;
2010-05-19 10:01:01 -04:00
{
When we search for a rotated DTM, everything is the same, except the coordinates..
Therefore we create a TPA of the 'original' DTM, containing all the Points.
This then will be used to rotate the points}
SetLength( DTPA, len) ;
SetLength( RotTPA, len) ;
for i : = 0 to len- 1 do
DTPA[ i] : = Point( DPoints[ i] . x, DPoints[ i] . y) ;
2010-04-03 08:05:15 -04:00
2010-02-25 09:54:14 -05:00
// Retreive Client Data.
PtrData : = TClient( Client) . IOManager. ReturnData( x1, y1, W + 1 , H + 1 ) ;
2011-08-01 13:08:23 -04:00
SetLength( col_arr, Len) ;
SetLength( tol_arr, Len) ;
2011-08-01 13:04:16 -04:00
// C = DTM.C
for i : = 0 to Len - 1 do
begin
col_arr[ i] : = DPoints[ i] . c;
tol_arr[ i] : = DPoints[ i] . t;
end ;
ctsinfoarray : = Create_CTSInfoArray( Self. CTS,
col_arr, tol_arr, self. hueMod, self. satMod) ;
compare : = Get_CTSCompare( Self. CTS) ;
2010-02-25 09:54:14 -05:00
cd : = CalculateRowPtrs( PtrData, h + 1 ) ;
SetLength( aFound, 0 ) ;
SetLength( Points, 0 ) ;
2010-02-28 14:21:15 -05:00
if Alternating then
begin
MiddleAngle : = ( sAngle + eAngle) / 2.0 ;
s : = MiddleAngle; //Start in the middle!
AngleSteps : = 0 ;
end else
s : = sAngle;
2010-02-25 09:54:14 -05:00
while s < eAngle do
begin
2010-05-19 10:01:01 -04:00
RotPoints_DTM( DTPA, RotTPA, s) ;
2010-04-03 08:05:15 -04:00
//DTMRot now has the same points as the original DTM, just rotated!
//The other stuff in the structure doesn't matter, as it's the same as the original DTM..
2010-05-19 10:01:01 -04:00
//So from now on if we want to see what 'point' we're at, use RotTPA, for the rest just use the original DTM
MA : = ValidMainPointBox( RotTPA, x1, y1, x2, y2) ;
2010-04-03 08:05:15 -04:00
//CD(ClientData) starts at 0,0.. We must adjust the MA, since this is still based on the xs,ys,xe,ye box.
2010-02-27 21:01:18 -05:00
MA. x1 : = MA. x1 - x1;
MA. y1 : = MA. y1 - y1;
MA. x2 : = MA. x2 - x1;
MA. y2 : = MA. y2 - y1;
//MA is now fixed to the new (0,0) box...
2010-04-03 08:05:15 -04:00
for yy : = MA. y1 to MA. y2 do //(xx,yy) is now the coord of the mainpoint in the search area
2010-02-27 21:01:18 -05:00
for xx : = MA. x1 to MA. x2 do
2010-02-25 09:54:14 -05:00
begin
2010-02-27 21:01:18 -05:00
//Mainpoint can have area size as well, so we must check that just like any subpoint.
2010-05-19 10:01:01 -04:00
for i : = 0 to Len - 1 do
2010-02-25 09:54:14 -05:00
begin //change to use other areashapes too.
2010-02-27 21:01:18 -05:00
Found : = false ;
//With area it can go out of bounds, therefore this max/min check
2010-05-19 10:01:01 -04:00
StartX : = max( 0 , xx - DPoints[ i] . asz + RotTPA[ i] . x) ;
StartY : = max( 0 , yy - DPoints[ i] . asz + RotTPA[ i] . y) ;
EndX : = Min( MaxX, xx + DPoints[ i] . asz + RotTPA[ i] . x) ;
EndY : = Min( MaxY, yy + DPoints[ i] . asz + RotTPA[ i] . y) ;
2010-02-27 21:01:18 -05:00
for xxx : = StartX to EndX do //The search area for the subpoint
begin
for yyy : = StartY to EndY do
2010-02-25 09:54:14 -05:00
begin
// If we have not checked this point, check it now.
2010-02-25 10:23:41 -05:00
if ch[ xxx] [ yyy] and ( 1 shl i) = 0 then
2010-02-25 09:54:14 -05:00
begin
// Checking point i now. (Store that we matched it)
ch[ xxx] [ yyy] : = ch[ xxx] [ yyy] or ( 1 shl i) ;
2011-08-01 13:05:03 -04:00
if compare( ctsinfoarray[ i] , @ cd[ yyy] [ xxx] ) then
2010-02-27 21:01:18 -05:00
b[ xxx] [ yyy] : = b[ xxx] [ yyy] or ( 1 shl i) ;
2010-02-25 09:54:14 -05:00
end ;
2010-02-27 21:01:18 -05:00
//Check if the point matches the subpoint
if ( b[ xxx] [ yyy] and ( 1 shl i) < > 0 ) then
begin
//Check if it was supposed to be a goodpoint..
if GoodPoints[ i] then
begin
Found : = true ;
break;
end else //It was not supposed to match!!
goto AnotherLoopEnd;
end ;
2010-02-25 09:54:14 -05:00
end ;
2010-02-27 21:01:18 -05:00
if Found then Break; //Optimalisation, we must break out of this second for loop, since we already found the subpoint
end ;
if ( not found) and ( GoodPoints[ i] ) then //This sub-point wasn't found, while it should.. Exit this mainpoint search
goto AnotherLoopEnd;
2010-02-25 09:54:14 -05:00
end ;
2010-02-27 21:01:18 -05:00
//We survived the sub-point search, add this mainpoint to the results.
2010-02-25 09:54:14 -05:00
Inc( pc) ;
setlength( Points, pc) ;
Points[ pc- 1 ] : = Point( xx + x1, yy + y1) ;
Setlength( aFound, pc) ;
setlength( aFound[ pc- 1 ] , 1 ) ;
aFound[ pc- 1 ] [ 0 ] : = s;
if( pc = maxToFind) then
goto theEnd;
AnotherLoopEnd:
end ;
2010-02-28 14:21:15 -05:00
if Alternating then
begin
if AngleSteps mod 2 = 0 then //This means it's an even number, thus we must add a positive step
s : = MiddleAngle + ( aStep * ( anglesteps div 2 + 1 ) ) //Angle steps starts at 0, so we must add 1.
else
s : = MiddleAngle - ( aStep * ( anglesteps div 2 + 1 ) ) ; //We must search in the negative direction
inc( AngleSteps) ;
end else
s : = s + aStep;
2010-02-25 09:54:14 -05:00
end ;
TheEnd:
2011-08-01 13:04:16 -04:00
Free_CTSInfoArray( ctsinfoarray) ;
TClient( Client) . IOManager. FreeReturnData;
2010-02-27 21:01:18 -05:00
Result : = ( pc > 0 ) ;
2010-01-25 08:59:44 -05:00
{ Don' t forget to pre calculate the rotated points at the start.
Saves a lot of rotatepoint( ) calls. }
2010-02-25 09:54:14 -05:00
// raise Exception.CreateFmt('Not done yet!', []);
2010-01-25 08:59:44 -05:00
end ;
2010-04-02 11:55:54 -04:00
function TMFinder. GetColors( const Coords: TPointArray) : TIntegerArray;
2010-01-25 08:59:44 -05:00
var
Box : TBox;
Len, I, w, h : integer ;
PtrRet : TRetData;
Ptr : PRGB32;
begin
len : = high( Coords) ;
setlength( result , len+ 1 ) ;
box : = GetTPABounds( coords) ;
w : = 0 ;
h : = 0 ;
DefaultOperations( w, h, box. x2, box. y2) ;
TClient( Self. Client) . IOManager. GetDimensions( w, h) ;
PtrRet : = TClient( Client) . IOManager. ReturnData( 0 , 0 , Box. x2 + 1 , box. y2+ 1 ) ; //Otherwise lotsashit.
ptr : = PtrRet. Ptr;
for i : = 0 to len do
Result [ i] : = BGRToRGB( Ptr[ Coords[ i] . y* w + Coords[ i] . x] ) ;
end ;
end .