r - 沿具有多个节点的线以规则间隔垂直的线
问题描述
我正在尝试定期沿多条线(道路)进行采样,并且正在努力为每个路段获得精确的垂直角度。我已将每条道路分割成点,给出每条线改变方向的节点,到目前为止,我在每条道路的直线段内创建了一个点,并且看起来工作正常。
这是我用来为每个节点段生成垂直角的代码。
# 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 选择我的角度,或者我如何选择节点段两侧的点。
解决方案
首先,没有必要使用三角函数来解决这个问题。相反,您可以使用线段方程的斜率截距形式的倒数,然后计算通过给定点的垂直线上的点。
使用斜率截距形式参见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 表示与线的距离:
推荐阅读
- angular - 而不是 icon ,文本在 Angular6 中以 mat-step 形式出现
- reactjs - 向父母发送功能以刷新道具?
- mongodb - 线程“主”org.bson.codecs.configuration.CodecConfigurationException 中的异常:找不到类 org.bson.BsonElement 的编解码器
- angular - 用复选框和输入字段构建下拉菜单,它存在吗?
- prolog - 如何在 SWI-Prolog 中表示 semnet
- java - Android API 级别低于 24 的画中画模式
- javascript - 如何使用 Javascript 或 jQuery 从 iFrame 获取控件
- arrays - Perl:为 DNA 序列的对数得分创建和操作数组的散列
- r - 在一列地址上使用地理编码 - 不将它们识别为位置
- reactjs - React-final-form 忽略字段验证属性更改