I'm trying to find an efficient way to perform the following clipping operation on a CAShapeLayer that I have.
What I'm Trying to Do
I have a CAShapeLayer whose circular path consists of a UIBezierPath that has been constructed using the method [UIBezierPath bezierPathWithArcCenter:] (this is a full circle from 0 to 2PI radians), and inside of that circle, I want to cut out multiple lines that are drawn at different angles, making the area below the cut out lines transparent on the circle. I want these lines to begin and end at points on the outside of the circle aka the edges of the CAShapeLayer's path.
I'm wondering whether there is a way to use the mask property on the CAShapeLayer to accomplish this, or whether I should abandon the idea of cutting out from the full circle and just draw each arced triangle separately as different CAShapeLayers.
Thank you for your any help!
I ended up solving this by forgetting about using masks. Instead, I just constructed a UIBezierPath using the moveToPoint: and addLineToPoint: methods in order to draw the desired portions of the circle.
Related
I want to make an animation with a moving line, similar to a dog waging his tail.
I'm not sure how to begin. I've used Core Animation's CAShapeLayer for progress bars before but don't know if it would work for this. I also used PaintCode in the past to help for custom paths, for example to create a custom UIBezierPath for an object to animate on. But also not sure if PaintCode would help with this.
Any ideas?
This wouldn't be that hard. Yes, using a CAShapeLayer animation would be the way to go.
I would make the non-changing part of the image into a bitmap, and then draw your shape layer animation on top.
The trick with shape layer animation is that the shape you use needs to have the same number of control points for all the parts of your animation.
In the case of your tail animation you should be able to map it out as a set of quadratic bezier curves. You could probably draw the tail as a single thick path with a rounded end cap. (kCGLineCapRound). You'd make the starting curve a quadratic bezier curve with the starting point down at the beginning of the straight part of the tail, the next control point slightly to the right and below the curved tip, the next control point above and to the left of the first control point but still below and to the right of the tip, and the last control point at the tip.
The ending curve would have the first control point at the same place on the base of the tail, the second control point at about the top of the curve and to the left, the next control point above the curve and about 2/3 of the way between the base point and the tip, and the last point at the tip of the tail.
You might want to play with the path tool in Adobe Photoshop (or GIMP) and use it to create the starting and ending tail curve shapes using a single quadratic Bezier curve, then write down the control point positions that you use and enter them into your code.
You'd create a CABasicAnimation of the CAShapeLayer where you set the fromValue to the starting CGPath and the toValue to the ending CGPath. Just make sure that the starting and ending paths have the same number of control point.
I have a project called RandomBlobs (link) on Github that shows how to animate a curve using CGPaths and CABasicAnimations, but it is written in Objective-C, and instead of using quadratic bezier curves, it creates another kind of a curve called a Catmull-Rom spline. quadratic bezier curves are actually much simpler to set up than Catcall-Rom splines however, and the idea behind animating changes to a CAShapeLayer using CABasicAnimation should be fairly easy to translate from Objective-C to Swift if you've worked with CAShapelayers before. You could also use a series of Catmull-Rom splines to get the tail animation you're after. The advantage of Catmull-Rom splines is that all the control points are on the curve.
I'm trying to change the shape of a CAShapeLayer from a circle to a different shape. Looking at this question:
Smooth shape shift animation
I found the solution but my question is how can I visually see how many points a UIBezierPath has. Is there a way to color a point different than the line it produces?
For example,it's simple with a line to understand that there are two point, but if we make a circle with bezierPathWithRoundedRect, does that count as one point or are there more?
You would need to add the circle yourself to visually see the dots. Just keep track of the CGPoints you give to the path and draw a circle around each one.
Btw.. if you use PaintCode, you can edit the bezier path and see the point -- it's very useful.
I am drawing ellipse using following UIBezierPath method:
UIBezierPath *bpath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x, y, width, height)];
This gives me something like below:
But I want to draw ellipse at an angle like below:
I know one solution is to rotate the UIView. But I cannot do this because same view contain other bezier paths. So I want to know if there is any way to draw this ellipse at an angle?
Often the easiest way is to put this on a CAShapeLayer and then rotate the layer. The math for that tends to be very simple (particularly if you want to change the transform later). But you can also just rotate the path directly before drawing it by creating a rotation transform (CGAffineTransformMakeRotation) and using -applyTransform: to modify the path.
I have two shapes in a UIView - one, an ellipse and two, a triangle drawn using UIBezierPath. I need to draw the outline of these two shapes combined. How can I do it?
You can do an "outside" stroke (like stroke->outside in photoshop/pixelmator) by calling stroke to draw the outline and setting the inverse of your shapes as the clipping path first. To do the inverse of the clipping path see this answer: https://stackoverflow.com/a/10639523/461492 (read comments too).
So here are the steps:
Set the full area as the clipping path.
Call CGContextEOClip() for each of your shapes as described in the comments to the answer linked above.
Stroke your shapes.
This might not be exactly what you want - it will draw the stroke as normal but the whole interior (the fill area) of your shapes will not be drawn. So whereas the thickness of the stroke would normally extend within the interior of your shapes, and the internal angles of your stroke would normally have the correct corners (rounded/mitered) - in this case it would be more like you stroked the shapes then deleted the fill-area, or did an "outside" stroke in an image editing program.
I need to animate arcs (a.k.a donut segments) in the following scenarios where the arc maintains a constant radius r to the imaginary circle center (the arc sits right outside the circle).
1) Animate the arc stroke width from x to y, while maintaining a radius r and angle alpha.
2) Animate the arc angle from alpha to beta while maintaining a constant stroke width and radius.
3) do 1 and 2 together but possibly with independent animations/timings.
Here's what I have so far:
I’ve implemented the arc drawing as a custom view that simply draws the arc with CGContextAddArc. This is fine for a static arc but it doesn’t animate anything.
Also, I know how to draw clipped images with things like [UIBezierPath addClip].
The latter is interesting because I think that for scenario 1, I can achieve the desired effect in two ways: either keep drawing an arc and modify both stroke and radius to maintain the same perceived inner circle radius (which I’m not optimistic about, I’m afraid that the radius will “jiggle”), or draw a segment of a circle that grows in size (maybe by simply modifying the scale with an affine transform) and is then clipped by a static circular mask.
Now, how do I take all these concepts and nail them down into some actual drawing code? I don’t need real code (though that would be fine too), but more like a conceptual approach, like, can I do this all with a UIView with custom drawing, or do we need to talk about custom key animations that I understand involve CALayers and such. In other words, what’s the right architecture to do all this that would be easiest to code while being efficient from a compositing perspective for smooth animation?
You can already do this with a CAShapeLayer by creating the path for the arc and then animate different stroke properties. You could create the path for the full circle and use the strokeStart and strokeEnd properties to only stroke a certain part of the circle. It is worth noting that the shape layer is center stroked so they increase equally inwards and outwards as you increase the line width. To counter this you could either mask it with the same circle shape and double the line width or animate the path so that the radius increases by half of the line width increase so that the inner most point has the same distance to the center at all times.
The first example can be done by animating the lineWidth property and the second can be done by animating the strokeStart and strokeEnd properties
You should implement this using custom animatable properties on a CALayer subclass. This tutorial (with source here) is for creating animated pie charts and looks pretty good. You should be able to modify it for your requirements.