Rotate CAShapeLayer - objective-c

I'm trying to rotate a CAShapeLayer in place
UIBezierPath *aPath = [UIBezierPath bezierPath];
CGFloat originx = (97.5+250);
CGFloat originy = (205+250);
[aPath moveToPoint:CGPointMake(originx,originy)];
[aPath addArcWithCenter:CGPointMake(originx+15, originy-30) radius:15 startAngle:DEGREES_TO_RADIANS(180) endAngle:DEGREES_TO_RADIANS(360) clockwise:YES];
[aPath addLineToPoint:CGPointMake(originx+30,originy)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.anchorPoint = CGPointMake(originx, originy);
shapeLayer.path = [aPath CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor blueColor] CGColor];
[aPath closePath];
shapeLayer.transform = CATransform3DMakeRotation(310 * M_PI/180, 0.0, 0.0, 1.0);
[self.view.layer addSublayer:shapeLayer];
I want to rotate the shape around an axis within the shape itself (the code above makes my little shape rotate around an axis several hundred pixels from the actual centre.
I felt this should be controlled with an anchorpoint like this one:
shapeLayer.anchorPoint = CGPointMake(originx, originy);
but it seems to do nothing within the code.
Any ideas?

The anchorPoint is relative to the bounds of the layer. You can't use the anchor point to place your layer. Instead you can place your shape relative to the zero point, rotate it, and the move it to the desired point. Rotation and translation are done by the transform.

Related

Create UIView with four corner points?

How can i create UIView with four corner.
0 = "NSPoint: {79.583483072916664, 54.148963562011716}"; // top left
1 = "NSPoint: {274.96375, 30.877176879882814}"; // top right
2 = "NSPoint: {306.15565104166666, 357.91370518493653}"; // bottom right
3 = "NSPoint: {77.101464843749994, 363.47374218750002}"; // bottom left
I have no idea where to start.
As your view is not a regular rectangle you need to first draw a path i.e. BezierPath and get a shape and imposing the shape on to the View. This view myView would behave like any other normal view
UIView *myView = [[UIView alloc]initWithFrame:self.view.frame];
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:CGPointMake(points[0].x, points[0].y)];
[linePath addLineToPoint:CGPointMake(points[1].x, points[1].y)];
[linePath addLineToPoint:CGPointMake(points[2].x, points[2].y)];
[linePath addLineToPoint:CGPointMake(points[3].x, points[3].y)];
[linePath closePath];
CAShapeLayer *shape = [[CAShapeLayer alloc]init];
[shape setPath:linePath.CGPath];
myView.layer.mask=shape;
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
The output ScreenShot is as given below:
Your 4 corner points do not make a rectangle - a UIView cannot be an arbitrary quadrilateral.
For drawing irregular shapes you should look at Apple's docs for using bezier paths: https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/BezierPaths/BezierPaths.html
So something like this:
- (void)drawRect:(CGRect)rect {
[[UIColor redColor] setStroke];
[[UIColor yellowColor] setFill];
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:CGPointMake(points[0].x, points[0].y)];
[linePath addLineToPoint:CGPointMake(points[1].x, points[1].y)];
[linePath addLineToPoint:CGPointMake(points[2].x, points[2].y)];
[linePath addLineToPoint:CGPointMake(points[3].x, points[3].y)];
[linePath setLineWidth:LINE_WIDTH];
[linePath closePath];
}
What you want is polygon shape and not rectangle. You can not assign polygon shape to view. but if you want to display only part of view fall between these points, you can draw UIBezierPath path with these points on view and then apply blend to clip outer part. here is sample code.
self.backgroundColor = [UIColor redColor];
UIBezierPath *aPath = [UIBezierPath bezierPath];
[aPath moveToPoint:CGPointMake( a.x, a.y)];
[aPath addLineToPoint:CGPointMake(b.x, b.y)];
[aPath addLineToPoint:CGPointMake(c.x, c.y)];
[aPath addLineToPoint:CGPointMake( d.x, d.y)];
[aPath closePath];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = aPath.CGPath;
[self.layer setMask:shapeLayer];
You can use CALayer for corners, Below lines create a view with corners rounded by 8.
UIView *myView = [[UIView alloc] init];
myView.layer.masksToBounds = YES;
myView.layer.cornerRadius = 8.0;
Or you can create view with certain frame like
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(x, y, w, h)];

append arrowhead to UIBezierPath

I need your help:
I am trying to create a graph using UIBezierPaths with variable widths and consisting of a bezier curve with two control points. Now I'd like to add arrow heads to the end (right hand side) of these paths. Is there a way to do this i.e. by appending a subpath with a smaller lineWidth which contains a triangle?
here is a sample picture of some paths to which I'd like to add arrowheads:
Thanks for your help!
Let's assume you drew one of arcs like so:
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:point1];
[path addQuadCurveToPoint:point3 controlPoint:point2];
CAShapeLayer *shape = [CAShapeLayer layer];
shape.path = path.CGPath;
shape.lineWidth = 10;
shape.strokeColor = [UIColor blueColor].CGColor;
shape.fillColor = [UIColor clearColor].CGColor;
shape.frame = self.view.bounds;
[self.view.layer addSublayer:shape];
You can use atan2 to calculate the angle from the control point to the final point:
CGFloat angle = atan2f(point3.y - point2.y, point3.x - point2.x);
Note, it doesn't really matter if you use quad bezier or cubic, the idea is the same. Calculate the angle from the last control point to the end point.
You could then put an arrow head by calculating the corners of the triangle like so:
CGFloat distance = 15.0;
path = [UIBezierPath bezierPath];
[path moveToPoint:point3];
[path addLineToPoint:[self calculatePointFromPoint:point3 angle:angle + M_PI_2 distance:distance]]; // to the right
[path addLineToPoint:[self calculatePointFromPoint:point3 angle:angle distance:distance]]; // straight ahead
[path addLineToPoint:[self calculatePointFromPoint:point3 angle:angle - M_PI_2 distance:distance]]; // to the left
[path closePath];
shape = [CAShapeLayer layer];
shape.path = path.CGPath;
shape.lineWidth = 2;
shape.strokeColor = [UIColor blueColor].CGColor;
shape.fillColor = [UIColor blueColor].CGColor;
shape.frame = self.view.bounds;
[self.view.layer addSublayer:shape];
Where we use sinf and cosf to calculate the corners like so:
- (CGPoint)calculatePointFromPoint:(CGPoint)point angle:(CGFloat)angle distance:(CGFloat)distance {
return CGPointMake(point.x + cosf(angle) * distance, point.y + sinf(angle) * distance);
}
That yields something looking like:
Clearly, just adjust the distance parameters to control the shape of the triangle.

How to animate a drawn line in Objective C?

I am trying to animate drawn objects, for example I have drawn a line with this approach:
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(Center.x, Center.y)];
[path addLineToPoint:CGPointMake(Point.x,Point.y)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor whiteColor] CGColor];
shapeLayer.lineWidth = 1.5;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
After a while I need to animate the line to have a different Point, but keeping Center as is, but I have no idea how to do that. Is my approach alright? Is there a better way to do so?
Solved it:
CABasicAnimation *morph = [CABasicAnimation animationWithKeyPath:#"path"];
morph.duration = 1.0;
UIBezierPath *path5 = [UIBezierPath bezierPath];
[path5 moveToPoint:CGPointMake(P22.x+5, P22.y+5)];
[path5 addLineToPoint:CGPointMake(P21.x,P21.y)];
morph.fromValue = (id) path.CGPath;
morph.toValue = (id) path5.CGPath;
[shapeLayer addAnimation:morph forKey:nil];
//next line to update the shapeLayer's new path
shapeLayer.path = path5.CGPath;

Gradient as circle stroke color in CAShapeLayer

CAShapeLayer *circle = [CAShapeLayer layer];
circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(x, y, 100, 100) cornerRadius:50].CGPath;
// Configure the apperence of the circle
circle.fillColor = [UIColor whiteColor].CGColor;
circle.strokeColor = [UIColor darkGrayColor].CGColor;
circle.lineWidth = 1.8;
circle.lineDashPattern = #[#6, #3];
// Add to parent layer
[cell.layer addSublayer:circle];
I am using this code to draw a circle. Now, I want to use a gradient as stroke color. How can I do that?

2D Rotation of CALayer with UIBezierPath

I'm trying to rotate a CALayer which is composed of UIBezierPath. The display is great.
CALayer* layer = [CALayer layer];
CAShapeLayer *shapeView = [[CAShapeLayer alloc] init];
UIBezierPath *arc = [UIBezierPath bezierPath];
[arc moveToPoint:CGPointMake(center.x + obj1.startx * cos(obj1.angle), center.y + obj1.starty * cos(obj1.angle))];
[shapeView setPath:arc.CGPath];
[layer addSublayer:shapeView];
// Rotation
layer.transform = CATransform3DMakeRotation(angle, 0, 0, 1);
But the CATransform3DmakeRotation rotate the CAShape around the point (0,0) I guess.
I tried to set the anchorPoint to the center of the view but it's not working better.
It seems that the CAlayer has no content because its height and width are equal to zero.
What did I do wrong ?
Thanks