gpt4 book ai didi

ios - 如何曲线 CGMutablePath?

转载 作者:技术小花猫 更新时间:2023-10-29 10:55:03 24 4
gpt4 key购买 nike

具有以下形状:

enter image description here

我想知道你是如何让它像这样弯曲的:

enter image description here

也类似:

enter image description here

我假设所有的圆/线都打包到一个 CGMutablePath 中,然后对其应用某种曲线、圆弧或四边形曲线,尽管我是甚至难以复制它。有谁知道如何做到这一点?

最佳答案

在您的第一个示例中,您从一个具有多个闭合子路径的路径开始。显然你想扭曲子路径的中心,但让各个子路径相对于它们的(新)中心不扭曲。我将忽略它,因为即使没有它,解决方案也已经非常复杂。

那么,让我们考虑一下如何定义“扭曲场”。我们将使用三个控制点:

example with control points

warp 保持 fixedPoint 不变。它通过旋转缩放将起点移动到终点,不是通过简单地插值坐标。

此外,它根据与 fixedPoint 的距离应用旋转和缩放。而不仅仅是基于简单的欧几里得距离。请注意,我们不想对图片中“V”形的顶部端点应用任何旋转或缩放,即使这些端点与 fixedPoint 的距离是可测量的欧氏距离。我们想要测量沿 fixedPoint->startPoint 向量的距离,并随着距离的增加应用更多的旋转/缩放。

这一切都需要一些非常复杂的三角函数。我不会尝试解释细节。我只是要把代码转储给你,作为 UIBezierPath 上的一个类别:

UIBezierPath+Rob_warp.h

#import <UIKit/UIKit.h>

@interface UIBezierPath (Rob_warp)

- (UIBezierPath *)Rob_warpedWithFixedPoint:(CGPoint)fixedPoint startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint;

@end

UIBezierPath+Rob_warp.m

请注意,您需要来自 this answerRob_forEach 类别.

#import "UIBezierPath+Rob_warp.h"
#import "UIBezierPath+Rob_forEach.h"
#import <tgmath.h>

static CGPoint minus(CGPoint a, CGPoint b) {
return CGPointMake(a.x - b.x, a.y - b.y);
}

static CGFloat length(CGPoint vector) {
return hypot(vector.x, vector.y);
}

static CGFloat dotProduct(CGPoint a, CGPoint b) {
return a.x * b.x + a.y * b.y;
}

static CGFloat crossProductMagnitude(CGPoint a, CGPoint b) {
return a.x * b.y - a.y * b.x;
}

@implementation UIBezierPath (Rob_warp)

- (UIBezierPath *)Rob_warpedWithFixedPoint:(CGPoint)fixedPoint startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint {

CGPoint startVector = minus(startPoint, fixedPoint);
CGFloat startLength = length(startVector);
CGPoint endVector = minus(endPoint, fixedPoint);
CGFloat endLength = length(minus(endPoint, fixedPoint));
CGFloat scale = endLength / startLength;

CGFloat dx = dotProduct(startVector, endVector);
CGFloat dy = crossProductMagnitude(startVector, endVector);
CGFloat radians = atan2(dy, dx);

CGPoint (^warp)(CGPoint) = ^(CGPoint input){
CGAffineTransform t = CGAffineTransformMakeTranslation(-fixedPoint.x, -fixedPoint.y);
CGPoint inputVector = minus(input, fixedPoint);
CGFloat factor = dotProduct(inputVector, startVector) / (startLength * startLength);
CGAffineTransform w = CGAffineTransformMakeRotation(radians * factor);
t = CGAffineTransformConcat(t, w);
CGFloat factoredScale = pow(scale, factor);
t = CGAffineTransformConcat(t, CGAffineTransformMakeScale(factoredScale, factoredScale));
// Note: next line is not the same as CGAffineTransformTranslate!
t = CGAffineTransformConcat(t, CGAffineTransformMakeTranslation(fixedPoint.x, fixedPoint.y));
return CGPointApplyAffineTransform(input, t);
};

UIBezierPath *copy = [self.class bezierPath];
[self Rob_forEachMove:^(CGPoint destination) {
[copy moveToPoint:warp(destination)];
} line:^(CGPoint destination) {
[copy addLineToPoint:warp(destination)];
} quad:^(CGPoint control, CGPoint destination) {
[copy addQuadCurveToPoint:warp(destination) controlPoint:warp(control)];
} cubic:^(CGPoint control0, CGPoint control1, CGPoint destination) {
[copy addCurveToPoint:warp(destination) controlPoint1:warp(control0) controlPoint2:warp(control1)];
} close:^{
[copy closePath];
}];
return copy;
}

@end

好的,那么你如何使用这个疯狂的东西呢?对于示例中的“V”这样的路径,您可以这样做:

CGRect rect = path.bounds;
CGPoint fixedPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint startPoint = CGPointMake(fixedPoint.x, CGRectGetMaxY(rect));
path = [path Rob_warpedWithFixedPoint:fixedPoint startPoint:startPoint endPoint:endAnchor];

我将 fixedPoint 计算为路径边界框顶部边缘的中心,将 startPoint 计算为底部边缘的中心。 endAnchor 在我的测试程序中受用户控制。在模拟器中看起来像这样:

demo with V

气泡型路径如下所示:

demo with bubbles

你可以在这里找到我的测试项目:https://github.com/mayoff/path-warp

关于ios - 如何曲线 CGMutablePath?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25776819/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com