右转弯

 892974506_bdb55d_896 发布于 2023-02-13 09:40

我有一个问题,我有一堆长度,并希望从原点开始(假装我正面向y轴的正端),我向右移动并沿x轴正向移动length_i的距离.这时我又转了一圈,走了length_i的距离,重复了n次.我可以做到这一点,但我认为有一种更有效的方法,我缺乏数学背景:

## Fake Data
set.seed(11)
dat <- data.frame(id = LETTERS[1:6], lens=sample(2:9, 6), 
    x1=NA, y1=NA, x2=NA, y2=NA)

##   id lens x1 y1 x2 y2
## 1  A    4 NA NA NA NA
## 2  B    2 NA NA NA NA
## 3  C    5 NA NA NA NA
## 4  D    8 NA NA NA NA
## 5  E    6 NA NA NA NA
## 6  F    9 NA NA NA NA

## Add a cycle of 4 column    
dat[, "cycle"] <- rep(1:4, ceiling(nrow(dat)/4))[1:nrow(dat)]

##For loop to use the information from cycle column
for(i in 1:nrow(dat)) {

    ## set x1, y1
    if (i == 1) {
       dat[1, c("x1", "y1")] <- 0
    } else {
       dat[i, c("x1", "y1")] <- dat[(i - 1), c("x2", "y2")]
    }

    col1 <- ifelse(dat[i, "cycle"] %% 2 == 0, "x1", "y1")
    col2 <- ifelse(dat[i, "cycle"] %% 2 == 0, "x2", "y2")
    dat[i, col2] <- dat[i, col1]

    col3 <- ifelse(dat[i, "cycle"] %% 2 != 0, "x2", "y2")
    col4 <- ifelse(dat[i, "cycle"] %% 2 != 0, "x1", "y1")
    mag <- ifelse(dat[i, "cycle"] %in% c(1, 4), 1, -1)
    dat[i, col3] <- dat[i, col4] + (dat[i, "lens"] * mag)

}

这给出了期望的结果:

> dat

  id lens x1 y1 x2 y2 cycle
1  A    4  0  0  4  0     1
2  B    2  4  0  4 -2     2
3  C    5  4 -2 -1 -2     3
4  D    8 -1 -2 -1  6     4
5  E    6 -1  6  5  6     1
6  F    9  5  6  5 -3     2

这是一个情节:

library(ggplot2); library(grid)
ggplot(dat, aes(x = x1, y = y1, xend = x2, yend = y2)) + 
    geom_segment(aes(color=id), size=3, arrow = arrow(length = unit(0.5, "cm"))) + 
    ylim(c(-10, 10)) + xlim(c(-10, 10))

这似乎缓慢而笨重.我猜这是一个比我在for循环中做的项目更好的方法.什么是一种更有效的方式来保持编程权利?

在此输入图像描述

3 个回答
  • 这是使用复数的另一种方法.您可以通过乘以在复平面中"向右"旋转矢量-1i.下面的代码使第一次遍历进入正X(Re() - al轴)并且每次后续遍历将旋转到"右"

    imVecs <- lengths*c(0-1i)^(0:3)
    imVecs
    # [1]  9+0i  0-5i -9+0i  0+9i  8+0i  0-5i -8+0i  0+7i  8+0i  0-1i -5+0i  0+3i  4+0i  0-7i -4+0i  0+2i
    #[17]  3+0i  0-7i -5+0i  0+8i
    
    cumsum(imVecs)
    # [1] 9+0i 9-5i 0-5i 0+4i 8+4i 8-1i 0-1i 0+6i 8+6i 8+5i 3+5i 3+8i 7+8i 7+1i 3+1i 3+3i 6+3i 6-4i 1-4i
    #[20] 1+4i
    plot(cumsum(imVecs))
    lines(cumsum(imVecs))
    

    在此输入图像描述

    这是使用复平面旋转向右旋转45度的方法:

    > sqrt(-1i)
    [1] 0.7071068-0.7071068i
    > imVecs <- lengths*sqrt(0-1i)^(0:7)
    Warning message:
    In lengths * sqrt(0 - (0+1i))^(0:7) :
      longer object length is not a multiple of shorter object length
    > plot(cumsum(imVecs))
    > lines(cumsum(imVecs))
    

    情节:

    在此输入图像描述

    2023-02-13 09:43 回答
  • (正如@DWin所建议的)这是一个使用复数的解决方案,它可以灵活地应用于任何类型turn,而不仅仅是90度(-pi/2弧度)的直角.一切都是矢量化的:

    set.seed(11)
    dat <- data.frame(id = LETTERS[1:6], lens = sample(2:9, 6),
                                         turn = -pi/2)
    
    dat <- within(dat, { facing   <- pi/2 + cumsum(turn)
                         move     <- lens * exp(1i * facing)
                         position <- cumsum(move)
                         x2       <- Re(position)
                         y2       <- Im(position)
                         x1       <- c(0, head(x2, -1))
                         y1       <- c(0, head(y2, -1))
                       })
    
    dat[c("id", "lens", "x1", "y1", "x2", "y2")]
    #   id lens x1 y1 x2 y2
    # 1  A    4  0  0  4  0
    # 2  B    2  4  0  4 -2
    # 3  C    5  4 -2 -1 -2
    # 4  D    8 -1 -2 -1  6
    # 5  E    6 -1  6  5  6
    # 6  F    9  5  6  5 -3
    

    turn变量应该被视为一个输入lens.现在所有转弯都是-pi/2弧度,但你可以将它们中的每一个设置为你想要的任何一个.所有其他变量都是输出.


    现在玩得开心吧:

    trace.path <- function(lens, turn) {
      facing   <- pi/2 + cumsum(turn)
      move     <- lens * exp(1i * facing)
      position <- cumsum(move)
      x        <- c(0, Re(position))
      y        <- c(0, Im(position))
    
      plot.new()
      plot.window(range(x), range(y))
      lines(x, y)
    }
    
    trace.path(lens = seq(0, 1,  length.out = 200),
               turn = rep(pi/2 * (-1 + 1/200), 200))
    

    在此输入图像描述

    (我在这里复制图表的尝试:http://en.wikipedia.org/wiki/Turtle_graphics)

    我也让你尝试这些:

    trace.path(lens = seq(1, 10, length.out = 1000),
               turn = rep(2 * pi / 10, 1000))
    
    trace.path(lens = seq(0, 1,  length.out = 500),
               turn = seq(0, pi, length.out = 500))
    
    trace.path(lens = seq(0, 1,  length.out = 600) * c(1, -1),
               turn = seq(0, 8*pi, length.out = 600) * seq(-1, 1, length.out = 200))
    

    随意添加你的!

    2023-02-13 09:43 回答
  • 这不是一个漂亮的情节,但我已经将它包括在内,以表明这种"矢量化"坐标计算产生了正确的结果,不应该太难以适应您的需求:

    xx <- c(1,0,-1,0)
    yy <- c(0,-1,0,1)
    
    coords <- suppressWarnings(cbind(x = cumsum(c(0,xx*dat$lens)), 
                                     y = cumsum(c(0,yy*dat$lens))))
    plot(coords, type="l", xlim=c(-10,10), ylim=c(-10,10))
    

    在此输入图像描述

    2023-02-13 09:45 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有