Поиск всех точек внутри окружности в 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
}
}
}
будет ли это служить моей цели? Могу я сделать это быстрее?
7 ответов
будет ли это служить моей цели?
для вашего 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's 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
}
}
}
это около 4X ускорить.
тесты JS для решения представлены здесь. Симметрия-самая быстрая на моем компьютере. Тригонометрия!--28-->представлен Ниет темный Абсол очень умный, но он включает в себя дорогостоящие математические функции, такие как sin
и acos
, которые отрицательно влияют на производительность.
вы можете обойти необходимость условной проверки:
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)
.
вы можете получить ускорение, вычисляя как можно больше за пределами циклов. Также нет необходимости делать квадратный корень из теоремы Пифагора... просто держи все в порядке. Одно окончательное ускорение можно сделать, выполнив математику только для одной четверти круга (потому что она симметрична)... когда совпадение найдено, вы просто повторяете его для других трех четвертей.
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);
}
}
}
Если верно следующее:
( ( xPos - centreX)^2 + (yPos - centreY)^2 ) <= radius^2
здесь xPos
и yPos
являются координатами точки, которую вы проверяете, тогда точка находится внутри вашего круга.
кажется правильным. вы можете сделать это немного быстрее, найдя 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); }
}
для получения списка всех точек в круге, вы должны использовать:
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 для профилирования против других решений здесь.
я знаю, что этот вопрос имеет принятый ответ, но у меня есть гораздо более простое решение. Другие ответы смутили меня, так как я не знал, что 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
Вы можете проверить мое уравнение с помощью math, используя уравнение, которое будет проверять, находится ли данная точка внутри круг x*x + y*y <= r*r
или x^2 + y^2 <= r^2
Edit-супер сжатая версия 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))]
};
}