SwiftUI 中判断 Angle 角度区间是否重叠的实现问题
实现方案
思路说明
- 第一步:角度归一化:将所有输入的
Angle统一转换为[0, 2π)区间内的弧度值,处理负值、超过360度的异常输入 - 第二步:边界处理:如果任意一个区间的min和max归一化后值相等,说明该区间是完整360度圆环,直接返回重叠
- 第三步:区间包含判断:写辅助逻辑判断单个角度是否落在环形区间内,环形区间分跨0点(min > max)和不跨0点(min < max)两种情况处理
- 第四步:重叠判断:只要两个区间的任意一个端点落在对方区间内,即可判定为重叠
完整代码
import SwiftUI // Angle类型定义在SwiftUI中,按需导入 func areRangesOverlapping(min1: Angle, max1: Angle, min2: Angle, max2: Angle) -> Bool { // 角度归一化到 [0, 2π) 区间 func normalizedRadians(for angle: Angle) -> Double { let twoPi = Double.pi * 2 let rad = angle.radians.truncatingRemainder(dividingBy: twoPi) return rad < 0 ? rad + twoPi : rad } // 判断单个角度是否落在指定环形区间内 func isAngle(_ angle: Double, inCyclicRange min: Double, max: Double) -> Bool { if min <= max { return (min...max).contains(angle) } else { return angle >= min || angle <= max } } let nm1 = normalizedRadians(for: min1) let nM1 = normalizedRadians(for: max1) let nm2 = normalizedRadians(for: min2) let nM2 = normalizedRadians(for: max2) // 边界情况:任意区间为完整圆环,必然重叠 if nm1 == nM1 || nm2 == nM2 { return true } // 只要任意一端点落在对方区间内即重叠 return isAngle(nm2, inCyclicRange: nm1, max: nM1) || isAngle(nM2, inCyclicRange: nm1, max: nM1) || isAngle(nm1, inCyclicRange: nm2, max: nM2) || isAngle(nM1, inCyclicRange: nm2, max: nM2) }
边界调整说明
如果不需要将端点刚好接触的情况判定为重叠,只需要把闭区间判断调整为开区间即可:
// 调整后不判定端点接触为重叠 func isAngle(_ angle: Double, inCyclicRange min: Double, max: Double) -> Bool { if min <= max { return angle > min && angle < max } else { return angle > min || angle < max } }
测试用例示例
- 测试1:
min1: .degrees(340), max1: .degrees(20), min2: .degrees(350), max2: .degrees(10)→ 返回true - 测试2:
min1: .degrees(340), max1: .degrees(20), min2: .degrees(30), max2: .degrees(40)→ 返回false - 测试3:
min1: .degrees(0), max1: .degrees(100), min2: .degrees(20), max2: .degrees(80)→ 返回true
内容的提问来源于stack exchange,提问作者Isaak
相关产品推荐
相关产品推荐

