首页 > 解决方案 > 沿具有多个节点的线以规则间隔垂直的线

问题描述

我正在尝试定期沿多条线(道路)进行采样,并且正在努力为每个路段获得精确的垂直角度。我已将每条道路分割成点,给出每条线改变方向的节点,到目前为止,我在每条道路的直线段内创建了一个点,并且看起来工作正常。

这是我用来为每个节点段生成垂直角的代码。

# X and Y for 3 points along a line
road_node <- matrix(
    c(
        381103, 381112, 381117,
        370373, 370301, 370290
    ),
    ncol = 2,
)
road_node <- as.data.frame(road_node)

angle_inv <- c()
for (i in 2:nrow(road_node) - 1) {
    n1 <- road_node[i, ]
    n2 <- road_node[i + 1, ]
    x <- as.numeric(n1[1] - n2[1])
    y <- as.numeric(n1[2] - n2[2])
    ang <- atan2(y, x) + 1 / 2 * pi
    if (!is.na(ang) && ang < 0) {
        ang <- 2 + ang
    }
    angle_inv <- rbind(angle_inv, ang)
}

其中 road_node 给出了每个节点的坐标。

从中我取中点和反角在中点的两侧创建两个点,以产生一条线段。

# X Y and Angles (angles for one segment are the same
mids <- matrix(
    c(
        381374.5, 381351.0, 381320.5,
        371590.5,371560.0, 371533.590,
        2.3, 2.3, 2.3
    ),
    nrow = 3,
)

mids <- as.data.frame(mids)

pts <- c()
for (i in 1:nrow(mids)) {
    x1 <- mids[i, 1] + 10 * cos(mids[i, 3])
    y1 <- mids[i, 2] + 10 * sin(mids[i, 3])
    x2 <- mids[i, 1] - 10 * cos(mids[i, 3])
    y2 <- mids[i, 2] - 10 * sin(mids[i, 3])
    p1 <- cbind(x1, y1)
    p2 <- cbind(x2, y2)
    pair <- rbind(p1, p2)
    pts <- rbind(pts, pair)
}

一些线段似乎正确地垂直于它们关联的节点,但有些则不然。每个似乎正确地共享相同的长度。

我相信问题在于我如何使用 atan2 选择我的角度,或者我如何选择节点段两侧的点。

标签: rfor-loop

解决方案


首先,没有必要使用三角函数来解决这个问题。相反,您可以使用线段方程的斜率截距形式的倒数,然后计算通过给定点的垂直线上的点。

使用斜率截距形式参见2 点方程

此外,您的中点似乎不正确,并且只有 2 个中点,因为 3 点 = 2 条线段。

此代码似乎工作正常

# Function to calculate mid points
mid_point <- function(p1,p2) {
    return(c(p1[1] + (p2[1] - p1[1]) / 2,p1[2] + (p2[2] - p1[2]) / 2))
}

# Function to calculate slope of line between 2 points    
slope <- function(p1,p2) {
    return((p2[2] - p1[2]) / (p2[1] - p1[1]))
}

# Function to calculate intercept of line passing through given point wiht slope m
calc_intercept <- function(p,m) {
    return(p[2] - m * p[1])
}

# Function to calculate y for a given x, slope m and intercept b
calc_y <- function(x,m,b) {
    return(c(x, m * x + b))
}

# X and Y for 3 points along a line
road_node <- matrix(
    c(
        381103, 381112, 381117,
        370373, 370301, 370290
    ),
    ncol = 2,
)
road_node <- as.data.frame(road_node)

perp_segments <- c()

for (i in 2:nrow(road_node) - 1) {
    n1 <- road_node[i, ]
    n2 <- road_node[i + 1, ]
    # Calculate mid point
    mp <- mid_point(n1,n2)
    # Calculate slope
    m <- slope(n1,n2)
    # Calculate intercept subsituting n1
    b <- calc_intercept(n1,m)
    # Calculate inverse reciprocal of slope
    new_m <- -1.0 / m
    # Calculate intercept of perpendicular line through mid point
    new_b <- calc_intercept(mp,new_m)
    # Calculate points 10 units away in x direction at mid_point
    p1 <- rbind(calc_y(as.numeric(mp[1])-10,new_m,new_b))
    p2 <- rbind(calc_y(as.numeric(mp[1])+10,new_m,new_b))
    # Add point pair to output vector
    pair <- rbind(p1,p2)
    perp_segments <- rbind(perp_segments,pair)
}

这就是它的几何外观(图片)

我希望这有帮助。

编辑1:

我想了更多,想出了这个简化的功能。如果您将问题视为直角等腰三角形 (45,45,90),那么您需要做的就是找到距沿线段插值的参考点所需距离的点,然后反转其 x 和 y与参考点的距离,然后从参考点添加和减去这些距离。

函数 calc_perp

参数:
p1, p2 - 定义线段终点的两个点向量
n - 到线段的距离
interval - 沿着线段的参考点到起点的间隔(默认 0.5)
ratio - 布尔值,定义是否间隔是长度的比例或常数(默认 TRUE)

# Function to calculate Euclidean distance between 2 points
euclidean_distance <-function(p1,p2) {
    return(sqrt((p2[1] - p1[1])**2 + (p2[2] - p1[2])**2))
}

# Function to calculate 2 points on a line perpendicular to another defined by 2 points p,p2
# For point at interval, which can be a proportion of the segment length, or a constant
# At distance n from the source line
calc_perp <-function(p1,p2,n,interval=0.5,proportion=TRUE) {
    # Calculate x and y distances
    x_len <- p2[1] - p1[1]
    y_len <- p2[2] - p1[2]

    # If proportion calculate reference point from tot_length
    if (proportion) {
        point <- c(p1[1]+x_len*interval,p1[2]+y_len*interval)
    }
    # Else use the constant value
    else {
        tot_len <- euclidean_distance(p1,p2)
        point <- c(p1[1]+x_len/tot_len*interval,p1[2]+y_len/tot_len*interval)
    }    

    # Calculate the x and y distances from reference point to point on line n distance away    
    ref_len <- euclidean_distance(point,p2)
    xn_len <- (n / ref_len) * (p2[1] - point[1])
    yn_len <- (n / ref_len) * (p2[2] - point[2])

    # Invert the x and y lengths and add/subtract from the refrence point
    ref_points <- rbind(point,c(point[1] + yn_len,point[2] - xn_len),c(point[1] - yn_len,point[2] + xn_len))

    # Return the reference points
    return(ref_points)
}

例子

> calc_perp(c(0,0),c(1,1),1)
            [,1]       [,2]
point  0.5000000  0.5000000
       1.2071068 -0.2071068
      -0.2071068  1.2071068

> calc_perp(c(0,0),c(1,1),sqrt(2)/2,0,proportion=FALSE)
      [,1] [,2]
point  0.0  0.0
       0.5 -0.5
      -0.5  0.5

这是修改后的函数在您的示例中的几何外观,n = 10 表示与线的距离:

在此处输入图像描述


推荐阅读