Search code examples
iosswiftdrawcs193p

Coordinating smiley face on portrait mode doesn't work well


I'm new to swift and I currently follow screencasts from CS193P. In one episode, It show me to create smiley face using drawRect. I tried to replicate it but it's turn out It's doesn't work very well. In Original Screencast, it turn out to as well blown smiley face but In my exercise, mine is turn out to as follows;

enter image description here

It seem work on landscape mode though.

enter image description here

My Code is as follows and could you please guide me which parts is wrong ???

import UIKit

class FaceView: UIView {

    var faceCenter: CGPoint {
        return convertPoint(center, fromView:superview)
    }

    var scale:CGFloat {
        return 0.9
    }

    private struct Scaling {
        static let FaceRadiusToEyeRadiusRatio: CGFloat = 10
        static let FaceRadiusToEyeOffsetRatio: CGFloat = 3
        static let FaceRadiusToEyeSeperationRatio: CGFloat = 1.5
        static let FaceRadiusToMouthWidthRatio: CGFloat = 1
        static let FaceRadiusToMouthHeightRatio: CGFloat = 3
        static let FaceRadiusToMouthOffsetRatio: CGFloat = 3

    }

    private enum eye {case Left, Right}

    private func bezierPathForEye(whichEye: eye) -> UIBezierPath {

        let eyeRadius = faceRadius / Scaling.FaceRadiusToEyeRadiusRatio
        let eyeVerticalOffset = faceRadius / Scaling.FaceRadiusToEyeOffsetRatio
        let eyeHorizontalSeparation = faceRadius / Scaling.FaceRadiusToEyeSeperationRatio

        var eyeCenter = faceCenter
        eyeCenter.y = eyeVerticalOffset
        switch whichEye {
        case .Left: eyeCenter.x -= eyeHorizontalSeparation / 2
        case .Right: eyeCenter.x += eyeHorizontalSeparation / 2
        }

        let path = UIBezierPath(arcCenter: eyeCenter, radius: eyeRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)
        path.lineWidth = lineWidth;
        return path

    }

    private func bezierPathForSmile(fractionOfMaxSmile: Double) -> UIBezierPath {

        let mouthWidth = faceRadius / Scaling.FaceRadiusToMouthWidthRatio
        let mouthHeight = faceRadius / Scaling.FaceRadiusToMouthHeightRatio
        let mouthVerticalOffset = faceRadius / Scaling.FaceRadiusToMouthOffsetRatio

        let smileHeight = CGFloat(max(min(fractionOfMaxSmile,1),-1)) * mouthHeight

        let start = CGPoint(x:faceCenter.x - mouthWidth / 2 , y:faceCenter.y + mouthVerticalOffset)
        let end = CGPoint(x:start.x + mouthWidth, y: start.y)
        let cp1 = CGPoint(x:start.x + mouthWidth / 3, y: start.y + smileHeight)
        let cp2 = CGPoint(x:end.x - mouthWidth/3, y:cp1.y)
        let path = UIBezierPath()
        path.moveToPoint(start)
        path.addCurveToPoint(end, controlPoint1: cp1, controlPoint2: cp2)
        path.lineWidth = lineWidth

        return path


    }




    var faceRadius: CGFloat {
        return min(bounds.size.width,bounds.size.height) / 2 * scale
    }

    var lineWidth: CGFloat = 3 { didSet { setNeedsDisplay() } }
    var color: UIColor = UIColor.blueColor() { didSet { setNeedsDisplay() } }


    override func drawRect(rect: CGRect) {

        let facePath = UIBezierPath(arcCenter: faceCenter, radius: faceRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)

        facePath.lineWidth = 3
        color.set()
        facePath.stroke()

        bezierPathForEye(.Left).stroke()
        bezierPathForEye(.Right).stroke()

        let smiliness = 0.75
        let smilepath = bezierPathForSmile(smiliness)
        smilepath.stroke()
    }

}

FYI, That's not an assignment and I just trying to replicate things for exercising.


Solution

  • Change from

    eyeCenter.y = eyeVerticalOffset
    

    into this

    eyeCenter.y -= eyeVerticalOffset