Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw images evenly spaced along a path in iOS

What I want to do is move my finger across the screen (touchesMoved) and draw evenly spaced images (perhaps CGImageRefs) along the points generated by the touchesMoved. I can draw lines, but what I want to generate is something that looks like this (for this example I am using an image of an arrow but it could be any image, could be a picture of my dog :) ) The main thing is to get the images evenly spaced when drawing with a finger on an iPhone or iPad.

enter image description here

like image 422
cdasher Avatar asked Aug 05 '11 03:08

cdasher


1 Answers

First of all HUGE props go out to Kendall. So, based on his answer, here is the code to take a UIImage, draw it on screen along a path (not a real pathRef, just a logical path created by the points) based on the distance between the touches and then rotate the image correctly based on the VECTOR of the current and previous points. I hope you like it:

First you need to load an image to be used as a CGImage over and over again:

NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"arrow.png" ofType:nil];
  UIImage *img = [UIImage imageWithContentsOfFile:imagePath];
  image = CGImageRetain(img.CGImage);

make sure in your dealloc that you call

 CGImageRelease(image);

then in touchesBegan, just store the starting point in a var that is scoped outside the method (declare it in your header like this :) in this case I am drawing into a UIView

@interface myView : UIView {
    CGPoint lastPoint;
    }
@end

then in touches Began:

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

{

UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self];

}

and finally in touchesMoved, draw the bitmap to the screen and then when your distance has moved enough (in my case 73, since my image is 73 pixels x 73 pixels) draw that image to the screen, save the new image and set lastPoint equal to currentPoint

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

        UITouch *touch = [touches anyObject];   
        currentPoint = [touch locationInView:self];

        double deltaX = lastPoint.x - currentPoint.x;
        double deltaY = lastPoint.y - currentPoint.y;

        double powX = pow(deltaX,2);
        double powY = pow(deltaY,2);

        double distance = sqrt(powX + powY);
        if (distance >= 73){

            lastPoint = currentPoint;

             UIGraphicsBeginImageContext(self.frame.size);
            [drawImage.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
            CGContextSaveGState(UIGraphicsGetCurrentContext());

            float angle = atan2(deltaX, deltaY);
            angle *= (M_PI / 180);


            CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(currentPoint.x, currentPoint.y, 73, 73),[self CGImageRotatedByAngle:image angle:angle * -1]);
            CGContextRestoreGState(UIGraphicsGetCurrentContext());
             drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            distance = 0;

        }

    }


    - (CGImageRef)CGImageRotatedByAngle:(CGImageRef)imgRef angle:(CGFloat)angle
{
    CGFloat angleInRadians = angle * (M_PI / 180);
    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);

    CGRect imgRect = CGRectMake(0, 0, width, height);
    CGAffineTransform transform = CGAffineTransformMakeRotation(angleInRadians);
    CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, transform);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef bmContext = CGBitmapContextCreate(NULL,
                                                   rotatedRect.size.width,
                                                   rotatedRect.size.height,
                                                   8,
                                                   0,
                                                   colorSpace,
                                                   kCGImageAlphaPremultipliedFirst);
    CGContextSetAllowsAntialiasing(bmContext, FALSE);
    CGContextSetInterpolationQuality(bmContext, kCGInterpolationNone);
    CGColorSpaceRelease(colorSpace);
    CGContextTranslateCTM(bmContext,
                          +(rotatedRect.size.width/2),
                          +(rotatedRect.size.height/2));
    CGContextRotateCTM(bmContext, angleInRadians);
    CGContextTranslateCTM(bmContext,
                          -(rotatedRect.size.width/2),
                          -(rotatedRect.size.height/2));
    CGContextDrawImage(bmContext, CGRectMake(0, 0,
                                             rotatedRect.size.width,
                                             rotatedRect.size.height),
                       imgRef);

    CGImageRef rotatedImage = CGBitmapContextCreateImage(bmContext);
    CFRelease(bmContext);
    [(id)rotatedImage autorelease];

    return rotatedImage;
}

this will create an image that looks like this :

enter image description here

Going to add the following (with some changes to the above code in order to try and fill in the voids where touchesMoved is missing some points when you move fast:

CGPoint point1 = CGPointMake(100, 200);

CGPoint point2 = CGPointMake(300, 100);



double deltaX = point2.x - point1.x;
double deltaY = point2.y - point1.y;

double powX = pow(deltaX,2);
double powY = pow(deltaY,2);

double distance = sqrt(powX + powY);

distance = 0;


for (int j = 1; j * 73 < distance; j++ )
{
    double x =  (point1.x + ((deltaX / distance) * 73 * j));
    double y =  (point1.y + ((deltaY / distance) * 73 * j));


    NSLog(@"My new point is x: %f y :%f", x, y);
}
like image 178
cdasher Avatar answered Oct 09 '22 03:10

cdasher