swift - 在315°圆弧上绘制圆角

标签 swift core-graphics uibezierpath

我画的弧是270度,两端都有圆锥形。这是很好的工作,但现在我想改变我的拱315°(-45°),但我的角计算不会工作。
我试过用不同的方法来计算,但似乎找不到当起点和终点不是垂直的或水平的时,为圆弧添加圆角的通用函数的公式。
这是我的操场守则:

import UIKit
import PlaygroundSupport

class ArcView: UIView {

  private var strokeWidth: CGFloat {
    return CGFloat(min(self.bounds.width, self.bounds.height) * 0.25)
  }
  private let cornerRadius: CGFloat = 10

  override open func draw(_ rect: CGRect) {
    super.draw(rect)
    backgroundColor = UIColor.white

    drawNormalCircle()
  }

  func drawNormalCircle() {
    let strokeWidth = CGFloat(min(self.bounds.width, self.bounds.height) * 0.25)
    let innerRadius = (min(self.bounds.width, self.bounds.height) - strokeWidth*2) / 2.0
    let outerRadius = (min(self.bounds.width, self.bounds.height)) / 2.0

    var endAngle: CGFloat = 270.0
    let bezierPath = UIBezierPath(arcCenter: self.center, radius: outerRadius, startAngle: 0, endAngle: endAngle * .pi / 180, clockwise: true)

    var point = bezierPath.currentPoint
    point.y += cornerRadius
    let arc = UIBezierPath(arcCenter: point, radius: cornerRadius, startAngle: 180 * .pi / 180, endAngle: 270 * .pi / 180, clockwise: true)
    arc.apply(CGAffineTransform(rotationAngle: (360 - endAngle) * .pi / 180))

    var firstCenter = bezierPath.currentPoint
    firstCenter.y += cornerRadius

    bezierPath.addArc(withCenter: firstCenter, radius: cornerRadius , startAngle: 270 * .pi / 180 , endAngle: 0, clockwise: true)
    bezierPath.addLine(to: CGPoint(x: bezierPath.currentPoint.x, y: strokeWidth - cornerRadius))

    var secondCenter = bezierPath.currentPoint
    secondCenter.x -= cornerRadius
    bezierPath.addArc(withCenter: secondCenter, radius: cornerRadius , startAngle: 0, endAngle: 90 * .pi / 180, clockwise: true)
    bezierPath.addArc(withCenter: self.center, radius: innerRadius, startAngle: 270 * .pi / 180, endAngle: 0, clockwise: false)

    var thirdCenter = bezierPath.currentPoint
    thirdCenter.x += cornerRadius
    bezierPath.addArc(withCenter: thirdCenter, radius: cornerRadius , startAngle: 180 * .pi / 180, endAngle: 270 * .pi / 180, clockwise: true)

    bezierPath.addLine(to: CGPoint(x: bezierPath.currentPoint.x + strokeWidth - (cornerRadius * 2), y: bezierPath.currentPoint.y))

    var fourthCenter = bezierPath.currentPoint
    fourthCenter.y += cornerRadius
    bezierPath.addArc(withCenter: fourthCenter, radius: cornerRadius , startAngle: 270 * .pi / 180, endAngle: 0, clockwise: true)

    bezierPath.close()

    let backgroundLayer = CAShapeLayer()
    backgroundLayer.path = bezierPath.cgPath
    backgroundLayer.strokeColor = UIColor.red.cgColor
    backgroundLayer.lineWidth = 2
    backgroundLayer.fillColor = UIColor.lightGray.cgColor

    self.layer.addSublayer(backgroundLayer)
  }
}

let arcView = ArcView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
PlaygroundPage.current.liveView = arcView

对于我来说,问题是当角点不是给定的x角半径,或者y+角半径(在完全水平或垂直的情况下)时,如何计算角点的弧中心。当弧度是315度时,我怎么能有圆角呢?

最佳答案

这是我的解决办法。
只是简单的三角学

/// Create a path made with 6 small subpaths
///
/// - Parameters:
///   - startAngle: the start angle of the path in cartesian plane angles system
///   - endAngle: the end angle of the path in cartesian plane angles system
///   - outerRadius: the radius of the outer circle in % relative to the size of the view that holds it
///   - innerRadius: the radius of the inner circle in % relative to the size of the view that holds it
///   - cornerRadius: the corner radius of the edges
///
/// - Returns: the path itself
func createPath(from startAngle: Double, to endAngle: Double,
                outerRadius:CGFloat, innerRadius:CGFloat,
                cornerRadius: CGFloat) -> UIBezierPath {

    let path = UIBezierPath()
    let maxDim = min(view.frame.width, view.frame.height)
    let oRadius: CGFloat = maxDim/2 * outerRadius
    let iRadius: CGFloat = maxDim/2 * innerRadius
    let center = CGPoint.init(x: view.frame.width/2, y: view.frame.height/2)

    let startAngle = deg2rad(360.0 - startAngle)
    let endAngle = deg2rad(360.0 - endAngle)

    // Outer Finish Center point
    let ofcX = center.x + (oRadius - cornerRadius) * CGFloat(cos(endAngle - deg2rad(360)))
    let ofcY = center.y + (oRadius - cornerRadius) * CGFloat(sin(endAngle - deg2rad(360)))

    // Inner Finish Center point
    let ifcX = center.x + (iRadius + cornerRadius) * CGFloat(cos(endAngle - deg2rad(360)))
    let ifcY = center.y + (iRadius + cornerRadius) * CGFloat(sin(endAngle - deg2rad(360)))

    // Inner Starting Center point
    let iscX = center.x + (iRadius + cornerRadius) * CGFloat(cos(startAngle - deg2rad(360)))
    let iscY = center.y + (iRadius + cornerRadius) * CGFloat(sin(startAngle - deg2rad(360)))

    // Outer Starting Center point
    let oscX = center.x + (oRadius - cornerRadius) * CGFloat(cos(startAngle - deg2rad(360)))
    let oscY = center.y + (oRadius - cornerRadius) * CGFloat(sin(startAngle - deg2rad(360)))


    // Outer arch
    path.addArc(withCenter: center, radius: oRadius,
                startAngle: startAngle, endAngle: endAngle,
                clockwise: true)

    // Rounded outer finish
    path.addArc(withCenter: CGPoint(x: ofcX, y: ofcY), radius: cornerRadius,
                startAngle: endAngle, endAngle:endAngle +  deg2rad(90),
                clockwise: true)

    // Rounded inner finish
    path.addArc(withCenter: CGPoint(x: ifcX, y: ifcY), radius: cornerRadius,
                startAngle: endAngle +  deg2rad(90), endAngle: endAngle +  deg2rad(180),
                clockwise: true)

    // Inner arch
    path.addArc(withCenter: center, radius: iRadius,
                startAngle: endAngle, endAngle: startAngle,
                clockwise: false)

    // Rounded inner start
    path.addArc(withCenter:  CGPoint(x: iscX, y: iscY), radius: cornerRadius,
                startAngle:  startAngle + deg2rad(180), endAngle:  startAngle + deg2rad(270),
                clockwise: true)

    // Rounded outer start
    path.addArc(withCenter:  CGPoint(x: oscX, y: oscY), radius: cornerRadius,
                startAngle:  startAngle + deg2rad(270), endAngle:  startAngle,
                clockwise: true)

    return path
}

func deg2rad(_ number: Double) -> CGFloat {
    return CGFloat(number * .pi / 180)
}

用法:
 @IBOutlet weak var mainView: UIView!

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    let borderLayer = CAShapeLayer()
    borderLayer.path = createPath(from: 30, to: 120, outerRadius: 0.9, innerRadius: 0.3, cornerRadius: 5).cgPath
    borderLayer.strokeColor = UIColor.orange.cgColor
    borderLayer.fillColor = UIColor.orange.cgColor
    borderLayer.lineWidth = 0.0
    mainView.layer.addSublayer(borderLayer)
}

enter image description here

关于swift - 在315°圆弧上绘制圆角,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57912571/

相关文章:

ios - UIBezierPath 添加了产生幻影三角形的弧段

iphone - 如何模糊除 2 个节点之外的所有内容。 Spritekit( swift )

ios - didReceiveLocalNotification 总是在应用程序启动时触发

swift - 大中央调度

ios - 画一个简单的圆uiimage

ios - UIBezierPath 和 CAShapeLayer

ios - 用图案图像填充多个 UIBezierPath

ios - 以编程方式向 uicollectionview 添加约束 Swift

ios - 将 CGPathRef 转换为 CGMutablePathRef

ios - 在 iOS 上实现体积图