0

I have an image in UIImageView. I have drawn lines on the image sucdcessfully.Now I want to remove that specific line on which user will perform a long press gesture. how can I do that ? my code is :

{

        // gets the location in the form of (x,y) coordinates
        CGPoint  location=[sender locationInView:imageView];
        // convetrs the location relative to the image
        CGPoint contextLocation = CGPointMake(location.x*imageView.image.size.width/imageView.frame.size.width, location.y*imageView.image.size.height/imageView.frame.size.height);
        // converts the location point into NSValue
        NSValue *imagePoint=[NSValue valueWithCGPoint:contextLocation];
        // Adds the  image into NSMutable Array
        [imageLocations addObject:imagePoint];
        // color of line
        UIColor * linearcolor=[UIColor blueColor];


        UIGraphicsBeginImageContext(imageView.image.size);

        [imageView.image drawAtPoint:CGPointMake(0, 0)];


        CGContextRef context=UIGraphicsGetCurrentContext();

        // Brush widt
        CGContextSetLineWidth(context, 3.0);
        // Line Color
        CGContextSetStrokeColorWithColor(context, [linearcolor CGColor]);
        // Hard coded point for location 2
        CGPoint location2=CGPointMake(300, 400);


        CGContextMoveToPoint(context, contextLocation.x, contextLocation.y);

        CGContextAddLineToPoint(context, location2.x, location2.y);
        CGContextStrokePath(context);

        newImage=UIGraphicsGetImageFromCurrentImageContext();

        UIGraphicsEndImageContext();
        imageView.image=newImage;



    }
iOS_Learner
  • 159
  • 9

2 Answers2

2

It's simple. I add my code below as your question.

// gets the location in the form of (x,y) coordinates
    CGPoint  location=[sender locationInView:imageView];
    // convetrs the location relative to the image
    CGPoint contextLocation = CGPointMake(location.x*imageView.image.size.width/imageView.frame.size.width, location.y*imageView.image.size.height/imageView.frame.size.height);
    // converts the location point into NSValue
    NSValue *imagePoint=[NSValue valueWithCGPoint:contextLocation];
    // Adds the  image into NSMutable Array
    [imageLocations addObject:imagePoint];
    // color of line
    UIColor * linearcolor=[UIColor blueColor];


    UIGraphicsBeginImageContext(imageView.image.size);

    [imageView.image drawAtPoint:CGPointMake(0, 0)];


    CGContextRef context=UIGraphicsGetCurrentContext();

    // Brush widt
    CGContextSetLineWidth(context, 3.0);

    **CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);**

    // Hard coded point for location 2
    CGPoint location2=CGPointMake(300, 400);


    CGContextMoveToPoint(context, contextLocation.x, contextLocation.y);

    CGContextAddLineToPoint(context, location2.x, location2.y);
    CGContextStrokePath(context);

    newImage=UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();
    imageView.image=newImage;
}

Hope this is helpful.Enjoy.

Milan patel
  • 223
  • 2
  • 15
  • I want to delete that line on which user will perform the long press gesture. for example if line starts from point A (234,445) to point B (400,600). if user performs the gesture at line then that line should be deleted. and user can perform long press gesture at any point of line. – iOS_Learner Jan 16 '15 at 13:31
  • In the long press gesture method ,you can add the if and else condition like this.if (touch location>=234||touch location<=600){ //add your method..}else{ ... }. – Milan patel Jan 17 '15 at 04:39
0

What you need to do is find the line pressed and remove it from the array of points you have and then redraw the whole image with the lines.

I guess the problem is in how to find the correct line:

Lets say you have a location L gotten from the gesture. Then what you need is to iterate through all the point pairs such as

for(NSInteger i=0; i< imageLocations.count.count-1; i+=2)
{
   CGPoint T1 = [imageLocations[i] CGPointValue];
   CGPoint T2 = [imageLocations[i+1] CGPointValue];
}

Now you have points L, T1, T2. From here there are many ways to detect if the line is hit. What I like most is to first use a dot product to see if the press is near the line like so:

CGFloat dotValue = dot(normalized(T1-L), normalized(T2-L))

Find the procedures for the dot product and the normalization of a point online. Now the dotValue should be near -1 for the line to be hit. You should use something like if(dotValue > -.7f) continue; to remove all the lines too far from the press along the line.

Next is to actually find the line distance from the point. This is actually a Z component of a cross product:

CGFloat crossValue = fabsf(cross((L-T1), normalized(T2-T1)).z);

I know you have no Z component so use:

crossValue = A.x*B.y - A.y*B.x

So now that you have all this the pseudo code should be something like this:

CGPoint L;
NSInteger bestLineIndex = -1;
CGFloat bestLineDistance = 10000.0f; // something large

for (CGPoint T1, T2; NSInteger index)
{
    dotValue = ...
    if(dotValue < -.7)
    {
        crossValue = ...
        if(crossValue < bestLineDistance)
        {
           bestLineDistance = crossValue;
           bestLineIndex = index;
        }
    }
}

So in the end you have the index of your first line point which should be removed if not -1 (if -1 no line was found near the touch).

For line distance from a point using a cross product:

- (CGFloat)distanceBetweenPoint:(CGPoint)L andLineWithStart:(CGPoint)T1 end:(CGPoint)T2
{
    CGPoint T1toL = CGPointMake(L.x-T1.x, L.y-T1.y);
    CGPoint T2toL = CGPointMake(L.x-T2.x, L.y-T2.y);

    CGFloat T2toLDistance = sqrt(T2toL.x*T2toL.x + T2toL.y*T2toL.y);
    CGPoint T2toLNormalized = CGPointMake(T2toL.x/T2toLDistance, T2toL.y/T2toLDistance);

    CGFloat zComponentOfCross = T1toL.x*T2toLNormalized.y - T1toL.y*T2toLNormalized.x;

    return fabs(zComponentOfCross);
}
Matic Oblak
  • 16,318
  • 3
  • 24
  • 43
  • Thanks... I have implemented method, the way you suggested. but sometimes it doesn't delete the line which got hit by the user instead deletes some other. But most of the time its working fine..... – iOS_Learner Jan 19 '15 at 12:21
  • Try analyzing a bit to where the issue comes to. You might need to pimp the dotValue compare value if nothing else (the -.7). Also you might want to implement a minimum distance from the line. Try playing around a bit with those values. – Matic Oblak Jan 19 '15 at 12:27
  • Also with this algorithm if the line is VERY short it will be very hard to press it. For that you might want another check where you compare if both of the line points are very close to the touched location rather delete that one. – Matic Oblak Jan 19 '15 at 12:31
  • yes you were right ... I played with cross-value ...when ever I got cross value greater than bestlinedistance it didn't delete the line instead drew new line on the image.so I increased the value of line distance.... so right now its 97% working fine... sometimes it deletes the wrong line.... – iOS_Learner Jan 19 '15 at 13:44
  • I had to edit the crossValue equation as I misspelled it. Check if you have the same. – Matic Oblak Jan 19 '15 at 15:17
  • I am using one function for cross value, which I found on the internet. – iOS_Learner Jan 19 '15 at 15:24
  • would you like to tell me what sort of editing you wanted to to do ? – iOS_Learner Jan 19 '15 at 15:25
  • Simply read my answer again. Not the cross product method but how to get the crossValue.. Anyway I added the code to get the distance between the line and a point now. – Matic Oblak Jan 19 '15 at 15:26
  • If my UIImageView's contentMode property is set to be UIViewContentModeScaleToFill then it gives me perfect touch location but if the content mode is changed then it gives e.g. if it's UIViewContentModeScaleAspectFit then it doesn't give me the exact location though I am calculating the location of touch according to the image. my code is : CGPoint contextLocation=CGPointMake(location.x*imageView.image.size.width/imageView.frame.size.width, location.y*imageView.image.size.height/imageView.frame.size.height); – iOS_Learner Jan 20 '15 at 06:57
  • Yes, you need to include the image origin in this case as well as it is not at (0,0). It is best if you keep the scale to fill and then scale the image view proportionally. – Matic Oblak Jan 20 '15 at 07:28
  • I have checked the origin. its at (0,0) ...what else could be the reason. – iOS_Learner Jan 20 '15 at 07:54
  • do I need to make some change in calculation method for specific contentMode property of UIImageView ? – iOS_Learner Jan 20 '15 at 07:56
  • The origin of the image itself on the image view is not on (0,0). You can not check that anywhere, you need to compute it. In general if you use fit one of the origin coordinates will be larger then zero and if you use fill one of them will be smaller then zero. To get those values you need to compare the image and the view dimension ratio. – Matic Oblak Jan 20 '15 at 07:59
  • http://stackoverflow.com/questions/28166819/finding-touch-location-according-to-image-in-uiimageview – iOS_Learner Jan 27 '15 at 11:53