SRL Archive - Bugs

FindTPAinTPA


Shatterhand

2012-12-25 06:15:37

I want to make a function which will return true if two boxes cover each other. I would make TPAs from the boxes and use the FindTPAinTPA to get result. But I got some problems with the function.

Box2 := IntToBox(0,0,50,50);
Box1 := IntToBox(25,25,75,75);
if BoxMatch(Box1,Box2) then
Writeln('True')
else
Writeln('False');

The first problem is with the order. TPA1,TPA2 or TPA1,TPA2 -> its not the same. And according to Naum's tutorial FindTPAinTPA should not change the two input TPAs. As you can see on the second debug image, there is only one box there, one of the boxes (TPA) disappeared.
[PHP]{*******************************************************************************
function FindTPAinTPA(SearchTPA, TotalTPA: TPointArray; var Matches: TPointArray): Boolean;
Description: Looks for the TPA SearchTPA in the TPA TotalTPA and returns
the matched points to the TPA Matches. Returns true if there were atleast one
match(es).
*******************************************************************************} [/PHP]

The only way to make it work is to make the two TPAs again.
function BoxMatch(Box1, Box2 : TBox): Boolean;
var
TPA1, TPA2, Matches : TPointArray;
begin
TPAFromBoxWrap(Box1,TPA1);
TPAFromBoxWrap(Box2,TPA2);
if FindTPAinTPA(TPA2,TPA1,Matches) then
begin
Result := True;
Exit;
end;

TPAFromBoxWrap(Box1,TPA1);
TPAFromBoxWrap(Box2,TPA2);
if FindTPAinTPA(TPA1,TPA2,Matches) then
begin
Result := True;
Exit;
end;
end;
EDIT: It does not work at all! :(

riwu

2012-12-25 06:23:38

Hmm if i understand correctly, your first (and only?) problem is that swapping the TPAs will return different result when you expect it to be the same?

Yeah it would indeed be different if you give it a second thought.
Eg.
TPA1:= [Point(1, 1), Point(2, 2)];
TPA2:=[Point(1, 1)];

In this case, TPA2 is a proper subset of TPA1, hence TPA2 can be found in TPA1 but not the other way round. So 'SearchTPA' and 'TotalTPA' are not inter-exchangeable ;)

Shatterhand

2012-12-25 06:31:22

From: riwu
Hmm if i understand correctly, your first (and only?) problem is that swapping the TPAs will return different result when you expect it to be the same?

Yeah it would indeed be different if you give it a second thought.
Eg.
TPA1:= [Point(1, 1), Point(2, 2)];
TPA2:=[Point(1, 1)];

In this case, TPA2 is a proper subset of TPA1, hence TPA2 can be found in TPA1 but not the other way round. So 'SearchTPA' and 'TotalTPA' are not inter-exchangeable ;)

Its one of the problem, but it can be solved if I run the function twice, with different parameter orders.
The other proplem is that the function changes the inputs.

riwu

2012-12-25 06:44:52

From: Shatterhand
Its one of the problem, but it can be solved if I run the function twice, with different parameter orders.
The other proplem is that the function changes the inputs.

Hmm it doesn't change for me:

program new;
var
TPA1, TPA2, match: TPointArray;

begin
TPA1:= [Point(1, 1), Point(2, 2)];
TPA2:= [Point(1, 1)];
FindTPAinTPA(TPA1, TPA2, match);
writeln(TPA1);
writeln(TPA2);
end.

Shatterhand

2012-12-25 06:48:36

From: riwu
Hmm it doesn't change for me:

program new;
var
TPA1, TPA2, match: TPointArray;

begin
TPA1:= [Point(1, 1), Point(2, 2)];
TPA2:= [Point(1, 1)];
FindTPAinTPA(TPA1, TPA2, match);
writeln(TPA1);
writeln(TPA2);
end.

And if you do FindTPAinTPA(TPA2, TPA1, match)? It only changes when it returns False. As yon see on my image.

riwu

2012-12-25 07:02:28

From: Shatterhand
And if you do FindTPAinTPA(TPA2, TPA1, match)? It only changes when it returns False. As yon see on my image.

ah i see the problem…
From the source code:

SearchTPA[I].x := SearchTPA[I].x - SearchBox.x1;
SearchTPA[I].y := SearchTPA[I].y - SearchBox.y1;
SearchTPA is modified in the function, however as it is a value parameter it should not be able to modify the argument out of the function.

Could be to do with the way complex data types behaving as pointers in some cases?

Guess you will have to pass a copy (CopyTPA, but it has no wrapper so you will have to clear it after usage in PS) if you want to keep the input SearchTPA.

Shatterhand

2012-12-25 07:11:46

From: riwu
ah i see the problem…
From the source code:

SearchTPA[I].x := SearchTPA[I].x - SearchBox.x1;
SearchTPA[I].y := SearchTPA[I].y - SearchBox.y1;
SearchTPA is modified in the function, however as it is a value parameter it should not be able to modify the argument out of the function.

Could be to do with the way complex data types behaving as pointers in some cases?

Guess you will have to pass a copy (CopyTPA, but it has no wrapper so you will have to clear it after usage in PS) if you want to keep the input SearchTPA.

Well, I managed to make another function for box matching. But its too slow, so I gave this up. Thanks for the help anyways. :)

riwu

2012-12-25 07:13:23

From: Shatterhand
Well, I managed to make another function for box matching. But its too slow, so I gave this up. Thanks for the help anyways. :)

If you just want to match boxes, why not just compare the bounds of the boxes?

Shatterhand

2012-12-25 07:24:09

From: riwu
If you just want to match boxes, why not just compare the bounds of the boxes?

Yea I did that. Made a TPA from the lines of the boxes, and did a matching function for them. But even for two small boxes, thats like 50-100ms.

riwu

2012-12-25 07:26:15

From: Shatterhand
Yea I did that. Made a TPA from the lines of the boxes, and did a matching function for them. But even for two small boxes, thats like 50-100ms.

What i meant is, don't fill the boxes with TPA, that would indeed be quite slow. Simply compare the boxes's bounds (X1, Y1, X2, Y2).

Shatterhand

2012-12-25 07:29:40

From: riwu
What i meant is, don't fill the boxes with TPA, that would indeed be quite slow. Simply compare the boxes's bounds (X1, Y1, X2, Y2).

Yep I tried that.
function TPAMatch(TPA1, TPA2 : TPointArray): Boolean;
var
i, j : Integer;
begin
Result := False;
for i:=Low(TPA1) to High(TPA2) do
for j:=Low(TPA2) to High(TPA2) do
if ((TPA1[i].x = TPA2[j].x) and (TPA1[i].y = TPA2[j].y)) then
begin
Result := True;
Exit;
end;
end;



function TPAFromBoxBounds(Box : TBox): TPointArray;
var
x, y, i : Integer;
TPA : TPointArray;
begin
i := -1;
SetArrayLength(TPA,(2*(Box.x2-Box.x1)+2*(Box.y2-Box.y1))+4)
for x := Box.x1 to Box.x2 do
begin
Inc(i);
TPA[i] := Point(x,Box.y1);
Inc(i);
TPA[i] := Point(x,Box.y2);
end;
for y := Box.y1 to Box.y2 do
begin
Inc(i);
TPA[i] := Point(Box.x1,y);
Inc(i);
TPA[i] := Point(Box.x2,y);
end;
Result := TPA;
end;



function BoxMatch(Box1, Box2 : TBox): Boolean;
var
TPA1, TPA2 : TPointArray;
Time : Integer;
begin
MarkTime(Time);
TPA1 := TPAFromBoxBounds(Box1);
TPA2 := TPAFromBoxBounds(Box2);
DebugATPA([TPA1,TPA2],'');
Result := TPAMatch(TPA1,TPA2);
Debug('BoxMatch: ' +IntToStr(TimeFromMark(Time)) + 'ms.');
end;

masterBB

2012-12-25 07:34:19

On it.

DannyRS

2012-12-25 12:23:01

From: masterBB
On it.


I've been trying to do the same thing ;) would be amazingly useful, only fast way i found so far was to find one TPA make the bounds a bit larger then run the find colors of the second TPA inside those boxes like what shay suggested in members app :)

Hope we can figure this out

masterBB

2012-12-25 14:57:16

Yeah, it is Christmas here now. It takes two days in the Netherlands. So will have time starting on the 27th.