椭圆体的交点体积

时间:2016-01-26 10:59:22

标签: matlab rotation

我用椭球函数绘制两个椭圆体,并使用旋转手柄。为了计算交叉点体积(即透镜)和椭圆体之间没有旋转的交叉体积的情况,我使用了球体交叉体积的分析代码。 但是我被卡住了,如果椭圆体处于某些旋转状态,我将如何计算它们之间的交叉体积(即,间距)。我还需要计算交叉点直径。镜头 椭球相对于沿z轴的最大轴具有不同的旋转角度。这是一个代码:

 draw ellipsoid, [x,y,z] = ellipsoid(xc,yc,zc,xr,yr,zr,n);
 (xc,yc,zc)=center; semi-axis lengths = (Fmax,Fmin,Fmin);n
X=[0,2];  two ellipsoid x coordinates  i.e 0 is first ellipsoid
           and 2 is second ellipsoid respectively
Y=[0,2];   two ellipsoid y coordinates
Z=[0,2];   two ellipsoid z coordinates;
ROTATIONANGLE=[90,30];
RMIN=[1,2];  two ellipsoid minor axis radius 
RMAX=[3,5];  two ellipsoid major axis radius.
for a = 1:2  display ellipsoid
        [x, y, z] = ellipsoid(X(a),Y(a),Z(a),RMIN(a),RMAX(a),3.25,30);
S = surfl(x, y, z);
    rotate(S,[0,0,1],ROTATIONANGLE(a))
colormap copper
axis equal
xlabel('X')
ylabel('Y')`enter code here
zlabel('Z')
check the boolean condition 
hold on
end

1 个答案:

答案 0 :(得分:1)

据我所知,Matlab中没有这样的功能。我会使用Monte Carlo method来找到交叉点的近似体积。

您需要从某个框中生成随机点,并检查它们是否属于交叉点。你可以算出有多少分落入交叉点。知道了盒子的体积,落入交叉点的点数以及生成点的总数,就可以计算出所需的体积。

在图片上你可以看到交叉点内的红点:

Monte Carlo method to find volume of the intersection

找到一些足以解决问题的迭代非常重要。我通过计算一个小椭圆体的体积来验证该方法,这个椭球体放在一个较大的体内。在这种情况下,交点是一个小椭球本身,其体积可以通过分析找到。

您可以在下一张图片上看到相对误差作为迭代次数的函数:

Relative error of the Monte Carlo method

以下是代码:

该代码仅适用于围绕Z轴的旋转

X=[0,2];   %two ellipsoid x coordinates
Y=[0,2];   %two ellipsoid y coordinates
Z=[0,2];   %two ellipsoid z coordinates
ROTATIONANGLE=[90,30];
AXIS_A=[1,2];  %two ellipsoid minor axis radius 
AXIS_B=[3,5];  %two ellipsoid major axis radius
AXIS_C=[3.25,3.25];  %two ellipsoid major axis radius

ranges = zeros(3, 2);

do_plot = 1; %either plot ellipsoids or not

step_number = 100000;

for i = 1:2  %display ellipsoid

    if (do_plot == 1)
        [x, y, z] = ellipsoid(X(i),Y(i),Z(i),AXIS_A(i),AXIS_B(i),AXIS_C(i),20);
        S = surf(x, y, z);
        alpha(.1);
        rotate(S,[0,0,1], ROTATIONANGLE(i), [X(i),Y(i),Z(i)]);
    end

    %calculate the ranges for the simulation box
    ranges(1, 1) = min(ranges(1, 1), X(i) -   max(AXIS_A(i), AXIS_B(i))  );
    ranges(1, 2) = max(ranges(1, 2), X(i) +   max(AXIS_A(i), AXIS_B(i))  );

    ranges(2, 1) = min(ranges(2, 1), Y(i) -   max(AXIS_A(i), AXIS_B(i))  );
    ranges(2, 2) = max(ranges(2, 2), Y(i) +   max(AXIS_A(i), AXIS_B(i))  );

    ranges(3, 1) = min(ranges(3, 1), Z(i) - AXIS_C(i));
    ranges(3, 2) = max(ranges(3, 2), Z(i) + AXIS_C(i));

    if (do_plot == 1)
        hold on;
    end
end

counter = 0; %how many points targeted the intersection

for i = 1:step_number

    R = rand(3, 1).*(ranges(:, 2) - ranges(:, 1)) + ranges(:, 1); %a random point

    n = 1;
    val = calc_ellipsoid( R(1), R(2), R(3), X(n),Y(n),Z(n),AXIS_A(n),AXIS_B(n),AXIS_C(n),ROTATIONANGLE(n)*pi/180);

    if (val <= 1.0)
        n = 2;
        val = calc_ellipsoid( R(1), R(2), R(3), X(n),Y(n),Z(n),AXIS_A(n),AXIS_B(n),AXIS_C(n),ROTATIONANGLE(n)*pi/180);

        if (val <= 1.0)

            if (do_plot == 1)
                plot3(R(1), R(2), R(3), 'or', 'MarkerSize', 1, 'MarkerFaceColor','r');
            end

            counter = counter + 1;
        end
    end

end

cube_vol = 1; %the volume of the simulation box
for i=1:3
    cube_vol = cube_vol * (ranges(i, 2) - ranges(i, 1));
end

%approximated volume of the intersection
section_vol = cube_vol * counter / step_number;

display(['Cube volume: ', num2str(cube_vol)]);
display(['Targeted points: ', num2str(counter), ' from ', num2str(step_number)]);
display(['Section volume: ', num2str(section_vol)]);

if (do_plot == 1)
    hold off;
end

查找点是否属于椭圆体的函数(如果val是&lt; = 1.0),则执行此操作:

function [ val ] = calc_ellipsoid( x, y, z, x0, y0, z0, a, b, c, theta)

    x_cmp = ((x - x0)*cos(theta) + (y - y0)*sin(theta))^2   /(a^2);
    y_cmp = ((x - x0)*sin(theta) - (y - y0)*cos(theta))^2   /(b^2);
    z_cmp = (z - z0)^2 / (c^2);

    val = x_cmp + y_cmp + z_cmp;
end

<强>更新

为了找到共同身体的最大轴,您可以执行以下操作:

  1. 保存所有落入数组交叉点的点(代码中为R_arr

  2. 从结果数组中构造一个凸包:

    [K, v] = convhull(R_arr(:, 1), R_arr(:, 2), R_arr(:, 3));

    它将为您提供一个近似的体积v和用于构建船体的点的索引K

  3. 现在您有一个点的子集,它们位于交叉点体的表面上。数组中的所有点都存在多次。让我们摆脱重复:

    K = K(:); K = unique(K, 'stable');

  4. 现在阵列非常小(上面的示例大约300点),你可以通过它找到最长的距离。我为它编写了函数findAxis

    [A, B, d] = findAxis(R_arr(K, :));

    它会返回最远的点AB,以及它们之间的距离d

  5. 现在,当您知道这两个点时,您可以定义属于轴的另一个点。使用函数calc_coord

    C = calc_coord(A, B, ranges(3, 1));

    D = calc_coord(A, B, ranges(3, 2));

    我使用数组ranges中的值来指定轴的z - 坐标。

  6. 绘制轴!

  7. 对于上面的例子,情节如下所示:

    Axis of the intersection body

    凸包的体积为5.933。蒙特卡罗方法给了我们6.1889,因此结果非常接近。

    最长轴的长度为4.3264

    为了获得体积近似更好的直觉,我计算了相对误差:

    Relative error for Monte Carlo method and the convex hull

    正如您所看到的,即使经过几次迭代,蒙特卡罗方法也能提供更好的准确性。

    以下是具有轴计算功能的更新代码:

    X=[0,2];   %two ellipsoid x coordinates
    Y=[0,2];   %two ellipsoid y coordinates
    Z=[0,2];   %two ellipsoid z coordinates
    ROTATIONANGLE=[90,30];
    AXIS_A=[1,2];  %two ellipsoid minor axis radius 
    AXIS_B=[3,5];  %two ellipsoid major axis radius
    AXIS_C=[3.25,13.25];  %two ellipsoid major axis radius
    
    ranges = zeros(3, 2);
    
    do_plot = 1; %either plot ellipsoids or not
    
    step_number = 1000000;
    
    for i = 1:2  %display ellipsoid
    
        if (do_plot == 1)
            [x, y, z] = ellipsoid(X(i),Y(i),Z(i),AXIS_A(i),AXIS_B(i),AXIS_C(i),20);
            S = surf(x, y, z);
            alpha(.05);
            rotate(S,[0,0,1], ROTATIONANGLE(i), [X(i),Y(i),Z(i)]);
        end
    
        %calculate the ranges for the simulation box
        ranges(1, 1) = min(ranges(1, 1), X(i) -   max(AXIS_A(i), AXIS_B(i))  );
        ranges(1, 2) = max(ranges(1, 2), X(i) +   max(AXIS_A(i), AXIS_B(i))  );
    
        ranges(2, 1) = min(ranges(2, 1), Y(i) -   max(AXIS_A(i), AXIS_B(i))  );
        ranges(2, 2) = max(ranges(2, 2), Y(i) +   max(AXIS_A(i), AXIS_B(i))  );
    
        ranges(3, 1) = min(ranges(3, 1), Z(i) - AXIS_C(i));
        ranges(3, 2) = max(ranges(3, 2), Z(i) + AXIS_C(i));
    
        if (do_plot == 1)
            hold on;
        end
    end
    
    counter = 0; %how many points targeted the intersection
    
    R_arr = [];
    
    for i = 1:step_number
    
        R = rand(3, 1).*(ranges(:, 2) - ranges(:, 1)) + ranges(:, 1); %a random point
    
        n = 1;
        val = calc_ellipsoid( R(1), R(2), R(3), X(n),Y(n),Z(n),AXIS_A(n),AXIS_B(n),AXIS_C(n),ROTATIONANGLE(n)*pi/180);
    
        if (val <= 1.0)
            n = 2;
            val = calc_ellipsoid( R(1), R(2), R(3), X(n),Y(n),Z(n),AXIS_A(n),AXIS_B(n),AXIS_C(n),ROTATIONANGLE(n)*pi/180);
    
            if (val <= 1.0)
    
                if (do_plot == 1)
                    %plot3(R(1), R(2), R(3), 'or', 'MarkerSize', 1, 'MarkerFaceColor','r');
                end
    
                counter = counter + 1;
    
                R_arr = [R_arr; R'];
            end
        end
    
    end
    
    cube_vol = 1; %the volume of the simulation box
    for i=1:3
        cube_vol = cube_vol * (ranges(i, 2) - ranges(i, 1));
    end
    
    %approximated volume of the intersection
    section_vol = cube_vol * counter / step_number;
    
    display(['Cube volume: ', num2str(cube_vol)]);
    display(['Targeted points: ', num2str(counter), ' from ', num2str(step_number)]);
    display(['Section volume: ', num2str(section_vol)]);
    
    if (counter > 0)
    
        %hull
        [K, v] = convhull(R_arr(:, 1), R_arr(:, 2), R_arr(:, 3));
    
    
        display(['Approximated volume: ', num2str(v)]);
        trisurf(K, R_arr(:, 1), R_arr(:, 2), R_arr(:, 3), 'FaceColor','cyan')
        hold on;
        axis equal
    
        K = K(:);
        K = unique(K, 'stable');
    
        [A, B, d] = findAxis(R_arr(K, :));
    
        plot3(A(1, 1), A(1, 2), A(1, 3), 'or', 'MarkerSize', 10, 'MarkerFaceColor','r');
        plot3(B(1, 1), B(1, 2), B(1, 3), 'or', 'MarkerSize', 10, 'MarkerFaceColor','r');
    
        %axis
        C = calc_coord(A, B, ranges(3, 1));
        D = calc_coord(A, B, ranges(3, 2));
    
        p = [C; D];
    
        plot3(p(:, 1), p(:, 2), p(:, 3), '--g', 'LineWidth', 3);
    
    else
        display('There is no intersection!');
    end
    
    hold off;
    

    功能:

    function [ C] = calc_coord( A, B, z)
        x1 = A(1, 1);
        x2 = B(1, 1);
    
        y1 = A(1, 2);
        y2 = B(1, 2);
    
        z1 = A(1, 3);
        z2 = B(1, 3);
    
        y = (y2 - y1)*(z - z1)/(z2 - z1) + y1;
        x = (x2 - x1)*(y - y1)/(y2 - y1) + x1;
    
        C = [x, y, z];
    end
    
    function [ A, B, d ] = findAxis( point_arr )
    
        A_ind = 0; B_ind = 0; d = -1;
    
        n = size(point_arr, 1);
        i = 1;
    
        while (i < n)
    
            for j=(i+1):n
    
                cur_d = norm(point_arr(i, :) - point_arr(j, :));
    
                if (cur_d > d)
                    d = cur_d;
                    A_ind = i;
                    B_ind = j;
                end
            end
    
            i = i + 1;
        end
    
        A = point_arr(A_ind, :); 
        B = point_arr(B_ind, :);
    end
    

    <强>说明

    功能calc_ellipsoid

    该函数基于椭球方程(椭圆体围绕z轴旋转角度theta):

    ellipsoid equation

    该函数定义给定点是否位于椭球内部

    %the function calculates a value for some given point, which shows if the
    %point is inside of the ellipsoid or not.
    %for a point to be inside, the value has to be <=1
    
    function [ val ] = calc_ellipsoid( x, y, z, x0, y0, z0, a, b, c, theta)
    
        %x, y, z - coordinates of the point to be checked
        %x0, y0, z0 - center of the ellipsoid
        %a, b, c - axes of the ellipsoid
        %theta - angle of the rotation about the Z-axis
    
        x_cmp = ((x - x0)*cos(theta) + (y - y0)*sin(theta))^2   /(a^2);
        y_cmp = ((x - x0)*sin(theta) - (y - y0)*cos(theta))^2   /(b^2);
        z_cmp = (z - z0)^2 / (c^2);
    
        val = x_cmp + y_cmp + z_cmp;
    end
    

    如果您需要使用其他形状,您需要找到这样的方程式,以检查您的点是否属于形状。椭球方程是最简单的方法之一。

    功能findAxis

    该函数从点云中搜索两个点,它们之间的距离最长。在这里我们假设交叉点形状的轴经过这两个点(这是一个非常粗略的假设,但它有效)。

    %the function is given an array of all points which lay on the constructed
    %body. we assume, that the axis of the body is the longest line, connecting
    %some two points of this array. the function goes through all the points
    %and calculates the euclidian distance between them. 
    %the function returns points A and B, and the distance between them 
    
    function [ A, B, d ] = findAxis( point_arr )
    
        %point_arr - points from the bodies surface
        %A, B - end points of the found exis
        %d - distance between A and B
    
        A_ind = 0; B_ind = 0; d = -1;
    
        n = size(point_arr, 1);
        i = 1;
    
        while (i < n)
            for j=(i+1):n
    
                cur_d = norm(point_arr(i, :) - point_arr(j, :));
    
                if (cur_d > d)
                    d = cur_d;
                    A_ind = i;
                    B_ind = j;
                end
            end
    
            i = i + 1;
        end
    
        A = point_arr(A_ind, :); 
        B = point_arr(B_ind, :);
    end
    

    功能calc_coord

    该功能基于3D空间中的线方程:

    line equation

    该等式定义了一条线,该线穿过坐标为(x1, y1, z1)(x2, y2, z2)的2个点。我们使用这个函数两个在交点外形找到另外两个点,以便绘制轴更具说明性。如果你不打算拍出漂亮的照片,你真的不需要这个功能。

    %the function is given two points A and B, which were found in the
    %'findAxis' function. we want to find a new point C, which lay on the axis,
    %and have z-coordinate equal to 'z'. it is done merely to visualize the
    %axis in a better way.
    
    function [C] = calc_coord( A, B, z)
        x1 = A(1, 1);
        x2 = B(1, 1);
    
        y1 = A(1, 2);
        y2 = B(1, 2);
    
        z1 = A(1, 3);
        z2 = B(1, 3);
    
        y = (y2 - y1)*(z - z1)/(z2 - z1) + y1;
        x = (x2 - x1)*(y - y1)/(y2 - y1) + x1;
    
        C = [x, y, z];
    end