拍照,用零碎的,简略
本文次要是讲,抉择区域的旋转
- 照片的旋转,用仿射变换
- 抉择区域的旋转,就是旋转坐标系中的点,有一个坐标变换
手机 UIKit 框架下, view 的坐标系原点,是 view 的左上角
旋转坐标系中的点,个别坐标系用核心,不便
拍照,略。开始旋转抉择区域
1, 摆放好
下面有两个视图,放照片的 UIImageView, 和照片上拖拽视图 sketch
布局没有采纳,束缚
因为旋转的时候,他们的 frame 变来变去,
间接手动计算 frame, 更加的直观
if let img = image{ let s = img.size.size(in: measure.s) imgView.frame.size = s imgView.center = measure.center sketch.frame = imgView.frame // 照片 view.addSubview(imgView) // 照片上的,拖拽区域 view.addSubview(sketch) // ... }
零碎拍照,默认分辨率, 4 : 3
为了简化计算,这里 imageView 的高/宽 = 其 image 的高/宽
拍照的图片,很大,适合的放在指定的小区域中
extension CGSize{ func size(in std: CGSize) -> CGSize{ let hRatio = height / std.height let wRatio = width / std.width let reSolution = height / width let s: CGSize if hRatio > wRatio{ // 图片更窄 s = CGSize(width: std.height / reSolution, height: std.height) } else{ // 图片更宽 s = CGSize(width: std.width, height: std.width * reSolution) } return s }}
2, 旋转
从图 a 到图 b , 是一个右旋
- 旋转抉择区域视图,为了简化计算,旋转抉择区域的 frame 与看到的图片贴合
替换抉择区域的宽和高,就是批改尺寸 size,
复原其原来的中心点 center , 就是更新其原点
- 旋转抉择区域视图,上的四个拖拽点,
先在原来的坐标系中,旋转角度,
抉择区域视图的原点变了,四个拖拽点旋转角度后,还需一个平移的弥补
// 记录以后的角度 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: // 逆时针 angle -= 1 sketch.defaultPoints.update(clockwize: false, by: sizeOld) case .rhs: // 顺时针 angle += 1 // 旋转四个点 sketch.defaultPoints.update(clockwize: true, by: sizeOld) } // 图片视图,间接仿射变换 imgView.transform = CGAffineTransform(rotationAngle: ImgSingleAngle.time * angle) sketch.frame.size = CGSize(width: sizeOld.height, height: sizeOld.width) sketch.center = center let originNew = sketch.frame.origin // 再弥补四个点 sketch.defaultPoints.patch(vector: originNew - originOld) // 更新绘制 sketch.reloadData() }
旋转点的坐标,通过角度的变动,计算
// 拿 size, 去算中心点 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 // ... } // 顺时针旋转 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) }
3, 旋转增强,为了更好的利用手机区域,图片竖着更大,横着稍小一些
图片视图,仿射变换,是旋转 rotate + 缩放 scale
抉择区域视图 sketch, 不能简略的替换宽和高,
稍麻烦了一些
抉择区域视图 sketch 的 frame, 中心点不变,他的 size 有两个抉择,切换就好了
在上一步的根底上,计算抉择区域视图 sketch 的四个坐标
- 竖着的,转横着的,大变小,上一步的坐标,放大就行
- 横着的,转竖着的,小变大,先放大,再用规范坐标 ( 竖着的尺寸,替换后 ),投入计算
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: // 逆时针 angle -= 1 clockwize = false case .rhs: // 顺时针 angle += 1 clockwize = true // 下一步,对 UI 的批改,影响上一步 } 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: ratio) sketch.frame.size = smallS } else{ ratio = bigS.height / smallS.width sketch.frame.size = bigS } // 旋转四个拖拽的点之前,先复位 // 小的,变大的,的时候,须要操作 if Int(angle) % 2 == 0{ sketch.defaultPoints.scale(r: ratio, forS: sizeOld) } // 旋转,和平移弥补之前,先化为标注的,也就是竖着的尺寸 sketch.defaultPoints.update(clockwize: clockwize, by: sizeOld) imgView.transform = imgTransform sketch.center = center let originNew = sketch.frame.origin // 弥补,跟上一步一样 sketch.defaultPoints.patch(vector: originNew - originOld) // 四个拖拽的点, 属于失常规范的图片 // 横着摆放,大变小 if Int(angle) % 2 == 1{ sketch.defaultPoints.scale(r: ratio, forS: sizeOld) } // 绘制 sketch.reloadData() }