当立方贝塞尔曲线中的端点变化时找到新的控制点

Hit*_*tel 16 android bezier cubic android-canvas

我在我的Android应用程序中实现了三次贝塞尔曲线逻辑.

我在自定义视图的onDraw上在画布上实现了三次贝塞尔曲线代码.

// 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);
Run Code Online (Sandbox Code Playgroud)

我在下面的图像中可视化上面的代码.

输出上述代码

[更新]

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
Run Code Online (Sandbox Code Playgroud)

我想允许用户更改上面曲线的EndPoint,并根据新的End点,我使画布无效.

但问题在于,Curve由两个控制点维护,需要在EndPoint发生变化时重新计算.

就像,我只想在EndPoint从(300,200)变为(250,250)时找到新的控制点

如下图所示:

新图片

请帮我根据新的终点计算两个新的控制点,曲线形状将与前一个终点保持一致.

我在搜索期间参考以下参考链接:

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

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

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

http://cubic-bezier.com/

任何参考链接也在回答这个问题时表示赞赏.

nid*_*ido 12

更改端点意味着两件事,一个是P1的旋转和一个缩放因子.

缩放因子(让我们称之为s)是len(p1-p0)/ len(p2-p0)

对于旋转因子(让我们称之为r),我推迟到计算android中三个点之间的角度,这也给出了一个特定于平台的实现,但你可以通过缩放/旋转p1来检查与p0相关的正确性,你应该得到结果是p2.

接下来,对p0到c1和c2应用缩放和旋转.为方便起见,我将调用新的c1'd1'和新的d2.

d1 = rot(c1 - p0, factor) * s + p0
d2 = rot(c2 - p0, factor) * s + p0
Run Code Online (Sandbox Code Playgroud)

为rot()定义一些伪代码(旋转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);
}
Run Code Online (Sandbox Code Playgroud)

您的贝塞尔曲线现在按比例缩放并相对于p0旋转,p1变为p2,


use*_*109 6

首先,我会请您查看以下文章:

  1. 贝齐尔曲线
  2. 为什么B样条曲线
  3. B样条曲线总结

您要实现的是分段复合Bézier曲线.从n个控制点的摘要页面(包括开始/结束),您将获得(n - 1)/ 3个分段贝塞尔曲线.

控制点按字面形成曲线.如果没有给出具有新点的适当控制点,则无法创建平滑连接的贝塞尔曲线.生成它们是行不通的,因为它太复杂而且没有普遍接受的方式.

如果你没有/想要提供额外的控制点,你应该使用Catmull-Rom样条曲线,它通过所有控制点并且将是C1连续的(导数在曲线上的任何点都是连续的).

链接Catmull Rom Spline的java/android:

底线是,如果你没有控制点,不要使用立方贝塞尔曲线.生成它们是一个问题,而不是解决方案.


Lum*_*mis 6

看起来你在旋转和缩放一个正方形,你知道底部的两个点,需要计算另外两个.两个已知点形成两个三角形,另外两个,所以我们只需要在三角形中找到第三个点.设定终点是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;
            }
Run Code Online (Sandbox Code Playgroud)

...

还有其他方法可以做到这一点,在路径或事件的第一个和最后一个点之间有多少点并不重要.

//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);
Run Code Online (Sandbox Code Playgroud)