如何选择半径中包含的最多散点?

时间:2013-07-20 22:19:27

标签: algorithm lua scatter-plot cartesian-coordinates

设置示例

在尝试此问题之前,我已尝试到处寻找问题的解决方案。我的问题是我对数学或统计学不太了解,以便了解任何给定的算法对解决方案都有帮助。

在我的例子中,我看起来像散点图。在笛卡尔坐标平面上随机放置了一堆点。我希望能够在这个平面上绘制一个具有特定半径的圆。 圆圈必须包含可能的最大点数。

我应该采取哪些步骤来计算绘制圆圈的最佳点?

我正在寻找......

我希望我必须采取一系列步骤,以便弄清楚我应该开始绘制的图形(圆圈的中心点)。如果你有代码,我很擅长破译我不一定知道的语言,但我会在Lua中写这个(不幸的是我无法访问C部分)。

我真的想了解解决方案是如何运作的,所以我要感谢任何来源或解释。仅仅为了您的信息,性能非常重要,但我现在正在寻找任何解决方案。

奖金:)

由于我写这篇文章,我想我还可以问一下我希望我的代码能够执行的其他高级功能。但是当我真正踏上门时,我总能想出这些。

  • 距离圆心更远的点比距离更近的点更接近全重。重量可以简单地是线性函数,其中如果半径是10,则距离中心1仅为全重的10%,并且距离中心2,仅为全重的20%。距离中心10分钟将为您提供100%的重量。

  • 引入时间,圆的中心也是图形上的一个点(此点不是其他点的一部分,不应使用它们计算)。圆心以恒定速度移动,你必须选择一个足够靠近中心的点,因为所有点的所有重量随时间衰减。所以绘制圆圈的速度越快越好。 (这是高度理论化的,我不确定衰变会是什么样的。)

非常感谢您阅读本文并考虑我的问题!我可以提供额外的详细信息或回答您可能遇到的任何问题。

2 个答案:

答案 0 :(得分:1)

有一种更快的方法可以找到需要更多数学的最佳圆,并延伸到两个精确点中的第一个。

选择一个覆盖您感兴趣区域的网格,并在此网格中放置1,在此处绘制一个点,将0放在您没有的位置。您现在需要计算网格中每个点的分数。您可以通过将网格中每个点的值乘以一个权重来实现这一点,该权重取决于该点距离您得分的点数,然后将结果相加。这涵盖了您的基本问题(圆圈内的点的权重为1,否则为0)和第一个高级点,其中权重的变化更为渐进。

以这种方式查看问题,您需要一个二维过滤器,您需要将其应用于网格。应用它之后,您只需要在结果中找到最高得分点。以明显的方式执行此操作将非常缓慢,但事实证明,您可以使用快速傅立叶变换来加快这种速度,并且您可以使用数学库来计算它。

如果你没有练习数学或统计学,那么你需要对此进行一个很好的解释 - 比我能做的更好,我很害怕。它完成了很多,但我还没有找到我真正喜欢的解释。您可以查看http://www.analog.com/static/imported-files/tech_docs/dsp_book_Ch24.pdfhttp://archive.gamedev.net/archive/reference/programming/features/imageproc/page2.html中也引用了{{3}}。

答案 1 :(得分:0)

这需要大量的计算/数据,但你可以检查每一点,看看点是否在那里。 不是真正的数学,但它的工作......也不是很快。

我不知道您使用什么引擎来测试代码,但我使用的是LOVE2D。如果不是用于可视化您的解决方案的游戏制作,我强烈推荐它。你可以使用别的东西,这只是个人偏好。如果您对任何LOVE功能有疑问,请访问wiki on the love2d website.

function love.load() 
    points = { { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) }, { math.random( 0, love.graphics.getWidth() ), math.random( 0, love.graphics.getHeight() ) } }

    circles = {}
    for i = 0, love.graphics.getWidth() do
        for ii = 0, love.graphics.getHeight() do
            table.insert( circles, { hits = check_points( i, ii, 20, points ), x = i, y = ii } )
        end
    end
    circs = { { circles[1].hits, circles[1].x, circles[1].y } }
    largest = circs[1][1]

    for i = 1, #circles do
        if circles[i].hits >= largest then
            if circles[i].hits > largest then 
                circs = nil
                circs = {}
                table.insert( circs, { circles[i].hits, circles[i].x, circles[i].y } )
                largest = circs[1][1]
            elseif circles[i].hits == largest then
                local distance = math.sqrt( ( circles[i].x - circs[#circs][2] ) ^ 2 + ( circles[i].y - circs[#circs ][3] ) ^ 2 )
                if distance > 40 then
                    table.insert( circs, { circles[i].hits, circles[i].x, circles[i].y } )
                    largest = circs[1][1]
                end 
            end
        end
    end
end

function love.draw() 
    love.graphics.setColor( 255, 0, 0 )
    for i = 1, #circs do
        love.graphics.circle( 'fill', circs[i][2], circs[i][3], 20 )
    end
    love.graphics.setColor( 255, 255, 255 )
    for i = 1, #points do
        love.graphics.circle( 'fill', points[i][1], points[i][2], 1 )
    end
end

function check_points( x, y, r, ... )
    local hits = 0
    local p = ...
    for i = 1, #p do
        local distance = math.sqrt( ( x - p[i][1] ) ^ 2 + ( y - p[i][2] ) ^ 2 )
        if distance <= r then
            hits = hits + 1
        end
    end
    return hits
end

如果有人有更好,更有时间的解决方案,我想知道。我调查了一些事情,但没有真正奏效。

请注意,这个获得所有可能的分组,而不是圆圈。如果您想获得所有圈子,请删除

elseif circles[i].hits == largest then
    local distance = math.sqrt( ( circles[i].x - circs[#circs][2] ) ^ 2 + ( circles[i].y - circs[#circs ][3] ) ^ 2 )
    if distance > 40 then
        table.insert( circs, { circles[i].hits, circles[i].x, circles[i].y } )
        largest = circs[1][1]
    end 
end

并将其替换为

else
    table.insert( circs, { circles[i].hits, circles[i].x, circles[i].y } )
    largest = circs[1][1]
end

如果你想获得第一个或最后一个,你可以拿出整个

if circles[i].hits >= largest then
    if circles[i].hits > largest then 
        circs = nil
        circs = {}
        table.insert( circs, { circles[i].hits, circles[i].x, circles[i].y } )
        largest = circs[1][1]
    elseif circles[i].hits == largest then
        local distance = math.sqrt( ( circles[i].x - circs[#circs][2] ) ^ 2 + ( circles[i].y - circs[#circs ][3] ) ^ 2 )
        if distance > 40 then
            table.insert( circs, { circles[i].hits, circles[i].x, circles[i].y } )
            largest = circs[1][1]
       end 
   end
end

并将其替换为

if circles[i].hits >= largest then 
    circs = nil
    circs = {}
    table.insert( circs, { circles[i].hits, circles[i].x, circles[i].y } )
    largest = circs[1][1]
end

大于或等于会让你获得最后一个,更大的会让你获得第一个。 你可以建立更多,比如让它选择中间而不是左边的圆圈,或类似的东西。但同样,这不是一个真正的算法,而是更多的“扫描和检查”之类的东西。它始终是最佳解决方案,但是......

您还可以将for循环更改为.5或.25或其他内容。你获得的越小,你获得的精确度就越高,而且所需的时间也就越多。