樣條引數與曲線長度間的互相求解

2022-04-08 20:32:21 字數 2247 閱讀 6945

背景

在開發路徑外掛程式時,需要解決以下問題:獲得路徑上某一點到路徑起點的曲線長度;給定曲線長度,返回路徑上點的位置。路徑是由三次樣條(spline)組成的,三次樣條就是最高次數為 3 的一元多項式。設樣條為 p(t) = f(t), 只要知道 t 就可以得到具體位置的座標、一階導等資訊。設樣條曲線長度為 s,那麼要求的就是 t-s 和 s-t 的關係。不幸的是,曲線長度的計算沒有解析解,只有數值方法。數值方法不適用於遊戲中的時時運算,對效能影響太大。但是,如果事先對 s-t 或 t-s 曲線取樣,然後執行時找到最接近的取樣資料,就可以計算出大概的結果了。這種辦法有兩個問題需要解決:如何取樣;基於取樣資料如何根據 t 計算 s 或根據 s 計算 t。  

分析多段樣條組成的路徑長度不同、引數不同,需要他們的取樣和計算結果具有相同的誤差範圍,這樣才能保證乙個勻速運動的物體經過不同樣條時看起來沒有變速,所以必須引入乙個誤差的概念。取樣時誤差越小、路徑越長,取樣的資料量越大。關於計算,最開始想到的是最小二乘法進行曲線擬合。但後來發現,最小二乘法只能保證已知取樣點處誤差最小,而無法保證取樣點之間的準確程度,甚至會出現不單調的情況。然後想到的是使用 catmull-rom 樣條來平滑穿過這些點,但是同樣不能保證單調,而且端點問題很難處理。  

取樣最開始使用指定取樣數量、等距離取樣的方法。這種方法的缺點就是,無法控制誤差。要考慮誤差,就得關心曲線的變化過程。  

以極小的 dt 來計算 s,同時判斷當前 s 是否應該儲存到取樣表。如圖,在相鄰兩個點之間,認為曲線是直線,那麼在給定誤差範圍內,直線的斜率也是乙個範圍;然後計算下乙個點處的 s,考慮直線斜率的範圍,如果這個範圍與之前的範圍有交集,那麼交集作為新的斜率範圍;如果沒有交集,那麼前一點處應當新增新取樣資料,取樣值取斜率範圍內的中點,然後重新計算新的斜率範圍。

複製**

vector3 lastpoint = _c0, currentpoint;

vector2 currentsample = vector2.zero, basesample = vector2.zero, newsample;

float currentmaxslope, maxslope = float.maxvalue;

float currentminslope, minslope = float.minvalue;

// 估算長度、分段數

for (int i = 1; i <= minsegments; i++)

int segments = mathf.clamp((int)(currentsample.y * segmentsfactor / _error) + 1, minsegments, maxsegments);

list samples = new list((int)(segments * 0.1f) + 1);

samples.add(basesample);

lastpoint = _c0;

currentsample = vector2.zero;

for (int i = 1; i <= segments; i++)

else

}// 新增最後乙個取樣點

samples.add(currentsample);  

計算取樣過程已經保證了誤差在指定值以下,所以計算時直接在兩個取樣值之間線性插值即可。那麼如何找到最接近的取樣資料呢?這裡使用的方法不是折半查詢,而是先估計然後線性查詢(如果需要更快的話,可以考慮把折半查詢的「折半」換成「估計」)。  

///

/// 根據引數 t 獲取長度

///

public float getlength(float t)

else

return basesample.y + (t - basesample.x) * (_samples[index].y - basesample.y) / (_samples[index].x - basesample.x);

}  ///

/// 通過長度獲取位置(返回值為引數 t)

///

public float gettimeatlength(float s)

else

return basesample.x + (s - basesample.y) * (_samples[index].x - basesample.x) / (_samples[index].y - basesample.y);

}  結果 

通過驗證,這種方法的效果非常好,取樣點數量很少,精確度卻很高。並且精確度提高乙個數量級時,取樣數量通常只增加一到兩倍。移動物體時表現的非常平滑,在多段樣條間移動無論樣條差異多大都很平穩。

黎曼積分求解可微曲線的弧線長度

黎曼積分求解可微曲線的弧線長度 假設曲線y f x 在區間 a,b 內光滑 可微且連續。那麼可以根據微積分求解y f x 在a x b區間內形成的弧線長度。如圖 從微分的思想入手建立數學函式式,假設s為曲線上 x,f x 到 x dx,f x dx 兩點連線。這兩點在水平方向的長度為dx,在垂直方向...

二階貝塞爾曲線長度的計算

祝大家國慶中秋快樂!當乙隻單身狗,就需要有單身狗的覺悟 不要滿世界的找 吃!作為u3d菜鳥,最近專案中遇到乙個需求 做勻速曲線運動!基於以前對貝塞爾曲線的認識,無法滿足需求,就想繼續了解一下!歷史略過,乾貨開始!這裡介紹的很詳細了,本人在幾何上的理解如下,比套公式容易理解多了 private vec...

python微元法計算函式曲線長度的方法

計算曲線長度,根據線積分公式 令積分函式f x,y,z 為1,即計算曲線的長度,將其微元化 其中根據此時便可在python程式設計實現,給出4個例子,中已有詳細注釋,不再贅述 計算曲線長度,根據線積分公式 int a bf x,y,z dl,令積分函式為1,即計算曲線的長度 import numpi...