SRL Archive - SRL Snippets

FindTPAOval and FindBoundaryTPA + Other stuff


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.

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*…

YoHoJo

2011-11-10 19:29:07

Holy cock this is all really awesome stuff!!!
Great work, very useful!

Kyle Undefined

2011-11-10 22:41:15

HOLY Shhh! That would be badass to be implemented! It looks like it works really well too!

Nava2

2011-11-11 00:29:28

I do not really understand the point of the Oval one, but the Edge detection is nice.

Does it only work with a completely continuous TPA, thus, it won't work for a TPA with holes?

KingKong

2011-11-11 01:45:55

From: Nava2
I do not really understand the point of the Oval one, but the Edge detection is nice.



^This. Couldn't the scripter get any point from the TPA themselves? something like TPA[random(len(TPA))]. But the findtpabounds is very nice, i can think of a few place where this could be useful.

Main

2011-11-11 09:56:35

From: KingKong
^This. Couldn't the scripter get any point from the TPA themselves? something like TPA[random(len(TPA))]. But the findtpabounds is very nice, i can think of a few place where this could be useful.


The FindTPAOval will first find the boundary of this tpa and then fits the oval inside of the boundary TPA.

The point of FindTPAOval, is that its 99% guaranteed to give a player a point that is on the color/tpa they've entered.

You can use this for an tpa with holes, but it'll look like this.

Note that when I saay continuous, you can have some parts breaking off but as long as your color and tolerance covers the object quite well then should be no problem.


Most tree,monsters,rock has some "continuous" parts to it, its just up to the scripted to decide which one to use,

Nava2

2011-11-11 10:27:49

Hmm, maybe implement a maxBreak param ?

Main

2011-11-11 10:44:07

There is an increment, it is there to hopefully skip over, but i'll think about max break.


I'll def take a look at it, but there might not even be a need for it thou, as most objects in runescape doesn't have much break in it. We just gotta find the right color, but if failure to do so, maybe then that will create some break.

Nava2

2011-11-11 10:48:29

From: Main
There is an increment, it is there to hopefully skip over, but i'll think about max break.


I'll def take a look at it, but there might not even be a need for it thou, as most objects in runescape doesn't have much break in it. We just gotta find the right color, but if failure to do so, maybe then that will create some break.


I totally meant with the edge detection, my bad. :<

Main

2011-11-11 10:51:42

Am not sure what you mean, wanna draw something up? :p

Nava2

2011-11-11 10:52:30

just like if there is a break in the "continuous" region around the object, it will try to "fill it in" the best it can.

Main

2011-11-11 10:54:46

like a circle missing 1/4 of it?

EDIT: Maybe this what your talking about?
Offset should beable to smooth it out.


BTW, This could work for scar aswell:P

n3ss3s

2011-11-11 15:24:08

http://villavu.com/forum/showthread.php?t=17918


Main

2012-06-01 21:52:25

From: n3ss3s
http://villavu.com/forum/showthread.php?t=17918



Nice troll:P
But that'd be pretty good, if ben is still down for converting stuff in to c++:p



bumpy