How to fill space between two UIBezierPaths - iphone

I'm working on drawing application which provides drawing lines with variable line width which depends on drawing speed. This behavior inspired by Paper app.
Algorithm which I'm trying to implement -- draw two bezier path with variable distance between them. The solution which described in sosborn's answer. Then smooth paths and fill the distance between them.
Actually I don't figured out how to fill space between paths.

You create a single path from the 2 bezier curves and fill it, like this:
NSBezierPath* path = [NSBezierPath bezierPath];
// Move to the start point
[path moveToPoint:startPt];
// Make the lower part of the curve
[path curveToPoint:endPt controlPoint1:cp1 controlPoint2:cp2];
// Make the upper part of the curve as part of the same path:
[path curveToPoint:startPt contorPoint1:cp3 controlPoint2:cp4];
// Now fill it
[path fill];

Related

Move CALayer via UIBezierPath

I have a layer that will move from point A to point B on a UIBezierPath.
I have found a lot of samples those are refers to CAAnimation and UIBezierPath.
But I need to move my layer only from specified point to another on bezier path.
Any suggestions would be appreciated.
Thanks
Hope this will be helpful.
UIBezierPath *trackPath = [UIBezierPath bezierPath];
.
.
.
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
anim.path = trackPath.CGPath;
anim.repeatCount = 1;
anim.duration = 2.0;
[layerToAnimate addAnimation:anim forKey:#"pathGuide"];
If your bezier path is a circle or even a half circle, you could just skip the path and instead add the point to a larger square layer. Set the point to be a fixed distance from the center of that larger square layer. Then you can just rotate the larger layer on the z axis around the center whatever number of degrees you need it to move. Seems it would simplify things a bit, though I'm not sure exactly what else you need it to do.
i'd been looking to do something like this and fount this tutorial, it shows how to follow a specific path. It works with a car (a CALayer) and a UIBezierpath as the race track and is solved in this order:
Defining the path the car should follow (in this case your BezierPath)
Drawing the black line that defines the track; (N/A)
Drawing the white dashed center-line of the track; (N/A)
Creating the layer defining the car; (your Layer)
Animating the car along the path. (What your asked!)
You can check the reference Post here:
http://nachbaur.com/2011/01/07/core-animation-part-4/
Also you can download the source code here:
http://cdn5.nachbaur.com/wp-content/uploads/2011/01/CALayerAnimTest.zip?25881d
hope this helps!
regards,
Jorge.

iPhone: How to animate a CAShape line whose path is determined by user input

I'm attempting to replicate the "worm" that is sometimes displayed on political debates to represent the audiences opinion on how well a candidate answered a question. It's basically a line that animates along the x axis to represent time, up and down the y axis to represent opinion.
I see that I can do this animation by
Creating a UIBezierPath and use its moveToPoint/addLineToPoint methods with a predefined set of coordinates.
Create a CAShapeLayer and set its path property to the above UIBezierPath.
Create a CABasicAnimation and add it to the CAShapeLayer.
This is all fine but I need for the line to be affected in real time by user input (tapping a button to move the line up or down), meaning that in step one above I cannot have a set of pre-defined coordinates. The line should move horizontally unless it receives input from the user to make it also move vertically.
So my question is how would I go about this? Can I still somehow use the method I described in the bullet points above with some modification or do I have to use a different means?
Many thanks for any advice!
[edit]
I just had a thought, this may work but be a little inefficient and I'm not sure if the created path would be very short i.e. not the full path from the starting point instead just the currently drawn part of the path?! What if I did the following:
create two variables, lastPoint and currentPoint;
repetitively call a draw method that does the following
[path moveToPoint: lastPoint];
[path addLineToPoint: currentPoint];
lastPoint = currentPoint;
currentPoint = [self calculateNewPointFromUserInput];
repeat;
Two points will be very short for you, you can take an array of user's touch events and then draw last 10-15 points from the array. I think this will serve your purpose.

iPhone: Line connectors attached to shapes

How would you draw a line connector between two shapes, such that the line draws with the proper angles and move along with any movement of the shapes?
Something like this:
I imagine a UIBezier Curve is what I need, but any tutorials or help in getting started would be appreciated.
I think UIBezierPath is the right way to go, so you should definitely read up on it. I wrote a quick example for making a path there are many more options I'm not using.
Drawing the paths is not the difficult part. You'll have to track all the boxes you create and store the connections between them somehow, it depends greatly on how you store the boxes but a relational database feels like the right solution. Given these objects and connections, you'll generate paths in drawrect for one of your views.
- (void)drawRect:(CGRect)rect {
// say we already created a "Make" box
UIBoxThing *make = ...
// and here we already created a "Diagrams" box
UIBoxThing *diagrams = ...
[[UIColor blackColor] setStroke];
// since we know Diagrams and Make are connected (via some other data), we must draw an arrow between them
UIBezierPath *path = [[UIBezierPath alloc] init];
path.lineWidth = 2;
// the midpoint of the right side of our first box
CGPoint start = CGPointMake(make.frame.origin.x+make.frame.size.width, make.frame.origin.y+(make.frame.size.height/2));
[path moveToPoint:start];
// the midpoint of the left size of our second box
CGPoint end = CGPointMake(diagram.frame.origin.x, diagram.frame.origin.y+(diagram.frame.size.height/2));
[path addLineToPoint:end];
[path stroke];
}
This would be complimented with code that can tell if boxes are to the right of one another or the left, and you can bend the line with addCurveToPoint: or a number of other methods on UIBezierPath. Most of the path stuff is depending on your style, there's no one correct style to connect two points.

Slice a UIImageView into a custom shape

I have a UIImageView that contains an image of a circle. I would like to be able to remove a portion of the image (while maintaining the transparency) to create the effect of a slice missing as shown below. My ultimate goal is to create something like the ITunes app, where as you play a song preview, the circle slowly fills in, in a clockwise direction.
If you don't need the image of the circle for anything other than the progress display, you could skip the UIImageView and just use CoreGraphics to draw the progress indicator. The basic steps would be:
Create a path - CGContextBeginPath
Add an arc using CGContextAddArc
Fill the path using CGContextFillPath
Close the path - CGContextClosePath
Repeat this for each progress step, changing the endpoint of your arc each time.
I've implemented a similar filling-up circle with the following code:
(the delegate provides a value between 0 and 1)
- (void)drawRect:(CGRect)rect
{
CGFloat endAngle=([self.delegate giveCompletion]+0.75)*2*M_PI;
UIBezierPath *path=[UIBezierPath bezierPathWithArcCenter:self.center radius:self.bounds.size.width/(3) startAngle:0.75*2*M_PI endAngle:endAngle clockwise:YES];
[path addLineToPoint:self.center];
[path addLineToPoint:CGPointMake(self.center.x, self.center.y+self.bounds.size.width/(3)) ];
[path addClip];
[[UIColor blueColor]setFill];
UIRectFill(self.bounds);
}
I haven't figured out how to dynamically make it fill up yet, though I guess that this would depend heavily on the specific context where it is being used. Hope it is of any help! Cheers.

How can I get all points in CGPath curve or quad curve

I have made a quad curve path using the method CGPathAddQuadCurveToPoint. I got the path perfectly. But, I want to know all the coordinate points which are participated in the path.
Is there a way to retrieve all the coordinate points in a path?
If not do u have any other solution for retrieving all the points in a curve mathematically.
Thanks in advance,
Vamshi
You can do this using the wykobi C++ library routine for cubic bezier curves. Wykobi's library supports quadratic Bezier curves also.
Of course as someone pointed out you don't want all the points (although not impossible, it would just take infinite time :). Wykobi makes it easy to get a certain number of points -- if your start, c1, c2, and end points (where c1, c2 are the control points) are exactly the same as the ones given to CGContextAddCurveToPoint then the points will lie perfectly on the line drawn by core graphics -- so you can do things like draw a pattern at several points on the path.
See: http://www.codeproject.com/Articles/22568/Computational-Geometry-C-and-Wykobi
Also, after I started using wykobi I heard that there is a similar, maybe even better library that is part of Boost, but have not checked it out yet.
I created a C++ Class WPoint as a bridge between wykobi points and CGPoints (C++ fun!). Here's some code (without WPoint, but you can imagine that it is exactly the same layout as a CGPoint so if you do the right cast you can convert easily.
NSMutableArray* result = [[NSMutableArray alloc] init];
wykobi::cubic_bezier<CGFloat,2> bezier;
bezier[0] = (WPoint)p1; // start point, in CG we did a CGMoveToPoint
bezier[1] = (WPoint)b1i; // control 1
bezier[2] = (WPoint)b2i; // control 2
bezier[3] = (WPoint)p2; // end point
std::vector<WPoint> point_list;
int numPoints = p2.dist(p3) * pointDensity;
// *** here's the magic ***
wykobi::generate_bezier(bezier,std::back_inserter(point_list), numPoints);
for (int i=0; i<numPoints; i++) {
CGPoint p = (CGPoint)(point_list[i]);
[result addObject:[NSValue valueWithCGPoint:p]];
}
// result has your points!
Here's a link to the Boost geometry library:
http://www.boost.org/doc/libs/1_47_0/libs/geometry/doc/html/geometry/introduction.html
Use CGContextSetLineDash
The purpose of this function is to create a dashed line, but You can use it to get smaller segments.
starting point of each segment can be treated as points.
CGSize bbSize = CGPathGetBoundingBox(path).size;
UIGraphicsBeginImageContext(bbSize);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 1.0);
CGContextAddPath(ctx, path);
CGContextSetLineDash(ctx, phase, lengths, count);
CGContextReplacePathWithStrokedPath(ctx);
result = CGContextCopyPath(ctx);
UIGraphicsEndImageContext();
If you want to work on the moveto, lineto, and curveto elements of the path, use CGPathApply. You pass this a pointer to a function in your program, and it calls that function once per element of the path.
Unfortunately, there's no way to just ask for each element like there is with AppKit's NSBezierPath. The function is the only way.
If you want to determine every pixel intersected by the path, too bad—that's not practical, and I can't even think of why you'd want that information. Some contexts, such as PDF contexts, don't even have pixels; in those cases, any question involving pixels is a non sequitur.
A quadratic curve is just that -- a curve. It's impossible to get a list of all of the points on it because there are infinitely many points, and it's not a simple line segment.
See Getting Information about Quartz Paths for a list of the functions you can use to query a CGPath object. Unfortunately, it seems like the most useful information you're going to get is with CGPathContainsPoint(), which only tells you if a given point is contained within the area of the path.
If not do u have any other solution for retrieving all the points in a curve mathematically.
What do you need them for, i.e. what problem are you trying to solve? If it is to intersect two curves, you can do this mathematically. Just set the two curve equations equal to each other and solve for the unknown.
I guess you're after something equivalent to the Java2D FlatteningPathIterator class. For example Java2D's path.getPathIterator(null, 1.0) returns an iterator of only 'lineTo' segments even if the original path had curveTo and quadTo, the double argument controls the 'flatness', giving you an easy way to calculate any point on the curve.
I'm searching for the same thing in Cocoa, but have found nothing. If you find a solution please let me know.
There are curve implmentations around (e.g. http://sourceforge.net/projects/curves/) that could be ported, but there's always a risk that if you don't use the same algorithm as Cocoa then there could be errors between your interpolation and the stroked NSBezierPath/CGPath.