我有一个三维空间中的二维平面: x+y+z=1,我想要在这个平面上生成随机点(x,y,z)。如何选择这些点使它们均匀分布?
正如评论中所提到的,该问题未明确说明。尽管如此,这是一个有趣的问题。因为没有给出分布,我只选择了一个。以下是更精确/一般的问题:
假设我有一个平面
P
在R^3
中,由ax + by + cz = d
定义。让
c
是点P
上距离原点最近的点。如何在
c
的某个半径r
内均匀地选择P
上的一个点?
令 n = (a,b,c)
。 n
是垂直于 P
的向量。
生成任意非零向量在平面 ax + by + cz = d
上,称其为 w
。您可以通过将 n
与不平行于 n
的任何非零向量进行叉乘来实现此目的。
在 [0,2pi)
范围内随机旋转 w
,使其绕 n
旋转。您可以使用http://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula来实现。
现在,通过归一化,您已经得到了方向。
direction = direction / direction.magnitude
如果 d
是0,则完成。否则:
根据http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_plane,计算平面到 Vector3(0,0,0)的距离为 c。
翻译射线的起点
origin of the ray = vector3.zero + c * ( n )
比例尺 = 随机范围(最小值,最大值)
这是我实现该算法的 C 代码。我从头开始编写了所有矢量工具,因此有点混乱。我没有彻底测试过这个代码。
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
typedef struct {
double x, y, z;
} vec3;
vec3 vec(double x, double y, double z);
vec3 crossp(vec3 u, vec3 v);
vec3 add(vec3 u, vec3 v);
double dotp(vec3 u, vec3 v);
double norm2(vec3 u);
double norm(vec3 u);
vec3 scale(vec3 u, double s);
vec3 normalize(vec3 u);
void print_vec3(vec3 u);
// generates a random point on the plane ax + by + cz = d
vec3 random_on_plane(double r, double a, double b, double c, double d) {
// The normal vector for the plane
vec3 n = vec(a, b, c);
// create a normal vector on the plane ax + by + cz = 0
// we take any vector not parallel to n
// and find the cross product
vec3 w;
if (n.x == 0)
w = crossp(n, vec(1,0,0));
else
w = crossp(n, vec(0,0,1));
// rotate the vector around n by a random angle
// using Rodrigues' rotation formula
// http://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula
double theta = ((double)rand() / RAND_MAX) * M_PI;
vec3 k = normalize(n);
w = add(scale(w, cos(theta)),
scale(crossp(k, w), sin(theta)));
// Scale the vector fill our disk.
// If the radius is zero, generate unit vectors
if (r == 0) {
w = scale(w, r/norm(w));
} else {
double rand_r = ((double)rand() / RAND_MAX) * r;
w = scale(w, rand_r/norm(w));
}
// now translate the vector from ax + by + cz = 0
// to the plane ax + by + cz = d
// http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_plane
if (d != 0) {
vec3 t = scale(n, d / norm2(n));
w = add(w, t);
}
return w;
}
int main(void) {
int i;
srand(time(NULL));
for (i = 0; i < 100; i++) {
vec3 r = random_on_plane(10, 1, 1, 1, 1);
printf("random v = ");
print_vec3(r);
printf("sum = %f, norm = %f\n", r.x + r.y + r.z, norm(r));
}
}
vec3 vec(double x, double y, double z) {
vec3 u;
u.x = x;
u.y = y;
u.z = z;
return u;
}
vec3 crossp(vec3 u, vec3 v) {
vec3 w;
w.x = (u.y * v.z) - (u.z * v.y);
w.y = (u.z * v.x) - (u.x * v.z);
w.z = (u.x * v.y) - (u.y * v.x);
return w;
}
double dotp(vec3 u, vec3 v) {
return (u.x * v.x) + (u.y * v.y) + (u.z * v.z);
}
double norm2(vec3 u) {
return dotp(u, u);
}
double norm(vec3 u) {
return sqrt(norm2(u));
}
vec3 scale(vec3 u, double s) {
u.x *= s;
u.y *= s;
u.z *= s;
return u;
}
vec3 add(vec3 u, vec3 v) {
u.x += v.x;
u.y += v.y;
u.z += v.z;
return u;
}
vec3 normalize(vec3 u) {
return scale(u, 1/norm(u));
}
void print_vec3(vec3 u) {
printf("%f %f %f\n", u.x, u.y, u.z);
}
Eugene几乎正确:在区间[0,1)上生成两个随机数,分别称为A、B。然后x=min(A,B),y=max(A,B)-x,z=1-(x+y)。基本上,您选择线段[0,1)上的两个点,您的三个坐标是由这两个点定义的三个区间。
a
、b
和c
。但你总是会得到分布在三角形内的点。 - Cris Luengo我先给你一个简单的算法
x = rand()
y = rand()
z = 1 - x - y
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
srand(time(NULL));
int x= ( rand() - rand() ) ;
int y= ( rand() - rand() ) ;
int z=1-x-y;
printf("x=%d y=%d z=%d",x,y,z);
}
只需使用 srand()
来为随机数生成器设定种子,使用 rand()
分配一个随机数。
如果您需要创建指定范围内的随机数,请使用 rand() % ( maxnumber + 1 )
,其中 maxnumber 是您想要的最大值。
如果您希望所有的数字都是正数,则可以尝试以下方法:
int main()
{
srand(time(NULL));
int x, y , z = -1;
while ( z < 0 )
{
x = rand() ;
y = rand() ;
z = 1 - (x + y );
}
printf("x=%d y=%d z=%d",x,y,z);
}
警告
上述代码可能需要一些时间才能执行完毕,因此不要期望立即得到结果。
x
和y
,然后计算z
。 - Eugene Sh.