Search code examples
phpmathcollision-detection

Detect wether a point is inside a circle subset in a square


I need to plot images inside a circle on a grid.

See picture below of grid/circle.

Example of grid

The green circle is the container, no images should be plotted outside.

See example below. Purple squares = not placed, yellow squares = placed (As they're inside the green circle and they will fit).

The coloured squares represent the images that will be placed.

Squares are 50x50. While grid tiles are 100x100.

Example where images should be placed.

Currently, my program will generate the circle, grid and mark the X inside each grid tile, regardless of wether it is inside the container circle.

See below example of program working and placing images.

How could I work out if the image would fit inside the tile that is inside the circle.

The tile does not have to be 100% inside the circle. See the second image. See the tile on the bottom in the centre. The tile slightly protrudes the circle but the image 50x50 can still fit inside the tile.

Please see the function below that places the X inside each grid. Current implementation

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;
        }
    }
}

The code above is a simplified version of my program. The grid array is dynamically generated, but I don't think this matters for this question.


Solution

  • This equation satisfies whenever the point is inside a circle:

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

    So you should check it before inserting the image.

    For all corners you would only check one of them, depending on the quarter of the chart you are. f.e, upper right quarter, image_x would be $x, image_y would be $y (whitout resting the width and dividing by 2). For down left quarter, -$x, $-y.

    More detailed, checking bounds. Considering that the circle is placed at (0,0) and with a radius of 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