Поиск всех точек в круге в 2D пространстве

Я представляю свое 2D-пространство (рассмотрим окно), где каждый пиксель отображается как ячейка в 2D-массиве. то есть окно 100x100 представлено массивом одинаковых размеров.

Теперь, учитывая точку в окне, если я рисую круг радиуса r, я хочу найти все точки, лежащие в этом круге.

Я думал, что проверю каждую точку в квадратной области вокруг радиуса с side = 2*r, если она лежит в круге или нет. Я могу использовать формулу с нормальным расстоянием?

Следовательно, возможно следующее:

for (x=center-radius ; x<center+radius ; x++){
    for (y=center-radius ; y<center+radius; y++) {
        if (inside) {
            // Do something
        }
    }
}

Будет ли это служить моей цели? Могу ли я сделать это быстрее?

Ответ 1

Будет ли это служить моей цели?

Для вашего 100x100, да.

Могу ли я сделать это быстрее?

Да. Например, вы можете:

  • Проверить только 1 квадрант и получить другие очки из-за симметрии.
  • Пропустите квадратный корень при расчете расстояния.

код:

for (x = xCenter - radius ; x <= xCenter; x++)
{
    for (y = yCenter - radius ; y <= yCenter; y++)
    {
        // we don't have to take the square root, it slow
        if ((x - xCenter)*(x - xCenter) + (y - yCenter)*(y - yCenter) <= r*r) 
        {
            xSym = xCenter - (x - xCenter);
            ySym = yCenter - (y - yCenter);
            // (x, y), (x, ySym), (xSym , y), (xSym, ySym) are in the circle
        }
    }
}

Это примерно 4 раза быстрее.

JS tests для решений, представленных здесь. Симметрия самая быстрая на моем компьютере. Тригонометрия представленная Niet The Dark Absol, очень умна, но включает в себя дорогие математические функции, такие как sin и acos, которые отрицательно влияют на производительность.

Ответ 2

Вы можете обойти необходимость условной проверки:

for(x=center-radius; x<center+radius; x++) {
    yspan = radius*sin(acos((center-x)/radius));
    for(y=center-yspan; y<center+yspan; y++) {
        // (x,y) is inside the circle
    }
}

При необходимости вы можете round(yspan).

Ответ 3

Вы можете получить ускорение, вычислив как можно больше за пределами петель. Также нет необходимости делать квадратный корень теории Пифагора... просто держите все в квадрате. Окончательное ускорение можно сделать, только делая математику на одну четверть круга (потому что она симметрична)... когда совпадение найдено, вы просто копируете его еще три четверти.

radiusSquared = radius*radius;
rightEdge = centerX+radius;
bottomEdge = centerY+radius;
for(x = centerX; x <= rightEdge; x++){
    xSquared = x*x;
    for(y = centerY; y <= bottomEdge; y++){
        ySquared = y*y;
        distSquared = xSquared+ySquared;
        if(distSquared <= radiusSquared){
            // Get positions for the other quadrants.
            otherX = centerX-(x-centerX);
            otherY = centerY-(y-centerY);
            // Do something for all four quadrants.
            doSomething(x, y);
            doSomething(x, otherY);
            doSomething(otherX, y);
            doSomething(otherX, otherY);
        }
    }
}

Ответ 4

Если выполняется следующее:

( ( xPos - centreX)^2 + (yPos - centreY)^2 ) <= radius^2

где xPos и yPos - это координаты точки, которую вы проверяете, тогда точка находится внутри вашего круга.

Ответ 5

кажется правильным. вы можете сделать это немного быстрее, найдя minY, а затем сделав DoSomething от -rangeY до + rangeY для текущего X.

for(dx=0;dx<rad; dx++)
{
  rangeY = 0;
  while (!inside(x, rangeY)) //inside == check if x*x + y*y <r*r
    rangeY++;

  for(y=center-rangeY;y<center+rangeY;y++) 
  {
    DoSomething(centerX - dx, y);
    DoSomething(centerX + dx, y);      }
}

Ответ 6

Чтобы получить список всех точек в круге, вы должны использовать:

var radius = 100, r2 = radius * radius;
var circle = [];
for (var dx = -radius; dx <= radius; dx++) {
  var h = Math.sqrt(r2 - dx * dx) | 0;
  for (var dy = -h; dy <= h; dy++) {
    circle.push([dx, dy])
  }
}

Смотрите http://jsperf.com/circles/2 для профилирования других решений здесь.

Ответ 7

Я знаю, что этот вопрос имеет принятый ответ, но у меня гораздо более легкое решение. Другие ответы смутили меня, поскольку я не знал, что были center, xcenter, ycenter, а математика за функциями осталась необъяснимой, и я отправился искать собственное математическое решение.

Мое уравнение очень просто:

cx - точка x в центре круга

cy является точкой y в центре круга

rad - радиус круга

Что мое уравнение/функция делает, вычисляет точки, вычисляя каждую возможную точку с учетом радиуса и добавляя и вычитая смещение cx и cy.

//Creates an array filled with numbers
function range(begin, end) {
    for (var i = begin, arr = []; i < end; i++) {
      arr.push(i);
    }

    return arr;
}

function calculateAllPointsInCircle(cx, cy, rad) {

   var rang = range(-rad, rad + 1);
   var px = [];
   var py = [];
   var xy = [];

   for (var i = 0; i < rang.length; i++) {
     var x = cx + rang[i];
     px.push(x);

     for (var l - rang.length - 1; l > 0; l--) {
        var y = cy + rang[l];
        if (!py.indexOf(y)===-1) { py.push(y); }

        xy.push(x+','+y);
     }
   }

   return {
     x: x,
     y: y,
     xy: xy
   }
}

Производительность намного выше, чем другие ответы: http://jsperf.com/point-in-circle/4 Вы можете проверить мое уравнение с помощью математики, используя уравнение, которое будет проверять, должна ли данная точка находиться внутри круга x*x + y*y <= r*r ИЛИ x^2 + y^2 <= r^2

Редактировать - Сверхвысокая версия ES6:

function range(begin, end) {
  for (let i = begin; i < end; ++i) {
    yield i;
  }
}

function calculateAllPointsInCircle(cx, cy, rad) {
    return {
        x: [cx + i for (i of range(-rad, rad + 1))],
        y: [cy + i for (i of range(-rad, rad + 1))]
    };
}