Main
2011-11-10 19:13:08
I made these two guys for an research project, turns out they could be pretty damn useful in rs.
FindboundaryTPA
~ Finds boundary of an continuous tpa and stores it as a tpa.

FindTPAOval
~ Fits on Oval inside an continuous color (stored as TPA of course), and stores an random point from this oval as a Tpoint for user to interact with.

Note: Both of these function is very fast, both of them together can be executed in sub 1 seconds!!
There is also a few complimentary functions:
PtToPol;
PolToPt;
PtToHyp;
TPLength;
TPALength;
Here is the full list and explanations.
Here's more explanation on the variables inside of FindTPAOval:
Increment: Integer; I recommend using 45 for runescae

OffSet: Tpoint; This should be changed only if you have an "hour glass" shaped object or something like that…

SortPoint: Tpoint; SortFromPoint: Boolean; By default, its on sort by size, but if you want to find a tree closest to point ( X, Y), turn sort from point on.

Recenter: Boolean; I HIGHLY RECOMMEND TURNING THIS ON!

I've also included an test script and this tree picture for ya to play with. I know the wording in this thread is crazy, but hopefully you guys could find some uses for this *cough* pvp *cough*…
FindboundaryTPA
~ Finds boundary of an continuous tpa and stores it as a tpa.

FindTPAOval
~ Fits on Oval inside an continuous color (stored as TPA of course), and stores an random point from this oval as a Tpoint for user to interact with.

Note: Both of these function is very fast, both of them together can be executed in sub 1 seconds!!
There is also a few complimentary functions:
PtToPol;
PolToPt;
PtToHyp;
TPLength;
TPALength;
Here is the full list and explanations.
Function FindTPAOval( Color, Tolerance, Increment: Integer; OffSet, StartPoint, EndPoint, SortPoint: Tpoint; SortFromPoint, Recenter: Boolean): Tpoint;
{*******************************************************************************
Function FindTPAOval( Color, Tolerance, Increment: Integer; OffSet, StartPoint, EndPoint, SortPoint: Tpoint; SortFromPoint, Recenter: Boolean): Tpoint;
By: Main
Description: Finds the ( largest) or (closest to a sort point) CONTINUOUS TPA,
fits an oval inside this TPA and stores an random point in this oval on to it.
*******************************************************************************}
Var
I, R, H, T: Integer;
OBox, SBox: TBox;
MP, OMP, Rab: Tpoint;
TPA, TTPA: TpointArray;
ATPA : T2DPointArray;
Begin
MarkTime( T);
SetArrayLength( TPA, EndPoint.X * EndPoint.Y);
If FindColorsSpiralTolerance( MP.X, MP.Y, TPA, Color, StartPoint.X, StartPoint.Y, EndPoint.X - 1, EndPoint.Y - 1, Tolerance) Then
Begin
TTPA := TPA
ATPA := TPAToATPA( TTPA, 40);
If SortFromPoint Then
SortATPAFromFirstPoint( ATPA, SortPoint)
Else
SortATPASize( ATPA, True);
TTPA := FindBoundaryTPA( MiddleTPA( ATPA[ 0]), TPA, 90, StartPoint, EndPoint);
MP := MiddleTPA( FindBoundaryTPA( MiddleTPA( ATPA[ 0]), TPA, 90, StartPoint, EndPoint));
If Recenter Then
Begin
For I := 0 To 10 Do
Begin
MP := MiddleTPA( FindBoundaryTPA( MP, TPA, 90, StartPoint, EndPoint));
If ( PtToHyp( MP, OMP) < 10) Then
Begin
Break;
End Else
OMP := MP;
End;
Writeln( 'Recentered ' + IntToStr( I) + ' times.');
End;
End Else
Begin
Writeln( 'Terminated, did not find a proper TPA');
Exit;
End;
OBox := GetTPABounds( TPA);
For H := 0 To TPALength( TTPA, True) Do
Begin
If ( SBox.Y1 = 0) and Not( PointInTPA( PolToPt( 0, H, MP), TPA)) Then
SBox.Y1 := MP.Y - H;
If ( SBox.X2 = 0) and Not( PointInTPA( PolToPt( 90, H, MP), TPA)) Then
SBox.X2 := MP.X + H;
If ( SBox.Y2 = 0) and Not( PointInTPA( PolToPt( 180, H, MP), TPA)) Then
SBox.Y2 := MP.Y + H;
If ( SBox.X1 = 0) and Not( PointInTPA( PolToPt( 270, H, MP), TPA)) Then
SBox.X1 := MP.X - H;
End;
Rab := IntToPoint( TPLength( Point( MP.X - SBox.X1, SBox.X2 - MP.X), False) - OffSet.X, TPLength( Point( MP.Y - SBox.Y1, SBox.Y2 - MP.Y), False) - OffSet.Y);
SetArrayLength( TTPA, MSEP.X * MSEP.Y);
I := 0;
For R := 0 To 360 Do
Begin
For H := 0 To Round( Sqrt( Sqr( Rab.X * Rab.Y) / ( 1 + Sqr( Rab.X * Cos( Radians( R))) + Sqr( Rab.Y * Sin( Radians( R)))))) Do
Begin
TTPA[ I] := PolToPt( R, H, MP);
Inc( I);
H := H + Random( Round( Abs( Round( Sqrt( Sqr( Rab.X * Rab.Y) / ( 1 + Sqr( Rab.X * Cos( Radians( R))) + Sqr( Rab.Y * Sin( Radians( R)))))) - Increment)) / 4);
End;
R := R + Random( Increment);
End;
SortTPAFrom( TTPA, MP);
SetArrayLength( TTPA, I);
DebugTPA( TTPA, '');
Result := TTPA[ Random( Length( TTPA))];
Writeln( 'Found an random point in ' + IntToStr( TimeFromMark( T)) + ' miliseconds.');
End;
Function FindBoundaryTPA( TP: Tpoint; TPA: TPointArray; Increment: Integer; SP, EP: Tpoint): TPointArray;
{*******************************************************************************
Function FindTPABound( TP: Tpoint; TPA: TPointArray; Increment: Integer; SP, EP: Tpoint): TPointArray;
By: Main
Description: From an point TP inside an CONTINUOUS TPA, find the boundary of this
that can be reached radially from the point TP.
*******************************************************************************}
Var
I, R, H: Integer;
Begin
I := 0;
SetArrayLength( Result, 360);
For R := 0 to 359 do
Begin
For H := 1 to TPALength( TPA, True) do
Begin
If Not( WithInBox( SP.X, SP.Y, EP.X - 1, EP.Y - 1, PolToPt( R, H, TP))) Or Not( PointInTPA( PolToPt( R, H, TP), TPA)) Then
Begin
Result[ I] := PolToPt( R, H - 1, TP);
Inc( I);
Break;
End;
End;
R := R + Increment;
End;
SetArrayLength( Result, I)
DebugTPA( Result, '');
End;
Function PtToPol( A: Integer; I, C: Tpoint): Integer;
{*******************************************************************************
Function PtToPol( A: Integer; I, C: Tpoint): Integer;
By: Main
Description: Convert an point 'I' to a angle from the center point'C'.
'A' is a over ride if you wish to use a custom compass angle.
*******************************************************************************}
var
N: TPoint;
D , H: Integer;
Begin
If A = 0 Then
D := Round( RS_GetCompassAngleDegrees)
else
D := A;
I.X := I.X - C.X;
I.Y := I.Y - C.Y;
H := Round( Hypot( I.X, I.Y));
If H = 0 Then
H := 1;
I.X := 76 * I.X / H;
I.Y := 76 * I.Y / H;
N := Inttopoint( - Round( 1000 * Sin( Radians( D))), - Round( 1000 * Cos( Radians( D))));
H := Round( Hypot( N.X, N.Y));
N := IntToPoint( 76 * N.X / H, 76 * N.Y / H);
Result := 360 - Round( Degrees( ArcCos( ( N.X * I.X + N.Y * I.Y) / ( 1 + Hypot( I.X, I.Y) * Hypot( N.X, N.Y)))));
If Result > 0 Then
Begin
If D < 180 Then
Begin
If ( ( I.X < 0) and ( I.Y < N.Y)) or ( ( I.X > 0) and ( I.Y < -1 * N.Y)) Then Result:= 360 - Result;
End else
If ( ( I.X < 0) and ( I.Y > -1 * N.Y)) or ( ( I.X > 0) and ( I.Y > N.Y)) Then Result:= 360 - Result;
End;
End;
Function PolToPt( A, H: Integer; C: Tpoint): TPoint;
{*******************************************************************************
Function PolToPt( A, H: Integer; C: Tpoint): TPoint;
By: Main
Description: Convert a angle 'A' to a point from the center'C' where 'H'is the
distance of the result from the point'C'.
*******************************************************************************}
Var
P: TPoint;
Rh: Integer;
Begin
A := 360 - A;
P.X := Round( - 100 * Sin( Radians( Compas + A )));
P.Y := Round( - 100 * Cos( Radians( Compas + A )));
Rh := Round( Hypot( P.X, P.Y));
P.X := C.X + H * P.X / Rh
P.Y := C.Y + H * P.Y / Rh;
Result:= P;
End;
Function PtToHyp( I, C: TPoint): Integer;
{*******************************************************************************
Function PtToHyp( I, C: TPoint): Integer;
By: Main
Description: Get the distance 'I' from the center point 'C'.
*******************************************************************************}
Begin
Result := Round( Hypot( I.X - C.X, I.Y - C.Y));
End;
Function WithInBox( SX, SY, EX, EY: Integer; I: Tpoint): Boolean;
Begin
If ( I.X > SX) and ( I.X < EX) and ( I.Y > SY) and ( I.Y < EY) Then
Result := True
Else
Result := False;
End;
Procedure ShowTPA(Points: TPointArray);
Var
Bmp : Integer;
Box : TBox;
TempTPA : TPointArray;
Begin
Box := GetTPABounds(Points);
Bmp := BitmapFromClient( 0, 0, MSEP.X - 1, MSEP.Y - 1);
TempTPA := CopyTPA(Points);
OffsetTPA(TempTPA,Point( 0, 0));
DrawTPABitmap(Bmp,TempTPA,clRed);
DisplayDebugImgWindow( MSEP.X, MSEP.Y);
DrawBitmapDebugImg(Bmp);
FreeBitmap(Bmp)
End;
Function TPLength( TP: TPoint; Max: Boolean): Integer;
{*******************************************************************************
Function TPLength( TP: TPoint; Max: Boolean): Integer;
By: Main
Description: Find the biggest value of an TPoint (whether its x or y).
*******************************************************************************}
Begin
If TP.X < TP.Y Then
TP := IntToPoint( TP.Y, TP.X);
If Max Then
Result := TP.X
Else
Result := TP.Y;
End;
Function TPALength( TPA: TPointArray; Max: Boolean): Integer;
{*******************************************************************************
Function TPALength( TPA: TPointArray; Max: Boolean): Integer;
By: Main
Description: Find the biggest or smallest side of an TPA bound.
*******************************************************************************}
Var
DaBox: Tbox;
TestPoint: Tpoint;
Begin
DaBox := GetTPABounds( TPA);
If ( DaBox.X2 - DaBox.X1) > ( DaBox.Y2 - DaBox.Y1) Then
TestPoint := IntToPoint( DaBox.X2 - DaBox.X1, DaBox.Y2 - DaBox.Y1)
Else
TestPoint := IntToPoint( DaBox.Y2 - DaBox.Y1, DaBox.Y2 - DaBox.Y1);
If Max Then
Result := TestPoint.X
Else
Result := TestPoint.Y;
End;
Here's more explanation on the variables inside of FindTPAOval:
Increment: Integer; I recommend using 45 for runescae

OffSet: Tpoint; This should be changed only if you have an "hour glass" shaped object or something like that…

SortPoint: Tpoint; SortFromPoint: Boolean; By default, its on sort by size, but if you want to find a tree closest to point ( X, Y), turn sort from point on.

Recenter: Boolean; I HIGHLY RECOMMEND TURNING THIS ON!

I've also included an test script and this tree picture for ya to play with. I know the wording in this thread is crazy, but hopefully you guys could find some uses for this *cough* pvp *cough*…


Offset should beable to smooth it out.