4

エッジで折り返すことができる長方形のグリッドを作成しようとしています。ビデオゲームをプレイする人なら誰でも、おそらくこの概念に精通しているでしょう。世界地図上で一方向に十分に進むと、最初の場所に戻ることになります。ただし、エッジが負の座標領域にスクロールする可能性があるため、ビューポートの設定が困難になります。

負の座標を取り、その実際の値を決定するのは簡単です。

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

ここで、AddPointsとModPointsは、2つの入力の各座標にそれぞれ+と演算子を適用して、出力値を生成します。mod

問題は、この操作を逆にすることです。両方の座標が正である点と、上と左の値が正または負になる可能性のあるTRect(および下または右がマップの端を超えている可能性がある)が与えられ、MAP_SIZEがグローバルスコープで宣言されている場合、同じ計算を最大4回実行しなくても、ポイントが表示長方形でカバーされている領域内にあるかどうかを判断する方法はありますか?

4

3 に答える 3

4

そう信じる。

私が考えることができる最悪のケース(grid = [0,1)x [0,1))はこれです:Top = -0.25、Left = -0.25、Bottom = 0.25、Right = 0.25

これは(ラップされたとき)のように見えます:

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

今のところ、ポイントがそれらの内側にあるかどうかを確認するために、4つのコーナーをテストする必要があります。ただし、[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を追加し、それが新しいrect内にあるかどうかをテストします。

TestNew=AddPoints(Test,MAP_SIZE)

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

私はこれを徹底的にテストしていませんが、現在は正しいと信じています。

于 2009-07-12T02:10:16.427 に答える
3

これにより、ポイントが長方形内にあるかどうかをテストできます。

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;
于 2009-07-12T02:17:45.073 に答える
0

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);
}
于 2009-07-13T08:33:33.867 に答える