沿路径绘制图案

5

我的目标是采取这样的模式

enter image description here

并沿着圆形路径重复绘制,以产生类似于此图像的内容:

enter image description here

我在其他问题中找到了几个代码示例和一个完整的演示项目这里,但结果是这样的:

enter image description here

我认为两张图片之间的差异很明显,但我发现很难描述(请原谅我的图形词汇不足)。结果似乎是平铺而没有所需的旋转/变形图案。我想我可以接受缺少变形,但旋转是关键。我认为也许应该修改绘制回调以包括旋转,但无法找出如何在回调点检索/确定角度。
我考虑了一种方法,手动变形/旋转图像,并围绕中心点多次绘制它以实现我想要的效果,但我相信CoreGraphics可以更有效地完成,并且代码更少。
任何有关如何实现我想要的结果的建议将不胜感激。
以下是ChalkCircle项目中相关的代码:
const float kPatternWidth = 8;
const float kPatternHeight = 8;

void DrawPatternCellCallback(void *info, CGContextRef cgContext)
{
UIImage *patternImage = [UIImage imageNamed:@"chalk_brush.png"];
CGContextDrawImage(cgContext, CGRectMake(0, 0, kPatternWidth, kPatternHeight), patternImage.CGImage);
}

- (void)drawRect:(CGRect)rect {
float startDeg = 0; // where to start drawing
float endDeg = 360; // where to stop drawing
int x = self.center.x;
int y = self.center.y;
int radius = (self.bounds.size.width > self.bounds.size.height ? self.bounds.size.height : self.bounds.size.width) / 2 * 0.8;
CGContextRef ctx = UIGraphicsGetCurrentContext();


const CGRect patternBounds = CGRectMake(0, 0, kPatternWidth, kPatternHeight);
const CGPatternCallbacks kPatternCallbacks = {0, DrawPatternCellCallback, NULL};


CGAffineTransform patternTransform = CGAffineTransformIdentity;
CGPatternRef strokePattern = CGPatternCreate(
NULL,
patternBounds,
patternTransform,
kPatternWidth, // horizontal spacing
kPatternHeight,// vertical spacing
kCGPatternTilingNoDistortion,
true,
&kPatternCallbacks);
CGFloat color1[] = {1.0, 1.0, 1.0, 1.0};


CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
CGContextSetStrokeColorSpace(ctx, patternSpace);


CGContextSetStrokePattern(ctx, strokePattern, color1);


CGContextSetLineWidth(ctx, 4.0);


CGContextMoveToPoint(ctx, x, y - radius);
CGContextAddArc(ctx, x, y, radius, (startDeg-90)*M_PI/180.0, (endDeg-90)*M_PI/180.0, 0);
CGContextClosePath(ctx);
CGContextDrawPath(ctx, kCGPathStroke);


CGPatternRelease(strokePattern);
strokePattern = NULL;
CGColorSpaceRelease(patternSpace);
patternSpace = NULL;

}

SAM的解决方案

我修改了Sam的解决方案,使其能够处理非正方形图案,将结果居中,并通过对传入图像进行计算来删除硬编码数字:

#define MAX_CIRCLE_DIAMETER   290.0f
#define OVERLAP 1.5f

-(void) drawInCircle:(UIImage *)patternImage
{
    int numberOfImages = 12;
    float diameter =  (MAX_CIRCLE_DIAMETER * numberOfImages * patternImage.size.width) / ( (2.0 * M_PI * patternImage.size.height) + (numberOfImages * patternImage.size.width));

    //get the radius, circumference and image size
    CGRect replicatorFrame = CGRectMake((320-diameter)/2.0f, 60.0f, diameter, diameter);
    float radius = diameter/2;
    float circumference = M_PI * diameter;
    float imageWidth = circumference/numberOfImages;
    float imageHeight = imageWidth *  patternImage.size.height / patternImage.size.width;

    //create a replicator layer and add it to our view
    CAReplicatorLayer *replicator = [CAReplicatorLayer layer];

    replicator.frame = replicatorFrame;
    [self.view.layer addSublayer:replicator];

    //configure the replicator
    replicator.instanceCount = numberOfImages;

    //apply a rotation transform for each instance
    CATransform3D transform = CATransform3DIdentity;
    transform = CATransform3DRotate(transform, M_PI / (numberOfImages/2), 0, 0, 1);
    replicator.instanceTransform = transform;

    //create a sublayer and place it inside the replicator
    CALayer *layer = [CALayer layer];
    //the frame places the layer in the middle of the replicator layer and on the outside of
    //the replicator layer so that the the size is accurate relative to the circumference
    layer.frame = CGRectMake(radius - (imageWidth/2.0) - (OVERLAP/2.0), -imageHeight/2.0, imageWidth+OVERLAP, imageHeight);

    layer.anchorPoint = CGPointMake(0.5, 1);
    [replicator addSublayer:layer];

    //apply a perspective transform to the layer
    CATransform3D perspectiveTransform = CATransform3DIdentity;
    perspectiveTransform.m34 = 1.0f / -radius;
    perspectiveTransform = CATransform3DRotate(perspectiveTransform, (M_PI_4), -1, 0, 0);
    layer.transform = perspectiveTransform;

    //set the image as the layer's contents
    layer.contents = (__bridge id)patternImage.CGImage;
}

很抱歉,你试图做的事情非常复杂,因为图案在圆形内部被压缩,在外部被拉伸。你可能需要降级到OpenGL来实现它。 - David Rönnqvist
是的,我草拟了一些代码来将矩形转换为变形弧线,但希望不必自己写哈哈。 - software evolved
1个回答

9

使用核心动画的复制层,我成功创建了这个结果:enter image description here

我认为这已经接近您所需要的了。在这个示例中,所有图像都是正方形,每个图像都应用了3D X旋转。

#import <QuartzCore/QuartzCore.h>    


//set the number of images and the diameter (width) of the circle
int numberOfImages = 30;
float diameter = 450.0f;

//get the radius, circumference and image size
float radius = diameter/2;
float circumference = M_PI * diameter;
float imageSize = circumference/numberOfImages;

//create a replicator layer and add it to our view
CAReplicatorLayer *replicator = [CAReplicatorLayer layer];
replicator.frame = CGRectMake(100.0f, 100.0f, diameter, diameter);
[self.view.layer addSublayer:replicator];

//configure the replicator
replicator.instanceCount = numberOfImages;

//apply a rotation transform for each instance
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DRotate(transform, M_PI / (numberOfImages/2), 0, 0, 1);
replicator.instanceTransform = transform;

//create a sublayer and place it inside the replicator
CALayer *layer = [CALayer layer];
//the frame places the layer in the middle of the replicator layer and on the outside of the replicator layer so that the the size is accurate relative to the circumference
layer.frame = CGRectMake(radius - (imageSize/2), -imageSize/2, imageSize, imageSize);
layer.anchorPoint = CGPointMake(0.5, 1);
[replicator addSublayer:layer];

//apply a perspective transofrm to the layer
CATransform3D perspectiveTransform = CATransform3DIdentity;
perspectiveTransform.m34 = 1.0f / -radius;
perspectiveTransform = CATransform3DRotate(perspectiveTransform, (M_PI_4), -1, 0, 0);
layer.transform = perspectiveTransform;

//set the image as the layer's contents
layer.contents = (__bridge id)[UIImage imageNamed:@"WCR3Q"].CGImage;

Sam,你太棒了!我会延迟接受你的答案,直到我可以颁发给你赏金(明天)。谢谢! - software evolved
所以我必须等待2天才能设置赏金,现在我还需要等待24小时才能颁发它!哈哈 - software evolved
感谢您设置悬赏,我很高兴代码能够帮到您。 - Sam
你将“不可能”变为了“可能”,很高兴你愿意分享你的知识。点一个赞。 - Unheilig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接