按比例缩放贝塞尔曲线-计算控制点 [英] Scale a Bezier Curve Proportionally - calculate control points

查看:255
本文介绍了按比例缩放贝塞尔曲线-计算控制点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试绘制贝塞尔曲线(Core Graphics中的任意曲线)并按比例缩小(或扩展)它,并给出另外两个端点。我有一种可行的方法,但最终会弄平曲线,而不能完全保留形状。也许我弄乱了代码或逻辑,但我同时拥有两个原始点和控制点。给定另一组端点,我想计算适当的控制点以在新端点之间产生相同的形状。

I'm trying to take a bezier curve (any arbitrary curve in Core Graphics) and shrink (or expand) it proportionally given another two end points. I have an approach that sort of works, but it ends up 'flattening' out the curves, and not retaining the shape exactly. Maybe I've messed up the code or logic, but I have the two original points along with the control point(s). Given another set of end points I want to calculate the appropriate control points to produce the same shape between the new end points.

以下是将计算1个控制点的主要代码:

Here's the main code that will calculate 1 control point:

CGPoint (^ScaledCtrlPoint)(CGPoint, CGPoint, CGPoint, CGPoint, CGPoint) = ^CGPoint (CGPoint refPoint1, CGPoint refPoint2, CGPoint bevPoint1, CGPoint bevPoint2, CGPoint ctrlPoint){
        //Normalize points to refPoint1
        refPoint2.x -= refPoint1.x; refPoint2.y -= refPoint1.y;
        ctrlPoint.x -= refPoint1.x; ctrlPoint.y -= refPoint1.y;
        //Normalize bevPoints to bevPoint1
        bevPoint2.x -= bevPoint1.x; bevPoint2.y -= bevPoint1.y;
        //Calculate control point angle
        CGFloat theta = PointTheta(refPoint2);
        CGFloat refHyp = (refPoint2.y != 0.0f) ? refPoint2.y / sinf(theta) : refPoint2.x / cosf(theta);
        theta = PointTheta(bevPoint2);
        CGFloat bevHyp = (bevPoint2.y != 0.0f) ? bevPoint2.y / sinf(theta) : bevPoint2.x / cosf(theta);
        theta = PointTheta(ctrlPoint);
        CGFloat ctrlHyp = (ctrlPoint.y != 0.0f) ? ctrlPoint.y / sinf(theta) : ctrlPoint.x / cosf(theta);
        ctrlHyp *= (bevHyp / refHyp);
        return CGPointMake(bevPoint1.x + cosf(theta) * ctrlHyp, bevPoint1.y + sinf(theta) * ctrlHyp);
    };

bevPoints 是我的新点m用于计算新的控制点。 refPoints ctrlPoint 是贝塞尔曲线的原始点。如您所见,我正在尝试按与原始端点到新端点相同的比例缩小ctrlPoint(也可以提高)。

The bevPoints are the new points I'm using to calculate the new control point. The refPoints and ctrlPoint are the original points of the bezier curve. As you can see, I'm trying to scale the ctrlPoint down (could also work up) by the same ratio as the the original end points are to the new end points.

我还使用另一个函数,用于计算入射角。很简单:

I also use another function, which I use to calculate incident angles. It's pretty simple:

CGFloat         PointTheta(CGPoint point){
    //This assumes an origin of {0, 0} and returns a theta for the given point
    CGFloat theta = atanf(point.y / point.x);
    //Using arc tan requires some adjustment depending on the point quadrant
    if (point.x == 0.0f) theta = (point.y >= 0.0f) ? M_PI_2 : M_PI + M_PI_2;
    else if (point.x < 0.0f) theta += M_PI;
    else if (point.x > 0.0f && point.y < 0.0f) theta += (M_PI * 2);
    return theta;
}


推荐答案

我会计算 CGAffineTransform 与参数

(a, b, -b, a, tx, ty)

(即不偏斜的转换)将旧端点映射到新端点,然后

(i.e. a transform without skewing) that maps the old endpoints to the new endpoints, and then apply this transform to the old control point to get the new control point.

将2个旧端点映射到2个新端点的条件给出了a的4个等式, b,tx,ty,甚至不用三角函数也可以求解这些方程。

The condition that the 2 old endpoints are mapped to the 2 new endpoints gives 4 equations for a, b, tx, ty, and these equations can even be solved without trigonometric functions.

这篇关于按比例缩放贝塞尔曲线-计算控制点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆