x, y 및 z 방향으로 0 ~ d 미터 사이에 3D 공간이 있다고 상상해보십시오 (길이 d 의 큐브 ). 이제 이것을 작은 입방체의 3D 배열로 나누고 싶다고 가정 해 봅시다. 우리 는 각 방향으로 n 개의 큐브를 원합니다 . 이는 각 큐브의 길이, 너비 및 높이가 d / n 임을 의미합니다 (d / n이 완벽하게 나눈다 고 가정 할 수 있음). 다음 배열에 보관할 수 있습니다.
Cube* cubes[n][n][n];
이제 반경 r 및 위치 p 의 구를 가질 수 있다고 가정 해 보겠습니다 . 여기서 p 는 3d 공간 내부의 어느 곳이든 가능하고 r 에는 제약 조건이 없습니다. 이 구체와 교차하는 모든 큐브를 찾고 반환하는 가장 효율적인 방법은 무엇입니까?
현재 저는 배열의 모든 큐브를 반복하고 피타고라스 정리를 사용하여 각 큐브와 p 사이의 거리를 확인하고 있으며 아래에 의사 코드를 작성했습니다.
Cube* getIntersectingCubes(r,p) {
Cube* cubes[n][n][n];
Cube* result[];
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
for(int k=0;k<n;k++) {
if(distanceBetween(cubes[i][j][k],p) < r) {
result.add(cubes[i][j][k]);
}
}
}
}
return result;
}
그러나이 작업을 수행하는 더 좋은 방법이 있습니다. 동일한 출력을 반환하지만 가능한 한 적은 수의 큐브를 확인하려면 어떻게해야합니까?
좌표계와 알고리즘을 작업하는 데 여전히 문제가있는 경우 다이어그램으로 시작하십시오.
본질적으로 당신이 가진 것은 큐브의 3D 그리드이며 당신의 포인트 p
는 큐브를 완전히 설명하는 한 당신이 좋아하는 방식으로 선택할 수 있습니다. 결정하려는 것은 반경 r
이 큐브의 일부와 교차하는 큐브에 대한 것입니다. 세 개의 벡터로 처리 할 수 있습니다. 큐브 원점을 벡터로 취급하기 만하면됩니다. 큐브 에서 가장 먼 지점을 결정하기 위해 원점 벡터에 추가 할 수 d / n
있는 두 번째 벡터 ( p
또는 범위라고 함)를 형성하는 데 사용할 수있는 각 큐브 ( ) 의 측면 길이를 알고 p_extent
있습니다. 그래서 p_extent
같을 것이다 d/n
된 I + d/n
J의 +의 d/n
케이 .
좌표를 벡터로 처리하는 데 도움이되는 구조체를 만들 수 있습니다. 예 :
typedef struct {
double x, y, z;
} vect_pos;
두 벡터를 사용하여 간단히 더하기 (예 : p
+ p_extent
)하여 원점에서 큐브의 가장 먼 점을 설명하는 벡터를 형성 할 수 있습니다 . (입방체 내부의 벡터 방향이 원점 벡터와 동일한 부호 방향을 갖기를 원합니다 (그러므로 해당 방향의 단위 벡터로 간단히 곱할 수 있습니다). 예를 들어 점이 -3
i -1
j 및 2
k입니다 . i j k를p_extent
벡터로 곱합니다 . ( 각 8 사분면 의 입방체 원점 벡터와 각 사분면에있는 값을 상상해보십시오 .-1
-1
1
x, y, z
두 개를 더하려면 vector_pos
간단히 벡터 더하기를 사용할 수 있습니다.
/* vector addition */
vect_pos vect_add (const vect_pos *a, const vect_pos *b)
{
vect_pos c = { .x = 0. };
c.x = a->x + b->x;
c.y = a->y + b->y;
c.z = a->z + b->z;
return c;
}
큐브의 모서리에서 좌표를 선택해야하는 마지막 주름은 원점 벡터가 항상 원점에 가장 가까운 모서리를 가리 키지 않는다는 것입니다 (위 다이어그램의 그림에서 p
원점을 시계 반대 방향으로 회전하면 가리키는 위치). 축을 기준으로 90도만큼. (대안은 큐브의 중심을 원점으로 선택하는 것이지만 계산 횟수가 두 배가됩니다).
가장 가까운 모서리 문제는 간단한 확인과 r
가장 가까운 모서리와 가장 먼 모서리 사이 에 있는지 여부를 계산하기 위해 원점의 모서리를 큐브 측면 길이만큼 이동하여 처리 할 수 있습니다 (큐브는 여전히 동일한 큐브 임) 큐브 원점으로 설명 된 가장 먼 모서리에서 벡터 거리 공식을 사용하여 각각 원점으로부터의 거리를 계산할 수 r
있으며 둘 사이에 있으면 구가 해당 큐브와 교차합니다.
거리를 계산하기 전에 원점에 가장 가까운 점을 선택하려면 다음을 사용할 수 있습니다.
/* point in cube closest to origin */
vect_pos closest_pt (const vect_pos *p, const int len)
{
vect_pos c = { p->x >= 0 ? p->x : p->x + len,
p->y >= 0 ? p->y : p->y + len,
p->z >= 0 ? p->z : p->z + len };
return c;
}
( 0, 0, 0
양의면이 있는 원점 에서 큐브를 선택하면 좌표가 음수 인 경우 큐브의 측면 길이를 추가하여 큐브에서 가장 가까운 점을 원점으로 선택하기 만하면됩니다)
거리 계산의 경우 제곱합의 단순 제곱근 :
/* vector distance */
double vect_dist (const vect_pos *p)
{
return sqrt (p->x * p->x + p->y * p->y + p->z * p->z);
}
있는지 확인하려면 r
각 큐브 내에서 가장 가깝고 먼 거리 사이의 폭포는 당신이 핸들 원점으로 같은 방향으로 어느 정도 벡터를 선택하는 간단한 기능을 모두 넣을 수, 벡터를 추가하고 각의 거리를 비교 r
, 예를
/* does r intersect cube at postition p */
int intersect (vect_pos *p, const double r, const int len)
{
vect_pos c = closest_pt (p, len), /* closest pt to origin */
p_extent = { .x = c.x >= 0 ? len : -len, /* length, unit vector */
.y = c.y >= 0 ? len : -len, /* pointing outward */
.z = c.z >= 0 ? len : -len },
p_farthest = vect_add (&c, &p_extent); /* farthest point in cube */
double nearest = vect_dist (&c), /* distance to nearest */
farthest = vect_dist (&p_farthest); /* distance to farthest */
return nearest <= r && r <= farthest; /* return radius in between */
}
그게 기본입니다. 편의상 포인트를 출력하는 짧은 기능을 추가 할 수 있습니다.
void prn_pos (const vect_pos *p)
{
printf ("(% d, % d, % d)\n",
(int)p->x, (int)p->y, (int)p->z);
}
다음, 추가 main()
의 입력을 허용하는 r
, d
그리고 n
그 결과를 출력한다 :
int main (int argc, char **argv) {
double r = argc > 1 ? strtod (argv[1], NULL) : .9; /* r */
int d = argc > 2 ? strtol (argv[2], NULL, 0) : 1, /* d */
n = argc > 3 ? strtol (argv[3], NULL, 0) : d, /* n */
dn = 0, /* d/n */
nc = 0, /* number of cubes in each direction */
total = 0, /* total cubes in search grid */
intersecting = 0; /* number of cubes that intersect sphere */
if (r < 0 || d < 0) { /* validate length inputs */
fputs ("error: negtive length in input of r or d.\n", stderr);
return 1;
}
if (!n || n < 0) { /* validate n not zero or negative */
fputs ("error: n - divide by zero or negative.\n", stderr);
return 1;
}
if (d < r) { /* ensure d >= r */
int min_d = ceil (r);
n *= min_d / d;
d = min_d;
}
if (d % n) { /* validate d equally divisible by n */
fputs ("error: d not equally divisible by n.\n", stderr);
return 1;
}
dn = d / n; /* cube side length */
nc = ceil (r / dn) + 1; /* limit of cubes needed per-direction */
total = nc * nc * nc * 8; /* total number of cubes in search grid */
printf ("\nOut of %d cubes, the following intersect sphere of radius %.2f\n\n",
total, r);
for (int i = -d; i <= d; i += dn) /* loop -d to d */
for (int j = -d; j <= d; j += dn)
for (int k = -d; k <= d; k += dn) {
vect_pos p = { i, j, k }; /* vector to cube origin */
if (intersect (&p, r, dn)) { /* does it intersect sphere? */
prn_pos (&p); /* output cube origin */
intersecting++; /* increment count */
}
}
printf ("\nintersecting cubes: %d\n", intersecting);
}
헤더 추가 :
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
그런 다음 수학 라이브러리에 대한 링크를 컴파일 -lm
하면 테스트 할 작업 프로그램이 있습니다. 에 대한 인수하는 경우 r
, d
또는이 n
코드가 사용이 제공되지 않습니다 .90
, 1
및 1
기본값으로. 루프 제한은 각 차원 에서 최소 -(next int above r)
~ ~ (next int above r)
또는 d
보다 크거나 짧지 않은 값 으로 지정됩니다 r
.
사용 / 출력 예시
r = .9
and d = 1
와 함께 기본 케이스 n = 1
:
$ ./bin/cube-sphere-intersect
Out of 64 cubes, the following intersect sphere of radius 0.90
(-1, -1, -1)
(-1, -1, 0)
(-1, 0, -1)
(-1, 0, 0)
( 0, -1, -1)
( 0, -1, 0)
( 0, 0, -1)
( 0, 0, 0)
intersecting cubes: 8
그리드에 큐브를 그리면 원점을 둘러싼 8 개의 큐브입니다.
선택 r = 5.5
, d = 6
그리고 n = 1
다른 길이되는 큐브의 측면 이외의 동일한 결과를 줄 것이다 :
$ ./bin/cube-sphere-intersect 5.5 6 1
Out of 64 cubes, the following intersect sphere of radius 5.50
(-6, -6, -6)
(-6, -6, 0)
(-6, 0, -6)
(-6, 0, 0)
( 0, -6, -6)
( 0, -6, 0)
( 0, 0, -6)
( 0, 0, 0)
intersecting cubes: 8
r
길이를 exacly로 입력하면 1
여기 r
에서 최소 또는 최대 길이와 같은 것으로 간주할지 여부를 선택할 수 있습니다. 큐브 정말이 점으로 거리를 알아,하지만 말을 동등하게 좋은 인수가 있음을 접선에 거짓말을 기술적으로합니다 교차 의미하지 않는다 "감동"말의 인수가 있습니다 그 교차 (사용할지 여부의 선택 <=
또는 <
비교에서 당신에게 맡겨져 있습니다)
예를 들어 1.0 < sqrt(2)
( 1.414...
) 사이에 입력 하면 32 개의 큐브가 교차합니다.
$ ./bin/cube-sphere-intersect 1.1
Out of 216 cubes, the following intersect sphere of radius 1.10
(-2, -1, -1)
(-2, -1, 0)
(-2, 0, -1)
(-2, 0, 0)
(-1, -2, -1)
(-1, -2, 0)
(-1, -1, -2)
(-1, -1, -1)
(-1, -1, 0)
(-1, -1, 1)
(-1, 0, -2)
(-1, 0, -1)
(-1, 0, 0)
(-1, 0, 1)
(-1, 1, -1)
(-1, 1, 0)
( 0, -2, -1)
( 0, -2, 0)
( 0, -1, -2)
( 0, -1, -1)
( 0, -1, 0)
( 0, -1, 1)
( 0, 0, -2)
( 0, 0, -1)
( 0, 0, 0)
( 0, 0, 1)
( 0, 1, -1)
( 0, 1, 0)
( 1, -1, -1)
( 1, -1, 0)
( 1, 0, -1)
( 1, 0, 0)
intersecting cubes: 32
그런 다음 반경에 sqrt(2) <= sqrt(3)
대해 56 큐브 교차 등을 찾을 수 있습니다.
이것은 그것을 구현하는 한 가지 방법 일뿐입니다. 궁금하다면 각 큐브의 중심을 큐브의 원점으로 사용하도록 다시 작성하십시오. 구조체를 사용할 필요가 없으며 각각에 대해 x, y, z
직접 작업 할 수 있지만 구조체는 논리를 명확하게 유지하는 데 도움이됩니다. 자세히 살펴보고 추가 질문이 있으면 알려주세요.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다