本文演算法來自
https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf
作者對比了幾個演算法,主要突出的是 Largest-Triangle-Three-Buckets演算法,我個人翻譯為最大三點【三角】面積特征,同樣作者給出了代碼,我也找到了C#代碼,適當改了下,主要是說說演算法
主要說說幾點:
1:演算法的主要源于Visvalingam-Whyatt,也就是基于點與前后點形成的面積是否大于閾值,小于閾值則洗掉點,
簡單說一下Visvalingam-Whyatt,
①當節點從首位開始,連接前兩個(因為是首位,沒有后面),緊接著是第二點,2點連接首點,連接三點,依次向下,末位點參考首點
②當形成全部的三角后洗掉面積最小的結點,并由移至附近兩點,重新形成三角形【或者從頭重新連接~~】
③重復①,確定所有三角形的面積都小于閾值
2:LTTB是可以控制回傳點的數量(亮點!!)
基本操作:點集排除首尾點后的 數量與輸出點的數量(同樣減去首尾點,也就是-2)的比值,然后每比值的一個點集,默認第一個點是獨立的一個點集,最后一個點也是獨立的一個點集
理論上第二步是選擇點與下兩個點集中的點所形成的最大的三角形的面積的點,實際上,演算法中是 點1確定,點集3通過計算按照第幾個點集,然后計算這個點集中所有的點的平均值(X,Y兩個值的平均值)所創造的點,不一定存在,
這樣子就可以確定點1,點集2,然后不斷篩選點集2的點,經行計算面積來比較大小,最后 依次重復上述步驟到下一個點,直至結束,
同樣,不用平均值,也可以列舉點集3與點集2的點與點1 所形成的每個三角形的面積,論文中 作者指出 差不多的效果~~(水啊??)
最后 視覺效果上真的不錯! 不過論文中說,當波峰值較大時,也有可能表現不好~
代碼實作的步驟:
零 初始點1為首點
① 計算比值(除去首尾,每個點集的數量)
② 計算點集3中點的平均點
③ 列舉點集2與點集3的平均和點1形成最大的三角形面積,并加入輸出點集
④ 點1設定位點集2的最大面積點,并進入下一次回圈步驟②
截圖

代碼 來自https://github.com/cgddrd/CSharp-LargestTriangleThreeBuckets(略微改造)
public static List<Point> Get(List<Point> data, int threshold) { int dataLength = data.Count; if (threshold >= dataLength || threshold == 0) return data; // Nothing to do List<Point> sampled = new List<Point> (threshold); // 點集大小,排除首尾點,閾值減2, double every = (double)(dataLength - 2) / (threshold - 2); int a = 0; Point maxAreaPoint = new Point(); int nextA = 0; sampled.Add(data[a]); //默認添加首點 for (int i = 0; i < threshold - 2; i++) { // 假設第三個點是此前區間的平均值,大概率不存在,憑空捏造一個?? double avgX = 0; double avgY = 0; int avgRangeStart = (int)(((i + 1) * every) + 1); int avgRangeEnd = (int)(((i + 2) * every) + 1); avgRangeEnd = avgRangeEnd < dataLength ? avgRangeEnd : dataLength; int avgRangeLength = avgRangeEnd - avgRangeStart; for (; avgRangeStart < avgRangeEnd; avgRangeStart++) { avgX += data[avgRangeStart].X; // * 1 enforces Number (value may be Date) avgY += data[avgRangeStart].Y; } avgX /= avgRangeLength; avgY /= avgRangeLength; // +1是為了排除當前點 int rangeOffs = (int)(Math.Floor((i + 0) * every) + 1); int rangeTo = (int)(Math.Floor((i + 1) * every) + 1); // Point a double pointAx = data[a].X; // enforce Number (value may be Date) double pointAy = data[a].Y; double maxArea = -1; for (; rangeOffs < rangeTo; rangeOffs++) { //計算面積 點1 點集2 虛擬的點3~~ double area = Math.Abs((pointAx - avgX) * (data[rangeOffs].Y - pointAy) - (pointAx - data[rangeOffs].X) * (avgY - pointAy) ) * 0.5; if (area > maxArea) { maxArea = area; maxAreaPoint = data[rangeOffs]; nextA = rangeOffs; //設定下一個點 } } sampled.Add(maxAreaPoint); a = nextA; // 進入下一次回圈 } sampled.Add(data[dataLength - 1]); //默認添加尾點 return sampled; }
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/273086.html
標籤:WPF
上一篇:C#
