Распределение точек по поверхности внутри границ - PullRequest
2 голосов
/ 03 января 2011

Меня интересует способ (алгоритм) распределения заранее определенного числа точек по 4-сторонней поверхности, например, квадрат.

Основная проблема заключается в том, что каждая точка должна иметь минимум и максимумблизость друг к другу (случайно между двумя предопределенными значениями).По сути, расстояние между любыми двумя точками не должно быть ближе, чем, скажем, к 2, и больше, чем 3.

Мой код будет реализован в ruby ​​(точки - это местоположения, поверхность - карта), но любаяидеи или отрывки определенно приветствуются, поскольку все мои идеи включают в себя достаточное количество грубой силы.

Ответы [ 4 ]

4 голосов
/ 03 января 2011

Попробуйте этот документ .Он имеет хороший, интуитивно понятный алгоритм, который делает то, что вам нужно.

В нашей модели мы приняли другую модель: мы считаем, что каждый центр связан со всеми своими соседями отталкивающей строкой.

В начале моделирования центры распределяются случайным образом, а также сильные стороны струн.Мы выбираем случайным образом переместить один центр;затем мы вычисляем результирующую силу, вызванную всеми соседями данного центра, и вычисляем смещение, которое пропорционально и ориентировано в смысле результирующей силы.

После определенного числа итераций (которое зависит отчисло центров и степень начальной случайности) система становится стабильной.

Если из рисунков не ясно, этот подход генерирует равномерно распределенные точки.Вместо этого вы можете использовать силу, которая равна нулю внутри ваших границ (например, между 2 и 3) и ненулевой в противном случае (отталкивающая, если точки слишком близки, привлекательная, если слишком далеко).

Реализация на Python (извините, я не знаю ruby).Просто импортируйте это и вызовитеiform (), чтобы получить список точек.

import numpy as np
from numpy.linalg import norm
import pylab as pl

# find the nearest neighbors (brute force)
def neighbors(x, X, n=10):
  dX = X - x
  d = dX[:,0]**2 + dX[:,1]**2
  idx = np.argsort(d)
  return X[idx[1:11]]

# repulsion force, normalized to 1 when d == rmin
def repulsion(neib, x, d, rmin):
  if d == 0:
    return np.array([1,-1])

  return 2*(x - neib)*rmin/(d*(d + rmin))

def attraction(neib, x, d, rmax):
  return rmax*(neib - x)/(d**2)

def uniform(n=25, rmin=0.1, rmax=0.15):
  # Generate randomly distributed points
  X = np.random.random_sample( (n, 2) )

  # Constants
  # step is how much each point is allowed to move
  #   set to a lower value when you have more points
  step = 1./50.

  # maxk is the maximum number of iterations
  #   if step is too low, then maxk will need to increase
  maxk = 100

  k = 0

  # Force applied to the points
  F = np.zeros(X.shape)

  # Repeat for maxk iterations or until all forces are zero
  maxf = 1.
  while maxf > 0 and k < maxk:
    maxf = 0
    for i in xrange(n):
      # Force calculation for the i-th point
      x = X[i]
      f = np.zeros(x.shape)

      # Interact with at most 10 neighbors
      Neib = neighbors(x, X, 10)

      # dmin is the distance to the nearest neighbor
      dmin = norm(Neib[0] - x)

      for neib in Neib:
        d = norm(neib - x)
        if d < rmin:
          # feel repulsion from points that are too near
          f += repulsion(neib, x, d, rmin)
        elif dmin > rmax:
          # feel attraction if there are no neighbors closer than rmax
          f += attraction(neib, x, d, rmax)

      # save all forces and the maximum force to normalize later
      F[i] = f
      if norm(f) <> 0:
        maxf = max(maxf, norm(f))

    # update all positions using the forces
    if maxf > 0:
      X += (F/maxf)*step

    k += 1

  if k == maxk:
    print "warning: iteration limit reached"

  return X
1 голос
/ 04 января 2011

Я мог бы попробовать сделать это наугад, затем пройти и отбросить точки, которые должны быть близки к другим точкам.Вы можете сравнить квадрат расстояния, чтобы сэкономить математическое время.

Или создайте ячейки с границами и поместите точку в каждую.Менее случайный, это зависит от того, является ли это «просто для внешности» или нет.Но это может быть очень быстро.

1 голос
/ 03 января 2011

Я предполагаю, что одна из ваших идей о грубой силе включает в себя просто многократное генерирование точек случайным образом и проверку, чтобы убедиться, что ограничения оказываются выполненными.

Другой способ - взять конфигурацию, которая удовлетворяет ограничениям, и многократно возмущать небольшую ее часть, выбранную случайным образом, например, перемещать одну точку, чтобы перейти к случайно выбранной конфигурации поблизости. Если вы делаете это достаточно часто, вам следует перейти к произвольной конфигурации, которая практически не зависит от начальной точки. Это может быть оправдано под http://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm или http://en.wikipedia.org/wiki/Gibbs_sampling.

0 голосов
/ 05 января 2011

Я пошел на компромисс и в итоге использовал метод сэмплирования Пуассона.

Результат был довольно близок к тому, что мне было нужно, особенно при меньшем количестве попыток (что также резко снижает стоимость).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...