Scale a Bezier Curve Proportionally - calculate control points

孤街浪徒 提交于 2019-12-13 18:26:43

问题


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.

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

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;
}

回答1:


I would compute the CGAffineTransform with parameters

(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.

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.



来源:https://stackoverflow.com/questions/12264741/scale-a-bezier-curve-proportionally-calculate-control-points

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!