Bezier eğrisi kod tam analizi gibi seviyor! | CSDN blog seçimi

Yazar | Wei Wei Miao

Editör | Tu Min

Üretildi | CSDN Blogu

Doğrudan konuya gidin, başarmak istediğimiz şey bir Android Müşteri İçine bir tür benzer efekt uygulayın.Örneğin, aşk şeklindeki resme tıklarsanız, küçük bir aşk kalbi oluşacak ve kaybolana kadar kıvrımlı bir şekilde yükselecektir.

Metin açıklaması ancak böyle olabilir, dinamik resme doğrudan bakalım, etkisi daha sezgiseldir.

Bu vaka kendi başıma yazılmıştır, çünkü daha önce bu Bézier eğrisini biraz anladım ve bu etkiyi tesadüfen gördüm. Çok iyi olduğunu düşündüm, bu arada bir demo yazdım ve Besse hakkında biraz bilgi edindim Er eğrisi bilgisi.

Öncelikle, bu durumun kodunu anlamak için Android özel Görünümü ile ilgili temel bilgilere sahip olmanız ve Bezier eğrileriyle ilgili bazı formül ve algoritmaları anlamanız gerekiyor. Ancak önemli değil, kodu formüle göre uygulayabildiğimiz sürece Bessel hakkında derinlemesine bir anlayışa sahip olmamıza gerek yok.

Bezier eğrisi ile ilgili bazı bilgilere bir göz atalım, aynı zamanda büyük adamın blogundan da öğrendim. Bakalım Bezier eğrisi nedir?

Bézier eğrisi veya Bézier eğrisi olarak da bilinen Bézier eğrisi, iki boyutlu grafik uygulamalarına uygulanan matematiksel bir eğridir. Genel vektör grafik yazılımı, eğriyi doğru bir şekilde çizmek için kullanır. Bezier eğrisi, çizgi parçaları ve düğümlerden oluşur. Düğümler, sürüklenebilir dayanaklardır. Çizgi parçaları, uzatılabilir lastik bantlar gibidir. Çizim aracında gördüğümüz kalem aracı, bunu yapmaktır. Bu tür bir vektör eğrisi.

Daha canlı olması için doğrudan dinamik resme bakalım.

Birinci dereceden Bezier eğrisi formülü: P0'dan P1'e ardışık noktalarla tanımlanan bir çizgi parçası

İkinci dereceden Bezier eğrisi formülü: P0-P1, P1-P2 eğrisinin tanjantından oluşan yörünge

Üçüncü dereceden Bezier eğrisi formülü:

Yukarıdaki dinamik grafikten, eğrinin hesaplama formülünü ve yol oluşum yasasını çok sezgisel olarak görebilirsiniz. Elde etmek istediğimiz etki, üçüncü dereceden Bezier eğrisi formülüdür. Her şeyden önce, eğrinin yolunu belirlemeniz gerekiyorsa, önce nokta konumunu belirlemelisiniz. Nokta konumunu bu şekilde aşağıda gösterildiği gibi belirledim:

Bu üç noktayı kullanıyorum, her iki taraf da rastgele seçilebilir. Bu durumda, eğrimiz ekranda ve oluşumu kabaca yukarıdaki dinamik resme benziyor. Ardından koda bakın:

private Point setPoint1 {

Puan noktaları = yeni Nokta {

yeni Nokta (mLoveX, mLoveY),

yeni Nokta (0, mCanvasHeight / 2),

yeni Nokta (mCanvasWidth + 20, -mLoveWidth-10),

};

dönüş noktaları;

}

private Point setPoint2 {

Puan noktaları = yeni Nokta {

yeni Nokta (mLoveX, mLoveY),

yeni Nokta (mCanvasWidth, mCanvasHeight / 2),

yeni Nokta (-mLoveWidth-20, -mLoveWidth-10),

};

dönüş noktaları;

}

Yukarıdaki kod, iki noktanın koordinatlarını başlatmak içindir, mLoveX, mLoveY, aşkımızın başlangıç konumunu temsil eder. İlk montaj noktası şekildeki mavi çizgiye karşılık gelir ve ikinci montaj noktası turuncuya karşılık gelir.

Bir sonraki kısım önemli kısım, Bezier eğri formülünü kod formuna çevirmektir.Dinamik grafiğe göre bir t değeri vardır ve aralığı evettir.Bu da çok canlıdır. T 0'dan 1'e değiştiğinde demektir Eğri çizildi. Koda bakın:

/ **

* Noktaya göre eğrinin yolu üzerindeki noktayı alın, k değişim trendi

* /

private Point deCasteljau (Point points, float k) {

final int n = points.length;

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

for (int j = 0; j < n-i; j ++) {

points.x = (int) ((1-k) * points.x + k * points.x);

points.y = (int) ((1-k) * points.y + k * points.y);

}

dönüş noktaları;

}

Az önce tanımladığımız iki noktanın seti içeri aktarılabilir, böylece k değerindeki değişikliğe göre karşılık gelen pozisyonun eğrisi üzerindeki nokta koordinatları elde edilebilir. Daha sonra, görevimiz yeni k değerini takip etmek için bir alt iş parçacığı başlatmak, k değerini 0'dan 1'e eklemek ve sonra döndürülen her nokta nesnesi tüm eğrinin koordinat dağılımıdır. Puan almak için alt iş parçacığını çalıştıran kod:

mLoveThread = new Thread (yeni Runnable {

@Override

public void run {

süre (k < 1) {

k + = 0.01;

Nokta noktası = deCasteljau (mPoints, k);

mLoveX = nokta.x;

mLoveY = nokta.y;

eğer (mLoveY < = -mLoveWidth || mLoveY > = mCanvasHeight) {

k = 1;

}

eğer (mLoveX < = -mLoveWidth || mLoveX > = mCanvasWidth) {

k = 1;

}

postInvalidate; // Eşzamansız yenileme

Deneyin {

Thread.sleep (80);

} catch (InterruptedException e) {

e.printStackTrace;

}

}

}

});

Yukarıdaki kod aracılığıyla, aşk resminin x ve y koordinatlarını alabilir ve ardından onDraw aracılığıyla çizebiliriz.

@Override

korumalı void onDraw (Canvas canvas) {

super.onDraw (tuval);

mCanvasWidth = canvas.getWidth;

mCanvasHeight = canvas.getHeight;

mLoveBitmapX = mCanvasWidth / 2-mLoveBitmapWidth / 2;

mLoveBitmapY = mCanvasHeight-2 * mLoveBitmapHeight;

drawLoveBitmap (tuval);

canvas.drawBitmap (mDefLove, mLoveX, mLoveY, mPaint);

// Rasgele çizin

canvas.drawText ("Beğen", mCanvasWidth / 2-mPaint.getTextSize, mLoveBitmapY + mLoveBitmapHeight + 100, mPaint);

canvas.drawLine (0, mLoveBitmapY + mLoveBitmapHeight + 20, mCanvasWidth, mLoveBitmapY + mLoveBitmapHeight + 20, mPaint);

}

Buradaki aşk için altı farklı resim kullandım.Aşk fonksiyonu formülünü kullanarak çizmeyi denemek istedim ama pes ettim.Hesaplama çok yavaş.Her aşk hesaplaması duraklatılmalı ve resmi değiştirmem gerekiyor. form.

Son olarak, yalnızca bu resme tıkladıktan sonra çizilen işlevden bahsediyorum. OnTouchEvent'teki tıklamanın koordinat konumunu alıyorum ve ardından tıklama konumunun aşk resminde olup olmadığına karar veriyorum. Kod şu şekildedir:

özel boole isTouchLoveArea (int touchX, int touchY) {

touchX'e dön > = mLoveBitmapX touchX < = mLoveBitmapX + mLoveBitmapWidth

touchY > mLoveBitmapY touchY < = mLoveBitmapY + mLoveBitmapHeight;

}

Sonunda tanıtılacak hiçbir şey yok, geri kalanı temelde özel Görünüm bilgisidir, biz esas olarak Dikkat Bu Bezier eğrisinin nasıl çizileceği gayet iyi, bu nedenle kodun tamamı aşağıdaki gibidir:

paket com.example.xww.my uygulama ruhsat;

android.content.Context'i içe aktarın;

ithal android.graphics.Bitmap;

android.graphics.BitmapFactory dosyasını içe aktarın;

ithal android.graphics.Canvas;

ithal android.graphics.Paint;

ithal android.graphics.Point;

ithal android.os.Build;

android.support.annotation.able dosyasını içe aktarın;

ithal android.support.annotation.RequiresApi;

ithal android.util.AttributeSet;

ithal android.view.MotionEvent;

android.view.View içe aktarın;

java.util.Random içe aktarın;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

/ **

* @author xww

* @desciption: Sevdiğiniz zaman aşk yüzer ve sevginin yolu Bezier eğrisiyle çizilir

* @ : https://blog.csdn.net/smile_running

* @tarih 2019/7 / 30

* @ saat 20:59

* /

@RequiresApi (api = Build.VERSION_CODES.N)

public class LoveView, View {

özel Boya mPaint;

// Aşk resmi

özel Bitmap mLoveBitmap;

özel Bitmap mLove1;

özel Bitmap mLove2;

özel Bitmap mLove3;

özel Bitmap mLove4;

özel Bitmap mLove5;

özel Bitmap mLove6;

özel Bitmap mDefLove;

özel int mLoveWidth;

özel int mLoveX;

özel giriş mLoveY;

// Resmin x ve y koordinatları

özel int mLoveBitmapX;

özel int mLoveBitmapY;

// Resmin genişliği ve yüksekliği

özel int mLoveBitmapWidth;

özel int mLoveBitmapHeight;

// Tuval genişliği ve yüksekliği

özel int mCanvasWidth;

özel int mCanvasHeight;

// Temas noktası

özel int mTouchX;

private int mTouchY;

özel ExecutorService mExecutorService;

özel Konu mLoveThread;

// rastgele sayı

özel Rastgele mRandom;

private float k; // eğri eğimi k:

private Point mPoints; // Eğri üzerinde rastgele noktaların bir koleksiyonunu oluşturur

@Override

korumalı void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {

setMeasuredDimension (measureSpecWidth (widthMeasureSpec), measureSpecHeigth (heightMeasureSpec));

}

/ **

* TAM: Tam değer, yani 64dp gibi belirli bir değer

* AT_MOST: üst Görünüm ile aynı boyuta ulaşabilen maksimum değer, yani wrap_content türü

* BELİRLENMEDİ: Belirtilmedi, yani bu Görünüm sonsuz olabilir

*

* @param widthMeasureSpec genişlik değerinde iletildi

* @ dönüş genişliği değeri

* /

private int measureSpecWidth (int widthMeasureSpec) {

int mode = MeasureSpec.getMode (widthMeasureSpec);

int size = MeasureSpec.getSize (widthMeasureSpec);

dönüş modu == ÖlçüSpec.EXACTLY? boyut: Math.min (200, boyut);

}

private int measureSpecHeigth (int heightMeasureSpec) {

int mode = MeasureSpec.getMode (heightMeasureSpec);

int size = MeasureSpec.getSize (heightMeasureSpec);

dönüş modu == ÖlçüSpec.EXACTLY? boyut: Math.min (200, boyut);

}

private void init {

initPaint;

initBitmap;

mRandom = new Random;

mExecutorService = Executors.newWorkStealingPool (6);

}

özel void initBitmap {

mLoveBitmap = BitmapFactory.decodeResource (getResources, R.drawable.loveclick);

mLoveBitmap = Bitmap.createScaledBitmap (mLoveBitmap, 180, 180, false);

mLoveBitmapWidth = mLoveBitmap.getWidth;

mLoveBitmapHeight = mLoveBitmap.getHeight;

mLove1 = BitmapFactory.decodeResource (getResources, R.drawable.love1);

mLove2 = BitmapFactory.decodeResource (getResources, R.drawable.love2);

mLove3 = BitmapFactory.decodeResource (getResources, R.drawable.love3);

mLove4 = BitmapFactory.decodeResource (getResources, R.drawable.love4);

mLove5 = BitmapFactory.decodeResource (getResources, R.drawable.love5);

mLove6 = BitmapFactory.decodeResource (getResources, R.drawable.love6);

mLove1 = reSizeLove (mLove1);

mLove2 = reSizeLove (mLove2);

mLove3 = reSizeLove (mLove3);

mLove4 = reSizeLove (mLove4);

mLove5 = reSizeLove (mLove5);

mLove6 = reSizeLove (mLove6);

mDefLove = mLove1;

mLoveWidth = mLove1.getWidth;

setDefPosition;

}

private Bitmap reSizeLove (Bitmap src) {

Bitmap.createScaledBitmap (src, 160, 160, false) döndür;

}

private void initPaint {

mPaint = new Paint;

mPaint.setColor (getResources.getColor (android.R.color.holo_purple));

mPaint.setStrokeWidth (8f);

mPaint.setStyle (Paint.Style.FILL);

mPaint.setDither (true);

mPaint.setAntiAlias (doğru);

mPaint.setTextSize (45f);

}

public LoveView (Bağlam bağlamı) {

bu (bağlam);

}

public LoveView (Bağlam bağlamı, @able AttributeSet attrs) {

bu (bağlam, attrs, 0);

}

public LoveView (Bağlam bağlamı, @able AttributeSet attrs, int defStyleAttr) {

süper (bağlam, attrs, defStyleAttr);

içinde;

}

@Override

korumalı void onDraw (Canvas canvas) {

super.onDraw (tuval);

mCanvasWidth = canvas.getWidth;

mCanvasHeight = canvas.getHeight;

mLoveBitmapX = mCanvasWidth / 2-mLoveBitmapWidth / 2;

mLoveBitmapY = mCanvasHeight-2 * mLoveBitmapHeight;

drawLoveBitmap (tuval);

canvas.drawBitmap (mDefLove, mLoveX, mLoveY, mPaint);

// Rasgele çizin

canvas.drawText ("Beğen", mCanvasWidth / 2-mPaint.getTextSize, mLoveBitmapY + mLoveBitmapHeight + 100, mPaint);

canvas.drawLine (0, mLoveBitmapY + mLoveBitmapHeight + 20, mCanvasWidth, mLoveBitmapY + mLoveBitmapHeight + 20, mPaint);

}

private Point setPoint1 {

Puan noktaları = yeni Nokta {

yeni Nokta (mLoveX, mLoveY),

yeni Nokta (0, mCanvasHeight / 2),

yeni Nokta (mCanvasWidth + 20, -mLoveWidth-10),

};

dönüş noktaları;

}

private Point setPoint2 {

Puan noktaları = yeni Nokta {

yeni Nokta (mLoveX, mLoveY),

yeni Nokta (mCanvasWidth, mCanvasHeight / 2),

yeni Nokta (-mLoveWidth-20, -mLoveWidth-10),

};

dönüş noktaları;

}

private void setDefPosition {

mLoveX = mCanvasWidth / 2-mLoveWidth / 2;

mLoveY = mLoveBitmapY-80;

}

private void drawDynamicLove {

setDefPosition;

// Sevgi kalbinin tarzını ve konumunu belirleyin

int color = mRandom.nextInt (6) + 1;

mDefLove = getBitmap (renk);

k = 0; // başla

// Bezier yolunun noktalarını ekleyin

eğer (mRandom.nextInt (2) == 0) {

mPoints = setPoint1;

} Başka {

mPoints = setPoint2;

}

mLoveThread = new Thread (yeni Runnable {

@Override

public void run {

süre (k < 1) {

k + = 0.01;

Nokta noktası = deCasteljau (mPoints, k);

mLoveX = nokta.x;

mLoveY = nokta.y;

eğer (mLoveY < = -mLoveWidth || mLoveY > = mCanvasHeight) {

k = 1;

}

eğer (mLoveX < = -mLoveWidth || mLoveX > = mCanvasWidth) {

k = 1;

}

postInvalidate; // Eşzamansız yenileme

Deneyin {

Thread.sleep (80);

} catch (InterruptedException e) {

e.printStackTrace;

}

}

}

});

mExecutorService.execute (mLoveThread);

}

private Bitmap getBitmap (int color) {

anahtarı (renk) {

dava 1:

dönüş mLove1;

durum 2:

dönüş mLove2;

durum 3:

dönüş mLove3;

vaka 4:

dönüş mLove4;

vaka 5:

dönüş mLove5;

vaka 6:

dönüş mLove6;

}

dönüş;

}

private void drawLoveBitmap (Kanvas kanvas) {

canvas.drawBitmap (mLoveBitmap, mLoveBitmapX, mLoveBitmapY, mPaint);

}

/ **

* Noktaya göre eğrinin yolu üzerindeki noktayı alın, k değişim trendi

* /

private Point deCasteljau (Point points, float k) {

final int n = points.length;

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

for (int j = 0; j < n-i; j ++) {

points.x = (int) ((1-k) * points.x + k * points.x);

points.y = (int) ((1-k) * points.y + k * points.y);

}

dönüş noktaları;

}

@Override

public boolean onTouchEvent (MotionEvent olayı) {

mTouchX = (int) event.getX;

mTouchY = (int) event.getY;

switch (event.getAction) {

case MotionEvent.ACTION_DOWN:

eğer (isTouchLoveArea (mTouchX, mTouchY)) {

drawDynamicLove;

}

kırmak;

case MotionEvent.ACTION_UP:

kırmak;

}

return super.onTouchEvent (olay);

}

özel boole isTouchLoveArea (int touchX, int touchY) {

touchX'e dön > = mLoveBitmapX touchX < = mLoveBitmapX + mLoveBitmapWidth

touchY > mLoveBitmapY touchY < = mLoveBitmapY + mLoveBitmapHeight;

}

}

Bu, tüm efektin kod diyagramıdır. Activity_main'e koyun ve etkisini görmek için çalıştırın.

Sorumluluk Reddi: Bu makale, CSDN blog makalelerinden bir seçkidir ve telif hakkı yazara aittir. Eser sahibi: Mew Whiskers

Orijinal: https://blog.csdn.net/smile_Running/article/details/98170645

SON

Zafer Kralı: Zhang Daxian, Huya'yı bıraktı, hayranlar diğer canlı yayınları patlattı ve Douyu'ya kötü bir eleştiri yapmak için bir araya geldi mi?
önceki
Başkentlerde acıyor! Yanlışlıkla yere düştü ve faraş buraya dürttü ... Doktor: Körü körüne çekip çıkarma
Sonraki
"Dışarı çıkmak suçtur!" 71 yaşındaki adam bir grupla İç Moğolistan'ın otlaklarını gezdi ve 4 gün sonra ortadan kayboldu.
Zaferin Kralı Dünya Şampiyonası: eStar Huahai, Baili Xuance'ı yakın dövüşte oynadı ve azıcık çılgın öğreti
Ne tür bir Python programcısı NumPy'yi anlamaz? | CSDN blog seçimi
Yarının Gemisi: Lütfen Rin Dong'a beni tekrar azarlaması için yalvarın! Yüksek savunma öncüsü, nasıl kullanılacağını bilir
Linux çekirdeği UDP paket alımının verimliliği nasıl hızlı bir şekilde optimize edilir? | CSDN blog seçimi
King of Glory: Athena ve Wonder Woman geri dönüyor, oyuncular bu kısıtlamaların da geri dönmesini öneriyor
2018'de Çin'in kredi kartı endüstrisinin piyasa durumu ve gelişme eğiliminin analizi. Gelecekteki tüketim senaryoları geniş geliştirme alanı getirecek
Aoki kahverengi ne tür peri saç rengi?
Kralın İhtişamının Yeniden Düzenlenmesi: Xuan Ce güçleniyor, Zhuge Liang geri yuvarlanarak yüz tokadı bir an mı planlıyor?
CEO akşam çalışması: bugün büyük şirketlerin manşetlerine bir bakış
Onmyoji SP Arakawanın ana zaman çizelgesi spekülasyonu: eski arkadaşlar yeni düşman olur, Xiaolang "gamalı haç" mı?
NetEase Bulut Müzik Mühendisi, mesaj kuyruğunu dönüştürmenin yolunu kişisel olarak ortaya çıkardı! | Teknik Başlıklar
To Top