我不能把我的头放在atan2的计算上,把一个geom_arc放在预定的一边。
这是一些带有四对点的虚拟数据,ABC。我想画四条弧线,每条弧线的侧面都有较小的角度,并打印角度。计算角度dregrees是可行的,但我需要一些开关来纠正atan2和/或2)另一个开关把弧线放在预定的一侧。仅仅交换start和end没有任何影响。
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 %>%
# dAB = distance between A and B (same as distance BC)
mutate(dAB = sqrt((xA - xB)^2 + (yA - yB)^2)) %>%
mutate(dBC = sqrt((xB - xC)^2 + (yB - yC)^2)) %>%
# calculate atan AB for arc start
mutate(arcAB = atan2(yA - yB, xA - xB)) %>%
# calculate atan BC for arc end
mutate(arcBC = atan2(yC - yB, xC - xB)) %>%
# calculate angle degree
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)) %>%
# calculate position for angle dreeg text
mutate(xAC = (xA + xC) / 2) %>%
mutate(yAC = (yA + yC) / 2)
tmp
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") +
geom_arc(aes(x0 = xB, y0 = yB, r = dAB, start = arcAB, end = arcBC)) + # plus or minus 2*pi
geom_text(aes(x = xAC, y = yAC, label = paste0(arc_deg, "°"))) +
coord_fixed() + theme_bw()以上代码仅适用于右下角弧:

我见过this,在左上角的弧形上,+ 2*pi会产生预期的效果,但我认为这需要四种不同的方法来覆盖所有情况。
我知道这可能更像是一个数学问题,并考虑问其他地方,但最终这是ggforce::geom_arc的一个应用程序,其他人可能也有类似的问题。(对我来说,如果我只需给出A、B和C的坐标,以及顺时针方向的起点和终点,那就太完美了。)
发布于 2021-11-11 17:58:56
你好像在找这样的东西:
tmp %>%
mutate(r = sqrt((yA - yB)^2 + (xA - xB)^2),
thetaAB = atan2(xA - xB, yA - yB),
thetaAB = ifelse(thetaAB < 0, thetaAB + 2 * pi, thetaAB),
thetaBC = atan2(xC - xB, yC - yB),
thetaBC = ifelse(thetaBC < 0, thetaBC + 2 * pi, thetaBC),
direction = ifelse(abs(thetaAB - thetaBC) > pi, "switch", "keep"),
Start = ifelse(abs(thetaAB - thetaBC) > pi & thetaAB < thetaBC,
thetaAB + 2 * pi, thetaAB),
End = ifelse(abs(thetaAB - thetaBC) > pi & thetaBC < thetaAB,
thetaBC + 2 * pi, thetaBC),
arc_deg = format((End - Start) * 180/pi, digits = 4),
xAC = (xA + xC) / 2,
yAC = (yA + yC) / 2) %>%
ggplot() +
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") +
geom_arc(aes(x0 = xB, y0 = yB, r = r, start = Start, end = End)) + # plus or minus 2*pi
geom_text(aes(x = xAC, y = yAC, label = paste0(arc_deg, "°"))) +
coord_fixed() +
theme_bw()

这里要认识到的关键是:
geom_arc而言,在y轴上(在12点钟的位置)出现0度,并从那里顺时针方向测量正角。通常,当使用三角函数时,我们会认为0度是沿着x轴,逆时针方向测量的。这是atan2背后的假设之一。这意味着您需要将atan2计算为atan2([delta x], [delta y]),而不是相反的方法(文档中说是atan2([delta y], [delta x]),这就是您的代码所用的方式)。由于希望测量两条线之间最小的角度(即小于π弧度的一条),因此需要找出角度之间的哪个差大于pi弧度,在这些情况下,将2 * pi添加到这两个角度中的较小的角度上。这确保了角度始终低于pi弧度。https://stackoverflow.com/questions/69930723
复制相似问题