2B eğriyi veri depolama için noktalara dönüştürme


12

Ben bir dosya veya veritabanına kaydedebilirsiniz böylece herhangi bir eğri yani yol minimum nokta sayısına dönüştürür bir algoritma oluşturdum.

Yöntem basittir: Üç noktayı eşit adımlarla hareket ettirir ve bu noktaların oluşturduğu çizgiler arasındaki açıyı ölçer. Açı toleranstan daha büyükse, o noktaya kadar yeni bir kübik eğri oluşturur. Sonra çizgileri ileri doğru hareket ettirir ve açıyı tekrar ölçer…

Android Path Class'ı bilenler için - dstPath'in noktaları bir Array'a kaydeden özel bir sınıf olduğunu unutmayın, böylece daha sonra puanları kaydedebilirim, srcPath bir Bölgeler birliğinin sonucudur ve bu nedenle benim için önemli bir nokta yoktur kaydetmek.

Sorun, çemberin kaynak kodun mükemmel bir daire ve dikdörtgenden oluştuğu aşağıdaki kod tarafından üretilen bu görüntüde görebileceğiniz gibi düzgün görünmemesi. Tolerans açısını ve basamak uzunluğunu değiştirmeye çalıştım, ama hiçbir şey yardımcı olmuyor. Acaba bu algoritma için herhangi bir gelişme önerebilir misiniz, yoksa farklı bir yaklaşım.

EDIT: Şimdi Android java kullananların tüm kodunu yayınladım, böylece kolayca deneyebilir ve deneyebilirler.

resim açıklamasını buraya girin

public class CurveSavePointsActivity extends Activity{

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(new CurveView(this));
    }

    class CurveView extends View{

        Path srcPath, dstPath;
        Paint srcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Paint dstPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        public CurveView(Context context) {
            super(context);

            srcPaint.setColor(Color.BLACK);
            srcPaint.setStyle(Style.STROKE);
            srcPaint.setStrokeWidth(2);
            srcPaint.setTextSize(20);

            dstPaint.setColor(Color.BLUE);
            dstPaint.setStyle(Style.STROKE);
            dstPaint.setStrokeWidth(2);
            dstPaint.setTextSize(20);

            srcPath = new Path();
            dstPath = new Path();

        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);

            //make a circle path
            srcPath.addCircle(w/4, h/2, w/6 - 30, Direction.CW);

            //make a rectangle path
            Path rectPath = new Path();
            rectPath.addRect(new RectF(w/4, h/2 - w/16, w*0.5f, h/2 + w/16), Direction.CW);


            //create a path union of circle and rectangle paths
            RectF bounds = new RectF();
            srcPath.computeBounds(bounds, true);
            Region destReg = new Region();
            Region clip = new Region();
            clip.set(new Rect(0,0, w, h));
            destReg.setPath(srcPath, clip);
            Region srcReg = new Region();
            srcReg.setPath(rectPath, clip); 
            Region resultReg = new Region();
            resultReg.op(destReg, srcReg, Region.Op.UNION);
            if(!resultReg.isEmpty()){
                srcPath.reset();
                srcPath.addPath(resultReg.getBoundaryPath());
            }

            //extract a new path from the region boundary path
            extractOutlinePath();

            //shift the resulting path bottom left, so they can be compared
            Matrix matrix = new Matrix();
            matrix.postTranslate(10, 30);
            dstPath.transform(matrix);

        }

         @Override 
            public void onDraw(Canvas canvas) { 
                super.onDraw(canvas);    
                canvas.drawColor(Color.WHITE);
                canvas.drawPath(srcPath, srcPaint);
                canvas.drawPath(dstPath, dstPaint);

                canvas.drawText("Source path", 40, 50, srcPaint);
                canvas.drawText("Destination path", 40, 100, dstPaint);
         }


         public void extractOutlinePath() {

             PathMeasure pm = new PathMeasure(srcPath, false); //get access to curve points

             float p0[] = {0f, 0f}; //current position of the new polygon
             float p1[] = {0f, 0f}; //beginning of the first line
             float p2[] = {0f, 0f}; //end of the first & the beginning of the second line
             float p3[] = {0f, 0f}; //end of the second line

             float pxStep = 5; //sampling step for extracting points
             float pxPlace  = 0; //current place on the curve for taking x,y coordinates
             float angleT = 5; //angle of tolerance

             double a1 = 0; //angle of the first line
             double a2 = 0; //angle of the second line

             pm.getPosTan(0, p0, null); //get the beginning x,y of the original curve into p0
             dstPath.moveTo(p0[0], p0[1]); //start new path from the beginning of the curve
             p1 = p0.clone(); //set start of the first line

             pm.getPosTan(pxStep, p2, null); //set end of the first line & the beginning of the second

             pxPlace = pxStep * 2;
             pm.getPosTan(pxPlace, p3, null); //set end of the second line


             while(pxPlace < pm.getLength()){
             a1 = 180 - Math.toDegrees(Math.atan2(p1[1] - p2[1], p1[0] - p2[0])); //angle of the first line
             a2 = 180 - Math.toDegrees(Math.atan2(p2[1] - p3[1], p2[0] - p3[0])); //angle of the second line

             //check the angle between the lines
             if (Math.abs(a1-a2) > angleT){

               //draw a straight line to the first point if the current p0 is not already there
               if(p0[0] != p1[0] && p0[1] != p1[1]) dstPath.quadTo((p0[0] + p1[0])/2, (p0[1] + p1[1])/2, p1[0], p1[1]);

               dstPath.quadTo(p2[0] , p2[1], p3[0], p3[1]); //create a curve to the third point through the second

               //shift the three points by two steps forward
               p0 = p3.clone();
               p1 = p3.clone();
               pxPlace += pxStep;
               pm.getPosTan(pxPlace, p2, null); 
               pxPlace += pxStep;
               pm.getPosTan(pxPlace, p3, null);
               if (pxPlace > pm.getLength()) break;
             }else{
               //shift three points by one step towards the end of the curve
               p1 = p2.clone(); 
               p2 = p3.clone();
               pxPlace += pxStep;
               pm.getPosTan(pxPlace, p3, null); 
             }
             }
             dstPath.close();
         }
    }

}

İşte orijinal ve algoritmamın ürettikleri arasında bir karşılaştırma:

yollar arasında karşılaştırma;  Türevde belirgin şekilde daha pürüzsüz köşeler


neden b-spline kullanmıyorsunuz?
GriffinHeart

4
bir şeyin bir daire ve bir dikdörtgen olduğunu biliyorsanız, neden bir daire ve bir dikdörtgen saklamıyorsunuz? Ve genelleştirilmiş formda - girdiniz ne olursa olsun, işinizi muhtemelen depolamak için makul bir biçimdir. Farklı bir soru gibi görünen bir sıkıştırma şeması arıyorsanız (veya en azından kaynak veriler hakkında çok daha fazla bilgiye ihtiyacımız var) yardımcı olmak).
Jeff Gates

İlk cümlede söylediğim gibi öngörülemeyen herhangi bir şekil olabilir - buradaki daire ve dikdörtgen sadece bir test örneğidir.
Lumis

@Lumis gerçekten b-spline'lara bakmalısın, ne için olduklarını. Kendi çözümünüzü uygulamak için herhangi bir neden var mı?
GriffinHeart

1
Peki path sınıfı, bu eğrileri spline ile oluşturacak ve böylece zaten kullanacaksınız. Ben daha az matematik odaklı başka bir öneri var: puan kaydetmek yerine, kullanıcı girişini (komut deseni) kaydetmek ve aynı "görüntü" oluşturmak için tekrar.
GriffinHeart

Yanıtlar:


6

Bence iki sorunun var:

Simetrik olmayan kontrol noktaları

Başlangıçta p0 ila p1 ve p1 ila p2 arasında eşit mesafelerle başlarsınız. Çizgi parçaları arasındaki tolerans açısı karşılanmazsa, p1 ve p2'yi ileriye taşırsınız, ancak p0'ı olduğu yerde tutun. Bu, p1 ile p2 arasındaki mesafeyi aynı tutarken p0 ile p1 arasındaki mesafeyi arttırır. Kontrol noktaları olarak p1'i kullanarak bir eğri oluşturduğunuzda, son eğriden bu yana kaç yinelemenin geçtiğine bağlı olarak p2'ye doğru eğilimli olabilir. Eğer p2'yi p1'den iki kat daha fazla hareket ettirirseniz, noktalar arasında eşit mesafeler elde edersiniz.

İkinci dereceden eğriler

Diğer cevaplarda da belirtildiği gibi, kuadratik eğri bu durum için çok iyi değildir. Oluşturduğunuz bitişik eğriler, kontrol noktasını ve bir teğeti . Giriş verileriniz sadece puan olduğunda, Catmull-Rom Spline bu amaç için iyi bir seçimdir. Kontrol noktaları için teğetlerin önceki ve sonraki noktalardan hesaplandığı kübik bir Hermite eğrisi.

Android'deki Path API, parametrelerle ilgili Hermite eğrilerinden biraz farklı olan Bézier eğrilerini destekler. Neyse ki Hermite eğrileri Bézier eğrilerine dönüştürülebilir.Buraya Googling yaparken bulduğum ilk örnek kod. Bu Stackoverflow cevabı da formülü veriyor gibi görünüyor.

Keskin kenarlar sorunundan da bahsettiniz. Sahip olduğunuz giriş verileriyle, gerçek bir keskin köşe veya çok dik bir eğri olup olmadığını tespit etmek imkansızdır. Bu bir sorun haline gelirse, gerektiğinde anında adımı artırarak / azaltarak yinelemeyi daha uyarlanabilir hale getirebilirsiniz.

Düzenle: sonra düşünmek sonra kuadratik eğrileri sonuçta kullanılabilir. Kontrol noktası olarak p1'i kullanarak p0'dan p2'ye ikinci dereceden bir eğri çizmek yerine, kontrol noktaları olarak yeni bir p0_1 noktası kullanarak p0'dan p1'e çizin. Aşağıdaki resme bakın. Yeni kontrol noktaları

P0_1, p0 ve p1'deki teğetlerin kesişimindeyse, sonuç düzgün olmalıdır. Daha da iyisi, çünküPathMeasure.getPosTan() üçüncü parametre olarak da teğet döndüğünden, bitişik noktalardan yaklaşıklar yerine gerçek doğru teğetleri kullanabilirsiniz. Bu yaklaşımla mevcut çözümünüzde daha az değişiklik yapmanız gerekir.

Bu cevaba dayanarak , kesişim noktası aşağıdaki formülle hesaplanabilir:

getPosTan(pxPlace0, p0, t0); // Also get the tangent
getPosTan(pxPlace1, p1, t1);
t1 = -t1; // Reverse direction of second tangent
vec2 d = p1 - p0;
float det = t1.x * t0.y - t1.y * t0.x;
float u = (d.y * t1.x - d.x * t1.y) / det;
float v = (d.y * t0.x - d.x * t0.y) / det; // Not needed ... yet
p0_1 = p0 + u * t0;

Ancak bu çözüm yalnızca u ve v'nin ikisi de negatif değilse çalışır. İkinci resme bakın: Işınlar kesişmiyor

Burada ışınlar çizgiler negatif olmasına rağmen kesişmez, çünkü u negatiftir. Bu durumda, öncekine sorunsuz bir şekilde bağlanacak ikinci dereceden bir eğri çizmek mümkün değildir. Burada daha kıvrımlı eğrilere ihtiyacınız var. Bunun için kontrol noktalarını bu cevapta daha önce verilen yöntemle hesaplayabilir veya doğrudan teğetlerden türetebilirsiniz. P0 teğet ışınına p0 + u * t0 ve diğer tersi için projeksiyon c0 ve c1 kontrol noktalarının her ikisini de verir. Ayrıca, teğet ışın üzerinde bulunduğu sürece c0 yerine p0 ve c0 arasında herhangi bir nokta kullanarak eğriyi ayarlayabilirsiniz.

Edit2: Çizim konumunuz p1 ise, bezier kontrol noktalarını aşağıdaki sahte kodla p2'ye hesaplayabilirsiniz:

vec2 p0, p1, p2, p3; // These are calculated with PathMeasure
vec2 cp1 = p1 + (p2 - p0) / 6;
vec2 cp2 = p2 - (p3 - p1) / 6;

Bunlarla p1'den p2'ye bir yol ekleyebilirsiniz:

path.cubicTo(cp1.x, cp1.y, cp2.x, cp2.y, p2.x, p2.y);

Vektör işlemlerini kodunuzla eşleşmek için kayan [ 2 ] dizilerdeki bileşen başına işlemlerle değiştirin . p1 = start;Başlatarak başlarsınız ve p2 ve p3 sonraki noktalardır. p0 başlangıçta tanımsızdır. Henüz p0 değerinin bulunmadığı ilk segment için, kontrol noktası olarak p1'den p2'ye cp2 ile ikinci dereceden bir eğri kullanabilirsiniz. P3'ün bulunmadığı yolun sonu için de, kontrol noktası olarak cp1 ile p1'den p2'ye kuadratik bir eğri çizebilirsiniz. Alternatif olarak, ilk segment için p0 = p1 ve son segment için p3 = p2 başlatabilirsiniz. Her segmentten sonra değerleri kaydırırsınızp0 = p1; p1 = p2; and p2 = p3; ileri giderken .

Yolu kaydederken p0 ... pN'nin tüm noktalarını kaydedersiniz. Gerektiği gibi hesaplanabildikleri için cp1 ve cp2 kontrol noktalarını kaydetmeye gerek yoktur.

Edit3: Eğri üretimi için iyi giriş değerleri elde etmek zor gibi görünüyor, başka bir yaklaşım öneriyorum: Serileştirme kullanın. Android Path bunu desteklemiyor gibi görünüyor, ancak Neyse ki Bölge sınıfı destekliyor. Kod için bu cevaba bakınız . Bu size kesin sonucu vermelidir. Optimize edilmemişse serileştirilmiş formda biraz yer kaplayabilir, ancak bu durumda çok iyi sıkıştırması gerekir. GZIPOutputStream kullanarak Android Java'da sıkıştırma kolaydır .


Kulağa umut verici geliyor. Bununla birlikte, p0 değil, kullanılan p1, p2, p3, p0 sadece hesaplandıklarında yeni belirli noktaları saklamak ve düz çizgiler uğruna içindir, böylece her adımdan örnek alınmazlar. Yeni kontrol noktaları için x, y hesaplamasında bana yardımcı olabilir misiniz?
Lumis

Bunu daha sonra yapabilirdim, ancak bu arada stackoverflow.com/questions/2931573/… 'a bakın . U ve v ile kesişim noktasını elde edebilirsiniz.
msell

Yardım için teşekkürler, bunu denemek istiyorum, ancak Android için Java'da yazılması gerekiyor. Hiçbir vector2 ve t1 ve p1 vb şamandıra dizileri vardır, bu yüzden t1 = -t1 veya u * t0 gibi doğrudan bir işlem yapamam. T1 = -t1'in t1.x = -t1x anlamına geldiğini varsayıyorum; t1.y = -t1.y vb, değil mi?
Lumis

Evet, daha kompakt ve okunabilir hale getirmek için sadece sahte koddu.
msell

Arsa kalınlaşıyor. Android'de iki yolun bölge kesişimi kenar yumuşatılmamış bir yol döndürdüğü için, tanjantlar yerin üstündedir. Bu nedenle uygun çözüm, önce verilen noktalardan düzgün bir eğri sürmek ve daha sonra örneklemek olacaktır. Kodunuz kenar yumuşatılmış bir yolda mükemmel çalışır, uygun kontrol noktaları üretir.
Lumis

13

W3C ne yapardı?

İnternette bu sorun vardı. World Wide Web Consortium ettim. 1999'dan beri önerilen standart bir çözüme sahiptir : Ölçeklenebilir Vektör Grafikleri (SVG) . Bu bir var XML özellikle 2D şekilleri saklamak için tasarlanmış tabanlı dosya biçimi.

" Ölçeklenebilir-ne? "

Ölçeklenebilir Vektör Grafikleri !

  • Ölçeklenebilir : Herhangi bir boyuta yumuşak bir şekilde ölçeklenmek içindir.
  • Vektör : Vektörlerin matematiksel kavramına dayanır .
  • Grafikler . Resim yapmak demekti.

İşte SVG sürüm 1.1 için teknik özellikler.
(Adından korkmayın; Okumak gerçekten hoş.)

Daireler veya dikdörtgenler gibi temel şekillerin tam olarak nasıl saklanacağını yazdılar. Örneğin, dikdörtgenler bu özelliklere sahip: , , , , , . ( Ve yuvarlak köşeler için kullanılabilir.)xywidthheightrxryrxry

İşte SVG'deki örnek dikdörtgeni: (Şey, gerçekten iki - bir tuval anahat için.)

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="12cm" height="4cm" viewBox="0 0 1200 400"
     xmlns="http://www.w3.org/2000/svg" version="1.1">
  <desc>Example rect01 - rectangle with sharp corners</desc>

  <!-- Show outline of canvas using 'rect' element -->
  <rect x="1" y="1" width="1198" height="398"
        fill="none" stroke="blue" stroke-width="2"/>

  <rect x="400" y="100" width="400" height="200"
        fill="yellow" stroke="navy" stroke-width="10"  />
</svg>

İşte neyi temsil ediyor:

mavi anahat ile sarı bir dikdörtgen

Spesifikasyonun dediği gibi, ihtiyacınız yoksa bazı özellikleri dışarıda bırakabilirsiniz. (Örneğin rxve ryöznitelikler burada kullanılmadı.) Evet, en üstte DOCTYPEsadece oyununuz için ihtiyacınız olmayacak bir ton cruft var . Onlar da isteğe bağlıdır.

Yollar

SVG yolları , bir kağıda kalem koyarsanız, onu hareket ettirir ve sonunda tekrar kaldırırsanız , bir yolunuz olduğu anlamına gelen "yollardır" . Onlar yok olması gereken kapalı ama olabilir.

Her yolun, yol verilerini , temelde sadece bir kağıda kalem koymak ve hareket ettirmek için bir komut dizisi diçeren bir özelliği ("çizmek" anlamına geldiğini düşünüyorum) vardır .

Üçgen örneğini veriyorlar:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="4cm" height="4cm" viewBox="0 0 400 400"
     xmlns="http://www.w3.org/2000/svg" version="1.1">
  <title>Example triangle01- simple example of a 'path'</title>
  <desc>A path that draws a triangle</desc>
  <rect x="1" y="1" width="398" height="398"
        fill="none" stroke="blue" />
  <path d="M 100 100 L 300 100 L 200 300 z"
        fill="red" stroke="blue" stroke-width="3" />
</svg>

kırmızı üçgen

Bkz dözniteliği path?

d="M 100 100 L 300 100 L 200 300 z"

MBir olan komut için taşı (koordinatlar ardından), Ls içindir üzere Hattı (koordinatlarla) ve z(; koordinatları gerekmez yani birinci konuma bir çizgi sırtını çizin) yolunu kapatmak için bir komuttur.

Düz çizgiler sıkıcı mı? Kullan kübik veya kuadratik Bézier komutları!

bazı kübik Béziers

Bézier eğrilerinin arkasındaki teori başka bir yerde ( Wikipedia'da olduğu gibi ) iyi ele alınmıştır, ancak işte yönetim özeti: Béziers'ın, aradaki eğrinin nereye gittiğini etkileyen birçok kontrol noktası ile bir başlangıç ​​ve bitiş noktası vardır.

ikinci dereceden bir Bézier'in izini sürmek

Belirtim ayrıca, istediğinizde en temel şekillerin yollara dönüştürülmesi için talimatlar verir.

SVG neden ve ne zaman kullanılır?

Bu yolda (pun amaçlı) gitmek istiyorsanız dikkatli olun, çünkü metindeki herhangi bir keyfi 2D şekli temsil etmek oldukça karmaşıktır! Kendinizi sadece (potansiyel olarak gerçekten çok) düz çizgilerden oluşan yollarla sınırlarsanız hayatınızı çok daha kolay hale getirebilirsiniz.

Ancak, rastgele şekiller istemeye karar verirseniz, SVG gitmenin yoludur: Harika araç desteğine sahiptir: XML ayrıştırma için düşük düzeyde ve SVG düzenleyici araçlarında birçok kitaplık bulabilirsiniz. için yüksek düzeyde .

Ne olursa olsun, SVG standardı iyi bir örnek teşkil ediyor.


Soru, bir eğriyi kaydetmemek, puanlara dönüştürmektir. Ancak bu referans için teşekkür ederiz, SVG standardını bilmek iyidir.
Lumis

@ Lumis Başlık ve içerik aksini öneriyor. Soruyu yeniden yazmayı düşünün. (Ya da şimdi bu oldukça kurulduğundan başka bir soru sorar.)
Anko

4

Kodunuz yanıltıcı bir yorum içeriyor:

dstPath.quadTo(p2[0] , p2[1], p3[0], p3[1]); //create a curve to the third point through the second

Bir kuadratik Bezier eğrisi yok değil gitmek yoluyla ikinci noktaya. İkinci noktadan geçmek istiyorsanız, hermite eğrisi gibi farklı bir eğri türüne ihtiyacınız vardır . Path sınıfını kullanabilmeniz için, hermite eğrilerini bezer'e dönüştürebilirsiniz.

Başka bir öneri puanları örneklemek yerine, atladığınız puanların ortalamasını kullanın.

Başka bir öneri, bir eşiği bir açı olarak kullanmak yerine, gerçek eğri ile yaklaşık eğri arasındaki farkı kullanın. Açılar asıl sorun değildir; asıl sorun, nokta kümesinin bezier eğrisine uymamasıdır.

Başka bir öneri kübik bezleyiciler kullanmak, birinin tanjantının diğerinin tanjantına uymasıdır. Aksi takdirde (kuadratikler ile) Bence eğrileriniz düzgün bir şekilde uyuşmaz.


Haklısın, ikinci nokta sadece eğriyi ona doğru "çekiyor". CubicTo, quadTo olarak biri yerine iki kontrol noktası gerektirir. Sorun elbette doğru kontrol noktalarının nasıl alınacağıdır. Kaynak Yolu düz veya yuvarlak herhangi bir şeklin bir kombinasyonu olabileceğinden keskin köşeleri kaybetmek istemediğimi unutmayın - temel olarak seçilen yolu kaydedebileceğim bir görüntü seçim aracı yapıyorum.
Lumis

4

İki yolun daha düzgün bir kesişimini elde etmek için, kesişmeden önce ölçeklendirebilir ve sonra ölçeklendirebilirsiniz.

Bunun iyi bir çözüm olup olmadığını bilmiyorum, ama benim için iyi çalıştı. Aynı zamanda hızlı. Örneğimde, oluşturduğum bir desenle (çizgiler) yuvarlak bir yolla kesişiyorum. Ölçeklendirildiğinde bile iyi görünüyor.

İşte benim kod:

    Path mypath=new Path(<desiredpath to fill with a pattern>);
    String sPatternType=cpath.getsPattern();

    Path pathtempforbounds=new Path(cpath.getPath());
    RectF rectF = new RectF();
     if (sPatternType.equals("1")){
         turnPath(pathtempforbounds, -45);
     }
     pathtempforbounds.computeBounds(rectF, true);

     float ftop=rectF.top;
     float fbottom=rectF.bottom;
     float fleft=rectF.left;
     float fright=rectF.right;
     float xlength=fright-fleft;

     Path pathpattern=new Path();

     float ypos=ftop;
     float xpos=fleft;

     float fStreifenbreite=4f;

     while(ypos<fbottom){
         pathpattern.moveTo(xpos,ypos);
         xpos=xpos+xlength;
         pathpattern.lineTo(xpos, ypos);
         ypos=ypos+fStreifenbreite;
         pathpattern.lineTo(xpos, ypos);
         xpos=xpos-xlength;
         pathpattern.lineTo(xpos, ypos);
         ypos=ypos-fStreifenbreite;
         pathpattern.lineTo(xpos, ypos);
         pathpattern.close();
         ypos=ypos+2*fStreifenbreite;

     }

     // Original vergrössern

     scalepath(pathpattern,10);
     scalepath(mypath,10);

     if (sPatternType.equals("1")){
         Matrix mdrehen=new Matrix();
         RectF bounds=new RectF();
         pathpattern.computeBounds(bounds, true);
         mdrehen.postRotate(45, (bounds.right + bounds.left)/2,(bounds.bottom + bounds.top)/2);
         pathpattern.transform(mdrehen);
     }

     RectF rectF2 = new RectF();
     mypath.computeBounds(rectF2, true);

     Region clip = new Region();
     clip.set((int)(rectF2.left-100f),(int)(rectF2.top -100f), (int)(rectF2.right+100f),(int)( rectF2.bottom+100f));
     Region region1 = new Region();
     region1.setPath(pathpattern, clip);

     Region region2 = new Region();
     region2.setPath(mypath, clip);

     region1.op(region2, Region.Op.INTERSECT);


     Path pnew=region1.getBoundaryPath();


     scalepath(pnew, 0.1f);
     cpath.setPathpattern(pnew);




public void turnPath(Path p,int idegree){
     Matrix mdrehen=new Matrix();
     RectF bounds=new RectF();
     p.computeBounds(bounds, true);
     mdrehen.postRotate(idegree, (bounds.right + bounds.left)/2,(bounds.bottom + bounds.top)/2);
     p.transform(mdrehen);
}

public void scalepath(Path p,float fscale){
     Matrix mverkleinern=new Matrix();
     mverkleinern.preScale(fscale,fscale);
     p.transform(mverkleinern);
}

resim açıklamasını buraya girin

Canvas.scale () ile yakınlaştırma yaparken hala pürüzsüz görünüyor: resim açıklamasını buraya girin


Kim bana görüntüleri eklemek için 10 itibar harcadı teşekkürler :-)
user1344545

1
Şaşırtıcı bir şekilde, bu basit hile iki problemi çözüyor: ilk olarak ortaya çıkan kavşak veya birleşim yolunu pürüzsüz hale getiriyor ve ikinci olarak da aynı ölçeklenmiş yolu örneklerken söz konusu kodum mükemmel pürüzsüz bir sonuç veriyor. Ne beklenmedik ve basit bir çözüm, teşekkür ederim!
Lumis

@user Düzenleme ücretsizdir. <2k rep kullanıcıları için bu aslında +2'dir.
Anko

@ Lumum Biraz kafam karıştı - yolları nasıl saklayacağınızı sorduğunuzu sanıyordum ?
Anko

1
Ne yazık ki, daha fazla testten sonra Bölge çizildiğinde yolun kaplayacağı pikseller kullandığından, Yolun ölçeklendirilmesi büyükse ve tekrar tekrar yapıldığında uygulamanın belleği yetersiz kaldığını gördüm. Bu yüzden bu çözüm sınırlı ve risklidir, ancak akılda tutulması iyidir.
Lumis

3

Çokgen enterpolasyonuna bakın ( http://en.wikipedia.org/wiki/Polynomial_interpolation )

Temel olarak, n eşit aralıklı düğüm alırsınız (optimum enterpolasyon eşit aralıklı değildir, ancak sizin durumunuz için yeterince iyi ve uygulanması kolay olmalıdır)

Eğer eğri arasındaki hatayı azaltır n düzeninde bir poligon ile bitirmek durumunda (<- Büyük varsa) çizgidir pürüzsüz yeter.

Sizin durumunuzda doğrusal (sıra 1) enterpolasyon yapıyorsunuz .

Diğer vaka ( GriffinHeart'ın önerdiği gibi) Splines kullanmaktı ( http://en.wikipedia.org/wiki/Spline_interpolation )

Her iki durumda da eğriniz için bir tür polinom uyumu sağlayabilirsiniz .


2

Dönüştürmenin noktası yalnızca depolama amaçlıysa ve ekranda geri oluşturduğunuzda düzgün olması gerekir, o zaman alabileceğiniz en yüksek aslına uygun depolama, yine de belirli bir eğriyi sürdürmek için gereken toplam depolama alanını en aza indirebilir dairenin niteliklerini (veya bir yay yerine) saklamak ve talep üzerine yeniden çizmek.

Menşei. Radius. Ark çizmek için başlatma / durdurma açıları.

Daireyi / yayı oluşturmak için yine de noktalara dönüştürmeniz gerekiyorsa, her zaman sadece nitelikleri saklarken, depolama alanından yükledikten sonra bunu yapabilirsiniz.


Kaynak yolu / eğri, serbest çizginin çizimi dahil herhangi bir şekil olabilir. Her bileşeni ayrı ayrı kaydetmek ve sonra yüklendiğinde birleştirmek zorunda kalacak bir çözüm düşünmüştüm, ancak çok fazla iş gerektiriyor ve her dönüşümün her birine uygulanması gereken karmaşık bir nesnenin manipülasyonunu yavaşlatacaktı. bileşenlerini tekrar kaydedebilmek için.
Lumis

2

Düz çizgilerin aksine eğrilere gitmenin bir nedeni var mı? Düz çizgilerle çalışmak daha kolaydır ve donanımda verimli bir şekilde oluşturulabilir.

Dikkate değer diğer yaklaşım, şeklin içinde, dışında veya ana hatlarında olup olmadığını belirten piksel başına birkaç bit saklamaktır. Bu iyi sıkıştırılmalıdır ve karmaşık seçimler için çizgilerden daha verimli olabilir.

Bu makaleleri ilginç / yararlı da bulabilirsiniz:


1

Eğri enterpolasyonuna bir göz atın - uygulayabileceğiniz birkaç eğri türü vardır. O daireye ne kadar çok puan kazanırsanız o kadar iyi. Depolama oldukça ucuzdur - bu nedenle 360 ​​yakın düğümü çıkarmak yeterince ucuzsa (konum için 8 baytta bile; 360 düğümü depolamak zor olur).

Burada bazı enterpolasyon örnekleri ile yerleştirebilirsiniz sadece dört nokta ; ve sonuçlar oldukça iyi (benim favorim bu durum için Bezier, ancak diğerleri diğer etkili çözümler hakkında bilgi verebilir).

Burada da oynayabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.