【问题标题】:How do I draw irregular polygons with a mix of rounded and sharp corners?如何绘制混合了圆角和尖角的不规则多边形?
【发布时间】:2021-07-07 03:19:21
【问题描述】:

我希望能够绘制混合了锐角和钝角的不规则多边形,其中一些角是圆的,而另一些则不是。

假设我有一个这样的多边形:

我想把它的所有角都画成圆角:

或每隔一个圆角:

我该怎么做?

David Rönnqvist 写了一篇出色的 very informative article 描述了绘制圆角背后的数学,但它相当复杂,如果您对三角学和几何学不满意,会导致您的大脑爆炸。

在同一个线程Anjali posted an answer 中,它展示了如何使用CGMutablePath 方法addArc(tangent1End:tangent2End:radius:transform:) 比David 的数学密集型方法更简单地绘制一个带圆角的三角形

但是,它并没有告诉我如何处理具有可变数量顶点的多边形,或者如何混合圆角和尖角。我该怎么做?

【问题讨论】:

    标签: ios core-animation polygon rounded-corners


    【解决方案1】:

    在不让自己发疯的情况下做到这一点的关键是方法addArc(tangent1End:tangent2End:radius:transform:)。这为现有的CGMutablePath 添加了一条弧线。该方法从路径的当前点开始。您指定一个点 tangent1End,这是您要为其绘制圆角的顶点,以及另一个点 tangent2End,它是您 pologon 中的下一个顶点。

    要绘制具有可变数量顶点的多边形,我们使用点数组。

    为了使所有角都变圆,您必须将路径的起点设置为多边形直线段上某处的某个点,然后在最后返回该点。计算2个点的中点很容易:

    let midpoint = CGPoint(x: (point1.x + point2.x)/2, y: (point1.y + point2.y)/2 )
    

    所以我们将路径的当前点移动到顶点数组中第一个点和最后一个点之间的中点作为起点:

    let midpoint = CGPoint(x: (first.point.x + last.point.x) / 2, y: (first.point.y + last.point.y) / 2 )
    path.move(to: midpoint)
    

    然后,对于多边形中的每个顶点,我们要么只画一条线到那个点(用于尖角),要么使用美妙、易于使用的addArc(tangent1End:tangent2End:radius:transform:) 来绘制一条线段,以圆弧,围绕那个顶点。 我将创建 UIView 的子类 RoundedCornerPolygonView。

    class RoundedCornerPolygonView: UIView {
    }
    

    它将自己设置为使其内容层为 CAShapeLayer。为此,您只需将类 var layerClass 添加到您的自定义 UIView 子类:

    // This class var causes the view's base layer to be a CAShapeLayer.
    class override var layerClass: AnyClass {
        return CAShapeLayer.self
    }
    

    为了跟踪点数组,以及哪些点应该是圆的,哪些应该是平滑的,我们将定义一个结构PolygonPoint

    struct PolygonPoint {
        let point: CGPoint
        let isRounded: Bool
    }
    

    我们会给我们的班级一个PolygonPoints 的数组:

    public var points = [PolygonPoint]()
    

    并添加一个 didSet 方法来更新我们的形状层的路径,如果它改变了:

    public var points = [PolygonPoint]() {
        didSet {
            guard points.count >= 3 else {
                print("Polygons must have at least 3 sides.")
                return
            }
            buildPolygon()
        }
    }
    

    这是从上面的PolygonPoints 数组构建多边形路径的代码:

    /// Rebuild our polygon's path and install it into our shape layer.
    private func buildPolygon() {
        guard points.count >= 3 else { return }
        drawPoints() // Draw each vertex into another layer if requested.
        let first = points.first!
        let last = points.last!
    
        let path = CGMutablePath()
    
        // Start at the midpoint between the first and last vertex in our polygon
        // (Since that will always be in the middle of a straight line segment.)
        let midpoint = CGPoint(x: (first.point.x + last.point.x) / 2, y: (first.point.y + last.point.y) / 2 )
        path.move(to: midpoint)
    
        //Loop through the points in our polygon.
        for (index, point) in points.enumerated() {
            // If this vertex is not rounded, just draw a line to it.
            if !point.isRounded {
                path.addLine(to: point.point)
            } else {
                //Draw an arc from the previous vertex (the current point), around this vertex, and pointing to the next vertex.
                let nextIndex = (index+1) % points.count
                let nextPoint = points[nextIndex]
                path.addArc(tangent1End: point.point, tangent2End: nextPoint.point, radius: cornerRadius)
            }
        }
    
        // Close the path by drawing a line from the last vertex/corner to the midpoint between the last and first point
        path.addLine(to: midpoint)
    
        // install the path into our (shape) layer
        let layer = self.layer as! CAShapeLayer
        layer.path = path
    }
    

    我在 Github 上创建了一个示例项目,它实现了上面定义的 RoundedCornerPolygonView 类,并允许您在运行时选择哪些角应该是圆角或平滑的。

    该项目名为“RoundedCornerPolygon”。 (链接)

    它的视图控制器类中也有代码,该代码从顶点数组 (CGPoints) 开始。它使用顶点数组中每个顶点的开关以及该顶点的标签来填充垂直堆栈视图。然后它构建一个PolygonPoints 数组并将其安装到RoundedCornerPolygonView

    如果用户切换任何开关,它会重建PolygonPoints 的数组并将它们传递给RoundedCornerPolygonView,后者会重新绘制自身。 屏幕如下所示:

    【讨论】:

    • @DavidRönnqvist 这是绘制圆角多边形的另一种极端方法:“让 CGPath 进行绘制!”我在圆角三角形上参考了您的答案,但是此代码也处理混合了凸角和凹角的多边形,并且不使用一点三角。 (我使用的 CGPath 函数为我处理所有这些。)
    猜你喜欢
    • 1970-01-01
    • 2015-01-08
    • 2021-12-13
    • 2014-12-10
    • 2011-12-03
    • 1970-01-01
    • 1970-01-01
    • 2014-05-25
    • 2017-11-17
    相关资源
    最近更新 更多