沿路径绘制图案

时间:2014-03-13 17:52:28

标签: ios iphone design-patterns path core-graphics

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

enter image description here

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

enter image description here

我在其他问题和完整的演示项目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;
}

1 个答案:

答案 0 :(得分:8)

使用Core Animation的复制器层,我设法创建了这个结果: 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;