문제

가장자리를 둘러쌀 수 있는 직사각형 격자를 만들려고 합니다.비디오 게임을 하는 사람이라면 누구나 다음 개념에 익숙할 것입니다.세계 지도에서 한 방향으로 충분히 이동하면 시작한 곳으로 다시 돌아올 수 있습니다.하지만 가장자리가 음의 좌표 영역으로 스크롤될 수 있으므로 뷰포트를 설정하는 데 약간의 어려움이 발생합니다.

음의 좌표를 취해 실제 값을 결정하는 것은 쉽습니다.

function GetRealCoords(value: TPoint): TPoint;
begin
   result := ModPoints(AddPoints(value, MAP_SIZE), MAP_SIZE);
end;

여기서 AddPoint와 ModPoint는 단순히 + 그리고 mod 연산자를 각각 두 입력의 각 좌표에 연결하여 출력 값을 생성합니다.

문제는 이 작업을 취소하는 것입니다.두 좌표가 모두 양수이고 위쪽 및 왼쪽 값이 양수 또는 음수일 수 있고(아래쪽 또는 오른쪽이 지도 가장자리 너머에 있을 수 있음) TRect가 전역 범위에서 선언된 MAP_SIZE를 사용하는 점은 다음과 같습니다. 동일한 계산을 최대 4번까지 실행할 필요 없이 점이 보기 직사각형으로 덮힌 영역 내에 있는지 여부를 확인할 수 있는 방법이 있습니까?

도움이 되었습니까?

해결책

이를 통해 포인트가 사각형 내에 있는지 테스트 할 수 있습니다.

function PointInRect(aPoint:TPoint;aRect:TRect):boolean;
begin
  Result:=(aPoint.X >= aRect.Left  ) and 
          (aPoint.X <  aRect.Right ) and 
          (aPoint.Y >= aRect.Top   ) and 
          (aPoint.Y <  aRect.Bottom);
end;

그러나 설명을 올바르게 이해하면 다음과 같은 것을 원합니다.

function NormalisePoint(aPoint:TPoint;aRect:TRect):TPoint;
var Width,Height:integer;
begin
  Width  := aRect.Right-aRect.Left;
  Height := aRect.Bottom-aRect.Top;

  if (Width=0) then
    aPoint.X := aRect.Left
  else
  begin
    while (aPoint.X< aRect.Left  ) do inc(aPoint.X,Width );
    while (aPoint.X>=aRect.Right ) do dec(aPoint.X,Width );
  end;

  if (Height=0) then
    aPoint.Y := aRect.Top
  else
  begin
    while (aPoint.Y< aRect.Top   ) do inc(aPoint.Y,Height);
    while (aPoint.Y>=aRect.Bottom) do dec(aPoint.Y,Height);
  end;
  Result := aPoint;
end;

다른 팁

나는 그렇다고 믿는다.

(grid=[0,1)x[0,1) ) 내가 생각할 수 있는 최악의 경우는 다음과 같습니다.위쪽=-0.25, 왼쪽=-0.25, 아래쪽=0.25, 오른쪽=0.25

(포장했을 때) 다음과 같습니다.

 ______
|_|  |_|
|      |
|_    _|
|_|__|_|

지금은 네 모퉁이를 테스트하여 점이 그 안에 있는지 확인해야 합니다.그러나 나는 [1,2) x [1,2) 공간에서 테스트를 수행함으로써 문제를 피할 수 있다고 생각합니다. 다시 한 번 사각형이되기 때문입니다.

 ______
|      |
|      |
|     _|_
|____|   |
     |___|

직사각형의 너비와 높이를 계산하여 문제를 단순화합니다.

Width=Mod(Right-Left+MAP_SIZE,MAP_SIZE)
Height=Mod(Bottom-Top+MAP_SIZE,MAP_SIZE)

이제 왼쪽 상단의 래핑된 위치를 계산합니다.

LeftNew=Mod(Left+MAP_SIZE,MAP_SIZE)
TopNew=Mod(Top+MAP_SIZE,MAP_SIZE)

새로운 아래쪽과 오른쪽을 계산합니다.

RightNew=LeftNew+Width
BottomNew=TopNew+Height

이제 테스트하려는 모든 포인트에 대해 MAP_SIZE를 추가하고 새 사각형 안에 있는지 테스트하세요!

TestNew=AddPoints(Test,MAP_SIZE)

If (TestNew.X>=LeftNew && TestNew.X<=RightNew && TestNew.Y>=TopNew && TestNew.T<=BottomNew)
{
  We have a point inside!
}

나는 이것을 철저하게 테스트하지는 않았지만 현재는 그것이 정확하다고 믿습니다.

2차원으로 작업하기 전에 1차원으로 생각해 보세요.숫자가 둘러싸일 수 있는 범위에 있는지 확인하고 싶습니다.시계의 7에서 2 사이의 3입니다.그런 다음 X 및 Y 좌표 모두에 대한 테스트를 수행할 수 있습니다.

더 간단한 문제에 대한 나의 해결책은 다음과 같습니다.

//assumes start and end are both in [0, divisor). (Because .net and most other languages do modulus WRONG.)
double ClockDistance(double start, double end, double clockSize) {
    return (end - start + clockSize) % clockSize;
}
//assumes inclusive bounds
bool ClockBetween(int n, double start, double end, double clockSize) {
    return ClockDistance(start, n, clockSize) 
           <= ClockDistance(start, end, clockSize);
}

일반화하면 다음과 같습니다.

//assumes rects oriented so bottom < top, not the other way around like in UI
bool RectContains(double x, double y, double left, double bottom, double right, double top, double worldWidth, double wordlHeight) {
    return ClockBetween(x, left, right, worldWidth) 
           && ClockBetween(y, bottom, top, worldHeight);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top