我的目标是采取这样的模式
并沿圆形路径反复绘制以产生类似于此图像的图像:
我在其他问题和完整的演示项目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;
}
最佳答案
使用Core Animation的复制器层,我设法创建了以下结果:
我认为这接近您的需求。在此示例中,所有图像均为正方形,并对其施加了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;