日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android 圆滑曲线,如何使用贝塞尔曲线在一组点上绘制平滑线?

發布時間:2025/4/5 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 圆滑曲线,如何使用贝塞尔曲线在一组点上绘制平滑线? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我需要通過一組頂點畫一條平滑的線。 該組頂點是由用戶在觸摸屏上拖動他們的手指來編譯的,該集合傾向于相當大并且頂點之間的距離相當小。 但是,如果我只是用一條直線連接每個頂點,結果非常粗糙(不平滑)。

我find了使用樣條插值(和/或其他我不理解的東西)的解決方案,通過添加一堆額外的頂點來平滑線條。 這些工作很好,但由于頂點列表已經相當大,將其增加10倍左右會產生重大的性能影響。

看起來平滑應該可以通過使用貝塞爾曲線而不添加額外的頂點來實現。

以下是基于此解決方案的一些代碼:

http://www.antigrain.com/research/bezier_interpolation/

當頂點之間的距離很大時它很有效,但是當頂點靠近在一起時它不能很好地工作。

有沒有更好的方法通過大量頂點繪制平滑曲線而不添加額外頂點的建議?

Vector gesture; protected void onDraw(Canvas canvas) { if(gesture.size() > 4 ) { Path gesturePath = new Path(); gesturePath.moveTo(gesture.get(0).x, gesture.get(0).y); gesturePath.lineTo(gesture.get(1).x, gesture.get(1).y); for (int i = 2; i < gesture.size() - 1; i++) { float[] ctrl = getControlPoint(gesture.get(i), gesture.get(i - 1), gesture.get(i), gesture.get(i + 1)); gesturePath.cubicTo(ctrl[0], ctrl[1], ctrl[2], ctrl[3], gesture.get(i).x, gesture.get(i).y); } gesturePath.lineTo(gesture.get(gesture.size() - 1).x, gesture.get(gesture.size() - 1).y); canvas.drawPath(gesturePath, mPaint); } } } private float[] getControlPoint(PointF p0, PointF p1, PointF p2, PointF p3) { float x0 = p0.x; float x1 = p1.x; float x2 = p2.x; float x3 = p3.x; float y0 = p0.y; float y1 = p1.y; float y2 = p2.y; float y3 = p3.y; double xc1 = (x0 + x1) / 2.0; double yc1 = (y0 + y1) / 2.0; double xc2 = (x1 + x2) / 2.0; double yc2 = (y1 + y2) / 2.0; double xc3 = (x2 + x3) / 2.0; double yc3 = (y2 + y3) / 2.0; double len1 = Math.sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0)); double len2 = Math.sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1)); double len3 = Math.sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2)); double k1 = len1 / (len1 + len2); double k2 = len2 / (len2 + len3); double xm1 = xc1 + (xc2 - xc1) * k1; double ym1 = yc1 + (yc2 - yc1) * k1; double xm2 = xc2 + (xc3 - xc2) * k2; double ym2 = yc2 + (yc3 - yc2) * k2; // Resulting control points. Here smooth_value is mentioned // above coefficient K whose value should be in range [0...1]. double k = .1; float ctrl1_x = (float) (xm1 + (xc2 - xm1) * k + x1 - xm1); float ctrl1_y = (float) (ym1 + (yc2 - ym1) * k + y1 - ym1); float ctrl2_x = (float) (xm2 + (xc2 - xm2) * k + x2 - xm2); float ctrl2_y = (float) (ym2 + (yc2 - ym2) * k + y2 - ym2); return new float[]{ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y}; }

Bezier Curves不是為了通過提供的點而設計的! 它們旨在塑造受控制點影響的平滑曲線。 此外,您不希望平滑的曲線遍歷所有數據點!

您應該考慮過濾數據集,而不是插值:

過濾

對于這種情況,您需要一個數據序列,作為點數組,按手指繪制手勢的順序:

你應該在wiki中查看“滑動平均值”。

您應該使用一個小的平均窗口。 (嘗試5 – 10分)。 其工作原理如下:(查找wiki以獲取更詳細的說明)

我在這里使用10點的平均窗口:首先計算點0 – 9的平均值,然后輸出結果作為結果點0,然后計算點1 – 10的平均值和輸出,結果1,依此類推。

計算N點之間的平均值:

avgX =(x0 + x1 …. xn)/ N.

avgY =(y0 + y1 …. yn)/ N.

最后,將結果點與線連接起來。

如果仍需要在缺失點之間進行插值,則應使用分段三次樣條。

一個三次樣條曲線遍歷所有3個提供的點。

您需要計算一系列它們。

但首先嘗試滑動平均值。 這很容易。

好問題。 您的(錯誤)結果是顯而易見的,但您可以嘗試將其應用于更小的數據集,可能通過用平均點替換關閉點組 。 在這種情況下,判斷兩個或多個點是否屬于同一組的適當距離可以在時間而不是空間中表示,因此您需要存儲整個觸摸事件(x,y和時間戳)。 我正在考慮這個因為我需要一種讓用戶通過觸摸繪制幾何圖元(矩形,線條和簡單曲線)的方法

這個是來做什么的? 為什么你需要如此準確? 我假設你只需要為用戶拖動手指的每英寸存儲大約4個頂點的東西。 考慮到這一點:

嘗試使用每個X中的一個頂點實際繪制之間,中間頂點用于指定曲線的加權點。

int interval = 10; //how many points to skip gesture.moveTo(gesture.get(0).x, gesture.get(0).y); for(int i =0; i +interval/2 < gesture.size(); i+=interval) { Gesture ngp = gesture.get(i+interval/2); gesturePath.quadTo(ngp.x,ngp.y, gp.x,gp.y); }

你需要調整這個以實際工作,但想法就在那里。

總結

以上是生活随笔為你收集整理的android 圆滑曲线,如何使用贝塞尔曲线在一组点上绘制平滑线?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。