沿具有多个节点的线的规则间隔的垂直线

时间:2019-06-26 10:48:29

标签: r for-loop

我试图以规则的间隔沿多条线(道路)进行采样,并努力获取每个路段的准确垂直角度。我已经将每条道路划分为多个点,从而给出了每条线改变方向的节点,到目前为止,我在每条道路的直线段内创建了一个点,并且看起来运行良好。

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

# 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选择角度,还是我如何在节点线段的两侧选择点。

1 个答案:

答案 0 :(得分:1)

首先,无需使用三角函数即可解决此问题。相反,您可以使用线段方程的斜率截距形式的倒数倒数,然后计算通过给定点的垂直线上的点。

请参见Equation from 2 points using Slope Intercept Form

此外,您的中点显示不正确,并且只有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)
}

This is how it looks geometrically (image)

我希望这会有所帮助。

编辑1:

我对此进行了更多考虑,并提出了此简化功能。如果您将问题修正为等腰三角形(45,45,90),那么您所要做的就是找到与沿线段插补的参考点所需距离的点,然后反转其x和y距参考点的距离,然后将其与参考点相加或减去。

函数calc_perp

参数:
p1,p2 -定义线段终点的两个点向量
n -距线段的距离
interval -从起点开始沿参考点的线段的间隔(默认值为0.5)
proportion -布尔值,定义间隔是长度的一部分还是常数(默认为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:

enter image description here