|
@@ -9,7 +9,7 @@
|
|
|
class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
private let minZoomScale: CGFloat = 1.0
|
|
|
private let maxZoomScale: CGFloat = 4.0
|
|
|
- private let zoomSensitivity: CGFloat = 0.2 // 灵敏度系数 (0.1-1.0)
|
|
|
+ private let zoomSensitivity: CGFloat = 0.2 // 灵敏度系数 (0.1-1.0)
|
|
|
lazy var scrollView: UIScrollView = {
|
|
|
let sv = UIScrollView()
|
|
|
sv.minimumZoomScale = 1.0
|
|
@@ -17,7 +17,7 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
sv.showsHorizontalScrollIndicator = false
|
|
|
sv.showsVerticalScrollIndicator = false
|
|
|
sv.delegate = self
|
|
|
- sv.backgroundColor = .yellow.withAlphaComponent(0.1)
|
|
|
+ sv.backgroundColor = .clear
|
|
|
return sv
|
|
|
}()
|
|
|
|
|
@@ -32,11 +32,11 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
private let slider: UISlider = {
|
|
|
let slider = UISlider()
|
|
|
slider.minimumValue = 1
|
|
|
- slider.maximumValue = 30
|
|
|
+ slider.maximumValue = 100
|
|
|
slider.setThumbImage(UIImage.circle(diameter: 10, color: .themeColor), for: .normal)
|
|
|
slider.minimumTrackTintColor = UIColor.themeColor
|
|
|
slider.maximumTrackTintColor = .white.withAlphaComponent(0.2)
|
|
|
- slider.value = 5
|
|
|
+ slider.value = 50
|
|
|
return slider
|
|
|
}()
|
|
|
|
|
@@ -55,13 +55,13 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
return button
|
|
|
}()
|
|
|
|
|
|
- lazy var panLineLabel: UILabel = UILabel.createLabel(text: "\(brushWidth)",font: .font(size: 14),textColor: .white)
|
|
|
+ lazy var panLineLabel: UILabel = UILabel.createLabel(text: "\(Int(brushWidth))",font: .font(size: 14),textColor: .white)
|
|
|
|
|
|
|
|
|
private var lastPoint = CGPoint.zero
|
|
|
private var swiped = false
|
|
|
- private var brushWidth: CGFloat = 5.0
|
|
|
- private var brushColor: UIColor = .themeColor
|
|
|
+ private var brushWidth: CGFloat = 50.0
|
|
|
+ private var brushColor: UIColor = .themeColor.withAlphaComponent(0.6)
|
|
|
|
|
|
private var drawingHistory: [UIImage] = [UIImage()]
|
|
|
private var historyIndex: Int = 0
|
|
@@ -73,7 +73,6 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
func setUpRemoveUploadView(){
|
|
|
let spaceH = 176.0
|
|
|
uploadImageViewMaxHeight = k_ScreenHeight-spaceH-k_Height_safeAreaInsetsBottom()-k_Nav_Height
|
|
|
- uploadImageBgView.backgroundColor = .blue.withAlphaComponent(0.1)
|
|
|
uploadImageBgView.snp.makeConstraints { make in
|
|
|
make.width.equalTo(k_ScreenWidth)
|
|
|
make.height.equalTo(uploadImageViewMaxHeight)
|
|
@@ -83,19 +82,16 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
|
|
|
override func setUpStackView() {
|
|
|
setUpRemoveUploadView()
|
|
|
-
|
|
|
setupUI()
|
|
|
setupGestures()
|
|
|
setupActions()
|
|
|
+
|
|
|
+ drawingImageView.layer.addSublayer(drawingLayer)
|
|
|
}
|
|
|
|
|
|
override func updateUploadImageViewFrame() {
|
|
|
super.updateUploadImageViewFrame()
|
|
|
-
|
|
|
- historyIndex = 0
|
|
|
- drawingHistory = [UIImage()]
|
|
|
- drawingImageView.image = drawingHistory[historyIndex]
|
|
|
- updateUndoRedoButtons()
|
|
|
+ clearDrawing()
|
|
|
}
|
|
|
|
|
|
// MARK: - Setup
|
|
@@ -110,13 +106,19 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
cusStackView.addSubviewToStack(scrollView)
|
|
|
|
|
|
// 添加绘图视图
|
|
|
+
|
|
|
+ // 移除所有点击手势(较粗暴)
|
|
|
+ uploadImageView.gestureRecognizers?.forEach {
|
|
|
+ if $0 is UITapGestureRecognizer {
|
|
|
+ uploadImageView.removeGestureRecognizer($0)
|
|
|
+ }
|
|
|
+ }
|
|
|
uploadImageView.addSubview(drawingImageView)
|
|
|
drawingImageView.snp.makeConstraints { make in
|
|
|
make.edges.equalToSuperview()
|
|
|
}
|
|
|
-
|
|
|
+ cusStackView.addSpacing(length: 10)
|
|
|
//stack add
|
|
|
-
|
|
|
let toolBtnView = UIView()
|
|
|
toolBtnView.addSubview(undoButton)
|
|
|
toolBtnView.addSubview(redoButton)
|
|
@@ -124,7 +126,7 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
cusStackView.addSubviewToStack(toolBtnView)
|
|
|
|
|
|
toolBtnView.snp.makeConstraints { make in
|
|
|
- make.height.equalTo(40)
|
|
|
+ make.height.equalTo(48)
|
|
|
}
|
|
|
|
|
|
undoButton.snp.makeConstraints { make in
|
|
@@ -154,7 +156,7 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
cusStackView.addSubviewToStack(slideView)
|
|
|
|
|
|
slideView.snp.makeConstraints { make in
|
|
|
- make.height.equalTo(40)
|
|
|
+ make.height.equalTo(48)
|
|
|
}
|
|
|
|
|
|
panImageView.snp.makeConstraints { make in
|
|
@@ -176,16 +178,10 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
make.height.equalTo(24)
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- func creatToolView(){
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
private func setupGestures() {
|
|
|
// 绘图手势
|
|
|
- let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handleDrawingPan(_:)))
|
|
|
+ let panGesture = ImmediatePanGestureRecognizer(target: self, action: #selector(handleDrawingPan(_:)))
|
|
|
panGesture.minimumNumberOfTouches = 1
|
|
|
panGesture.maximumNumberOfTouches = 1
|
|
|
drawingImageView.addGestureRecognizer(panGesture)
|
|
@@ -208,59 +204,60 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
clearButton.addTarget(self, action: #selector(clearDrawing), for: .touchUpInside)
|
|
|
undoButton.addTarget(self, action: #selector(undoDrawing), for: .touchUpInside)
|
|
|
redoButton.addTarget(self, action: #selector(redoDrawing), for: .touchUpInside)
|
|
|
-// generateButton.addTarget(self, action: #selector(generateImage), for: .touchUpInside)
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ // MARK: - 绘图属性
|
|
|
+ private var currentPath: UIBezierPath!
|
|
|
+
|
|
|
+ // 历史记录相关属性
|
|
|
+ private var pathsHistory: [CAShapeLayer] = []
|
|
|
+ private var undonePaths: [CAShapeLayer] = []
|
|
|
+ private var currentIndex: Int = -1
|
|
|
+
|
|
|
+ private lazy var drawingLayer: CAShapeLayer = {
|
|
|
+ let drawingLayer = CAShapeLayer()
|
|
|
+ drawingLayer.frame = drawingImageView.bounds
|
|
|
+ drawingLayer.fillColor = UIColor.clear.cgColor
|
|
|
+ drawingLayer.lineCap = .round
|
|
|
+ drawingLayer.lineJoin = .round
|
|
|
+ drawingLayer.lineWidth = brushWidth
|
|
|
+ drawingLayer.strokeColor = brushColor.cgColor
|
|
|
+ return drawingLayer
|
|
|
+
|
|
|
+ }()
|
|
|
|
|
|
- // MARK: - Drawing Methods
|
|
|
-
|
|
|
+ // MARK: - 手势处理方法
|
|
|
@objc private func handleDrawingPan(_ gesture: UIPanGestureRecognizer) {
|
|
|
let currentPoint = gesture.location(in: drawingImageView)
|
|
|
+ drawingLayer.lineWidth = brushWidth
|
|
|
|
|
|
- if gesture.state == .began {
|
|
|
- swiped = false
|
|
|
- lastPoint = currentPoint
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if gesture.state == .changed {
|
|
|
- swiped = true
|
|
|
- drawLine(from: lastPoint, to: currentPoint)
|
|
|
- lastPoint = currentPoint
|
|
|
- }
|
|
|
-
|
|
|
- if gesture.state == .ended {
|
|
|
- if !swiped {
|
|
|
- // 绘制单点
|
|
|
- drawLine(from: lastPoint, to: lastPoint)
|
|
|
- }
|
|
|
- saveDrawingToHistory()
|
|
|
+ switch gesture.state {
|
|
|
+ case .began:
|
|
|
+ currentPath = UIBezierPath()
|
|
|
+ currentPath.lineCapStyle = .round
|
|
|
+ currentPath.lineJoinStyle = .round
|
|
|
+ currentPath.move(to: currentPoint)
|
|
|
+
|
|
|
+ case .changed:
|
|
|
+ currentPath.addLine(to: currentPoint)
|
|
|
+ drawingLayer.path = currentPath.cgPath
|
|
|
+
|
|
|
+ case .ended, .cancelled:
|
|
|
+ // 保存当前路径
|
|
|
+ let finalizedLayer = createShapeLayer(from: currentPath)
|
|
|
+ drawingImageView.layer.addSublayer(finalizedLayer)
|
|
|
+
|
|
|
+ // 添加到历史记录
|
|
|
+ addToHistory(layer: finalizedLayer)
|
|
|
+
|
|
|
+ // 重置当前绘图
|
|
|
+ drawingLayer.path = nil
|
|
|
+ currentPath = nil
|
|
|
+
|
|
|
+ default: break
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- private func drawLine(from fromPoint: CGPoint, to toPoint: CGPoint) {
|
|
|
- UIGraphicsBeginImageContextWithOptions(drawingImageView.bounds.size, false, 0.0)
|
|
|
-
|
|
|
- guard let context = UIGraphicsGetCurrentContext() else { return }
|
|
|
-
|
|
|
- // 绘制现有图像
|
|
|
- drawingImageView.image?.draw(in: drawingImageView.bounds)
|
|
|
-
|
|
|
- // 绘制线条
|
|
|
- context.move(to: fromPoint)
|
|
|
- context.addLine(to: toPoint)
|
|
|
- context.setLineCap(.round)
|
|
|
- context.setLineWidth(brushWidth)// / scrollView.zoomScale) // 根据缩放比例调整画笔粗细
|
|
|
- context.setStrokeColor(brushColor.cgColor)
|
|
|
- context.setBlendMode(.normal)
|
|
|
- context.strokePath()
|
|
|
-
|
|
|
- // 设置新图像
|
|
|
- drawingImageView.image = UIGraphicsGetImageFromCurrentImageContext()
|
|
|
- UIGraphicsEndImageContext()
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
// MARK: - History Management
|
|
|
|
|
|
private func saveDrawingToHistory() {
|
|
@@ -274,10 +271,21 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
historyIndex = drawingHistory.count - 1
|
|
|
updateUndoRedoButtons()
|
|
|
}
|
|
|
-
|
|
|
+ // MARK: - 辅助方法
|
|
|
+ private func createShapeLayer(from path: UIBezierPath) -> CAShapeLayer {
|
|
|
+ let layer = CAShapeLayer()
|
|
|
+ layer.path = path.cgPath
|
|
|
+ layer.frame = drawingLayer.frame
|
|
|
+ layer.fillColor = drawingLayer.fillColor
|
|
|
+ layer.lineCap = drawingLayer.lineCap
|
|
|
+ layer.lineJoin = drawingLayer.lineJoin
|
|
|
+ layer.lineWidth = drawingLayer.lineWidth
|
|
|
+ layer.strokeColor = drawingLayer.strokeColor
|
|
|
+ return layer
|
|
|
+ }
|
|
|
private func updateUndoRedoButtons() {
|
|
|
- undoButton.isEnabled = historyIndex > 0
|
|
|
- redoButton.isEnabled = historyIndex < drawingHistory.count - 1
|
|
|
+ undoButton.isEnabled = currentIndex >= 0
|
|
|
+ redoButton.isEnabled = !undonePaths.isEmpty
|
|
|
}
|
|
|
|
|
|
// MARK: - Actions
|
|
@@ -285,37 +293,74 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
@objc private func brushSizeChanged(_ sender: UISlider) {
|
|
|
brushWidth = CGFloat(sender.value)
|
|
|
// panLineLabel.text = "\(brushWidth)"
|
|
|
- panLineLabel.text = String(format: "%.1f", brushWidth)
|
|
|
+ panLineLabel.text = "\(Int(brushWidth))"
|
|
|
+ drawingLayer.lineWidth = brushWidth
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // MARK: - 历史记录操作方法
|
|
|
+ private func addToHistory(layer: CAShapeLayer) {
|
|
|
+ // 如果当前不是最新状态,移除后面的记录
|
|
|
+ if currentIndex < pathsHistory.count - 1 {
|
|
|
+ pathsHistory.removeSubrange(currentIndex+1..<pathsHistory.count)
|
|
|
+ }
|
|
|
+
|
|
|
+ pathsHistory.append(layer)
|
|
|
+ currentIndex = pathsHistory.count - 1
|
|
|
+ undonePaths.removeAll()
|
|
|
+ updateUndoRedoButtons()
|
|
|
}
|
|
|
|
|
|
@objc private func clearDrawing() {
|
|
|
- drawingImageView.image = nil
|
|
|
- saveDrawingToHistory()
|
|
|
+ // 移除所有绘图图层
|
|
|
+ pathsHistory.forEach { $0.removeFromSuperlayer() }
|
|
|
+ undonePaths.forEach { $0.removeFromSuperlayer() }
|
|
|
+
|
|
|
+ // 重置历史记录
|
|
|
+ pathsHistory.removeAll()
|
|
|
+ undonePaths.removeAll()
|
|
|
+ currentIndex = -1
|
|
|
+
|
|
|
+ // 重置当前绘图
|
|
|
+ drawingLayer.path = nil
|
|
|
+ currentPath = nil
|
|
|
+
|
|
|
+ updateUndoRedoButtons()
|
|
|
}
|
|
|
|
|
|
@objc private func undoDrawing() {
|
|
|
- guard historyIndex > 0 else { return }
|
|
|
- historyIndex -= 1
|
|
|
- drawingImageView.image = drawingHistory[historyIndex]
|
|
|
+ guard currentIndex >= 0 else { return }
|
|
|
+
|
|
|
+ // 移除当前图层
|
|
|
+ let layerToRemove = pathsHistory[currentIndex]
|
|
|
+ layerToRemove.removeFromSuperlayer()
|
|
|
+
|
|
|
+ // 保存到重做栈
|
|
|
+ undonePaths.append(layerToRemove)
|
|
|
+
|
|
|
+ currentIndex -= 1
|
|
|
updateUndoRedoButtons()
|
|
|
}
|
|
|
|
|
|
@objc private func redoDrawing() {
|
|
|
- guard historyIndex < drawingHistory.count - 1 else { return }
|
|
|
- historyIndex += 1
|
|
|
- drawingImageView.image = drawingHistory[historyIndex]
|
|
|
+ guard !undonePaths.isEmpty else { return }
|
|
|
+
|
|
|
+ currentIndex += 1
|
|
|
+
|
|
|
+ // 从重做栈恢复
|
|
|
+ let layerToRestore = undonePaths.removeLast()
|
|
|
+ pathsHistory.insert(layerToRestore, at: currentIndex)
|
|
|
+ drawingImageView.layer.addSublayer(layerToRestore)
|
|
|
+
|
|
|
updateUndoRedoButtons()
|
|
|
}
|
|
|
|
|
|
|
|
|
override func generateImage() {
|
|
|
-
|
|
|
if kJudgeVip(externalBool: true, vc: self){ return } //判断 vip
|
|
|
guard let upLoadImage = upLoadImage else { return }
|
|
|
guard let maskImage = getBlackWhiteMaskImage() else { return }
|
|
|
|
|
|
-
|
|
|
-
|
|
|
let generatorModel = TSAIListPhotoGeneratorModel(upLoadImage: upLoadImage, generatorStyle: generatorStyle,additionalPrompt: additionalPrompt)
|
|
|
generatorModel.upLoadImages = [upLoadImage,maskImage]
|
|
|
|
|
@@ -330,11 +375,17 @@ class TSAIRemovePhotlVC: TSAIUploadPhotoVC {
|
|
|
}
|
|
|
|
|
|
}
|
|
|
-
|
|
|
+// 自定义立即响应的手势识别器
|
|
|
+class ImmediatePanGestureRecognizer: UIPanGestureRecognizer {
|
|
|
+ override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
|
|
+ super.touchesBegan(touches, with: event)
|
|
|
+ self.state = .began
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
extension TSAIRemovePhotlVC {
|
|
|
|
|
|
- func getBlackWhiteMaskImage() -> UIImage? {
|
|
|
+ func getBlackWhiteMaskImage1() -> UIImage? {
|
|
|
// 确保有原始图片
|
|
|
guard let originalImage = uploadImageView.image else {
|
|
|
print("没有可处理的图片")
|
|
@@ -373,12 +424,114 @@ extension TSAIRemovePhotlVC {
|
|
|
print("无法生成处理后的图像")
|
|
|
return nil
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return processedImage
|
|
|
-// UIImageWriteToSavedPhotosAlbum(processedImage, nil, nil, nil)
|
|
|
-// let alert = UIAlertController(title: "Image Generated", message: "The combined image has been saved to your photos.", preferredStyle: .alert)
|
|
|
-// alert.addAction(UIAlertAction(title: "OK", style: .default))
|
|
|
-// present(alert, animated: true)
|
|
|
+ // UIImageWriteToSavedPhotosAlbum(processedImage, nil, nil, nil)
|
|
|
+ // let alert = UIAlertController(title: "Image Generated", message: "The combined image has been saved to your photos.", preferredStyle: .alert)
|
|
|
+ // alert.addAction(UIAlertAction(title: "OK", style: .default))
|
|
|
+ // present(alert, animated: true)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ func getBlackWhiteMaskImage2() -> UIImage? {
|
|
|
+ UIGraphicsBeginImageContextWithOptions(drawingImageView.bounds.size, false, 1.0)
|
|
|
+ defer { UIGraphicsEndImageContext() }
|
|
|
+
|
|
|
+ guard let context = UIGraphicsGetCurrentContext() else { return nil}
|
|
|
+
|
|
|
+ for layer in pathsHistory {
|
|
|
+ if let path = layer.path {
|
|
|
+ context.addPath(path)
|
|
|
+ context.setLineWidth(layer.lineWidth)
|
|
|
+ context.setLineCap(CGLineCap(layer.lineCap))
|
|
|
+ context.setLineJoin(CGLineJoin(layer.lineJoin))
|
|
|
+ context.setStrokeColor(layer.strokeColor ?? UIColor.black.cgColor)
|
|
|
+ context.strokePath()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if let image = UIGraphicsGetImageFromCurrentImageContext() {
|
|
|
+ UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
|
|
|
+ return image
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ func getBlackWhiteMaskImage() -> UIImage? {
|
|
|
+ // 1. 安全检查
|
|
|
+ guard let originalImage = uploadImageView.image,
|
|
|
+ originalImage.size.width > 0,
|
|
|
+ originalImage.size.height > 0,
|
|
|
+ drawingImageView.bounds.size.width > 0,
|
|
|
+ drawingImageView.bounds.size.height > 0 else {
|
|
|
+ print("无效的图片或视图尺寸")
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 计算缩放比例
|
|
|
+ let scaleX = originalImage.size.width / drawingImageView.bounds.width
|
|
|
+ let scaleY = originalImage.size.height / drawingImageView.bounds.height
|
|
|
+
|
|
|
+ // 3. 创建与原始图片相同尺寸的上下文
|
|
|
+ UIGraphicsBeginImageContextWithOptions(originalImage.size, false, 1.0)
|
|
|
+ defer { UIGraphicsEndImageContext() }
|
|
|
+
|
|
|
+ guard let context = UIGraphicsGetCurrentContext() else { return nil }
|
|
|
+
|
|
|
+ // 4. 绘制全黑背景
|
|
|
+ UIColor.black.setFill()
|
|
|
+ context.fill(CGRect(origin: .zero, size: originalImage.size))
|
|
|
+
|
|
|
+ // 5. 应用缩放变换
|
|
|
+ context.saveGState()
|
|
|
+ context.scaleBy(x: scaleX, y: scaleY)
|
|
|
+
|
|
|
+ // 6. 绘制所有路径(转换为白色)
|
|
|
+ UIColor.white.setStroke()
|
|
|
+ for layer in pathsHistory {
|
|
|
+ if let path = layer.path {
|
|
|
+ context.addPath(path)
|
|
|
+ context.setLineWidth(layer.lineWidth)
|
|
|
+ context.setLineCap(CGLineCap(layer.lineCap))
|
|
|
+ context.setLineJoin(CGLineJoin(layer.lineJoin))
|
|
|
+ context.strokePath()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ context.restoreGState()
|
|
|
+
|
|
|
+ // 7. 生成并返回图像
|
|
|
+ if let image = UIGraphicsGetImageFromCurrentImageContext() {
|
|
|
+ UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
|
|
|
+ return image
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+extension CGLineCap {
|
|
|
+ init(_ shapeLayerLineCap: CAShapeLayerLineCap) {
|
|
|
+ switch shapeLayerLineCap {
|
|
|
+ case .round: self = .round
|
|
|
+ case .butt: self = .butt
|
|
|
+ case .square: self = .square
|
|
|
+ default: self = .round
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension CGLineJoin {
|
|
|
+ init(_ shapeLayerLineJoin: CAShapeLayerLineJoin) {
|
|
|
+ switch shapeLayerLineJoin {
|
|
|
+ case .round: self = .round
|
|
|
+ case .bevel: self = .bevel
|
|
|
+ case .miter: self = .miter
|
|
|
+ default: self = .round
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|