You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift需求:实现方法获取圆角矩形/圆角正方形周边n个带角度的点

Swift实现圆角矩形周边等角度分布点的坐标与角度计算

核心思路

以圆角矩形的中心为极坐标原点,将0~2π的圆周均分为numberOfPoints个角度,对每个角度计算射线与圆角矩形边界的交点,同时保留该角度值。这种方法能近似实现类似Apple Watch界面的等角度分布效果,且逻辑简洁易实现。

完整实现代码

import CoreGraphics
import SwiftUI // 若不需要SwiftUI的Angle,可替换为自定义弧度/角度类型

func getCoordinates(of numberOfPoints: Int, in roundedRect: CGRect, with cornerRadius: CGFloat) -> [(CGPoint, Angle)] {
    guard numberOfPoints > 0 else { return [] }
    
    let center = CGPoint(x: roundedRect.midX, y: roundedRect.midY)
    let halfWidth = roundedRect.width / 2 - cornerRadius
    let halfHeight = roundedRect.height / 2 - cornerRadius
    let twoPi = CGFloat.pi * 2
    
    var result = [(CGPoint, Angle)]()
    
    for i in 0..<numberOfPoints {
        let radians = twoPi * CGFloat(i) / CGFloat(numberOfPoints)
        let angle = Angle(radians: radians)
        
        let dx = cos(radians)
        let dy = sin(radians)
        
        var intersectionPoint: CGPoint
        
        // 判断射线更靠近水平边还是垂直边
        let horizontalRatio = abs(dx / halfWidth)
        let verticalRatio = abs(dy / halfHeight)
        
        if horizontalRatio >= verticalRatio {
            // 射线指向左右方向区域
            let signX = dx >= 0 ? 1.0 : -1.0
            let x = center.x + signX * halfWidth
            let y = center.y + (x - center.x) * (dy / dx)
            
            if y >= center.y - halfHeight && y <= center.y + halfHeight {
                // 交点在直边上
                intersectionPoint = CGPoint(x: x, y: y)
            } else {
                // 交点在圆角上,确定对应角的圆心
                let signY = y >= center.y ? 1.0 : -1.0
                let cornerCenter = CGPoint(x: center.x + signX * halfWidth, y: center.y + signY * halfHeight)
                
                // 计算从圆角圆心指向射线方向的单位向量
                let direction = CGPoint(x: dx, y: dy).normalized()
                intersectionPoint = CGPoint(
                    x: cornerCenter.x + direction.x * cornerRadius,
                    y: cornerCenter.y + direction.y * cornerRadius
                )
            }
        } else {
            // 射线指向上下方向区域
            let signY = dy >= 0 ? 1.0 : -1.0
            let y = center.y + signY * halfHeight
            let x = center.x + (y - center.y) * (dx / dy)
            
            if x >= center.x - halfWidth && x <= center.x + halfWidth {
                // 交点在直边上
                intersectionPoint = CGPoint(x: x, y: y)
            } else {
                // 交点在圆角上,确定对应角的圆心
                let signX = x >= center.x ? 1.0 : -1.0
                let cornerCenter = CGPoint(x: center.x + signX * halfWidth, y: center.y + signY * halfHeight)
                
                // 计算从圆角圆心指向射线方向的单位向量
                let direction = CGPoint(x: dx, y: dy).normalized()
                intersectionPoint = CGPoint(
                    x: cornerCenter.x + direction.x * cornerRadius,
                    y: cornerCenter.y + direction.y * cornerRadius
                )
            }
        }
        
        result.append((intersectionPoint, angle))
    }
    
    return result
}

// 辅助扩展:将CGPoint转换为单位向量
extension CGPoint {
    func normalized() -> CGPoint {
        let length = sqrt(x*x + y*y)
        guard length != 0 else { return .zero }
        return CGPoint(x: x/length, y: y/length)
    }
}

关键代码说明

  • 边界判断:通过比较水平/垂直方向的比率,确定射线先接触直边还是圆角区域
  • 直边交点计算:根据射线方向计算与矩形直边的交点,判断是否在合法范围内
  • 圆角交点计算:若射线指向圆角区域,先确定对应圆角的圆心,再沿射线方向取半径长度的点作为交点
  • 角度保留:直接使用均分后的弧度值创建Angle,与返回的坐标一一对应

内容的提问来源于stack exchange,提问作者ixany

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 14:41:04