android - numericos - que es una curva spline
Encuentre un nuevo punto de control cuando el punto final cambie en la curva bezier cúbica (4)
Estoy implementando la lógica de curva cúbica bezier en mi aplicación de Android.
He implementado el código de curva cúbica bezier en el lienzo en onDraw de vista personalizada.
// 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);
Visualizo el código de arriba en la siguiente imagen.
[Actualizado]
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
Quiero permitir que el usuario cambie el punto final de la curva anterior y, en función de los nuevos puntos finales, invalido el lienzo.
Pero el problema es que, Curve mantiene por dos puntos de control, que debe volver a calcular sobre el cambio en EndPoint.
Me gusta, solo quiero encontrar nuevos puntos de control cuando EndPoint cambie de (300,200) a (250,250)
Como en la siguiente imagen:
Ayúdame a calcular dos nuevos puntos de control basados en el nuevo punto final que la forma de la curva mantendrá igual que el punto final anterior .
Me refiero a los siguientes enlaces de referencia durante la búsqueda:
http://pomax.github.io/bezierinfo/
http://jsfiddle.net/hitesh24by365/jHbVE/3/
http://en.wikipedia.org/wiki/B%C3%A9zier_curve
Cualquier enlace de referencia también apreciado en respuesta a esta pregunta.
En primer lugar les pido que miren los siguientes artículos:
Lo que está intentando implementar es una curva de Bézier compuesta por partes. Desde la página Resumen de n puntos de control (incluye inicio / final), obtiene (n - 1) / 3 curvas de Bézier por partes.
Los puntos de control dan forma a la curva literalmente . Si no proporciona puntos de control adecuados con un nuevo punto, no podrá crear una curva bezier con una conexión suave. Generarlos no funcionará, ya que es demasiado complejo y no hay una forma universalmente aceptada.
Si no tiene / quiere dar puntos de control adicionales, debe usar la spline Catmull-Rom, que pasa por todos los puntos de control y será C1 continua (la derivada es continua en cualquier punto de la curva).
Enlaces para Catmull Rom Spline en java / android:
- http://hawkesy.blogspot.in/2010/05/catmull-rom-spline-curve-implementation.html
- https://github.com/Dongseob-Park/catmull-rom-spline-curve-android
- Catmull-rom splines para Android (similar a tu pregunta)
La línea de fondo es que si no tiene los puntos de control, no use la curva Bezic cúbica. Generarlos es un problema, no la solución.
Parece que estás aquí girando y escalando un cuadrado donde conoces los dos puntos inferiores y necesitas calcular los otros dos. Los dos puntos conocidos forman dos triángulos con los otros dos, por lo que solo necesitamos encontrar el tercer punto en un triángulo. Supongamos que el punto final es 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;
}
...
Hay otra manera de hacer esto donde no importa cuántos puntos tenga entre el primer y el último punto en la ruta o el evento de su 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);
Una pequeña variante sobre la sugerencia de 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]);
cambiar el punto final significa dos cosas, una rotación a lo largo de P1 y un factor de escala.
El factor de escala (llamémoslo s) es len (p1 - p0) / len (p2 - p0)
Para el factor de rotación (llamémoslo r), lo deferido a Cálculo del ángulo entre tres puntos en Android , lo que también proporciona una implementación específica de la plataforma, pero puede verificar la corrección escalando / rotando p1 en relación con p0, y debería obtener p2 como resultado.
A continuación, aplique escalado y rotación con respecto a p0 a c1 y c2. por conveniencia llamaré al nuevo c1 ''d1'' y al nuevo d2.
d1 = rot(c1 - p0, factor) * s + p0
d2 = rot(c2 - p0, factor) * s + p0
para definir algunos pseudocódigo para rot () (rotación 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);
}
Su curva de bezier ahora está escalada y girada en relación a p0, con p1 cambiado a p2,