1

単純な 2D グリッドを想像してください。グリッド上のオブジェクトは複数のセルを占めることができます (ただし、点は常に接続されています)。オブジェクトを区別するためだけに文字を使用する次の例を考えてみましょうA(Bオブジェクトが互いに近くに配置される可能性があるため、便利です)。

0 1 2 3 4 5 6 7 8 9 10
1 . . . . . . . . . .
2 . . . . . . . . . .
3 . . . A . . . . . .
4 . . A A A . . B B .
5 . . . A . . . B B .
6 . . . . . . . . . .

新しいオブジェクトをグリッド上に配置し、それらが重ならないようにするアルゴリズムが必要です。したがって、新しいオブジェクト ( で示されるC) を埋め込みたい場合、そのセルのいずれかの座標が既に占有されている場合、アルゴリズムは最も近い空き領域 (点のリスト) を見つけて新しいオブジェクトを割り当てる必要があります。オブジェクト C を、(4, 3)からのセルによって既に占有されている座標に挿入してみましょうA

0 1 2 3 4 5 6 7 8 9 10
1 . . . . . . . . . .
2 . C C . . . . . . .
3 . C C A . . . . . .
4 . . A A A . . B B .
5 . . . A . . . B B .
6 . . . . . . . . . .

ご覧のとおり、オブジェクトはオブジェクトの近くに収まるように移動されましたA。検索は、(方向で指定された) N、E、S、W の順序で占有されたセルの周りから開始し、その後、中央の方向 (NE、SE など) で開始する必要があると想定しています。

このアルゴリズムをどのように実装することをお勧めしますか?

更新: オブジェクトの位置は左上のポイントです。そして、最初に要求された位置と周囲の自由点との間で評価される距離から、最も近い点が取得されます。

4

2 に答える 2

4

可能な変位 (すなわち、シフト) を距離の増加順に反復したいとします。すべての変位は整数であるため、変位の 2 乗は 2 乗の合計である必要があります。次の Python コードは、 x変位ごとに次に考えられるy変位を追跡します。ペアのリストを生成します。各ペアは変位座標を表します。単一のリスト内のすべての要素は、原点から同じ距離にありますが、後のリストからの要素はより大きな距離になります。したがって、少なくとも距離に関しては、内部リストをどの順序でトラバースするかは問題ではありません。それらをランダム化することもできます。

def iter_distance(maxr = 10):
    r = 0
    d = [0]
    while r <= maxr:
        m = maxr*maxr + 1
        for x, y in enumerate(d):
            sq = x*x + y*y
            if sq < m:
                m = sq
                b = []
            if sq == m:
                b.append((x, y))
        for x, y in b:
            d[x] = y + 1
        if b[-1][0] == r:
            r += 1
            d.append(0)
        yield (b +
               [(x, -y) for x, y in b if y] +
               [(-x, y) for x, y in b if x] +
               [(-x, -y) for x, y in b if x*y])

for lst in iter_distance():
    marker = '*'
    for x, y in lst:
        print("{:5} {:5} {:10} {}".format(x, y, x*x + y*y, marker))
        marker = ' '

出力の最初の行は次のようになります。

    0     0          0 *
    0     1          1 *
    1     0          1  
    0    -1          1  
   -1     0          1  
    1     1          2 *
    1    -1          2  
   -1     1          2  
   -1    -1          2  
    0     2          4 *
    2     0          4  
    0    -2          4  
   -2     0          4  
    1     2          5 *
    2     1          5  
    1    -2          5  
    2    -1          5  
   -1     2          5  
   -2     1          5  
   -1    -2          5  
   -2    -1          5  
    2     2          8 *
    2    -2          8  
   -2     2          8  
   -2    -2          8  
    0     3          9 *
    3     0          9  
    0    -3          9  
   -3     0          9  

400 までの距離 (つまり、引数として 400 を渡すmaxr) の場合、37,556 の異なる距離に対して 502,625 行が得られるため、これらをアプリケーションにハードコードするのではなく、その場で生成する必要があります。ただし、これらの番号を使用して、実装を確認することができます.

パフォーマンスが気になる場合は、配列の代わりにプライオリティ キューを使用して、次のように記述できます。

#include <queue>
#include <utility>
#include <cmath>
#include <iostream>
#include <iomanip>

class displacement {
private:
  int _d;
  int _x;
  int _y;
public:
  displacement() : _d(0), _x(0), _y(0) {}
  displacement(int x, int y) : _d(x*x + y*y), _x(x), _y(y) {}
  int x() const { return _x; }
  int y() const { return _y; }
  int sqd() const { return _d; }
  bool operator<(const displacement& d) const { return sqd() > d.sqd(); }
};

static void print2(int x, int y, int sqd) {
  std::cout << std::setw(10) << x << ' '
            << std::setw(10) << y << ' '
            << std::setw(20) << sqd << ' '
            << std::endl;
}

static void print1(int x, int y, int sqd) {
  print2(x, y, sqd);
  if (y)
    print2(x, -y, sqd);
  if (x) {
    print2(-x, y, sqd);
    if (y)
      print2(-x, -y, sqd);
  }
}

int main(int argc, char** argv) {
  int maxr = 400;
  int maxrsq = maxr*maxr;
  std::priority_queue<displacement> q;
  q.push(displacement(0, 0));
  while (q.top().sqd() <= maxrsq) {
    const displacement& d = q.top();
    int x = d.x();
    int y = d.y();
    int sqd = d.sqd();
    print1(x, y, sqd);
    q.pop();
    q.push(displacement(x, y + 1));
    if (x == y) {
      q.push(displacement(x + 1, y + 1));
    }
    else {
      print1(y, x, sqd);
    }
  }
}

この場合、キューには個々の変位が含まれており、結果は同じ距離の個々の変位を任意の (おそらく実装定義の) 順序でリストに収集せずに出力します。指定されたディスプレイスメントのミラー イメージのみがすぐに印刷されます。ここのコードは完全な 8 回対称性を採用しているため、キューに一度に格納される要素の数は、最初の部分を除いて、これまでに生成された最大距離よりもさらに少なくなります。

于 2012-10-16T15:10:52.970 に答える
1

オブジェクトのオーバーラップをチェックするメソッドがあると思いますので、穴の平面と既に配置されているオブジェクトをカプセル化するオブジェクトを定義しPlaneます。オブジェクトが単一のポイントよりも大きい場合に、平面の右下端に配置する場合のように、平面に配置する場合、または平面に収まらない場合。boolean overlaps(Object2D object, Point position)Object2Dposition

@MvGが指摘したように、整数ポイントしかないため、可能な距離の数は限られているため、ポイント間の距離のルックアップテーブルを作成して、この方法でプロセスを高速化します(Javaを想定しています):

    // creates a lookup table with the possible offsets for each possible distance
    static Hashtable<Integer, List<Point>> createLookupPointOffsets(int gridWidth, int gridHeight)
    {
        Hashtable<Integer, List<Point>> l = new Hashtable<Integer, List<Point>>();
        for (int i = 0; i <= gridWidth; i++)
        {
            int i2 = i * i;
            for (int j = 0; j <= gridHeight; j++)
            {
                int sqrDistance = i2 + j * j; // distance^2
                List<Point> ps = l.get(sqrDistance);
                if (ps == null)
                {
                    ps = new List<Point>();
                    l.put(sqrDistance, ps);
                }
                ps.add(new Point(i, j));
            }
        }
    }

このようにして、インデックス付けされた可能な距離のオフセットの 1/4 が得られます。他のものについては、x 軸または y 軸、または両方の軸を介してポイントを反映する必要があります。このインデックス付きオフセットを使用してオブジェクトを配置するための最も近いポイントを評価するには、このメソッドを に追加します。変数は最後のメソッドの結果で初期化されるPlaneと仮定します。mIndexedOffsets

    // returns true if placed the object
    boolean place(Object2D object, Point position)
    {
        if (overlaps(object, position))
        {
            Integer[] distances = new Integer[mIndexedOffsets.keySet().size()];
            distances = mIndexedOffsets.keySet().ToArray(distances);
            // sort the keys in crescent order
            for (int k = 0; k < distances.length - 1; k++)
            {
                for (int l = k + 1; l < distances.length; l++)
                {
                    if (distances[k] > distances[l])
                    {
                        int t = distances[k];
                        distances[k] = distances[l];
                        distances[l] = t;
                    }
                }
            }
            for (int i = 0; i < distances.length; i++)
            {
                List<Point> ps = mIndexedOffsets.get(distances[i]);
                for (int j = 0; j < ps.size(); j++)
                {
                    Point p = ps.get(j);
                    Point newPoint = (Point) position.clone();
                    newPoint.x += p.x;
                    newPoint.y += p.y;
                    if (!overlaps(object, newPoint)
                    {
                        put(object, newPoint);
                        return true;
                    }
                    // test with the reflected points
                    newPoint = (Point) position.clone();
                    newPoint.x -= p.x;
                    newPoint.y += p.y;
                    if (!overlaps(object, newPoint)
                    {
                        put(object, newPoint);
                        return true;
                    }
                    newPoint = (Point) position.clone();
                    newPoint.x += p.x;
                    newPoint.y -= p.y;
                    if (!overlaps(object, newPoint)
                    {
                        put(object, newPoint);
                        return true;
                    }
                    newPoint = (Point) position.clone();
                    newPoint.x -= p.x;
                    newPoint.y -= p.y;
                    if (!overlaps(object, newPoint)
                    {
                        put(object, newPoint);
                        return true;
                    }
                }
            }
        }
        else
        {
            put(object, position); // puts the object in the desired position
            return true;
        }
        return false;
    }

それが役に立てば幸い。

于 2012-10-16T17:13:27.503 に答える