给定一个网格,找出哪些方块被半径为 R 的圆形物体占据

Given a Grid, find which Blocks are occupied by a circular object of radius R

提问人:Famosi 提问时间:11/3/2021 更新时间:11/20/2021 访问量:193

问:

从标题中可以猜到,我正在尝试解决以下问题。

给定一个大小为 NxN 的网格和一个半径为 R 的圆形物体 O,中心 C 位于 (x_c, y_c),找出哪些块被 O 占据。

示例如下图所示:

enter image description here

在该示例中,我预计输出为 [1,2,5,6]。

如果有人有建议或资源,我将不胜感激。

几何 网格 语言不可知 机器人

评论


答:

-2赞 Mario Abbruscato 11/5/2021 #1

我使用了 Python3 和 OpenCv,但它可以用任何语言完成。

源:

import cv2
import numpy as np
import math

def drawgrid(im,xv,yv,cx,cy,r):
    #params: image,grid_width,grid_height,circle_x,circle_y,circle_radius
    cellcoords = set() #i use set for unique values 
    h,w,d = im.shape

    #cell width,height
    cew = int(w/xv)
    ceh = int(h/yv)

    #center of circle falls in this cells's coords 
    nx = int(cx / cew )
    ny = int(cy / ceh )
    cellcoords.add((nx,ny))


    for deg in range(0,360,1):
        cirx = cx+math.cos(deg)*r
        ciry = cy+math.sin(deg)*r

        #find cell coords of the circumference point 
        nx = int(cirx / cew )
        ny = int(ciry / ceh )
        cellcoords.add((nx,ny))




    #grid,circle colors
    red = (0,0,255)
    green = (0,255,0)

    #drawing red lines
    for ix in range(xv):
        lp1 = (cew * ix , 0)
        lp2 = (cew * ix , h)
        cv2.line(im,lp1,lp2,red,1)

    for iy in range(yv):
        lp1 = (0 , ceh * iy)
        lp2 = (w , ceh * iy)
        cv2.line(im,lp1,lp2,red,1)

    #drawing green circle
    cpoint = (int(cx),int(cy))
    cv2.circle(im,cpoint,r,green)

    print("cells coords:",cellcoords)


imw=500
imh=500

im  = np.ndarray((imh,imw,3),dtype="uint8")
drawgrid(im,9,5, 187,156 ,50)


cv2.imshow("grid",im)
cv2.waitKey(0)

输出:单元格坐标:{(3, 2), (3, 1), (2, 1), (2, 2), (4, 1)}

cells coords are zero based x,y. 
So ...

1° cell top left is at (0,0) 
2° cell  is at (1,0) 
3° cell  is at (2,0) 

1° cell of 2° row is at (0,1) 
2° cell of 2° row is at (1,1) 
3° cell of 2° row is at (2,1) 
and so on ...

Getting cell number from cell coordinates might be fun for you

enter image description here

评论

1赞 Matt Timmermans 11/20/2021
不适用于非常大的圆圈,不会返回圆盘内部的大多数单元格。也很慢。
0赞 Mario Abbruscato 11/20/2021
显然,如果您需要它们,只需在找到的单元格之间添加单元格即可。为了加快这个过程,你可以在 for 循环语句中使用更大的角度步骤。或者更确切地说,所有那些距离圆心小于圆半径的单元格。
1赞 Matt Timmermans 11/21/2021
实际上,没有一个角度步长可以可靠地完成工作。你总是会错过一个正方形的一角,它戳在两点之间。
0赞 Matt Timmermans 11/20/2021 #2

查找受影响的行范围:

miny = floor(y_c-r);
maxy = ceil(y_c+r)-1;

对于每一行,通过将圆与具有最大交集的水平线相交来找到列的范围。有3种情况:

for (y=miny; y<=maxy; ++y) {
    if (y+1 < y_c)
        ytest = y+1;
    else if (y > y_c)
        ytest = y;
    else
        ytest = y_c;

    // solve (x-x_c)^2 + (ytest-y_c)^2 = r^2
    ydist2 = (ytest-y_c)*(ytest-y_c);
    xdiff = sqrt(r*r - ydist2);
    minx = floor(x_c - xdiff);
    maxx = ceil(x_c + xdiff)-1;

    for (x=minx; x<=maxx; ++x)
        output(x,y);
}