Question

How to Draw a straight line in iOS irrespective of how user draws it.

I want the line to be of the length of number of pixels user drags his finger.

But it needs to be either vertical or horizontal based on whether user slides his finger from left to right of the screen or top to bottom of the screen.

Lines should not be slanting or any other shape. It needs to be straight.

I have gone through articles which says "Open GL" is the only way.

I have tried coding it myself but when I change the direction from vertical to horizontal or vice versa, I get some extra line or gap between where horizontal line ends and where vertical line starts:

In header file:

@interface ViewController : UIViewController
{
    BOOL mouseSwiped;
    CGPoint lastPoint;
    CGPoint previousPoint;
    UIBezierPath *currentPath;
    CGFloat lastPointY;
    CGFloat lastPointX;
    BOOL xchanging;
    BOOL ychanging;
    NSMutableArray *arrayTouch;
}
@property (weak, nonatomic) IBOutlet UIImageView *drawImage;
@property UIBezierPath *currentPath;
@end

In implementation file:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {


    mouseSwiped = NO;
    UITouch *touch = [touches anyObject];

    if ([touch tapCount] == 2) {
        drawImage.image = nil;
        [arrayTouch removeAllObjects];
        return;
    }

    lastPoint = [touch locationInView:self.view];
    [arrayTouch addObject:touch];
    lastPointY  = lastPoint.y;
    lastPointX = lastPoint.x;
    lastPoint.y -= 1;
} 


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    mouseSwiped = YES;

    UITouch *touch = [touches anyObject];
    CGPoint currentPoint = [touch locationInView:self.view];
    currentPoint.y -= 1;
    int currentPointXVal = currentPoint.x;
    int currentPointYVal = currentPoint.y;

    int lastPointXVal = lastPoint.x;
    int lastPointYVal = lastPoint.y;

    int diffX = abs(currentPointXVal - lastPointXVal);
    int diffY = abs(currentPointYVal - lastPointYVal);

    if(currentPoint.x > lastPoint.x && diffX > diffY)
    {
        if(ychanging == YES)
        {
            lastPointY  = currentPoint.y;
            lastPointX = currentPoint.x;
            ychanging = NO;
        }
        xchanging = YES;
        NSLog(@"x increasing");
        NSLog(@"currentPoint: %@",NSStringFromCGPoint(currentPoint));
        NSLog(@"lastPoint: %@",NSStringFromCGPoint(lastPoint));

        UIGraphicsBeginImageContext(self.view.frame.size);
        [drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
        CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
        CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
        CGContextBeginPath(UIGraphicsGetCurrentContext());
        CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPointY);
        CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, lastPointY);
        CGContextStrokePath(UIGraphicsGetCurrentContext());
        drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }

    if(currentPoint.y > lastPoint.y && diffY > diffX)
    {
        if(xchanging == YES)
        {
            lastPointY  = currentPoint.y;
            lastPointX = currentPoint.x;
            xchanging = NO;
        }
        ychanging = YES;
        NSLog(@"y increasing");
        NSLog(@"currentPoint: %@",NSStringFromCGPoint(currentPoint));
        NSLog(@"lastPoint: %@",NSStringFromCGPoint(lastPoint));

        UIGraphicsBeginImageContext(self.view.frame.size);
        [drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
        CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
        CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
        CGContextBeginPath(UIGraphicsGetCurrentContext());
        CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointX, lastPoint.y);
        CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPointX, currentPoint.y);
        CGContextStrokePath(UIGraphicsGetCurrentContext());
        drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }

    if(currentPoint.x < lastPoint.x && diffX > diffY)
    {
        if(ychanging == YES)
        {
            lastPointY  = currentPoint.y;
            lastPointX = currentPoint.x;
            ychanging = NO;
        }
        xchanging = YES;
        NSLog(@"x decreasing");
        NSLog(@"currentPoint: %@",NSStringFromCGPoint(currentPoint));
        NSLog(@"lastPoint: %@",NSStringFromCGPoint(lastPoint));

        UIGraphicsBeginImageContext(self.view.frame.size);
        [drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
        CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
        CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
        CGContextBeginPath(UIGraphicsGetCurrentContext());
        CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPointY);
        CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, lastPointY);
        CGContextStrokePath(UIGraphicsGetCurrentContext());
        drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }

    if(currentPoint.y < lastPoint.y && diffY > diffX)
    {
        if(xchanging == YES)
        {
            lastPointY  = currentPoint.y;
            lastPointX = currentPoint.x;
            xchanging = NO;
        }

        ychanging = YES;
        NSLog(@"y decreasing");
        NSLog(@"currentPoint: %@",NSStringFromCGPoint(currentPoint));
        NSLog(@"lastPoint: %@",NSStringFromCGPoint(lastPoint));

        UIGraphicsBeginImageContext(self.view.frame.size);
        [drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
        CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
        CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
        CGContextBeginPath(UIGraphicsGetCurrentContext());
        CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointX, lastPoint.y);
        CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPointX, currentPoint.y);
        CGContextStrokePath(UIGraphicsGetCurrentContext());
        drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

    }





    lastPoint = currentPoint;

}

Is there any way I can do it without Open GL?

Was it helpful?

Solution

Sure - You can do this, just take away the slope from the line:

@implementation LineDrawingView
{
    CGPoint touchStart;
    CGPoint touchCurrent;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        touchStart   = (CGPoint) { -1, -1 };
        touchCurrent = (CGPoint) { -1, -1 };
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    if (touchStart.x != -1)
    {
        // calculate the line rotation
        enum { horizontal, vertical } lineRot = horizontal;

        if (touchStart.y == touchCurrent.y)
        {
            // straight line
            lineRot = horizontal;
        }
        else
        {
            // calculate the slope
            double slope = fabs((touchCurrent.y - touchStart.y) / (touchCurrent.x - touchStart.x));

            if (slope > 1)
                lineRot = vertical;
        }

        // draw the actual line
        CGPoint lineEndPoint = { };

        if (lineRot == horizontal)
            lineEndPoint = (CGPoint) { touchCurrent.x, touchStart.y }; // horizontal line
        else
            lineEndPoint = (CGPoint) { touchStart.x, touchCurrent.y }; // vertical line

        // actually draw the line
        [[UIColor redColor] setStroke];

        UIBezierPath *path = [UIBezierPath bezierPath];
        [path moveToPoint:touchStart];
        [path addLineToPoint:lineEndPoint];

        [path stroke];
    }
}

-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    touchStart = [[touches anyObject] locationInView:self];
    touchCurrent = touchStart;
    [self setNeedsDisplay];
}

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    touchCurrent = [[touches anyObject] locationInView:self];
    [self setNeedsDisplay];
}

-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    touchStart = touchCurrent = (CGPoint) { -1, -1 };
    [self setNeedsDisplay];
}

@end

You can extend this to use an array of lines if you'd like, this is just a simple explanation.

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