MATLAB——計算立方體的法向量

繪製立方體

  繪製立方體主要使用matlab自帶的patch()函數,該函數具體用法參照博客MATLAB——patch繪製多邊形

計算面的法向量

function [pos,n] = getNormalVector(cuboid)
% cuboid: the handle returned by function path()
% n: normal vectors of all flats

    vertices = cuboid.Vertices;
    faces = cuboid.Faces;
    n = zeros(size(faces,1),3);
    pos = zeros(size(faces,1),3);

    for i = 1:size(faces,1)
        index = faces(i,1:4);
        p1 = vertices(index(1),:)-vertices(index(2),:);
        p2 = vertices(index(2),:)-vertices(index(3),:);

        n(i,:) = cross(p1,p2);
        n(i,:) = -n(i,:)/norm(n(i,:));
        pos(i,:) = sum(vertices(index(:),:))/4;
        quiver3(pos(i,1),pos(i,2),pos(i,3),n(i,1),n(i,2),n(i,3),0.5);
    end

end

判斷點是否在立方體內

方法1:三角化後判斷

function inflag = inpolyhedron(point_set,p_detected)
% point_set: a set of points stores the coordinates
% p_detected: point to be detected
% inflag:
%     flag = 1: the point is in the polyhedron.
%     flag = 0: the point is not in the polyhedron.

% stores the coordinates of the convexes.
    tri = delaunayTriangulation(point_set);
    % number of the tetrahedrons decomposed from the polyhedron
    num_tet = size(tri,1);
    t_inflag = zeros(1,11);
    for i = 1:num_tet
        v1_coord = point_set(tri(i,1),:);
        v2_coord = point_set(tri(i,2),:);
        v3_coord = point_set(tri(i,3),:);
        v4_coord = point_set(tri(i,4),:);
        D0 =det( [v1_coord,1;v2_coord,1;v3_coord,1;v4_coord,1]);
        D1 = det([p_detected,1;v2_coord,1;v3_coord,1;v4_coord,1]);
        D2 = det([v1_coord,1;p_detected,1;v3_coord,1;v4_coord,1]);
        D3 = det([v1_coord,1;v2_coord,1;p_detected,1;v4_coord,1]);
        D4 = det([v1_coord,1;v2_coord,1;v3_coord,1;p_detected,1]);

        if D0*D1 > 0 && D0*D2>0 && D0*D3>0 && D0*D4 > 0
            t_inflag(i) = 1;
            break;
        end

    end
  
    if sum(t_inflag) > 0
        inflag = 1;
        disp('The point is in the polyhedron.');
    else
        inflag = 0;
        disp('The point is not in the polyhedron.');
    end
end

方法2:計算點與邊界距離

function [minDist, dist]= distToArena(cuboid,normal,point)
    % Calculate the distance from a point outside the cuboid to the center of the cuboid.
    % Input:
    %   cuboid: the handle of cuboid returned by the function patch().
    %   normal: the normal of faces.
    %   point:  the point outside the cuboid.
    % return
    %   minDist: The distance between the point and the surface of the cuboid,
    %           the direction along the line connecting the point and the center of the cuboid.
    %   dist:    The distance between the center of the cuboid and the surface of the cuboid,
    %           the direction along the line connecting the point and the center of the cuboid.
    faces = cuboid.Faces;
    minDist = inf;

    arenaCenter = sum(cuboid.Vertices(:,:))/size(cuboid.Vertices,1);
    for i = 1:size(faces,1)
        angle = getAngle(normal(i,:),point-arenaCenter);
        if angle<=90
            for j=1:4
                faceCenter = sum(cuboid.Vertices(faces(i,:),:))/4;
            end
            distToFace = norm((faceCenter-arenaCenter))/cos(deg2rad(angle));
            dir = point-arenaCenter;
            dir = dir/norm(dir);
            onFace = dir*distToFace+arenaCenter;
            
            vertices = cuboid.Vertices(faces(i,:),:);
            x = [min(vertices(:,1)), max(vertices(:,1))];
            y = [min(vertices(:,2)), max(vertices(:,2))];
            z = [min(vertices(:,3)), max(vertices(:,3))];
            
            if onFace(1)>=x(1) && onFace(1)<=x(2) ...
               && onFace(2)>=y(1) && onFace(2)<=y(2) ...
               && onFace(3)>=z(1) && onFace(3)<=z(2)
                minDist = norm(point-arenaCenter) - distToFace;
                dist = distToFace;
                return
            end
        end
    end
end

代碼整合


cuboid = drawCuboid([1;2;2],[1;2;8],[0;0;0],'b',0.02);
view([50,50,100]);
point = [1.5,3,7];
inpolyhedron(cuboid.Vertices,point)
view(3)
hold on
[pos, normal] = getNormalVector(cuboid);

[minDist, d] = distToArena(cuboid,normal,point);
arenaControl(pos, normal, point)

dir = (point - [1 2 8]);
dir = dir/norm(dir);
toFace = dir.*d+[1 2 8];
plot3(toFace(1),toFace(2),toFace(3),'*')
%quiver3(1,2,8,toFace(1),toFace(2),toFace(3));
toPoint = dir.*(minDist+d)+[1 2 8];
plot3(toPoint(1),toPoint(2),toPoint(3),'o')
%quiver3(1,2,8,toPoint(1),toPoint(2),toPoint(3));
plot3(point(1),point(2),point(3),'x')

function inflag = inpolyhedron(point_set,p_detected)
% point_set: a set of points stores the coordinates
% p_detected: point to be detected
% inflag:
%     flag = 1: the point is in the polyhedron.
%     flag = 0: the point is not in the polyhedron.

% stores the coordinates of the convexes.
    tri = delaunayTriangulation(point_set);
    % number of the tetrahedrons decomposed from the polyhedron
    num_tet = size(tri,1);
    t_inflag = zeros(1,11);
    for i = 1:num_tet
        v1_coord = point_set(tri(i,1),:);
        v2_coord = point_set(tri(i,2),:);
        v3_coord = point_set(tri(i,3),:);
        v4_coord = point_set(tri(i,4),:);
        D0 =det( [v1_coord,1;v2_coord,1;v3_coord,1;v4_coord,1]);
        D1 = det([p_detected,1;v2_coord,1;v3_coord,1;v4_coord,1]);
        D2 = det([v1_coord,1;p_detected,1;v3_coord,1;v4_coord,1]);
        D3 = det([v1_coord,1;v2_coord,1;p_detected,1;v4_coord,1]);
        D4 = det([v1_coord,1;v2_coord,1;v3_coord,1;p_detected,1]);

        if D0*D1 > 0 && D0*D2>0 && D0*D3>0 && D0*D4 > 0
            t_inflag(i) = 1;
            break;
        end

    end
  
    if sum(t_inflag) > 0
        inflag = 1;
        disp('The point is in the polyhedron.');
    else
        inflag = 0;
        disp('The point is not in the polyhedron.');
    end
end

function [pos,n] = getNormalVector(cuboid)
% cuboid: the handle returned by function path()
% n: normal vectors of all flats

    vertices = cuboid.Vertices;
    faces = cuboid.Faces;
    n = zeros(size(faces,1),3);
    pos = zeros(size(faces,1),3);

    for i = 1:size(faces,1)
        index = faces(i,1:4);
        p1 = vertices(index(1),:)-vertices(index(2),:);
        p2 = vertices(index(2),:)-vertices(index(3),:);

        n(i,:) = cross(p1,p2);
        n(i,:) = -n(i,:)/norm(n(i,:));
        pos(i,:) = sum(vertices(index(:),:))/4;
        quiver3(pos(i,1),pos(i,2),pos(i,3),n(i,1),n(i,2),n(i,3),0.5);
    end

end

function [minDist, dist]= distToArena(cuboid,normal,point)
    % Calculate the distance from a point outside the cuboid to the center of the cuboid.
    % Input:
    %   cuboid: the handle of cuboid returned by the function patch().
    %   normal: the normal of faces.
    %   point:  the point outside the cuboid.
    % return
    %   minDist: The distance between the point and the surface of the cuboid,
    %           the direction along the line connecting the point and the center of the cuboid.
    %   dist:    The distance between the center of the cuboid and the surface of the cuboid,
    %           the direction along the line connecting the point and the center of the cuboid.
    faces = cuboid.Faces;
    minDist = inf;

    arenaCenter = sum(cuboid.Vertices(:,:))/size(cuboid.Vertices,1);
    for i = 1:size(faces,1)
        angle = getAngle(normal(i,:),point-arenaCenter);
        if angle<=90
            for j=1:4
                faceCenter = sum(cuboid.Vertices(faces(i,:),:))/4;
            end
            distToFace = norm((faceCenter-arenaCenter))/cos(deg2rad(angle));
            dir = point-arenaCenter;
            dir = dir/norm(dir);
            onFace = dir*distToFace+arenaCenter;
            
            vertices = cuboid.Vertices(faces(i,:),:);
            x = [min(vertices(:,1)), max(vertices(:,1))];
            y = [min(vertices(:,2)), max(vertices(:,2))];
            z = [min(vertices(:,3)), max(vertices(:,3))];
            
            if onFace(1)>=x(1) && onFace(1)<=x(2) ...
               && onFace(2)>=y(1) && onFace(2)<=y(2) ...
               && onFace(3)>=z(1) && onFace(3)<=z(2)
                minDist = norm(point-arenaCenter) - distToFace;
                dist = distToFace;
                return
            end
        end
    end
end

function angle = getAngle(A,B)
    angle = acos(dot(A,B)/(norm(A)*norm(B)))/pi*180;
end


結果展示

顯示立方體,並在每個面中心處將法向量畫出。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章