Recent

Author Topic: Distance between two rectangles  (Read 2278 times)

Tomi

  • Full Member
  • ***
  • Posts: 125
Distance between two rectangles
« on: July 13, 2023, 05:11:58 pm »
Hello everybody!

I would like calculate the distance between two rectangle-shaped objects. I need the distance between nearest edges of these objects.
I already made a code for this before and this code worked well in Game Maker between two 32x32 size rectangles, until I resized one of these or both rectangles and I don't know, what is causing the error?
In Lazarus, this code is not works correctly, because often gives false values.
If somebody see the error in my piece of code or know a better solution, please publish it here for me. It would be big help for me and maybe other programmers.

Code: Pascal  [Select][+][-]
  1. function pointdistance(x1: integer; y1: integer; x2: integer; y2: integer): double;
  2. begin
  3.   pointdistance:=sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
  4. end;
  5.  
  6. function distance(x1: word; y1: word; w1: word; h1: word; x2: word; y2: word; w2: word; h2: word): double;
  7. var collisionvalue: boolean;
  8. begin
  9.  collisionvalue:=(abs(x1-x2)*2<(w1+w2)) and (abs(y1-y2)*2<(h1+h2));
  10.  if collisionvalue=true then
  11.     distance:=0
  12.  else
  13.  begin
  14.         if (x2>x1+w1) and (y2+h2<y1) then // Up right:
  15.             distance:=pointdistance(x1+w1,y1,x2,y2+h2)
  16.         else
  17.         if (x2>x1+w1) and (y2>y1+h1) then // Down right:
  18.             distance:=pointdistance(x1+w1,y1+h1,x2,y2)
  19.         else
  20.         if (x2+w2<x1) and (y2+h2<y1) then // Up left:
  21.             distance:=pointdistance(x1,y1,x2+w2,y2+h2)
  22.         else
  23.         if (x2+w2<x1) and (y2>y1+h1) then // Down left:
  24.             distance:=pointdistance(x1,y1+w1,x2+h2,y2)
  25.         else
  26.         if x2>x1+w1 then // Right:
  27.             distance:=x2-(x1+w1)
  28.         else
  29.         if x2+w2<x1 then // Left:
  30.             distance:=x1-(x2+w2)
  31.         else
  32.         if y2+h2<y1 then // Up:
  33.             distance:=y1-(y2+h2)
  34.         else
  35.         if y2>y1+h1 then // Down:
  36.             distance:=y2-(y1+h1);
  37.  end;
  38. end;

Handoko

  • Hero Member
  • *****
  • Posts: 5208
  • My goal: build my own game engine using Lazarus
Re: Distance between two rectangles
« Reply #1 on: July 13, 2023, 08:48:51 pm »
This should work:

Code: Pascal  [Select][+][-]
  1. function Distance(x1, y1, w1, h1, x2, y2, w2, h2: Integer): Double;
  2. begin
  3.   Result := 0;
  4.   if (x1 < x2+w2) and (x2 < x1+w1) and (y1 < y2+h2) and (y2 < y1+h1) then
  5.     Exit;
  6.   if (x2>x1+w1) and (y2+h2<y1) then // Up right:
  7.     Result := pointdistance(x1+w1,y1,x2,y2+h2)
  8.   else
  9.   if (x2>x1+w1) and (y2>y1+h1) then // Down right:
  10.     Result := pointdistance(x1+w1,y1+h1,x2,y2)
  11.   else
  12.   if (x2+w2<x1) and (y2+h2<y1) then // Up left:
  13.     Result := pointdistance(x1,y1,x2+w2,y2+h2)
  14.   else
  15.   if (x2+w2<x1) and (y2>y1+h1) then // Down left:
  16.     Result := pointdistance(x1,y1+w1,x2+h2,y2)
  17.   else
  18.   if x2>x1+w1 then // Right:
  19.     Result :=x2-(x1+w1)
  20.   else
  21.   if x2+w2<x1 then // Left:
  22.     Result := x1-(x2+w2)
  23.   else
  24.   if y2+h2<y1 then // Up:
  25.     Result := y1-(y2+h2)
  26.   else
  27.   if y2>y1+h1 then // Down:
  28.     Result := y2-(y1+h1);
  29. end;

For performance reason you should always use Integer instead of Word, especially on 64-bit system.

~ edit ~
I found a bug in your collision detection calculation. For other bugs, see Eugene Loza's post below.
« Last Edit: July 13, 2023, 08:58:44 pm by Handoko »

Eugene Loza

  • Hero Member
  • *****
  • Posts: 690
    • My games in Pascal
Re: Distance between two rectangles
« Reply #2 on: July 13, 2023, 08:53:27 pm »
Quote
because often gives false values.
Try to debug and see when exactly this happens.
E.g. you have a typo in this line:
Code: Pascal  [Select][+][-]
  1. Result := pointdistance(x1,y1+w1,x2+h2,y2)
should be h1, not w1 and w2 not h2 - if I understood your notation correctly.
There can be others less obvious errors, but just make sure that all of the conditions work as you expect them - test them one-by-one and note if the output is right.

EDIT: I also don't see how you treat "=" conditions. It may so happen that you fall through all the conditions without any of those firing.
« Last Edit: July 13, 2023, 08:58:35 pm by Eugene Loza »
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

Handoko

  • Hero Member
  • *****
  • Posts: 5208
  • My goal: build my own game engine using Lazarus
Re: Distance between two rectangles
« Reply #3 on: July 13, 2023, 08:56:19 pm »
+1 for Eugene Loza

Tomi

  • Full Member
  • ***
  • Posts: 125
Re: Distance between two rectangles
« Reply #4 on: July 14, 2023, 02:19:58 pm »
Thank you both for your helpful reply!
I have remove the 'collisionvalue' line from the code and changed to Handoko's piece of code and I corrected the typo as Eugene Loza suggested. It seems, now the function gives correct values without errors.
Otherwise, I tried another method, but it showed slightly different values:

Code: Pascal  [Select][+][-]
  1. bigrectanglex1:=min(x1,x2);
  2. bigrectangley1:=min(y1,y2);
  3. bigrectanglex2:=max(x1+w1,x2+w2);
  4. bigrectangley2:=max(y1+h1,y2+h2);
  5. xdist:=(bigrectanglex2-bigrectanglex1)-(w1+w2);
  6. ydist:=(bigrectangley2-bigrectangley1)-(h1+h2);
  7. innerrectx1:=max(x1,x2)-xdist;
  8. innerrecty1:=max(y1,y2)-ydist;
  9. innerrectx2:=max(x1,x2);
  10. innerrecty2:=max(y1,y2);
  11. distance:=pointdistance(innerrectx1,innerrecty1,innerrectx2,innerrecty2);

It is based on this Google suggestion:
"Combine the two rectangles into one large rectangle. Subtract from the large rectangle the first rectangle and the second rectangle. What is left after the subtraction is a rectangle between the two rectangles, the diagonal of this rectangle is the distance between the two rectangles."

Kays

  • Hero Member
  • *****
  • Posts: 586
  • Whasup!?
    • KaiBurghardt.de
Re: Distance between two rectangles
« Reply #5 on: July 14, 2023, 05:20:38 pm »
Is there a reason you don’t simply use
  • tRect.intersectsWith for “collision detection” and
  • ((A + B).size − A.size − B.size).distance for distance between non-intersecting tRects?
I mean yes, it’s not fully documented, but other than that?
Yours Sincerely
Kai Burghardt

Guva

  • Jr. Member
  • **
  • Posts: 90
Re: Distance between two rectangles
« Reply #6 on: July 15, 2023, 06:06:40 am »
There is a good library . 90 % covers all desires
http://www.partow.net/projects/fastgeo/index.html

Tomi

  • Full Member
  • ***
  • Posts: 125
Re: Distance between two rectangles
« Reply #7 on: July 15, 2023, 03:24:19 pm »
Is there a reason you don’t simply use
  • tRect.intersectsWith for “collision detection” and
  • ((A + B).size − A.size − B.size).distance for distance between non-intersecting tRects?
I mean yes, it’s not fully documented, but other than that?
:o
I've never heard of this function before... but it looks good too. Unfortunately, my FreePascal knowledge is not very detailed yet. Thank you very much for bringing it to my attention; I will try it out.

wp

  • Hero Member
  • *****
  • Posts: 12027
Re: Distance between two rectangles
« Reply #8 on: July 15, 2023, 06:51:23 pm »
I would like calculate the distance between two rectangle-shaped objects. I need the distance between nearest edges of these objects.
What do you understand as "distance between nearest edges"? Since your code calculates the distance between points, I guess you do not mean the distance between "edges" but between "corner points", such as the line AC in the attached drawing. This is ok, when, like for collision detection, you need the closest distance between points on the rectangle borders. But what in case of rectangles A and B for which the vertical dimensions overlap? Their closest distance is the distance between the right edge of rect A and the left edge of rect B (line ABn), but not the closest distance between corner points (line AB).

 

TinyPortal © 2005-2018