Why does CGAffineTransform(Rotate) work differently for UIBezierCurve and UIImageView?

Viewed 136

I’m using a drawingView which is simply a VC’s view to draw a rectangle that rotates depending on a pan gesture. I apply 3 transforms on it. I translate the rectangle half it’s width left to put the top center of the rectangle at 0,0; rotate it some multiple of 45º and then translate it to the position of the gesture begin. This works perfectly.

When the pan gesture ends I want to drop an image view of the same size exactly where the rectangle is. The code for the drawing view are the save as the VC with the exception that in the drawing view the CGAffineTransform is applied to the path

  func addImageView(_ x: CGFloat, _ y: CGFloat, _ direction: Direction) {
    let myImageView = MyImageView(frame: CGRect(x: 0, y: 0, width: 116, height: 200))
    myImageView = UIColor.systemBlue

    var viewTransform = CGAffineTransform.identity

    viewTransform = viewTransform.translatedBy(x: -58, y: 0)

    var angle: CGFloat?
    let pi = CGFloat.pi

    switch direction {
    case .up:
      angle = 0
    case .upRight:
      angle = pi / 4.0
    case .right:
      angle = pi / 2.0
    case .downRight:
      angle = 3 * pi / 4.0
    case .down:
      angle = pi
    case .downLeft:
      angle = 5 * pi / 4.0
    case .left:
      angle = 3 * pi / 2.0
    case .upLeft:
      angle = 7 * pi / 4.0
    default:
      angle = nil
    }

    if angle != nil {
      viewTransform = viewTransform.rotated(by: angle!)
    }

    viewTransform = viewTransform.translatedBy(x: x, y: y)
    myImageView = viewTransform
    view.addSubview(myImageView)
    print("myImageView: \(myImageView)")
  }

If there is no rotation the imageView drops perfectly. If there is rotation it (in all but one case) vanishes off the screen. In one case it basically draws (at the correct angle) but in a very wrong position.

I’m not sure what the image view is rotating “About” and have had no luck tracking down the correct mathematical changes.

Edit: When doing just the initial translate and the rotation; everything is fine and the UIImage rotates around the center of the frame. When I then add a translate after the rotation; it changes the point around which the view rotates making a bigger circle.

So the problem is moving the rotated view into place after the rotation is done.

Drawing UIBezierCurve works fine UIImageView is off course

Drawing code for drawing view

class DraggingView: UIView {

  var currVector:(origin: CGPoint, direction: Direction)?

    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
      guard currVector != nil else {
        return
      }

      let drawRect: CGRect = CGRect(x: 0, y: 0,
                                    width: 116, height: 200)

      let drawPath = UIBezierPath(roundedRect: drawRect, cornerRadius: 10.0)
      drawPath.apply(CGAffineTransform(translationX: -58, y: 0))

      var transform: CGAffineTransform?
      let pi = 3.1415927

      switch currVector!.direction {
      case .downLeft:
        transform = CGAffineTransform(rotationAngle: pi / 4.0)
      case .downRight:
        transform = CGAffineTransform(rotationAngle: -pi / 4.0)
      case .left:
        transform = CGAffineTransform(rotationAngle: pi / 2.0)
      case .right:
        transform = CGAffineTransform(rotationAngle: -pi / 2.0)
      case .up:
        transform = CGAffineTransform(rotationAngle: pi)
      case .upLeft:
        transform = CGAffineTransform(rotationAngle: 3 * pi / 4.0)
      case .upRight:
        transform = CGAffineTransform(rotationAngle: -3 * pi / 4.0)
      default:
        transform = nil
      }

      if transform != nil {
        drawPath.apply(transform!)
      }
      drawPath.apply(CGAffineTransform(translationX: currVector!.origin.x, y: currVector!.origin.y))
      UIColor.label.setStroke()

      drawPath.stroke()
    }

  public func setVector(origin: CGPoint, direction: Direction) {
    currVector = (origin, direction)
    self.setNeedsDisplay()
  }

  public func clearVector() {
    currVector = nil
  }
}
0 Answers
Related