objective-ccore-graphicsline-drawing

Line Drawing in iOS


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?


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.