ggforce geom_arc使用问题:如何计算atan2并将圆弧绘制在指定侧
解决方案
核心原理:ggforce::geom_arc默认沿逆时针方向从start角度绘制到end角度,只要保证end与start的逆时针差值等于你计算出的带符号最小夹角arc_deg(弧度制),就能自动落在夹角更小的一侧,不需要复杂的多场景判断。
具体修改逻辑
- 你已经计算出了带符号的最小夹角
arc_deg,如果该值为负,说明逆时针从arcAB到arcBC的实际跨度超过180°,只需要给arcBC加2*pi就能得到正确的逆时针小夹角终点 - 原有角度标注的坐标计算为A、C中点,可能落到夹角外侧,建议改为基于圆弧中点角度计算标注位置,和圆弧方向匹配
完整可运行代码
# 加载依赖包 library(tidyverse) library(ggforce) tmp <- tibble(xA = c(11, 14, 11, 14), yA = c(8, 8, 7, 7), xB = c(10, 15, 10, 15), yB = c(10, 10, 5, 5), xC = c(8, 17, 8, 17), yC = c(11, 11, 4, 4)) tmp <- tmp %>% # 计算AB、BC距离 mutate(dAB = sqrt((xA - xB)^2 + (yA - yB)^2), dBC = sqrt((xB - xC)^2 + (yB - yC)^2)) %>% # 计算AB、BC相对于B点的弧度 mutate(arcAB = atan2(yA - yB, xA - xB), arcBC = atan2(yC - yB, xC - xB)) %>% # 计算带符号的最小角度(角度制) mutate(arc_deg = round((arcBC * (180 / pi)) - (arcAB * (180 / pi)), 1)) %>% mutate(arc_deg = case_when( arc_deg > 180 ~ arc_deg - 360, arc_deg < -180 ~ arc_deg + 360, TRUE ~ arc_deg)) %>% # 调整geom_arc的终点角度,保证逆时针跨度为最小夹角 mutate(arc_end = ifelse(arc_deg < 0, arcBC + 2*pi, arcBC)) %>% # 计算圆弧中点角度,用于标注位置 mutate(mid_angle = arcAB + arc_deg*pi/180/2) %>% # 计算标注位置:在B点到圆弧中点的连线上,距离B点1.2倍dAB的位置(可按需调整系数) mutate(label_x = xB + dAB * 1.2 * cos(mid_angle), label_y = yB + dAB * 1.2 * sin(mid_angle)) # 绘图 ggplot(tmp) + geom_segment(aes(x = xB, xend = xA, y = yB, yend = yA), size = 1, col = "blue") + geom_segment(aes(x = xB, xend = xC, y = yB, yend = yC), size = 1, col = "green") + geom_text(aes(x = xB + 0.2, y = yB), label = "B") + geom_text(aes(x = xA + 0.2, y = yA), label = "A") + geom_text(aes(x = xC - 0.2, y = yC), label = "C") + # 用调整后的arc_end作为终点 geom_arc(aes(x0 = xB, y0 = yB, r = dAB, start = arcAB, end = arc_end)) + # 用修正后的位置标注角度 geom_text(aes(x = label_x, y = label_y, label = paste0(arc_deg, "°"))) + coord_fixed() + theme_bw()
扩展说明
如果需要强制顺时针绘制圆弧,只需要调整逻辑:判断如果arc_deg为正,给arcAB加2*pi,交换start和end即可,不需要额外处理其他场景。
内容的提问来源于stack exchange,提问作者Rumpl
相关产品推荐
相关产品推荐

