2013-04-17 15 views
16

Sto implementando la logica della curva di Bezier cubica nella mia Applicazione Android.Trova un nuovo punto di controllo quando si modifica il punto finale nella curva cubica di bezier

Ho implementato il codice della curva di Bezier cubico su tela in onDraw della visualizzazione personalizzata.

// 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); 

Visualizzo il codice sopra riportato nell'immagine seguente.

Output of above code

[Aggiornamento]

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 

voglio permettere all'utente di cambiare EndPoint di sopra della curva, e sulla base dei nuovi punti finali, ho invalida la tela.

Ma il problema è che Curva mantiene due punti di controllo, che devono essere ricalcolati in seguito alla modifica in EndPoint.

Come, voglio solo trovare nuovi punti di controllo quando EndPoint cambiamento da (300.200) a (250.250)

Come seguente immagine:

New Image

Please help me per calcolare due nuove Punti di controllo basati sul nuovo punto finale che la forma della curva manterrà la stessa del punto finale precedente.

Mi riferisco seguenti link di riferimento durante la ricerca:

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

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

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

http://cubic-bezier.com/

Qualsiasi link di riferimento apprezzato anche in risposta di questa domanda.

+1

come stai calcolando i primi due punti di controllo? Stai cercando di disegnare in base all'evento di movimento dell'utente? –

+1

@ArunCThomas: ho aggiornato la domanda con la logica per la selezione del punto di controllo predefinito –

+0

Sono piuttosto sicuro che lo copra in http: //pomax.github.io/bezierinfo/# polybezier =) –

risposta

12

cambiare il punto finale significa due cose, una rotazione lungo P1 e un fattore di scala.

Il fattore di scala (consente di chiamare s) è len (p1 - p0)/len (p2 - p0)

Per il fattore di rotazione (consente di chiamare r) ti rimetto a Calculating the angle between three points in android, che dà anche un'implementazione specifica della piattaforma, ma è possibile verificare la correttezza ridimensionando/ruotando p1 in relazione a p0, e si dovrebbe ottenere p2 come risultato.

Successivamente, applicare ridimensionamento e rotazione rispetto a p0 a c1 e c2. per comodità chiamerò il nuovo c1 'd1' e il nuovo d2.

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

definire alcuni pseudocodice per rot() (rotazione 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); 
} 

la curva di Bezier viene ora ridimensionata e ruotata rispetto a p0, con p1 cambiato in p2,

+1

Per favore correggimi che il fattore = r. –

+0

il 'fattore' come nella mia risposta è un fattore di scala, quindi quantifica la zappa molte volte più a lungo/più breve la linea p1-p3 è quindi la linea p1-p2. – nido

+0

Ok, il fattore è solo per aumentare o diminuire l'area della curva in base alla scala del nuovo punto. –

6

Innanzitutto Vorrei chiederti di esaminare i seguenti articoli:

  1. Bezier Curves
  2. Why B-Spline Curve
  3. B-Spline Curve Summary

cosa si sta cercando di attuare è una curva di Bézier tratti composito. Dalla pagina Riepilogo per n punti di controllo (includi inizio/fine) ottieni (n - 1)/3 curve di Bézier a tratti.

I punti di controllo modellano la curva letteralmente. Se non si assegnano i punti di controllo appropriati con un nuovo punto, non sarà possibile creare una curva Bezier collegata in modo fluido. Generarli non funzionerà, in quanto è troppo complesso e non esiste un modo universalmente accettato.

Se non si dispone/si desidera fornire punti di controllo aggiuntivi, è necessario utilizzare la spline Catmull-Rom, che passa attraverso tutti i punti di controllo e sarà continua C1 (la derivata è continua in qualsiasi punto della curva).

Collegamenti per Catmull Rom Spline in Java/Android:

Linea di fondo è che se non si dispone di i punti di controllo non usano la curva cubica di Bezier. Generarli è un problema, non la soluzione.

6

Sembra che tu stia qui ruotando e ridimensionando un quadrato in cui conosci i due punti in basso e devi calcolare gli altri due. I due punti noti formano due triangoli con gli altri due, quindi dobbiamo solo trovare il terzo punto in un triangolo. Supose il punto finale è 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; 
      } 

...

C'è altro modo per fare questo, dove non importa quanti punti avete tra il primo e l'ultimo punto della percorso o evento la sua forma.

//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

Una piccola variante per il suggerimento di 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

Vorrei usare matrix.mapPoints (p). Ci ho pensato anch'io, ma ha bisogno di farlo solo se vuole utilizzare i punti di controllo per qualcos'altro o memorizzarli per un uso futuro, poiché possono sempre essere derivati ​​da p0, p1 e p3. – Lumis

Problemi correlati