Take pictures, use systematic, simple

This article is mainly about the rotation of the selected region

  • The rotation of the photo, using affine transformation

  • The rotation of the selected region, the point in the rotation frame, has a coordinate transformation

The origin of the coordinate system of the view, in the mobile phone UIKit frame, is the top left corner of the view

Rotate the point in the coordinate system, the general coordinate system uses the center, convenient


Take a picture, skip. Start rotating the selection area

1. Put it away

There are two views, UIImageView for putting photos, and Sketch, the drag-and-drop view on photos

Layout does not use constraints

Because as they rotate, their frames change,

Calculating the frame directly by hand is more intuitive

if let img = image{ let s = img.size.size(in: Imgview.frame. size = s imgview.center = measure.center sketch = imgView.frame // Photo View. addSubview(imgView) // On the photo, drag area view.addSubview(Sketch) //... }Copy the code

System photography, default resolution, 4:3

To simplify the calculation, here the height/width of the imageView is equal to the height/width of its image

The picture taken is large and suitable for the designated area

extension CGSize{ func size(in std: CGSize) -> CGSize{ let hRatio = height / std.height let wRatio = width / std.width let reSolution = height / width let Width: STD. Height/reSolution, height: Width: STD. Width, height: STD. Width * reSolution)} else{return s}}Copy the code

2, rotate

From figure A to figure B, it’s a dextral rotation

  • Rotate the selection area view. To simplify the calculation, rotate the frame of the selection area to fit the image you see

Swap the width and height of the selected area, that is, change the size,

To restore its original center point, center, is to update its origin

  • Rotate the four drag points on the Selection area view,

I’m going to rotate the Angle in my original frame,

The origin of the selection area view has changed, and the rotation Angle of the four drag points also needs a translation compensation

Var Angle: CGFloat = 0 @objc func rightTurn(){rotate(with:.rhs)} func rotate(with direction: RotateOpt) { let sizeOld = sketch.frame.size let originOld = sketch.frame.origin let center = sketch.center switch Direction {case. LHS: / / counterclockwise Angle - = 1 sketch. DefaultPoints. Update (clockwize: false, by: sizeOld) case. The RHS: + = 1 / / / / Angle clockwise rotate four points in the sketch. DefaultPoints. Update (clockwize: true, by: Imgview. transform = CGAffineTransform(rotationAngle: ImgSingleAngle.time * angle) sketch.frame.size = CGSize(width: sizeOld.height, height: SizeOld. Width) the sketch. Center = center let originNew = the sketch. The frame. The origin / / compensation four points the sketch again. DefaultPoints. Patch (vector: OriginNew - originOld) // Update sketch. ReloadData ()}Copy the code

The coordinates of the rotation point, calculated by the change in Angle

Mutating func update(clockwize beC: Bool, by area: CGSize){let lhsTop: CGPoint, rhsTop: CGPoint, rhsBottom: CGPoint, lhsBottom: CGPoint let center = CGPoint(x: area.width / 2, y: area.height / 2 ) if beC{ lhsTop = clockwize(rightTurn: leftTop, forCoordinate: center) // ... } else{ lhsTop = antiClockwize(leftTurn: leftTop, forCoordinate: center) // ... } leftTop = lhsTop // ... } // Rotate private func clockwize(rightTurn target: CGPoint, forCoordinate Origin: CGPoint) -> CGPoint { let dx = target.x - origin.x let dy = target.y - origin.y let radius = sqrt(dx * dx + dy * dy) let  azimuth = atan2(dy, dx) // in radians let x = origin.x - radius * sin(azimuth) let y = origin.y + radius * cos(azimuth) return CGPoint(x: x, y: y) }Copy the code

3. Enhanced rotation. In order to make better use of the mobile phone area, the picture is larger vertically and smaller horizontally

Image view, affine transform, rotate + scale

Select Area View Sketch, can’t simply swap width and height,

It’s a little bit more difficult

Select the frame of the Region View Sketch, the center point is unchanged, its size has two choices, toggle

Based on the previous step, the four coordinates of the selected Region view Sketch are calculated
  • It’s up, it’s down, it’s up, it’s down, it’s down

  • Horizontal, turn vertical, small to large, first enlarge, then use standard coordinates (vertical size, after exchange), input calculation

func rotate(with direction: RotateOpt) {guard let img = image else {return} let imgRatio = img.size. Height/img.size. Width let const = 4.0/3 print(imgRatio, const) let sizeOld = sketch.frame.size let originOld = sketch.frame.origin let center = sketch.center let bigS = img.size.size(in: measure.s) let clockwize: Bool switch direction { case .lhs: RHS: // counterclockwise Angle -= 1 clockwize = false case. RHS: // clockwise Angle += 1 clockwize = true} var ratio: CGFloat = 1 let smallS = img.size.size(by: measure.horizontal) var imgTransform = CGAffineTransform(rotationAngle: ImgSingleAngle.time * angle) if Int(angle) % 2 == 1{ ratio = smallS.width / bigS.height imgTransform = imgTransform.scaledBy(x: ratio, y: Size = smallS} else{ratio = bigs.height/smalls.width sketch. Frame. Size = bigS} // Rotate the four drag points before, To reset / / small, bigger, when need to manipulate the if Int (Angle) % 2 = = 0 {sketch. DefaultPoints. Scale (r: thewire, forS: SizeOld)} / / rotation, and translation compensation before, first into annotation, namely with the size of the sketch. DefaultPoints. Update (clockwize: clockwize, by: Imgview. transform = imgTransform sketch. Center = center let originNew = sketch. Keep up with the step as the sketch. DefaultPoints. Patch (vector: OriginNew originOld) / / four drag and drop point, belongs to the normal standard of photo / / sideways, large to small if Int (Angle) % 2 = = {sketch. DefaultPoints. 1 scale (r: Ratio, forS: sizeOld)} // Draw sketch. ReloadData ()}Copy the code

Previously, low imitation scan omnipotent King’s selection area function

github repo