首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ggforce geom_arc:如何计算atan并在预期的侧绘制弧线

ggforce geom_arc:如何计算atan并在预期的侧绘制弧线
EN

Stack Overflow用户
提问于 2021-11-11 15:18:04
回答 1查看 94关注 0票数 0

我不能把我的头放在atan2的计算上,把一个geom_arc放在预定的一边。

这是一些带有四对点的虚拟数据,ABC。我想画四条弧线,每条弧线的侧面都有较小的角度,并打印角度。计算角度dregrees是可行的,但我需要一些开关来纠正atan2和/或2)另一个开关把弧线放在预定的一侧。仅仅交换startend没有任何影响。

代码语言:javascript
复制
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的坐标,以及顺时针方向的起点和终点,那就太完美了。)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-11 17:58:56

你好像在找这样的东西:

代码语言:javascript
复制
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弧度。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69930723

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档