MATLABで作成し​たベジエ曲線に等分割​に点を打つ方法が知り​たいです。

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

 Accepted Answer

Atsushi Ueno
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)) % ←ここを追加, 等分割した各線分の長さ
ans = 1×10
14.1421 14.1421 14.1421 14.1421 14.1421 14.1421 14.1421 14.1421 14.1421 14.1421
plot(pv1,pv2,'*--'); % ←ここを追加, 等分割に点を打ち、座標同士を結ぶ直線を生成
hold on
scatter(P(:,1), P(:,2),'filled')
hold off

9 Comments

HY
HY on 2 Dec 2023
早速のご返答ありがとうございます。
一点質問があります。
hypot(diff(pv1),diff(pv2)) % ←ここを追加, 等分割した各線分の長さ
このコードでいう等分割した各線分の長さというのは、分割された曲線の長さを意味しますでしょうか?
もしくは、等分割に点を打ち、座標同士を結んだ直線の長さのことでしょうか?
Atsushi Ueno
Atsushi Ueno on 2 Dec 2023
等分割に点を打ち、座標同士を結んだ直線の長さです。
diff 関数は配列の隣接要素間の差分を返し、hypot 関数は二乗和の平方根 (斜辺の長さ) を返します。
HY
HY on 2 Dec 2023
ご回答ありがとうございます。
大変助かりました。
HY
HY on 4 Dec 2023
度々すみません。
ベジエ曲線の制御点の位置を変えてみたところ、等分割にならなかったのですが(下図)、コード内の数値を送させ売れば等分割に点を打つことが可能なのでしょうか?
Atsushi Ueno
Atsushi Ueno on 4 Dec 2023
それは均等にならないです。
ベジエ曲線において、数式の媒介変数 t が0.0から1.0まで動くと曲線上の開始点から終点まで座標が動きますが、私が示したのは媒介変数 t を均等に分割したのであって(例:10分割ならt=[0,0.1,0.2,...,0.9,1.0]) 曲線状の端点の長さが均等になる様にした訳ではありません。
「ベジエ曲線に等分割​に点を打つ方法」の解釈違いでした。申し訳ございません。
HY
HY on 4 Dec 2023
ご回答ありがとうございます。
私の説明不足と理解不足で申し訳ございません。
①ベジエ曲線を等間隔に10分割する方法
②その分割点を今度は直線で結ぶ
⓷さらにその各線分の長さをを知る
この流れのコードをもし可能でしたら教えていただけると幸いです。
こんな感じでしょうか
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
Atsushi Ueno
Atsushi Ueno on 5 Dec 2023
改めて別回答にまとめました(MATLABでfor文を使ったら負けなので) 。

Sign in to comment.

More Answers (1)

Atsushi Ueno
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))) % 追加:等分割した各線分の長さ
ans = 1×10
21.3195 21.4908 21.7286 19.6123 21.5911 21.6585 19.6028 21.4541 21.2721 21.6330
plot(pv1(div),pv2(div),'*--'); % 追加:等分割に点を打ち、座標同士を結ぶ直線を生成
hold on
scatter(P(:,1), P(:,2),'filled')
hold off

3 Comments

HY
HY on 8 Dec 2023
ご回答誠にありがとうございます。
確認、ご連絡が遅くなってしまい、申し訳ございません。
一点、質問いたします。
上記の%制御点%曲がっているベジエ曲線
この2つの制御点はどのような違いがあるのでしょうか?
Atsushi Ueno
Atsushi Ueno on 8 Dec 2023
Edited: Atsushi Ueno on 8 Dec 2023
これは単に、当初の制御点(2点)を結ぶベジエ曲線だと、先の回答と本回答の違いを見分けられなかったので、「媒介変数tの動きに対しムラのある曲線」となるように制御点を増やしてグニャグニャ曲げて、本当に曲線を当分割出来たのか試してみただけです。
HY
HY on 11 Dec 2023
ご回答ありがとうございます。
無事解決できました。

Sign in to comment.

Categories

Find more on 数学 in Help Center and File Exchange

Products

Release

R2023b

Asked:

HY
on 2 Dec 2023

Commented:

HY
on 11 Dec 2023

Community Treasure Hunt

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

Start Hunting!