我正在寻找一种连接所有具有相同斜率并共享公共点的线的解决方案。例如,在加载STL文件并使用平面切割后,切割器输出包括定义轮廓的点。逐个连接它们形成(或多个)折线。但是,当它们的斜率相同并且它们共享一个共同点时,某些线可以合并。例如,[[0,0,0],[0,0,1]]和[[0,0,1],[0,0,2]]可以用一条线表示[[0,0, 0],[0,0,2]。
我写了一个函数,可以分析所有行并连接它们,如果它们可以合并。但是当行数很大时,这个过程很慢。我想在VTK管道中,有没有办法进行行合并?
干杯!
plane = vtk.vtkPlane()
plane.SetOrigin([0,0,5])
plane.SetNormal([0,0,1])
cutter = vtk.vtkCutter()
cutter.SetCutFunction(plane)
cutter.SetInput(triangleFilter.GetOutput())
cutter.Update()
cutStrips = vtk.vtkStripper()
cutStrips.SetInputConnection(cutter.GetOutputPort())
cutStrips.Update()
cleanDataFilter = vtk.vtkCleanPolyData()
cleanDataFilter.AddInput(cutStrips.GetOutput())
cleanDataFilter.Update()
cleanData = cleanDataFilter.GetOutput()
print cleanData.GetPoint(0)
print cleanData.GetPoint(1)
print cleanData.GetPoint(2)
print cleanData.GetPoint(3)
print cleanData.GetPoint(4)
输出结果为:
(0.0,0.0,5.0) (5.0,0.0,5.0) (10.0,0.0,5.0) (10.0,5.0,5.0) (10.0,10.0,5.0)
逐个连接上述点将形成表示切割结果的折线。我们可以看到,行[point0,point1]和[point1,point2]可以合并。
以下是合并行的代码: 假设LINES由列表表示:[[(p0),(p1)],[(p1),(p2)],[(p2),(p3)],...]
appended = 0
CurrentLine = LINES[0]
CurrentConnectedLine = CurrentLine
tempLineCollection = LINES[1:len(LINES)]
while True:
for HL in tempLineCollection:
QCoreApplication.processEvents()
if checkParallelAndConnect(CurrentConnectedLine, HL):
appended = 1
LINES.remove(HL)
CurrentConnectedLine = ConnectLines(CurrentConnectedLine, HL)
processedPool.append(CurrentConnectedLine)
if len(tempLineCollection) == 1:
processedPool.append(tempLineCollection[0])
LINES.remove(CurrentLine)
if len(LINES) >= 2:
CurrentLine = LINES[0]
CurrentConnectedLine = CurrentLine
tempLineCollection = LINES[1:len(LINES)]
appended = 0
else:
break
解决方案:
我想出了一种使用某种vtk数据结构进一步加速这一过程的方法。我发现折线将存储在单元格中,可以使用GetCellType()进行检查。由于折线的点顺序已经排序,我们不需要全局搜索哪些线与当前线共线。对于折线上的每个点,我只需要检查点[i-1],点[i],点[i + 1]。如果它们是共线的,那么该行的结尾将更新到下一个点。此过程将继续,直到达到折线结束。与全球搜索方法相比,速度增加了很多。
答案 0 :(得分:1)
不确定它是否是缓慢的主要来源(取决于你的共线性上有多少正向命中),但是从向量中移除项目代价很高(O(n)),因为它需要重新组织其余的矢量,你应该避免它。但即使没有对共线性的打击,LINES.remove(CurrentLine)
调用肯定会减慢速度,并且实际上没有任何需要 - 只需保持向量不变,将最终结果写入新向量(processedPool
并最终摆脱LINES
向量。您可以通过制作bool数组(向量)来修改算法,对每个项目初始化为“false”,然后当您删除一行时,实际上不删除它,但只将其标记为“true”并且您跳过所有你有“真”的行,即这样的东西(我不会说python所以语法不准确):
wasRemoved = bool vector of the size of LINES initialized at false for each entry
for CurrentLineIndex = 0; CurrentLineIndex < sizeof(LINES); CurrentLineIndex++
if (wasRemoved[CurrentLineIndex])
continue // skip a segment that was already removed
CurrentConnectedLine = LINES[CurrentLineIndex]
for HLIndex = CurrentLineIndex + 1; HLIndex < sizeof(LINES); HLIndex++:
if (wasRemoved[HLIndex])
continue;
HL = LINES[HLIndex]
QCoreApplication.processEvents()
if checkParallelAndConnect(CurrentConnectedLine, HL):
wasRemoved[HLIndex] = true
CurrentConnectedLine = ConnectLines(CurrentConnectedLine, HL)
processedPool.append(CurrentConnectedLine)
wasRemoved[CurrentLineIndex] = true // this is technically not needed since you won't go back in the vector anyway
LINES = processedPool
BTW,LINES
用于这种算法的真正正确的数据结构将是一个链表,因为那时你将有O(1)复杂度去除,你不需要布尔数组。但是一个快速的谷歌搜索显示,这不是如何在Python中实现列表,也不知道它是否会干扰您的程序的其他部分。或者,使用一个集可能会使它更快(虽然我希望时间类似于我的“bool数组”解决方案),请参阅python 2.7 set and list remove time complexity
如果这不能解决问题,我建议您测量程序各个部分的时间以找出瓶颈。