【问题标题】:Detect wether a point is inside a circle subset in a square检测一个点是否在正方形的圆形子集中
【发布时间】:2016-01-26 22:04:28
【问题描述】:

我需要在网格上的圆圈内绘制图像。

见下图网格/圆。

绿色圆圈是容器,不要在外面绘制图像。

请参见下面的示例。紫色方块 = 未放置,黄色方块 = 放置(因为它们在绿色圆圈内,它们会适合)。

彩色方块代表将要放置的图像。

正方形为 50x50。而网格图块是 100x100。

目前,我的程序将生成圆、网格并在每个网格图块内标记 X,无论它是否在容器圆内。

请参阅下面的程序工作和放置图像的示例。

我怎样才能确定图像是否适合圆圈内的图块。

图块不必 100% 位于圆圈内。见第二张图。查看中心底部的瓷砖。磁贴略微突出了圆圈,但 50x50 的图像仍可放入磁贴内。

请参阅下面将 X 放置在每个网格内的函数。

public function placeImages()
{
    $boxes = 5;
    $circumference = 700;
    $width = ($circumference / $boxes);

    $this->grid = array(
        array(
            'width'  =>
                array(
                    'x1' => 0,
                    'y1' => 0,
                    'x2' => 700,
                    'y2' => 0,
                ),
            'height' =>
                array(
                    'x1' => 0,
                    'y1' => 0,
                    'x2' => 0,
                    'y2' => 700,
                ),
        ),
        array(
            'width'  =>
                array(
                    'x1' => 0,
                    'y1' => 140,
                    'x2' => 700,
                    'y2' => 140,
                ),
            'height' =>
                array(
                    'x1' => 140,
                    'y1' => 0,
                    'x2' => 140,
                    'y2' => 700,
                ),
        ),
        array(
            'width'  =>
                array(
                    'x1' => 0,
                    'y1' => 280,
                    'x2' => 700,
                    'y2' => 280,
                ),
            'height' =>
                array(
                    'x1' => 280,
                    'y1' => 0,
                    'x2' => 280,
                    'y2' => 700,
                ),
        ),
        array(
            'width'  =>
                array(
                    'x1' => 0,
                    'y1' => 420,
                    'x2' => 700,
                    'y2' => 420,
                ),
            'height' =>
                array(
                    'x1' => 420,
                    'y1' => 0,
                    'x2' => 420,
                    'y2' => 700,
                ),
        ),
        array(
            'width'  =>
                array(
                    'x1' => 0,
                    'y1' => 560,
                    'x2' => 700,
                    'y2' => 560,
                ),
            'height' =>
                array(
                    'x1' => 560,
                    'y1' => 0,
                    'x2' => 560,
                    'y2' => 700,
                ),
        ),
        array(
            'width'  =>
                array(
                    'x1' => 0,
                    'y1' => 700,
                    'x2' => 700,
                    'y2' => 700,
                ),
            'height' =>
                array(
                    'x1' => 700,
                    'y1' => 0,
                    'x2' => 700,
                    'y2' => 700,
                ),
        ),
    );

    //This removes the grid item for the bottom and right lines, not needed within the loop.
    array_pop($this->grid);

    foreach ($this->grid as $grid) {
        $x = $grid['width']['x1'];
        $y = $grid['width']['y1'];

        for ($j = 0; $j < $boxes; $j++) {
            $this->drawLine($x, $y, ($x + $width), ($y + $width), '#ff3200');
            $this->drawLine(($x + $width), $y, $x, ($y + $width), '#ff3200');

            //50 × 50 = Image size
            $imageX = floor($x + ($width - 50) / 2);
            $imageY = floor($y + ($width - 50) / 2);;


            $image = Image::make(base_path('test.png'))->opacity(50);

            $this->image->insert($image, 'top-left', $imageX, $imageY);

            $x = $x + $width;
        }
    }
}

上面的代码是我的程序的简化版本。网格数组是动态生成的,但我认为这对这个问题并不重要。

【问题讨论】:

  • 我看到你更新,玩边距。创建一个变量$margin,并重新计算:$width=$width-$margin。玩到你满意为止

标签: php math collision-detection


【解决方案1】:

只要点在圆内,这个方程就满足:

(x - center_x)^2 + (y - center_y)^2

所以你应该在插入图像之前检查它。

对于所有角落,您只需检查其中一个,具体取决于您所在的图表的四分之一。 f.e,右上四分之一,image_x 将是 $x,image_y 将是 $y(不包括宽度并除以 2)。对于左下四分之一,-$x, $-y。

更详细,检查界限。考虑到圆位于 (0,0) 处,半径为 700:

$bounding_x = $x;
$bounding_y = $y;

if($x > 0)
   $bounding_x += width;

if($x < 0)
   $bounding_x -= width;

if($y > 0)
   $bounding_y += width;

if($y < 0)
   $bounding_y -= width;

if ($bounding_x*$bounding_x + $bounding_y*$bounding_y < 490000)
//....insert image

【讨论】:

  • 您需要检查所有四个角。
  • 不完全是,这种方法只会检查正方形的中心。对于所有角落,您只会检查其中一个,具体取决于您所在的图表的四分之一。 f.e,右上四分之一,image_x 将是 $x,image_y 将是 $y(不包括宽度并除以 2)。对于左下四分之一,-$x, $-y。
  • 仅检查中心是不够的(如果您愿意,也可能不准确)。事实上,您可以对四角测试进行微优化。
  • 这似乎没有按预期工作。它只匹配右下角。 i.stack.imgur.com/vvOeV.jpg
  • 490000是怎么计算出来的?
【解决方案2】:

判断一个正方形是否在圆内的基本理论是检查它的四个角是否都在圆内。这适用于您的图块和图像占位符。

圈子的属性

你需要先找到半径(r)和中心(cx,cy)。如果我们认为您的右上角是 (0, 0),那么:

radius = circumference / (pi * 2)    //considering 2(pi)r = circumference

cx, cy = (r, -r)    //your center is r away from the top-right 

检测

现在你应该检查你的数组,看看所有图块的所有角是否都在圆圈内。让我们看看如何检测一个点是否落在圆内。

function withinCircle(x, y) {       

   return ((r - x)*(r - x) + (y - r)*(y - r) < r * r) ;       

}

该函数测试该点的xy 坐标是否在半径之外。您的圆圈在平面的 270-360 范围内这一事实被视为标志。

【讨论】:

  • 您是在正方形内测试点,而不是在圆圈内!
【解决方案3】:

您可以测试正方形的角是否在圆内。 如果正方形的一个顶点是(a,b), 您将无法绘制它是 sqrt(a^2+b^2) > 半径。

这是假设圆心坐标为(0,0),如果不是这样,圆坐标为(x,y),我们需要将所有点移动(-x,- y),在这种情况下,测试是:

sqrt((a-x)^2+(b-y)^2) > 半径。

【讨论】:

  • 你需要考虑圆心。
【解决方案4】:

我假设圆由边界框(0,0)-&gt;(2r,2r) 定义,而正方形为(x1,y1)-&gt;(x2,y2)

执行测试的一种有效方法是检查离中心最远的角是否位于圆内。

if (x1 < r) dx= r - x1; else dx= x2 - r;
if (y1 < r) dy= r - y1; else dy= y2 - r;
if dx * dx + dy * dy <= r * r
    // Wholly inside

【讨论】:

  • 感谢您的回答。我想我的问题可能措辞错误。你能看到我的编辑吗(第三张图片上方的段落)。磁贴不必完全在圆圈内,只要在足够容纳图像的范围内即可。
  • @CharliePrynn 我想你可能读错了我的答案。我没有提到瓷砖,是吗?这些公式适用于任何正方形,实际上是任何矩形。
  • @CharliePrynn - 你的意思是如果瓷砖的单个像素落在圆圈内,它应该被认为是放置的?
  • 如果足够多的图块落在圆圈内以使图像放置在中心,则应视为已放置,正确。
  • 我不确定,不是我。我相信这可能会解决问题,我仍在努力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多