iPhone: Line connectors attached to shapes - iphone

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.

Related

How to get UIBezierPath from CGPoint or CGPath

I am working on one application in that I need to get User input for UIBezierPath and in that case I have CGPoints array so my question is How can I Create or Define UIBezierPath from CGPoints.
I have searched a lot but not getting any positive information so please suggest me some informative things for my problem.
For Example :- If user Draw something on the screen then I need to detect that Drawing and respond accordingly (I have also try with Custom gesture recognition but not getting success so have to move on UIBezierPath).
Please give me proper guidance.
Thanks.
For the first case it's enough to add manually all the points, possibly in a loop.
For the second case see this method:
+ (UIBezierPath *)bezierPathWithCGPath:(CGPathRef)CGPath;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:point1];
[path addLineToPoint:point2];
[path addLineToPoint:point3];
//...

How to fill space between two UIBezierPaths

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];

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.

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.

Is it ever possible to call pointInside: on an irregular shape?

I'm drawing an oblong 'egg' shape (on iOS), and want to use it as a boundary for particles. My thought is to use the curve paths to make a UIView and then use hitTest:withEvent: or pointInside:withEvent: to enforce boundary collision.
The problem is, of course, that UIView is always rectangular. How would you go about checking to see if a point is inside an irregular shape like this?
- (void)drawRect:(CGRect)rect {
int w = rect.size.width;
int h = rect.size.height;
CGContextBeginPath(context);
CGContextMoveToPoint(context, w/2, h/5);
CGContextAddCurveToPoint(context, w*0.1, h/4.3, w*0.1, h*0.82, w/2, h*0.8);
CGContextAddCurveToPoint(context, w*0.9, h*0.82, w*0.9, h/4.3, w/2, h*0.2);
I'm using openFrameworks, for what that's worth. This code is just Obj-C but I'm open to any C++/obj-C++ solutions out there.
If you make a CGPathRef you can use CGPathContainsPoint. You can use that same CGPathRef to render into the context. You could also call CGContextPathContainsPoint on the context containing the path, but depending on when you need to test you might not have a context. And another alternative is the containsPoint selector on UIBezierPath.
If you want to code this from scratch, http://www.softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm goes through a couple of different algorithms that will work for an arbitrary polygon.