Clear Filters
Clear Filters

1つの平面で2つに分​けられた3次元空間で​各点が2つの空間のど​ちらに属しているかを​知りたい。

32 views (last 30 days)
Yusaku Ohta
Yusaku Ohta on 30 Aug 2023
Commented: Yusaku Ohta on 31 Aug 2023
3次元空間上に複数の点があるとします。
1つの平面によって3次元空間を2つに分けた場合、
各点が2つの空間のどちらに属しているかを知りたいです。
平面をa(x-p)+b(y-q)+c(z-r)=0とします。
この場合、平面上の点はP(x,y,z)です。
インデックスで0か1で分かればいいです。
どのように求めればよいのでしょうか教えてください。
分かりづらいところは質問してください。
お答えします。
宜しくお願いします。

Accepted Answer

Atsushi Ueno
Atsushi Ueno on 30 Aug 2023
平面の式を実際に計算した結果を sign 関数に通せば期待する結果が得られると思います。
  • 零:平面上の点 ⇒ 0
  • 正:2つの空間のどちらか ⇒ +1
  • 負:2つの空間のどちらか ⇒ -1
function result = judgement(x,y,z)
p = 1; q = 2; r = 3;
a = 5; b = 5; c = 5;
result = sign(a*(x-p)+b*(y-q)+c*(z-r));
end
注意点:浮動小数点数を入力した場合、結果が0(ちょうど平面上)になる事は滅多にありません。代数的に0になるはずでも演算誤差によって正負どちらかに外れる事が起こり得ます。かといって「絶対に0にならない」とも言い切れないので厄介です。代数的に厳密な結果を方法としては symbolic math toolboxを使用する方法があります。
  1 Comment
Yusaku Ohta
Yusaku Ohta on 31 Aug 2023
シンプルかつ必要十分なご回答ありがとうございました。
私のやりたかったことにドンピシャでした。
大変助かりました。

Sign in to comment.

More Answers (1)

交感神経優位なあかべぇ
Edited: 交感神経優位なあかべぇ on 30 Aug 2023
平面を境に空間の点を2分割するコードを書きました。
体力があるときにもうちょっと詳細を解説するかも……
point_cloud = (rand(100,3) - 0.5) .* 100;% 3次元空間上の複数の点 (:,1), (:,2), (:,3)はそれぞれX,Y,Zの値
plane = (rand(2,3) - 0.5) .* 50; % 平面の式 (配列の各要素は[a,b,c;p,q,r]を示す)
is_normal_side = divice_by_plane(point_cloud,plane); % 空間上の各点を平面を境とした分割を判定する。
% 以下データの可視化
conner = get_plane_conner(plane, 75);% 平面の式から、plane_sizeで示す大きさの四角形の4つの頂点座標を取得する。
cData = repmat([0,1,0],size(point_cloud,1),1);
cData(is_normal_side,:) = repmat([1,0,0],nnz(is_normal_side),1);
scatter3(point_cloud(:,1),point_cloud(:,2),point_cloud(:,3),'Marker','.','CData',cData);
hold on;
patch(conner(:,1),conner(:,2),conner(:,3),[0,0,0.3],'FaceAlpha',0.4);
% 空間上の各点を平面を境とした分割を判定する。
function is_normal_side = divice_by_plane(point_cloud,plane)
arguments(Input)
point_cloud(:,3)% 3次元空間上の複数の点 (:,1), (:,2), (:,3)はそれぞれX,Y,Zの値
plane(2,3) % [a,b,c; p,q,r]の配列
end
arguments(Output)
is_normal_side(:,1) logical % 平面を境にした各点の分割判定(1は面の法線方向側)
end
% 体力があるときに以下解説するかも...
point_cloud = point_cloud + plane(2,:);
zRad = atan2(plane(1,2),plane(1,1));
yRad = atan2(-plane(1,3),hypot(plane(1,2),plane(1,1)));
cosZ = cos(-zRad);
sinZ = sin(-zRad);
zmatrix = eye(3,'like',plane);
zmatrix([1,2], [1,2]) = [cosZ,-sinZ;sinZ,cosZ];
cosY = cos(-yRad);
sinY = sin(-yRad);
ymatrix = eye(3,'like',plane);
ymatrix([1,3],[1,3]) = [cosY,sinY;-sinY,cosY];
point_cloud = (ymatrix * zmatrix * (point_cloud)')';
is_normal_side = point_cloud(:,1) > 0;
end
% 平面の式から、plane_sizeで示す大きさの四角形の4つの頂点座標を取得する。
function conner = get_plane_conner(plane, plane_size)
arguments(Input)
plane(2,3) % [a,b,c; p,q,r]の配列
plane_size(1,1) % 平面の大きさ
end
arguments(Output)
conner(4,3) % 四角形の4つの頂点座標
end
zRad = atan2(plane(1,2),plane(1,1));
yRad = atan2(-plane(1,3),hypot(plane(1,2),plane(1,1)));
cosZ = cos(zRad);
sinZ = sin(zRad);
zmatrix = eye(3,'like',plane);
zmatrix([1,2], [1,2]) = [cosZ,-sinZ;sinZ,cosZ];
cosY = cos(yRad);
sinY = sin(yRad);
ymatrix = eye(3,'like',plane);
ymatrix([1,3],[1,3]) = [cosY,sinY;-sinY,cosY];
x = [0,0,0,0];
y = [plane_size,plane_size,-plane_size,-plane_size];
z = [plane_size,-plane_size,-plane_size,plane_size];
conner = (zmatrix * ymatrix * [x;y;z])';
conner = conner - plane(2,:);
end
  1 Comment
Yusaku Ohta
Yusaku Ohta on 31 Aug 2023
詳細な情報ありがとうございます。
私の数学力不足でis_normal_sideの一部が理解不明でしたが、
その他部分は大変参考になりました。
どちらの回答を採用するか大変迷ったのですが、今回はシンプルな回答を採用させていただきます。
申し訳ありません。
とても有益な情報を本当にありがとうございました。

Sign in to comment.

Products


Release

R2023a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!