偏移 a line/vector 平行于给定的线
offset a line/vector parallel to given lines
给定一些 XY 坐标,我试图创建与原始坐标平行的新线。
然而,当向量 'goes back' 时它们似乎相交,像这样:
(BLUE:原始坐标,ORANGE:编程坐标应该是平行的)
这是完整的 python 代码。
import numpy as np
import matplotlib.pyplot as plt
xN = [11.86478, 24.851482, 75.38245, 84.50359, 58.3, 58.001]
yN = [4.3048816, 3.541581, 4.0219164, 2.854434, 0.0, 0.001]
newX = []
newY = []
d = 1
for i in range(len(xN)-1):
r = np.sqrt((xN[i+1]-xN[i])**2+(yN[i+1]-yN[i])**2)
dx = d/r*(yN[i]-yN[i+1])
dy = d/r*(xN[i+1]-xN[i])
newX.append(xN[i]+dx)
newY.append(yN[i]+dy)
plt.plot(xN, yN)
plt.plot(newX, newY)
plt.show()
有没有algorithm/technique实现不与原线相交的平行偏移?谢谢
更新:
虽然将 abs()
添加到 dx/dy d/r*abs(yN[i]-yN[i+1])
解决了第一部分,但如果我想一路走下去,它仍然相交,因为线的大小相同。
我正在努力实现以下目标(为了视觉理解,我手动创建了平行线):
我认为你必须像这样使用绝对值
dx = d/r*abs(yN[i]-yN[i+1])
dy = d/r*abs(xN[i+1]-xN[i])
这给出了
您是在寻找这个结果吗?
编辑:
又看了一遍,挺有意思的。要仅在一侧延伸,您需要在沿线时考虑线的“惯用手”。我认为它是一条微分几何曲线,切向量 t (dx, dy) 及其法线 n (dy, - dx)(你已经在你的代码中使用过它)跨越第三个向量,我认为它叫做双法向量 b=t x n。由于您只想在一侧扩展线,因此您必须考虑 b 的行为:它是否“翻转”,即曲线是否改变方向?我已将此添加到代码中(做得不好,可能需要润色但说明了要点,s3
是 b 的 z 分量,因为我只检查“翻转” , 还加了点说明):
import numpy as np
import matplotlib.pyplot as plt
xN = [11.86478, 24.851482, 75.38245, 84.50359, 58.3, 0.4]
yN = [4.3048816, 3.541581, 4.0219164, 2.854434, 0.0, 1.0]
newX = []
newY = []
d = 1
dx = 1
dy = 1
s3 = dx*dx + dy*dy
for i in range(len(xN)-1):
if s3 < 0:
newX.append(xN[i]+dy)
newY.append(yN[i]-dx)
else:
newX.append(xN[i]-dy)
newY.append(yN[i]+dx)
r = np.sqrt((xN[i+1]-xN[i])**2+(yN[i+1]-yN[i])**2)
dy = d/r*(yN[i+1]-yN[i])
dx = d/r*(xN[i+1]-xN[i])
s3 = dx*dx + dy*dy # this is the cross product, z-component
if s3 < 0:
newX.append(xN[i+1]+dy)
newY.append(yN[i+1]-dx)
else:
newX.append(xN[i+1]-dy)
newY.append(yN[i+1]+dx)
plt.plot(xN, yN)
#plt.plot(newX, newY)
plt.plot(newX, newY, 'o')
plt.show()
这导致
所有点现在都在曲线的一侧。这仍然不理想,因为 - 如果您在点之间画线 - 外线会切断原始线。这是由于需要延长外部曲线,但仍未考虑。我想你可以通过在原始曲线上的急转弯周围插入更多点来解决这个问题。
经过一些研究,我找到了一个解决方案,它通过选定的偏移值来偏移线条。
这是从 C# algorithm 中提取并编码到 Python 中的。
注意: 这不适用于共线形状。此外,这是通过显式编码完成的,需要改进。
完整代码:
import numpy as np
import matplotlib.pyplot as plt
xN = [11.86478, 24.851482, 75.38245, 84.50359, 58.3, 0.4]
yN = [4.3048816, 3.541581, 4.0219164, 2.854434, 0.0, 1.0]
newX = []
newY = []
def findIntesection(p1x, p1y, p2x, p2y, p3x,p3y, p4x, p4y):
dx12 = p2x - p1x
dy12 = p2y - p1y
dx34 = p4x - p3x
dy34 = p4y - p3y
denominator = (dy12*dx34-dx12*dy34)
t1 = ((p1x - p3x) * dy34 + (p3y - p1y) * dx34)/ denominator
t2 = ((p3x - p1x) * dy12 + (p1y - p3y) * dx12)/ -denominator;
intersectX = p1x + dx12 * t1
intersectY = p1y + dy12 * t1
if (t1 < 0): t1 = 0
elif (t1 > 1): t1 = 1
if (t2 < 0): t2 = 0
elif (t2 > 1): t2 = 1
return intersectX,intersectY
def normalizeVec(x,y):
distance = np.sqrt(x*x+y*y)
return x/distance, y/distance
def getEnlarged(oldX, oldY, offset):
num_points = len(oldX)
for j in range(num_points):
i = j - 1
if i < 0:
i += num_points
k = (j + 1) % num_points
vec1X = oldX[j] - oldX[i]
vec1Y = oldY[j] - oldY[i]
v1normX, v1normY = normalizeVec(vec1X,vec1Y)
v1normX *= offset
v1normY *= offset
n1X = -v1normY
n1Y = v1normX
pij1X = oldX[i] + n1X
pij1Y = oldY[i] + n1Y
pij2X = oldX[j] + n1X
pij2Y = oldY[j] + n1Y
vec2X = oldX[k] - oldX[j]
vec2Y = oldY[k] - oldY[j]
v2normX, v2normY = normalizeVec(vec2X,vec2Y)
v2normX *= offset
v2normY *= offset
n2X = -v2normY
n2Y = v2normX
pjk1X = oldX[j] + n2X
pjk1Y = oldY[j] + n2Y
pjk2X = oldX[k] + n2X
pjk2Y = oldY[k] + n2Y
intersectX,intersetY = findIntesection(pij1X,pij1Y,pij2X,pij2Y,pjk1X,pjk1Y,pjk2X,pjk2Y)
#print(intersectX,intersetY)
newX.append(intersectX)
newY.append(intersetY)
getEnlarged(xN, yN, 1)
plt.plot(xN, yN)
plt.plot(newX, newY)
plt.show()
这给出了以下输出:
给定一些 XY 坐标,我试图创建与原始坐标平行的新线。
然而,当向量 'goes back' 时它们似乎相交,像这样:
(BLUE:原始坐标,ORANGE:编程坐标应该是平行的)
这是完整的 python 代码。
import numpy as np
import matplotlib.pyplot as plt
xN = [11.86478, 24.851482, 75.38245, 84.50359, 58.3, 58.001]
yN = [4.3048816, 3.541581, 4.0219164, 2.854434, 0.0, 0.001]
newX = []
newY = []
d = 1
for i in range(len(xN)-1):
r = np.sqrt((xN[i+1]-xN[i])**2+(yN[i+1]-yN[i])**2)
dx = d/r*(yN[i]-yN[i+1])
dy = d/r*(xN[i+1]-xN[i])
newX.append(xN[i]+dx)
newY.append(yN[i]+dy)
plt.plot(xN, yN)
plt.plot(newX, newY)
plt.show()
有没有algorithm/technique实现不与原线相交的平行偏移?谢谢
更新:
虽然将 abs()
添加到 dx/dy d/r*abs(yN[i]-yN[i+1])
解决了第一部分,但如果我想一路走下去,它仍然相交,因为线的大小相同。
我正在努力实现以下目标(为了视觉理解,我手动创建了平行线):
我认为你必须像这样使用绝对值
dx = d/r*abs(yN[i]-yN[i+1])
dy = d/r*abs(xN[i+1]-xN[i])
这给出了
您是在寻找这个结果吗?
编辑:
又看了一遍,挺有意思的。要仅在一侧延伸,您需要在沿线时考虑线的“惯用手”。我认为它是一条微分几何曲线,切向量 t (dx, dy) 及其法线 n (dy, - dx)(你已经在你的代码中使用过它)跨越第三个向量,我认为它叫做双法向量 b=t x n。由于您只想在一侧扩展线,因此您必须考虑 b 的行为:它是否“翻转”,即曲线是否改变方向?我已将此添加到代码中(做得不好,可能需要润色但说明了要点,s3
是 b 的 z 分量,因为我只检查“翻转” , 还加了点说明):
import numpy as np
import matplotlib.pyplot as plt
xN = [11.86478, 24.851482, 75.38245, 84.50359, 58.3, 0.4]
yN = [4.3048816, 3.541581, 4.0219164, 2.854434, 0.0, 1.0]
newX = []
newY = []
d = 1
dx = 1
dy = 1
s3 = dx*dx + dy*dy
for i in range(len(xN)-1):
if s3 < 0:
newX.append(xN[i]+dy)
newY.append(yN[i]-dx)
else:
newX.append(xN[i]-dy)
newY.append(yN[i]+dx)
r = np.sqrt((xN[i+1]-xN[i])**2+(yN[i+1]-yN[i])**2)
dy = d/r*(yN[i+1]-yN[i])
dx = d/r*(xN[i+1]-xN[i])
s3 = dx*dx + dy*dy # this is the cross product, z-component
if s3 < 0:
newX.append(xN[i+1]+dy)
newY.append(yN[i+1]-dx)
else:
newX.append(xN[i+1]-dy)
newY.append(yN[i+1]+dx)
plt.plot(xN, yN)
#plt.plot(newX, newY)
plt.plot(newX, newY, 'o')
plt.show()
这导致
所有点现在都在曲线的一侧。这仍然不理想,因为 - 如果您在点之间画线 - 外线会切断原始线。这是由于需要延长外部曲线,但仍未考虑。我想你可以通过在原始曲线上的急转弯周围插入更多点来解决这个问题。
经过一些研究,我找到了一个解决方案,它通过选定的偏移值来偏移线条。
这是从 C# algorithm 中提取并编码到 Python 中的。
注意: 这不适用于共线形状。此外,这是通过显式编码完成的,需要改进。
完整代码:
import numpy as np
import matplotlib.pyplot as plt
xN = [11.86478, 24.851482, 75.38245, 84.50359, 58.3, 0.4]
yN = [4.3048816, 3.541581, 4.0219164, 2.854434, 0.0, 1.0]
newX = []
newY = []
def findIntesection(p1x, p1y, p2x, p2y, p3x,p3y, p4x, p4y):
dx12 = p2x - p1x
dy12 = p2y - p1y
dx34 = p4x - p3x
dy34 = p4y - p3y
denominator = (dy12*dx34-dx12*dy34)
t1 = ((p1x - p3x) * dy34 + (p3y - p1y) * dx34)/ denominator
t2 = ((p3x - p1x) * dy12 + (p1y - p3y) * dx12)/ -denominator;
intersectX = p1x + dx12 * t1
intersectY = p1y + dy12 * t1
if (t1 < 0): t1 = 0
elif (t1 > 1): t1 = 1
if (t2 < 0): t2 = 0
elif (t2 > 1): t2 = 1
return intersectX,intersectY
def normalizeVec(x,y):
distance = np.sqrt(x*x+y*y)
return x/distance, y/distance
def getEnlarged(oldX, oldY, offset):
num_points = len(oldX)
for j in range(num_points):
i = j - 1
if i < 0:
i += num_points
k = (j + 1) % num_points
vec1X = oldX[j] - oldX[i]
vec1Y = oldY[j] - oldY[i]
v1normX, v1normY = normalizeVec(vec1X,vec1Y)
v1normX *= offset
v1normY *= offset
n1X = -v1normY
n1Y = v1normX
pij1X = oldX[i] + n1X
pij1Y = oldY[i] + n1Y
pij2X = oldX[j] + n1X
pij2Y = oldY[j] + n1Y
vec2X = oldX[k] - oldX[j]
vec2Y = oldY[k] - oldY[j]
v2normX, v2normY = normalizeVec(vec2X,vec2Y)
v2normX *= offset
v2normY *= offset
n2X = -v2normY
n2Y = v2normX
pjk1X = oldX[j] + n2X
pjk1Y = oldY[j] + n2Y
pjk2X = oldX[k] + n2X
pjk2Y = oldY[k] + n2Y
intersectX,intersetY = findIntesection(pij1X,pij1Y,pij2X,pij2Y,pjk1X,pjk1Y,pjk2X,pjk2Y)
#print(intersectX,intersetY)
newX.append(intersectX)
newY.append(intersetY)
getEnlarged(xN, yN, 1)
plt.plot(xN, yN)
plt.plot(newX, newY)
plt.show()
这给出了以下输出: