Search code examples
objective-cdrawingcs193p

How to draw a perfect squiggle in set card game with objective-c?


I'm trying to draw squiggle in Set Card Game. The output is not even close to what I want. How should I improve the drawing?

  • Please ignore the shading in "What I want" picture. I have figured out how to do that. The question is how to drawing the shape of squiggle
  • The purpose of this is to practice drawing with objective-c. So just using png picture is not a solution here...

..

#define SQUIGGLE_CURVE_FACTOR 0.5
 - (UIBezierPath *)drawSquiggleAtPoint:(CGPoint)point
{
    CGFloat dx = self.bounds.size.width * SYMBOL_WIDTH_RATIO / 2;
    CGFloat dy = self.bounds.size.height * SYMBOL_HEIGHT_RATIO / 2;

    UIBezierPath *path = [[UIBezierPath alloc] init];
    CGFloat dsqx = dx * SQUIGGLE_CURVE_FACTOR;
    CGFloat dsqy = dy * SQUIGGLE_CURVE_FACTOR;
    [path moveToPoint:CGPointMake(point.x - dx, point.y)];
    [path addQuadCurveToPoint:CGPointMake(point.x - dsqx, point.y + dsqy) controlPoint:CGPointMake(point.x - dx, point.y + dy + dsqy)];
    [path addCurveToPoint:CGPointMake(point.x + dx, point.y) controlPoint1:point controlPoint2:CGPointMake(point.x + dx, point.y + dy * 2)];
    [path addQuadCurveToPoint:CGPointMake(point.x + dsqx, point.y - dsqy) controlPoint:CGPointMake(point.x + dx, point.y - dy - dsqy)];
    [path addCurveToPoint:CGPointMake(point.x - dx, point.y) controlPoint1:point controlPoint2:CGPointMake(point.x - dx, point.y - dy * 2)];

    return path;
}
  • What I got:

What I got

  • What I want:

What I want


final version

- (UIBezierPath *)drawSquiggleAtPoint:(CGPoint)point
{
    CGSize size = CGSizeMake(self.bounds.size.width * SYMBOL_WIDTH_RATIO, self.bounds.size.height * SYMBOL_HEIGHT_RATIO);

    UIBezierPath *path = [[UIBezierPath alloc] init];
    [path moveToPoint:CGPointMake(104, 15)];
    [path addCurveToPoint:CGPointMake(63, 54) controlPoint1:CGPointMake(112.4, 36.9) controlPoint2:CGPointMake(89.7, 60.8)];
    [path addCurveToPoint:CGPointMake(27, 53) controlPoint1:CGPointMake(52.3, 51.3) controlPoint2:CGPointMake(42.2, 42)];
    [path addCurveToPoint:CGPointMake(5, 40) controlPoint1:CGPointMake(9.6, 65.6) controlPoint2:CGPointMake(5.4, 58.3)];
    [path addCurveToPoint:CGPointMake(36, 12) controlPoint1:CGPointMake(4.6, 22) controlPoint2:CGPointMake(19.1, 9.7)];
    [path addCurveToPoint:CGPointMake(89, 14) controlPoint1:CGPointMake(59.2, 15.2) controlPoint2:CGPointMake(61.9, 31.5)];
    [path addCurveToPoint:CGPointMake(104, 15) controlPoint1:CGPointMake(95.3, 10) controlPoint2:CGPointMake(100.9, 6.9)];

    [path applyTransform:CGAffineTransformMakeScale(0.9524*size.width/100, 0.9524*size.height/50)];
    [path applyTransform:CGAffineTransformMakeTranslation(point.x - size.width/2 - 3 * size.width /100, point.y - size.height/2 - 8 * size.height/50)];

    return path;
}

Solution

  • Here's some code that generates a fairly decent rendition of a squiggle

    - (void)drawSquiggle
    {
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        // translate and scale the squiggle
        CGContextSaveGState( context );
        CGContextTranslateCTM( context, 0, 100 );
        CGContextScaleCTM( context, 2.0, 2.0 );
    
        // create the squiggle path
        CGContextMoveToPoint( context, 104.0, 15.0 );
        CGContextAddCurveToPoint( context, 112.4 , 36.9,   89.7,  60.8,   63.0,  54.0 );
        CGContextAddCurveToPoint( context,  52.3 , 51.3,   42.2,  42.0,   27.0,  53.0 );
        CGContextAddCurveToPoint( context,   9.6 , 65.6,    5.4,  58.3,    5.0,  40.0 );
        CGContextAddCurveToPoint( context,   4.6 , 22.0,   19.1,   9.7,   36.0,  12.0 );
        CGContextAddCurveToPoint( context,  59.2 , 15.2,   61.9,  31.5,   89.0,  14.0 );
        CGContextAddCurveToPoint( context,  95.3 , 10.0,  100.9,   6.9,  104.0,  15.0 );
    
        // draw the squiggle
        CGContextSetLineCap( context, kCGLineCapRound );
        CGContextSetLineWidth( context, 2.0 );
        CGContextStrokePath( context );
    
        // restore the graphics state
        CGContextRestoreGState( context );
    }
    

    This is what it produces

    enter image description here


    Scaling and Translating the Squiggle

    There are two ways to change the size and position of the squiggle.

    One way is to change all the number that are passed to the CGContextAddCurveToPoint function. For example, if you adjust the x values with x = (x-3) * 0.9524 and adjust all the y values with y = (y-8) * 0.9524, then the squiggle fits nicely into a 100x50 rectangle.

    The other way is to change the affine transform of your drawing context before drawing the squiggle. You can apply translation and scale transformations to place/size the squiggle wherever you want it. Note that the order in which the transformations are applied is important. Also, you can save and restore the graphics state so that the transformations are only applied to the squiggle, and not other items that you are drawing. The code above moves the squiggle 100 pixels down, and makes it twice as big.