MATLABで作成したベジエ曲線に等分割に点を打つ方法が知りたいです。
21 views (last 30 days)
Show older comments
MATLABで作成したベジエ曲線に等分割(例えば10分割)に点を打つ方法が知りたいです。
また、等分割した点の座標同士を結ぶ直線を生成し、その直線の長さを”ミリメートル”単位として知れるようにしたいです。
ベジエ曲線のコードは以下(制御点は例)を使用しました。
P = [0 0; 100 100]; %制御点
syms t
B = bernsteinMatrix(1,t);
bezierCurve = simplify(B*P);
bc1 = sym2poly(bezierCurve(1)); % ベジエ曲線の多項式係数を抽出
bc2 = sym2poly(bezierCurve(2)); % ベジエ曲線の多項式係数を抽出
plot(polyval(bc1,0:0.01:1), polyval(bc2,0:0.01:1)) % 数値解(点群)を得てからプロットA = sqrt(2)
hold on
scatter(P(:,1), P(:,2),'filled')
hold off
0 Comments
Accepted Answer
Atsushi Ueno
on 2 Dec 2023
Edited: Atsushi Ueno
on 2 Dec 2023
> MATLABで作成したベジエ曲線に等分割(例えば10分割)に点を打つ方法が知りたいです。また、等分割した点の座標同士を結ぶ直線を生成し、その直線の長さを”ミリメートル”単位として知れるようにしたいです。
→既にプロットする際に polyval 関数で数値解(点群)を得ています。もっと間引いた点群を取得すればやりたい事が出来ます。直線の長さの単位は無次元[-]です。単位を決めるには基準とする長さを定義する必要があります。基準が1[m]なら、現在表示している距離の1000倍がミリメートル単位[mm]になります。
P = [0 0; 100 100]; %制御点
syms t
B = bernsteinMatrix(1,t);
bezierCurve = simplify(B*P);
bc1 = sym2poly(bezierCurve(1)); % ベジエ曲線の多項式係数を抽出
bc2 = sym2poly(bezierCurve(2)); % ベジエ曲線の多項式係数を抽出
% plot(polyval(bc1,0:0.01:1), polyval(bc2,0:0.01:1)) % 数値解(点群)を得てからプロットA = sqrt(2)
pv1 = polyval(bc1,0:0.1:1); % ←ここを追加, もっと間引いた点群を取得
pv2 = polyval(bc2,0:0.1:1); % ←ここを追加, もっと間引いた点群を取得
hypot(diff(pv1),diff(pv2)) % ←ここを追加, 等分割した各線分の長さ
plot(pv1,pv2,'*--'); % ←ここを追加, 等分割に点を打ち、座標同士を結ぶ直線を生成
hold on
scatter(P(:,1), P(:,2),'filled')
hold off
9 Comments
Atsushi Ueno
on 4 Dec 2023
こんな感じでしょうか
P = [0 0; 0 100; 50 100; 50 0; 100 0; 100 100]; %制御点
divstep = 1000; % 曲線を離散的に分割して計算する際の分割数(下記とは無関係,細かい方が正確)
linediv = 10; % 曲線の分割数
syms t
B = bernsteinMatrix(5,t);
bezierCurve = simplify(B*P);
bc1 = sym2poly(bezierCurve(1)); % ベジエ曲線の多項式係数を抽出
bc2 = sym2poly(bezierCurve(2)); % ベジエ曲線の多項式係数を抽出
pv1 = polyval(bc1,0:1/divstep:1); % 間引いた点群を取得()
pv2 = polyval(bc2,0:1/divstep:1); % 間引いた点群を取得(なるべく細かい方が良い)
len = hypot(diff(pv1),diff(pv2)); % 間引いた点群間の長さ
div10 = sum(len) / linediv; % ベジエ曲線全体の長さの10分の1
div(1) = 1; div(linediv+1) = divstep;
for k = 2:linediv % どこで分割すべきか探していく
for m = 1:divstep
div(k) = m;
if sum(len(div(k-1):div(k))) > div10 % 次の分割点までの距離が全体の10分の1を超えたところ
break;
end
end
end
plot(pv1(div),pv2(div),'*--'); % ←ここを追加, 等分割に点を打ち、座標同士を結ぶ直線を生成
hold on
scatter(P(:,1), P(:,2),'filled')
hold off
More Answers (1)
Atsushi Ueno
on 5 Dec 2023
Edited: Atsushi Ueno
on 5 Dec 2023
要件の解釈違いがありましたので、コメントの数値解法を整理して(for文を削除して)改めて回答致します。
やっている事は下記の通りです。これでベジエ曲線を曲げたり歪めたりしても当分割された点群が求められます。
ベジエ曲線を求める⇒ベジエ曲線上の点群を得る⇒開始点からの積算距離を得る⇒積算距離群の内、最長距離を当分割した各距離への最近傍点のインデックスを求める⇒ベジエ曲線上の点群(先のインデックス分のみ)を描画する
divstep = 1000; % 追加:曲線を離散的に分割して計算する際の分割数(下記とは無関係,細かい方が正確)
linediv = 10; % 追加:曲線の分割数
P = [0 0; 100 100]; %制御点
P = [0 0; 0 100; 50 100; 50 0; 100 0; 100 100]; % 追加:曲がっているベジエ曲線
syms t
B = bernsteinMatrix(5,t); % 変更:近似階数を1⇒5(制御点数-1)に変更
bezierCurve = simplify(B*P);
bc1 = sym2poly(bezierCurve(1)); % ベジエ曲線の多項式係数を抽出
bc2 = sym2poly(bezierCurve(2)); % ベジエ曲線の多項式係数を抽出
% plot(polyval(bc1,0:0.01:1), polyval(bc2,0:0.01:1)) % 数値解(点群)を得てからプロットA = sqrt(2)
pv1 = polyval(bc1,0:1/divstep:1); % 追加:間引いた点群を取得
pv2 = polyval(bc2,0:1/divstep:1); % 追加:間引いた点群を取得
len = cumsum(hypot(diff(pv1),diff(pv2))); % 追加:開始点から各点までの距離(積算値)
thrsh = 0:len(end)/linediv:len(end); % 追加:ベジエ曲線全体の長さの10分の1区切り
div = dsearchn(len',thrsh'); % 追加:積算値の中から10分の1区切りの最近傍店のindexを探す
hypot(diff(pv1(div)),diff(pv2(div))) % 追加:等分割した各線分の長さ
plot(pv1(div),pv2(div),'*--'); % 追加:等分割に点を打ち、座標同士を結ぶ直線を生成
hold on
scatter(P(:,1), P(:,2),'filled')
hold off
3 Comments
Atsushi Ueno
on 8 Dec 2023
Edited: Atsushi Ueno
on 8 Dec 2023
これは単に、当初の制御点(2点)を結ぶベジエ曲線だと、先の回答と本回答の違いを見分けられなかったので、「媒介変数tの動きに対しムラのある曲線」となるように制御点を増やしてグニャグニャ曲げて、本当に曲線を当分割出来たのか試してみただけです。
See Also
Categories
Find more on Mathematics and Optimization in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!