How to draw an ellipse using UIBezierPath at an angle? - ios

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.

Related

Clip Drawing to Opaque (Stroke) Part of CAShapeLayer

I have a CAShapeLayer with an opaque stroke and a transparent fill. I then want to call myContext.drawRadialGradient, but have this radial gradient clip to the stroke of my shape layer. Currently, I'm calling myShapeLayer.path.addClip(), which clips the radial gradient to the fill region of the shape layer, instead of the stroke.
In other words, I'd like to use either just the opaque part of a layer or just the stroke (same thing in my case), and use it to clip the current context. I've been searching the CoreGraphics docs for a while to no avail.
Found my answer. You can create a new UIBezierPath that is a copy of your existing one, with a stroke, as below:
let strokePath = UIBezierPath(cgPath: oldPath.cgPath.copy(
strokingWithWidth: ..., lineCap: ..., lineJoin: ..., miterLimit: ...))
strokePath.addClip()
What if you add your shape layer as the mask of your gradient layer? That should work, since that's what a mask layer is supposed to do.
If that doesn't work you might need to capture your shape layer to an image and install THAT as the mask of your gradient layer.
Convert the stroked path to a new path whose fill area is the same as the original stroke. Now you have a fillable area that you can use as clipping area. The CGContext way to do this is by calling replacePathWithStrokedPath. As the docs explicitly say:
For example, you can clip to the stroked version of a path by calling this function followed by a call to the function clip().

Masking CALayer with Lines

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.

Common outline for two shapes drawn in drawRect: ObjectiveC

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.

How to animate arc/donut segment stroke and length change

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.

How to distort a Sprite into a trapezoid?

I am trying to transform a Sprite into a trapezoid, I don't really care about the interpolation even though I know without it my image will lose detail. All I really want to do is Transform my rectangular Sprite into a trapezoid like this:
/ \
/ \
/__________\
Has anyone done this with CGAffineTransforms or with cocos2d?
The transformation you're proposing is not affine. Affine transformations have to be undoable. So they can typically:
Scale
Rotate
Shear (make lopsided, like square -> parallelogram)
Translate
But they cannot "squeeze". Notice that the left and right sides of your trapezoid, if extended, would intersect at a particular spot. They're not parallel anymore. So you couldn't "undo" the transformation, because if there was anything to transform at that spot, you couldn't decide where they would transform to. In other words, if a transformation doesn't preserve parallelism, it pinches space, can't be undone, and isn't affine.
I don't know that much about transformations in Core Animation, so I hope that mathy stuff helps you find an alternative.
But I do know how you could do it in OpenGL, but it would require you to start over on how you draw your application:
If I'm envisioning the result you want correctly, you want to build your rectangle in 3D, use an affine transformation to rotate it away a little bit, and use a (non-affine) projection transformation to flatten it into a 2D image.
If you're not looking for a 3D effect, but you really just want to pinch in the corners, then you can specify a GL_RECT with the points of your trapezoid and map your sprite onto it as a texture.
The easiest thing might be to pre-squeeze your image in a photo editor, save it as a .png with transparency, and draw a rectangle with that image.
You need to apply a CATransform3D to the layer of the UIView.
To find out the right one, it is easier to use AGGeometryKit.
#import <AGGeometryKit/AGGeometryKit.h>
UIView *view = ...; // create a view
view.layer.anchorPoint = CGPointZero;
AGKQuad quad = view.layer.quadrilateral;
quad.tl.x += 20; // shift top left x-value with 20 pixels
quad.tr.x -= 20; // shift top right x-value with 20 pixels
view.layer.quadrilateral = quad; // the quad is converted to CATransform3D and applied

Resources