Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get rid of this "points" between my lines when I am drawing?

is there an easy way to not draw this points in my lines?
I don't know why this points are there because i never release my finger from screen during drawing of a line. enter image description here

I got the code from a drawing example.

// draw a line
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

mouseSwiped = YES;
UITouch *touch = [touches anyObject];   
CGPoint currentPoint = [touch locationInView:self.view];
currentPoint.y -= 0; // 20 only for 'kCGLineCapRound'
UIGraphicsBeginImageContext(self.view.frame.size);
//Albert Renshaw - Apps4Life
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)]; //originally self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushSize); // for size
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), r, g, b, alpha); //values for R, G, B, and Alpha
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

lastPoint = currentPoint;

mouseMoved++;

if (mouseMoved == 10) {
    mouseMoved = 0;
}

    }

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


//Draw a dot
if(!mouseSwiped) {

    UIGraphicsBeginImageContext(self.view.frame.size);
    [drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)]; //originally self.frame.size.width, self.frame.size.height)];
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushSize);
    CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), r, g, b, alpha);
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
    CGContextStrokePath(UIGraphicsGetCurrentContext());
    CGContextFlush(UIGraphicsGetCurrentContext());
    drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}
    }

This is the final version with unique alpha, color, brushSize for every line:

- (void) updateDrawingBoard 
{
UIGraphicsBeginImageContext(self.drawImage.bounds.size);

for ( NSDictionary *dict in paths ) {

   UIBezierPath *p = (UIBezierPath*)[dict objectForKey:@"path"];
   p.lineWidth = [[dict objectForKey:@"size"]floatValue];
   [[UIColor colorWithRed:[[dict objectForKey:@"red"]floatValue] 
                     green:[[dict objectForKey:@"green"]floatValue] 
                      blue:[[dict objectForKey:@"blue"]floatValue] 
                     alpha:[[dict objectForKey:@"alpha"]floatValue]] setStroke];
  [p stroke];
}
[[UIColor colorWithRed:r green:g blue:b alpha:alpha] setStroke];
[path stroke];

self.drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInView:self.drawImage];

path = [[UIBezierPath bezierPath] retain];
path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle = kCGLineJoinBevel;
path.lineWidth = brushSize;
[path moveToPoint:touchPoint];

[self updateDrawingBoard];
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInView:self.drawImage];

[path addLineToPoint:touchPoint];

NSDictionary   *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                        path,@"path",
                        [NSNumber numberWithFloat:r], @"red", 
                        [NSNumber numberWithFloat:g], @"green", 
                        [NSNumber numberWithFloat:b], @"blue", 
                        [NSNumber numberWithFloat:alpha], @"alpha", 
                        [NSNumber numberWithFloat:brushSize], @"size", nil];
[paths addObject:dict];
[path release];
path = nil;

[self updateDrawingBoard];
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInView:self.drawImage];

[path addLineToPoint:touchPoint];

[self updateDrawingBoard];
}
like image 265
madmax Avatar asked Jun 07 '11 08:06

madmax


People also ask

What is freeform shape?

Freeform Shapes - also called organic shapes, are irregular and uneven shapes. Their outlines may be curved, angular, or a combination of both. Form - an element of art, means objects that have three dimensions.


2 Answers

The problem is that you are gradually accumulating the line by drawing into an image. Where the old line and the new line overlap, you see "dots" from the overdraw.

The solution is to accumulate your points in a path and draw the image afresh each time using that path. Since you will be drawing a single path, not multiple overlapping paths, you shouldn't see the dots.

Outline of code:

  • Some time before drawing begins, create a CGMutablePathRef.
  • When you get a new point you want to add to your line, use CGPathAddLineToPoint.
  • When it's time to draw the path, use CGContextAddPath to add the line to the context, then fill or stroke as desired. You could also use CGContextDrawPath.

Alternatively, you can use UIBezierPath instead of CGMutablePathRef, in which case the steps are:

  • Create a UIBezierPath.
  • Use -addLineToPoint: to add lines to the path.
  • Use -stroke, -fill, and similar to draw the path into the context.

This is likely to be simpler if you are not accustomed to working with CoreGraphics directly.

I would drop the intermediate image and move this code into a view class (LineDrawView or CanvasView or something) rather than leaving the code in a view controller. Instead of updating an image, the view can just draw itself directly to the screene. The view would have methods to clear the path, undo strokes, and create an image of the path. The view controller would then use these to clear the canvas, undo lines, and save the drawing. You could enrich this later with functionality to configure the line style.

like image 61
Jeremy W. Sherman Avatar answered Sep 28 '22 20:09

Jeremy W. Sherman


I have been trying to beat this problem for a few days, trying out Jeremy W. Sherman's answer that is probably a very good idea but was not feasable for my implementation.

In my drawing app, I could not get the alpha curves to blend into each other by constantly render the path, though the dots disappeared. If you just want a clean, alpha-colored path this is probably the way to go.

But I found a solution to this that was much simpler; these adjustments create a perfect, alpha-colored path in realtime with blending (think of it as a felt tip pen kind of style):

CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapButt);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeMultiply);

Hope this helps anyone who's doing some simple CG painting in iOS.

like image 44
machineboy Avatar answered Sep 28 '22 20:09

machineboy