2013-04-17 8 views
16

Ich bin die kubische Bezier-Kurve-Logik in meiner one of Android Application implementieren.Finden Sie einen neuen Kontrollpunkt, wenn der Endpunkt in der kubischen Bezier-Kurve ändert

Ich habe kubische Bezier-Kurve Code auf Leinwand in OnDraw der benutzerdefinierten Ansicht implementiert.

// Path to draw cubic bezier curve 
Path cubePath = new Path(); 

// Move to startPoint(200,200) (P0) 
cubePath.moveTo(200,200); 

// Cubic to with ControlPoint1(200,100) (C1), ControlPoint2(300,100) (C2) , EndPoint(300,200) (P1) 
cubePath.cubicTo(200,100,300,100,300,200); 

// Draw on Canvas 
canvas.drawPath(cubePath, paint); 

Ich visualisieren obigen Code in der folgenden Abbildung.

Output of above code

[aktualisiert]

Logic for selecting first control points, I've taken , 
baseX = 200 , baseY = 200 and curve_size = X of Endpoint - X of Start Point 

Start Point  : x = baseX and y = baseY 
Control Point 1 : x = baseX and y = baseY - curve_size 
Control Point 2 : x = baseX + curve_size and y = baseY - curve_size 
End Point  : x = baseX + curve_size and y = baseY 

Ich möchte Benutzer ermöglichen, EndPoint von oben Kurve zu ändern, und auf der Grundlage der neuen Endpunkte, entkräften ich die Leinwand.

Aber Problem ist, dass Kurve durch zwei Kontrollpunkte, die nach der Änderung in EndPoint neu berechnet werden müssen.

Wie, ich möchte nur neue Kontrollpunkte finden, wenn EndPoint Wechsel von (300.200) bis (250.250)

Wie in folgendes Bild:

New Image

Bitte helfen Sie mir zwei zu berechnen neue Kontrollpunkte, basierend auf dem neuen Endpunkt, dass die Kurvenform unverändert zum vorherigen Endpunkt bleibt.

Ich verweise folgenden Referenz Links während Suche:

http://pomax.github.io/bezierinfo/

http://jsfiddle.net/hitesh24by365/jHbVE/3/

http://en.wikipedia.org/wiki/B%C3%A9zier_curve

http://cubic-bezier.com/

Jede Bezugnahme Link auch in Antwort auf diese Frage zu schätzen.

+1

, wie Sie die ersten beiden Kontrollpunkte Berechnung? Versuchen Sie, gemäß Benutzerbewegungsereignis zu zeichnen? –

+1

@ArunCThomas: Ich habe die Frage mit Logik für die Auswahl von Standard-Kontrollpunkt aktualisiert –

+0

Ich bin mir ziemlich sicher, dass ich das in http: //pomax.github abdecken.io/bezierinfo/# polybezier =) –

Antwort

12

Das Ändern des Endpunkts bedeutet zwei Dinge, eine Drehung entlang P1 und einen Skalierungsfaktor.

Der Skalierungsfaktor (nennen wir es s) len (p1 - p0)/len (p2 - p0)

Für den Rotationsfaktor (nennen wir es r) i verschieben Sie Calculating the angle between three points in android, das gibt auch eine plattformspezifische Implementierung, aber Sie können die Korrektheit überprüfen, indem Sie/rotationg p1 in Bezug auf p0 skalieren, und Sie sollten p2 als Ergebnis erhalten.

Als nächstes gelten Skalierung und Rotation in Bezug auf p0 bis c1 und c2. aus Bequemlichkeit werde ich den neuen c1 'd1' und den neuen d2 anrufen.

d1 = rot(c1 - p0, factor) * s + p0 
d2 = rot(c2 - p0, factor) * s + p0 

einige Pseudo-Code für rot() (Rotations http://en.wikipedia.org/wiki/Rotation_%28mathematics%29)

rot(point p, double angle){ 
    point q; 
    q.x = p.x * cos(angle) - p.y * sin(angle); 
    q.y = p.x * sin(angle) + p.y * cos(angle); 
} 

Ihre Bezierkurve skaliert wird nun zu definieren und in Bezug auf P0 gedreht, wobei P1 bis P2 verändert,

+1

Bitte korrigieren Sie mich, dass der Faktor = r. –

+0

der 'Faktor' wie in meiner Antwort ist ein Skalierungsfaktor, so dass es hoe vielmal länger/kürzer quantifiziert die Linie p1-p3 ist dann die Linie p1-p2. – nido

+0

Ok, Faktor ist nur für die Erhöhung oder Verringerung der Kurvenfläche basierend auf der Skala des neuen Punktes. –

6

Erstens Ich würde Sie bitten, in folgenden Artikeln zu suchen:

  1. Bezier CurvesWhy B-Spline Curve
  2. B-Spline Curve Summary

Was Sie implementieren möchten, ist eine abschnittsweise zusammengesetzte Bézier-Kurve. Auf der Seite Zusammenfassung für n Kontrollpunkte (include start/end) erhalten Sie (n - 1)/3 stückweise Bézier-Kurven.

Die Kontrollpunkte formen die Kurve wörtlich. Wenn Sie keine korrekten Kontrollpunkte mit einem neuen Punkt angeben, können Sie keine glatt verbundene Bezier-Kurve erstellen. Ihre Erzeugung wird nicht funktionieren, da sie zu komplex ist und es keinen allgemein akzeptierten Weg gibt.

Wenn Sie keine zusätzlichen Kontrollpunkte geben wollen/wollen, sollten Sie den Catmull-Rom Spline verwenden, der alle Kontrollpunkte durchläuft und C1 stetig ist (Ableitung ist an jeder Stelle der Kurve kontinuierlich).

Links für Catmull Rom Spline in java/android:

Unterm Strich ist, wenn Sie nicht haben Die Kontrollpunkte verwenden keine kubische Bezierkurve. Sie zu generieren ist ein Problem, nicht die Lösung.

6

Es scheint, dass Sie hier ein Quadrat drehen und skalieren, wo Sie die beiden unteren Punkte kennen und die anderen beiden berechnen müssen. Die zwei bekannten Punkte bilden mit den anderen beiden zwei Dreiecke, also müssen wir nur den dritten Punkt in einem Dreieck finden. Nehme an den Endpunkt ist x1, y1:

PointF c1 = calculateTriangle(x0, y0, x1, y1, true); //find left third point 
PointF c2 = calculateTriangle(x0, y0, x1, y1, false); //find right third point 

cubePath.reset(); 
cubePath.moveTo(x0, y0); 
cubePath.cubicTo(c1.x, c1.y, c2.x, c2.y, x1, y1); 


private PointF calculateTriangle(float x1, float y1, float x2, float y2, boolean left) { 
       PointF result = new PointF(0,0); 
       float dy = y2 - y1; 
       float dx = x2 - x1; 
       float dangle = (float) (Math.atan2(dy, dx) - Math.PI /2f); 
       float sideDist = (float) Math.sqrt(dx * dx + dy * dy); //square 
       if (left){ 
        result.x = (int) (Math.cos(dangle) * sideDist + x1); 
        result.y = (int) (Math.sin(dangle) * sideDist + y1);      
       }else{ 
        result.x = (int) (Math.cos(dangle) * sideDist + x2); 
        result.y = (int) (Math.sin(dangle) * sideDist + y2); 
       } 
       return result; 
      } 

...

Es andere Art und Weise, dies zu tun, wo es keine Rolle spielt, wie viele Punkte Sie zwischen dem ersten haben und den letzten Punkt in der Pfad oder Ereignis seine Form.

//Find scale 
Float oldDist = (float) Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); 
Float newDist = (float) Math.sqrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0)); 
Float scale = newDist/oldDist; 

//find angle 
Float oldAngle = (float) (Math.atan2(y1 - y0, x1 - x0) - Math.PI /2f); 
Float newAngle = (float) (Math.atan2(y2 - y0, x2 - x0) - Math.PI /2f); 
Float angle = newAngle - oldAngle; 

//set matrix 
Matrix matrix = new Matrix(); 
matrix.postScale(scale, scale, x0, y0); 
matrix.postRotate(angle, x0, y0); 

//transform the path 
cubePath.transform(matrix); 
4

Eine kleine Variante auf Anregung von

Lumis
// Find scale 
Float oldDist = (float) Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); 
Float newDist = (float) Math.sqrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0)); 
Float scale = newDist/oldDist; 

// Find angle 
Float oldAngle = (float) (Math.atan2(y1 - y0, x1 - x0)); 
Float newAngle = (float) (Math.atan2(y2 - y0, x2 - x0)); 
Float angle = newAngle - oldAngle; 

Matrix matrix = new Matrix(); 
matrix.postScale(scale, scale); 
matrix.postRotate(angle); 

float[] p = { c1.x, c1.y, c2.x, c2.y }; 
matrix.mapVectors(p); 
PointF newC1 = new PointF(p[0], p[1]); 
PointF newC2 = new PointF(p[2], p[3]); 
+1

Ich würde matrix.mapPoints (p) verwenden. Ich habe selbst darüber nachgedacht, aber er muss das nur tun, wenn er Kontrollpunkte für etwas anderes verwenden oder für die spätere Verwendung speichern möchte, denn sie können immer von p0, p1 und p3 abgeleitet werden. – Lumis

Verwandte Themen