Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Mastering CGAffineTransform

Chiharu Nameki
September 01, 2018

Mastering CGAffineTransform

マスタリング CGAffineTransform
iOSDC Japan 2018 LT

撮影した映像の向きがおかしい?Viewの位置計算で困ってる?
とても良い機会です。5分でCGAffineTransformをマスターしましょう!
CGAffineTransformはちっぽけなstructですが、使いこなせば非常に強力なAPIです。基本知識から組み合わせて掛けるときの考え方のコツなどを具体例と共にまとめました。もう座標計算に悩んで時間を使うことはありません!

Chiharu Nameki

September 01, 2018
Tweet

More Decks by Chiharu Nameki

Other Decks in Technology

Transcript

  1. SwiftͰͷఆٛ public struct CGAffineTransform { public var a: CGFloat public

    var b: CGFloat public var c: CGFloat public var d: CGFloat public var tx: CGFloat public var ty: CGFloat }
  2. ੜ੒ static var identity: CGAffineTransform init(a: CGFloat, b: CGFloat, c:

    CGFloat, d: CGFloat, tx: CGFloat, ty: CGFloat) init(translationX tx: CGFloat, y ty: CGFloat) init(scaleX sx: CGFloat, y sy: CGFloat) init(rotationAngle angle: CGFloat) ฏߦҠಈ ֦େɾॖখ ճస
  3. ద༻ let q = p.applying(transform) CGPoint
 
 ఺ CGSize
 


    αΠζ CGRect
 
 ྖҬ pʹtransformΛద༻ͯ͠qʹҠ͢ (x, y) (x, y) width height width height
  4. q = pABC let q = p.applying(a).applying(b).applying(c) let q =

    p.applying(a.concatenating(b).concatenating(c)) ࿈ଓͯ͠ద༻ concatenating Ͱ1ͭͷม׵ʹ·ͱΊΒΕΔ ͜ΕΒ͸਺ֶతʹ͸ɺ͜͏ ίʔυͱ਺ࣜͰॻ͘ॱ൪͕Ұॹʂ
  5. let length: CGFloat = 512 let squareSize = CGSize(width: length,

    height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ཁٻΛ͢΂ͯຬͨ͢ɺUIImageΛม׵͢Δίʔυʢશจʣ
  6. let length: CGFloat = 512 let squareSize = CGSize(width: length,

    height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻
  7. let length: CGFloat = 512 let squareSize = CGSize(width: length,

    height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻
  8. let length: CGFloat = 512 let squareSize = CGSize(width: length,

    height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻
  9. let length: CGFloat = 512 let squareSize = CGSize(width: length,

    height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻
  10. let length: CGFloat = 512 let squareSize = CGSize(width: length,

    height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻
  11. let length: CGFloat = 512 let squareSize = CGSize(width: length,

    height: length) UIGraphicsBeginImageContextWithOptions(squareSize, false, 1) let ctx = UIGraphicsGetCurrentContext()! let width = image.size.width let height = image.size.height let scale = min(1.0, length / min(width, height)) let transform = CGAffineTransform.identity .concatenating(.init(translationX: -width/2, y: -height/2)) .concatenating(.init(scaleX: scale, y: scale)) .concatenating(.init(translationX: length/2, y: length/2)) ctx.concatenate(transform) image.draw(in: CGRect(origin: .zero, size: image.size)) let resultImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() ॖখͱΫϩοϓͷͨΊʹΞϑΟϯม׵Λར༻
  12. ΞϑΟϯม׵Λ͞Βʹม׵͢Δ func translatedBy(x tx: CGFloat, y ty: CGFloat) -> CGAffineTransform

    func scaledBy(x sx: CGFloat, y sy: CGFloat) -> CGAffineTransform func rotated(by angle: CGFloat) -> CGAffineTransform
  13. ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2)

    .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y
  14. ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2)

    .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y
  15. ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2)

    .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y
  16. ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2)

    .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y
  17. ม׵ͷม׵ʁ transform = transform .translatedBy(x: 10, y: 0) .rotated(by: .pi/2)

    .scaledBy(x: 1.4, y: 1.4) .translatedBy(x: 5, y: 0) ʢಓҊ಺ͷΑ͏ͳΠϝʔδʣ ϩʔΧϧͷ࠲ඪܥ͕มΘ͍ͬͯ͘ x y
  18. ਺ֶతʹ͸ɺ͜͏ concatenating()΍CGRectͳͲͷapplying()ͱ͸൓ରଆ͔Βֻ͚Δ let transform = CGAffineTransform.identity .translatedBy(x: 10, y: 0)

    // A .rotated(by: .pi/2) // B .scaledBy(x: 1.4, y: 1.4) // C .translatedBy(x: 5, y: 0) // D let q = p.applying(transform) q = pDCBA
  19. @objc func handlePan(_ recognizer: UIPanGestureRecognizer) { let t = recognizer.translation(in:

    stamp.superview) stamp.center = stamp.center.applying(.init(translationX: t.x, y: t.y)) recognizer.setTranslation(.zero, in: stamp.superview) } @objc func handlePinch(_ recognizer: UIPinchGestureRecognizer) { let scale = recognizer.scale stamp.transform = stamp.transform.scaledBy(x: scale, y: scale) recognizer.scale = 1 } @objc func handleRotation(_ recognizer: UIRotationGestureRecognizer){ let rotation = recognizer.rotation stamp.transform = stamp.transform.rotated(by: rotation) recognizer.rotation = 0 } ֦େॖখͱճస → transform Ҡಈ → center ελϯϓͷUIViewͷϓϩύςΟΛมߋ࣮ͯ͠ݱ