Question

I want to make UBersense like app (http://blog.ubersense.com/2013/01/03/how-to-use-the-drawing-tools-in-ubersense/), there i need to draw two line with some angle, after that i can adjust the angle between two line by dragging any line or intersection point. can you guys please provide me some idea or code snippet.

screenshots url: https://picasaweb.google.com/yunusm7/AppScreenshots#slideshow/5952787957718627714

Thanks in advance.

Was it helpful?

Solution

You have a construction with three points, one point is an angle point, and two others are just vertices. First of all you should create a new class like this:

@interface MyAngle : NSObject {

}

@property (nonatomic) CGPoint p1;
@property (nonatomic) CGPoint p2;
@property (nonatomic) CGPoint v; // this is an angle point

@end 

You can use the default implementation of this without any tricks with such sample init:

- (id)init {
   if (self = [super init]) {
       p1 = CGPointMake(1,0);
       p2 = CGPointMake(0,1);
       v = CGPointZero;
   }
   return self;
}

But also as I understood you need to know the value of the angle. You can do this using the following way:

- (CGFloat)valueOfAngle {
    CGPoint v1 = CGPointMake(p1.x-v.x, p1.y-v.y);
    CGPoint v2 = CGPointMake(p2.x-v.x, p2.y-v.y);

    CGFloat scalarProduct = v1.x*v2.x + v1.y*v2.y;
    CGFloat lengthProduct = sqrt(v1.x*v1.x + v1.y*v1.y)*sqrt(v2.x*v2.x + v2.y*v2.y);
    CGFloat fraction = scalarProduct / lengthProduct;
    if (fraction < -1) fraction = -1;
    if (fraction > 1) fraction = 1;

    return acos(fraction);
}

If you want to obtain angles more than 180 degrees you should change the code above a little. But there are too much information about how to do this in the Internet, so I will skip this part.

Then you need to create an instance of MyAngle in your viewController. Let it be called "angle". Knowing coordinates of every three points if enough do draw it (!!!). Implement drawRect method in a view that will contain the MyAngle instance (I strongly recommend do to this on your own subclass of UIView):

- (void)drawRect {
    [super drawRect];

    // set options of drawing
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGFloat red[4] = {1.0f, 0.0f, 0.0f, 1.0f};
    CGContextSetLineWidth(c, 3.0);
    CGContextSetStrokeColor(c, red);

    // draw an angle directly
    CGContextBeginPath(c);
    CGContextMoveToPoint(c, angle.p1.x, angle.p1.y);
    CGContextAddLineToPoint(c, angle.v.x, angle.v.y);
    CGContextAddLineToPoint(c, angle.p2.x, angle.p2.y);
    CGContextStrokePath(c);

    // draw circles around vertices (like on the screenshot you provided)
    CGFloat R = 7.0f;
    CGContextBeginPath(c);
    CGContextAddEllipseInRect(c, CGRectMake(angle.p1.x - R, angle.p1.y - R, 2*R, 2*R));
    CGContextStrokePath(c);

    CGContextBeginPath(c);
    CGContextAddEllipseInRect(c, CGRectMake(angle.p2.x - R, angle.p2.y - R, 2*R, 2*R));
    CGContextStrokePath(c);

    CGContextBeginPath(c);
    CGContextAddEllipseInRect(c, CGRectMake(angle.v.x - R, angle.v.y - R, 2*R, 2*R));
    CGContextStrokePath(c);
}

And that's all you need to know for drawing what you want! You can change the stroke color or radius of three circles if you want.

Then you need to have a possibility to change the locations of your angle's points. For this you can just implement panGestureRecognizer in your viewController's viewDidLoad method like this:

UIPanGestureRecognizer *pan = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveAngle:)] autorelease];
pan.delegate = self;
[self.view addGestureRecognizer:pan]; 

Implement UIGestureRecognizerDelegate method:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        CGPoint p = [gestureRecognizer locationInView:self.view];
        CGFloat d1 = sqrt((p.x-angle.p1.x)*(p.x-angle.p1.x) + (p.y-angle.p1.y)*(p.y-angle.p1.y);
        CGFloat d2 = sqrt((p.x-angle.p2.x)*(p.x-angle.p2.x) + (p.y-angle.p2.y)*(p.y-angle.p2.y);
        CGFloat d3 = sqrt((p.x-angle.v.x)*(p.x-angle.v.x) + (p.y-angle.v.y)*(p.y-angle.v.y);

        // just check if we touched the screen near some of angle's points
        CGFloat tolerance = 15.0f;
        return (d1 < tolerance) || (d2 < tolerance) || (d3 < tolerance);
    }
    return YES;
}

and tagret's selector (also in your viewController):

- (void)moveAngle:(UIPanGestureRecognizer *)gr {
    CGPoint p = [gr locationInView:self.view];

    if (gr.state == UIGestureRecognizerStateBegan) {
        CGFloat d1 = sqrt((p.x-angle.p1.x)*(p.x-angle.p1.x) + (p.y-angle.p1.y)*(p.y-angle.p1.y);
        CGFloat d2 = sqrt((p.x-angle.p2.x)*(p.x-angle.p2.x) + (p.y-angle.p2.y)*(p.y-angle.p2.y);
        CGFloat d3 = sqrt((p.x-angle.v.x)*(p.x-angle.v.x) + (p.y-angle.v.y)*(p.y-angle.v.y);

        // pointToMove is your int variable
        CGFloat tolerance = 15.0f;
        if (d1 < tolerance) {
            pointToMove = 1;
        }
        else if (d2 < tolerance) {
            pointToMove = 2;
        }
        else {
            pointToMove = 3;
        }
    }
    else {
        if (pointToMove == 1) {
            angle.p1 = loc;
        }
        else if (pointToMove == 2) {
            angle.p2 = loc;
        }
        else {
            angle.v = loc;
        }
        [yourCustomView setNeedsDisplay];
        [yourLabel setText:[NSString stringWithFormat:@"%.3f", [angle valueOfangle]*180/PI]];
    }
}

Maybe I skip some evident things, but I think it should be enough for you to begin writing some code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top