【问题标题】:R-Cran: How can I rotate a Plot?R-Cran:我怎样才能旋转一个情节?
【发布时间】:2015-01-22 01:35:51
【问题描述】:

我有兴趣计算多边形内沿自定义方向 (alpha) 的最大距离。

以下链接解决了我的问题。 https://gis.stackexchange.com/questions/32552/how-to-calculate-the-maximum-distance-within-a-polygon-in-x-direction-east-west。 (第一个答案:执行计算和创建插图的 R 代码)

唯一的缺点是我必须在运行脚本之前旋转我的多边形,因为它会在 x 方向找到最大值。

该脚本还会在 x 轴上绘制具有最大距离的多边形。

由于我没有成功编辑绘图功能,有没有办法旋转绘图以便为找到的最大距离和自定义方向设置相同的方向?

谢谢

-- 可重现的例子 ---

我在我的多边形中添加以下行(x,y 坐标旋转 alpha = 30 度,与第一个答案的作者建议的方式相同)。

# --- modified lines ------
x <- c(29,  -3,  -9, -33, -11,  -3,  30)
y <- c(13, -38, -37, -22,  32,  39,  13)
df = data.frame(x,y)
p.raw = list(cbind(x=df$x, y=df$y))

#scale <- 10
#p.raw = list(scale * cbind(x=c(0:10,7,6,0), y=c(3,0,0,-1,-1,-1,0,-0.5,0.75,1,4,1.5,0.5,3)),
#             scale *cbind(x=c(1,1,2.4,2,4,4,4,4,2,1), y=c(0,1,2,1,1,0,-0.5,1,1,0)),
#             scale *cbind(x=c(6,7,6,6), y=c(.5,2,3,.5)))

#p.raw = list(cbind(x=c(0,2,1,1/2,0), y=c(0,0,2,1,0)))
#p.raw = list(cbind(x=c(0, 35, 100, 65, 0), y=c(0, 50, 100, 50, 0)))

# --- modified lines ------

从上一个链接到 R 脚本。

#
# Plotting functions.
#
points.polygon <- function(p, ...) {
  points(p$v, ...)
}
plot.polygon <- function(p, ...) {
  apply(p$e, 1, function(e) lines(matrix(e[c("x.min", "x.max", "y.min", "y.max")], ncol=2), ...))
}
expand <- function(bb, e=1) {
  a <- matrix(c(e, 0, 0, e), ncol=2)
  origin <- apply(bb, 2, mean)
  delta <-  origin %*% a - origin
  t(apply(bb %*% a, 1, function(x) x - delta))
}
#
# Convert polygon to a better data structure.
#
# A polygon class has three attributes:
#   v is an array of vertex coordinates "x" and "y" sorted by increasing y;
#   e is an array of edges from (x.min, y.min) to (x.max, y.max) with y.max >= y.min, sorted by y.min;
#   bb is its rectangular extent (x0,y0), (x1,y1).
#
as.polygon <- function(p) {
  #
  # p is a list of linestrings, each represented as a sequence of 2-vectors 
  # with coordinates in columns "x" and "y". 
  #
  f <- function(p) {
    g <- function(i) {
      v <- p[(i-1):i, ]
      v[order(v[, "y"]), ]
    }
    sapply(2:nrow(p), g)
  }
  vertices <- do.call(rbind, p)
  edges <- t(do.call(cbind, lapply(p, f)))
  colnames(edges) <- c("x.min", "x.max", "y.min", "y.max")
  #
  # Sort by y.min.
  #
  vertices <- vertices[order(vertices[, "y"]), ]
  vertices <- vertices[!duplicated(vertices), ]
  edges <- edges[order(edges[, "y.min"]), ]

  # Maintaining an extent is useful.
  bb <- apply(vertices <- vertices[, c("x","y")], 2, function(z) c(min(z), max(z)))

  # Package the output.
  l <- list(v=vertices, e=edges, bb=bb); class(l) <- "polygon"
  l
}
#
# Compute the maximal horizontal interior segments of a polygon.
#
fetch.x <- function(p) {
  #
  # Update moves the line from the previous level to a new, higher level, changing the
  # state to represent all edges originating or strictly passing through level `y`.
  #
  update <- function(y) {
    if (y > state$level) {
      state$level <<- y
      #
      # Remove edges below the new level from state$current.
      #
      current <- state$current
      current <- current[current[, "y.max"] > y, ]
      #
      # Adjoin edges at this level.
      #
      i <- state$i
      while (i <= nrow(p$e) && p$e[i, "y.min"] <= y) {
        current <- rbind(current, p$e[i, ])
        i <- i+1
      }
      state$i <<- i
      #
      # Sort the current edges by x-coordinate.
      #
      x.coord <- function(e, y) {
        if (e["y.max"] > e["y.min"]) {
          ((y - e["y.min"]) * e["x.max"] + (e["y.max"] - y) * e["x.min"]) / (e["y.max"] - e["y.min"])
        } else {
          min(e["x.min"], e["x.max"])
        }
      }
      if (length(current) > 0) {
        x.array <- apply(current, 1, function(e) x.coord(e, y))
        i.x <- order(x.array)
        current <- current[i.x, ]
        x.array <- x.array[i.x]     
        #
        # Scan and mark each interval as interior or exterior.
        #
        status <- FALSE
        interior <- numeric(length(x.array))
        for (i in 1:length(x.array)) {
          if (current[i, "y.max"] == y) {
            interior[i] <- TRUE
          } else {
            status <- !status
            interior[i] <- status
          }
        }
        #
        # Simplify the data structure by retaining the last value of `interior`
        # within each group of common values of `x.array`.
        #
        interior <- sapply(split(interior, x.array), function(i) rev(i)[1])
        x.array <- sapply(split(x.array, x.array), function(i) i[1])

        print(y)
        print(current)
        print(rbind(x.array, interior))


        markers <- c(1, diff(interior))
        intervals <- x.array[markers != 0]
        #
        # Break into a list structure.
        #
        if (length(intervals) > 1) {
          if (length(intervals) %% 2 == 1) 
            intervals <- intervals[-length(intervals)]
          blocks <- 1:length(intervals) - 1
          blocks <- blocks - (blocks %% 2)
          intervals <- split(intervals, blocks)  
        } else {
          intervals <- list()
        }
      } else {
        intervals <- list()
      }
      #
      # Update the state.
      #
      state$current <<- current
    }
    list(y=y, x=intervals)
  } # Update()

  process <- function(intervals, x, y) {
    # intervals is a list of 2-vectors. Each represents the endpoints of
    # an interior interval of a polygon.
    # x is an array of x-coordinates of vertices.
    #
    # Retains only the intervals containing at least one vertex.
    between <- function(i) {
      1 == max(mapply(function(a,b) a && b, i[1] <= x, x <= i[2]))
    }
    is.good <- lapply(intervals$x, between)
    list(y=y, x=intervals$x[unlist(is.good)])
    #intervals
  }
  #
  # Group the vertices by common y-coordinate.
  #
  vertices.x <- split(p$v[, "x"], p$v[, "y"])
  vertices.y <- lapply(split(p$v[, "y"], p$v[, "y"]), max)
  #
  # The "state" is a collection of segments and an index into edges.
  # It will updated during the vertical line sweep.
  #
  state <- list(level=-Inf, current=c(), i=1, x=c(), interior=c())
  #
  # Sweep vertically from bottom to top, processing the intersection
  # as we go.
  #
  mapply(function(x,y) process(update(y), x, y), vertices.x, vertices.y)
}

# --- modified lines ------
x <- c(29,  -3,  -9, -33, -11,  -3,  30)
y <- c(13, -38, -37, -22,  32,  39,  13)
df = data.frame(x,y)
p.raw = list(cbind(x=df$x, y=df$y))

#scale <- 10
#p.raw = list(scale * cbind(x=c(0:10,7,6,0), y=c(3,0,0,-1,-1,-1,0,-0.5,0.75,1,4,1.5,0.5,3)),
#             scale *cbind(x=c(1,1,2.4,2,4,4,4,4,2,1), y=c(0,1,2,1,1,0,-0.5,1,1,0)),
#             scale *cbind(x=c(6,7,6,6), y=c(.5,2,3,.5)))

#p.raw = list(cbind(x=c(0,2,1,1/2,0), y=c(0,0,2,1,0)))
#p.raw = list(cbind(x=c(0, 35, 100, 65, 0), y=c(0, 50, 100, 50, 0)))

# --- modified lines ------

p <- as.polygon(p.raw)

results <- fetch.x(p)
#
# Find the longest.
#
dx <- matrix(unlist(results["x", ]), nrow=2)
length.max <- max(dx[2,] - dx[1,])
#
# Draw pictures.
#
segment.plot <- function(s, length.max, colors,  ...) {
  lapply(s$x, function(x) {
    col <- ifelse (diff(x) >= length.max, colors[1], colors[2])
    lines(x, rep(s$y,2), col=col, ...)
  })
}
gray <- "#f0f0f0"
grayer <- "#d0d0d0"
plot(expand(p$bb, 1.1), type="n", xlab="x", ylab="y", main="After the Scan")
sapply(1:length(p.raw), function(i) polygon(p.raw[[i]], col=c(gray, "White", grayer)[i]))
apply(results, 2, function(s) segment.plot(s, length.max, colors=c("Red", "#b8b8a8"), lwd=4))
plot(p, col="Black", lty=3)
points(p, pch=19, col=round(2 + 2*p$v[, "y"]/scale, 0))
points(p, cex=1.25)

结果图将最大距离显示为 x 轴方向上的红色线段。因为我需要它在原始方向(向后旋转 alpha 30 度),所以我正在寻找最大距离 x,y 坐标,以通过 -alpha 执行反向旋转。

我得到的最大距离段x坐标来自:

 dx <- matrix(unlist(results["x", ]), nrow=2)
 length.max <- max(dx[2,] - dx[1,])

我无法获得 y 坐标。

apply(results, 2, function(s) segment.plot(s, length.max, colors=c("Red", "#b8b8a8"), lwd=2))

所以,我正在寻找一种将结果图轴旋转 alpha 的方法。

【问题讨论】:

  • 您尝试对 plot() 进行哪些编辑?你的尝试是如何失败的。你的问题可以通过最小的reproducible example得到很大的改善。

标签: r algorithm plot


【解决方案1】:

我从?polygon 中提取了一个小多边形示例。试试这个来旋转它

x <- c(1:9, 8:1)
y <- c(1, 2*(5:3), 2, -1, 17, 9, 8, 2:9)
# plot(x, y)
# polygon(x, y)
vertices <- matrix(c(x, y), byrow = T, nrow = 2)

rotate <- function(point, theta, degree = F) {
   if (degree) theta <- theta * pi / 180
   rotate.matrix <- matrix(c(cos(theta), -sin(theta), sin(theta), cos(theta)), byrow = T, nrow = 2)
   rotate.point <- rotate.matrix %*% point
   rotate.point
}

rotate.vertices <- apply(vertices, 2, rotate, theta = 1.3)
# plot(rotate.vertices[1, ], rotate.vertices[2, ], xlim = c(-20, 20), ylim = c(-20, 20))
# polygon(rotate.vertices[1, ], rotate.vertices[2, ])

theta 参数是您旋转多边形的角度。如果您喜欢度数而不是弧度,请务必设置degree = T

【讨论】:

    猜你喜欢
    • 2021-09-23
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多