我已将.obj网格文件转换为.stl。我还创建了一个平面几何体作为网格对象的支架,然后合并它们。但是,它存在差距。 有什么建议如何垂直地缩小差距,使其成为一个坚实的对象,我已经尝试过vtkFillHolesFilter和手动方式,但不会填补差距?
创建平面的代码:
implicitPolyDataDistance = vtk.vtkImplicitPolyDataDistance()
implicitPolyDataDistance.SetInput(stl_poly_data)
#create a grid
xCoords = vtk.vtkFloatArray()
for x, i in enumerate(np.linspace(xmin, xmax,50)):
xCoords.InsertNextValue(i)
yCoords = vtk.vtkFloatArray()
for y, i in enumerate(np.linspace(ymin, ymax, 50)):
yCoords.InsertNextValue(i)
zCoords = vtk.vtkFloatArray()
for z, i in enumerate(np.linspace(zmin, zmin + 1, 50)):
zCoords.InsertNextValue(i)
rgrid = vtk.vtkRectilinearGrid()
rgrid.SetDimensions(x + 1, y + 1 , z + 1)
rgrid.SetXCoordinates(xCoords)
rgrid.SetYCoordinates(yCoords)
rgrid.SetZCoordinates(zCoords)
signedDistances = vtk.vtkFloatArray()
signedDistances.SetNumberOfComponents(1)
signedDistances.SetName("SignedDistances")
# Evaluate the signed distance function at all of the grid points
for pointId in range(rgrid.GetNumberOfPoints()):
p = rgrid.GetPoint(pointId)
signedDistance = implicitPolyDataDistance.EvaluateFunction(p)
signedDistances.InsertNextValue(signedDistance)
# add the SignedDistances to the grid
rgrid.GetPointData().SetScalars(signedDistances)
# geometry filter to view the background grid
geometryFilter = vtk.vtkRectilinearGridGeometryFilter()
geometryFilter.SetInputData(rgrid)
geometryFilter.SetExtent(0, x + 1, 0, y + 1, (z + 1) // 2, (z + 1) // 2)
geometryFilter.Update()
# ================ END creating a plane =======================
合并stl poly数据和平面的代码:
meshAppend = vtk.vtkAppendPolyData()
meshAppend.AddInputData(stl_poly_data)
meshAppend.AddInputData(geometryFilter.GetOutput())
meshAppend.Update()
boundaryClean = vtk.vtkCleanPolyData()
boundaryClean.SetInputData(meshAppend.GetOutput())
boundaryClean.Update()
out = vtk.vtkPolyData()
out.DeepCopy(boundaryClean.GetOutput())
triangleTrans = vtk.vtkTriangleFilter()
triangleTrans.SetInputData(out)
triangleTrans.Update()
fill = vtk.vtkFillHolesFilter()
fill.SetInputData(out)
fill.SetHoleSize(1000000.0)
fill.Update()
答案 0 :(得分:1)
vtkFillHolesFilter
旨在填充孔,而不是填充两个可能断开连接的表面补丁之间的任意间隙。
可能对您有用的是,在我的自由曲面和平面补丁之间缝合一个“缝”,正如我在本文中所概述的:How to triangulate two non-intersecting polylines in 3D。这个想法是沿着边缘走,并根据一些简单的启发式方法创建新的接缝边缘。尽管如果边缘不在同一平面上,则拼接效果很好,但如果边缘分开得太大或太突然,则拼接可能会失败。另外,我建议沿边缘的点数大致相同数量级。
更新:我添加了一个功能示例,演示了您的示例的用法。
重要:拼接算法要求边缘以相同的方式定向!这对于我们为您的表面构造底部的方式很自然。
# This code has been written by normanius under the CC BY-SA 4.0 license.
# License: https://creativecommons.org/licenses/by-sa/4.0/
# Author: normanius: https://stackoverflow.com/users/3388962/normanius
# Date: July 2018
# Reference: https://stackoverflow.com/questions/51321415
import os
import vtk
import numpy as np
def extract_points(source):
# Travers the cells and add points while keeping their order.
points = source.GetPoints()
cells = source.GetLines()
cells.InitTraversal()
idList = vtk.vtkIdList()
pointIds = []
while cells.GetNextCell(idList):
for i in range(0, idList.GetNumberOfIds()):
pId = idList.GetId(i)
# Only add the point id if the previously added point does not
# have the same id. Avoid p->p duplications which occur for example
# if a poly-line is traversed. However, other types of point
# duplication currently are not avoided: a->b->c->a->d
if len(pointIds)==0 or pointIds[-1]!=pId:
pointIds.append(pId)
result = []
for i in pointIds:
result.append(points.GetPoint(i))
return result
def reverse_lines(source):
strip = vtk.vtkStripper()
strip.SetInputData(source)
strip.Update()
reversed = vtk.vtkReverseSense()
reversed.SetInputConnection(strip.GetOutputPort())
reversed.Update()
return reversed.GetOutput()
def find_closest_point(points, samplePoint):
points = np.asarray(points)
assert(len(points.shape)==2 and points.shape[1]==3)
nPoints = points.shape[0]
diff = np.array(points) - np.tile(samplePoint, [nPoints, 1])
pId = np.argmin(np.linalg.norm(diff, axis=1))
return pId
def stitch(edge1, edge2):
# Extract points along the edge line (in correct order).
# The following further assumes that the polyline has the
# same orientation (clockwise or counterclockwise).
points1 = extract_points(edge1)
points2 = extract_points(edge2)
n1 = len(points1)
n2 = len(points2)
# Prepare result containers.
# Variable points concatenates points1 and points2.
# Note: all indices refer to this targert container!
points = vtk.vtkPoints()
cells = vtk.vtkCellArray()
points.SetNumberOfPoints(n1+n2)
for i, p1 in enumerate(points1):
points.SetPoint(i, p1)
for i, p2 in enumerate(points2):
points.SetPoint(i+n1, p2)
# The following code stitches the curves edge1 with (points1) and
# edge2 (with points2) together based on a simple growing scheme.
# Pick a first stitch between points1[0] and its closest neighbor
# of points2.
i1Start = 0
i2Start = find_closest_point(points2, points1[i1Start])
i2Start += n1 # offset to reach the points2
# Initialize
i1 = i1Start
i2 = i2Start
p1 = np.asarray(points.GetPoint(i1))
p2 = np.asarray(points.GetPoint(i2))
mask = np.zeros(n1+n2, dtype=bool)
count = 0
while not np.all(mask):
count += 1
i1Candidate = (i1+1)%n1
i2Candidate = (i2+1+n1)%n2+n1
p1Candidate = np.asarray(points.GetPoint(i1Candidate))
p2Candidate = np.asarray(points.GetPoint(i2Candidate))
diffEdge12C = np.linalg.norm(p1-p2Candidate)
diffEdge21C = np.linalg.norm(p2-p1Candidate)
mask[i1] = True
mask[i2] = True
if diffEdge12C < diffEdge21C:
triangle = vtk.vtkTriangle()
triangle.GetPointIds().SetId(0,i1)
triangle.GetPointIds().SetId(1,i2)
triangle.GetPointIds().SetId(2,i2Candidate)
cells.InsertNextCell(triangle)
i2 = i2Candidate
p2 = p2Candidate
else:
triangle = vtk.vtkTriangle()
triangle.GetPointIds().SetId(0,i1)
triangle.GetPointIds().SetId(1,i2)
triangle.GetPointIds().SetId(2,i1Candidate)
cells.InsertNextCell(triangle)
i1 = i1Candidate
p1 = p1Candidate
# Add the last triangle.
i1Candidate = (i1+1)%n1
i2Candidate = (i2+1+n1)%n2+n1
if (i1Candidate <= i1Start) or (i2Candidate <= i2Start):
if i1Candidate <= i1Start:
iC = i1Candidate
else:
iC = i2Candidate
triangle = vtk.vtkTriangle()
triangle.GetPointIds().SetId(0,i1)
triangle.GetPointIds().SetId(1,i2)
triangle.GetPointIds().SetId(2,iC)
cells.InsertNextCell(triangle)
poly = vtk.vtkPolyData()
poly.SetPoints(points)
poly.SetPolys(cells)
poly.BuildLinks()
return poly
def add_to_renderer(renderer, item, color, opacity=1., linewidth=None):
colors = vtk.vtkNamedColors()
mapper = vtk.vtkPolyDataMapper()
mapper.SetScalarVisibility(False)
if hasattr(item, 'GetOutputPort'):
mapper.SetInputConnection(item.GetOutputPort())
elif isinstance(item, vtk.vtkPolyData):
mapper.SetInputData(item)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(colors.GetColor3d(color))
actor.GetProperty().SetOpacity(opacity)
if linewidth:
actor.GetProperty().SetLineWidth(linewidth)
renderer.AddActor(actor)
return mapper, actor
################################################################################
def run():
# Retrieve the original stl file.
reader = vtk.vtkSTLReader()
reader.SetFileName('improve.stl')
reader.Update()
# Extract the boundary edge in a continuous order.
edge1 = vtk.vtkFeatureEdges()
edge1.SetInputData(reader.GetOutput())
edge1.SetBoundaryEdges(1)
edge1.SetFeatureEdges(0)
edge1.SetNonManifoldEdges(0)
edge1.SetManifoldEdges(0)
edge1.Update()
boundaryStrips = vtk.vtkStripper()
boundaryStrips.SetInputConnection(edge1.GetOutputPort())
boundaryStrips.Update()
edge1 = boundaryStrips.GetOutput()
# Project the boundary edge to xy-plane.
edge2 = vtk.vtkPolyData()
edge2.DeepCopy(edge1)
points2 = edge2.GetPoints()
for i in range(edge2.GetNumberOfPoints()):
p = list(points2.GetPoint(i))
p[2] = 1125
points2.SetPoint(i, p)
bottom = vtk.vtkPolyData()
bottom.DeepCopy(reader.GetOutput())
points = bottom.GetPoints()
for i in range(points.GetNumberOfPoints()):
p = list(points.GetPoint(i))
p[2] = 1125
points.SetPoint(i, p)
# Perform the stitching.
# Requirement: edge1 and edge2 must be oriented the same way!
#edge2 = reverse_lines(edge2)
stitching = stitch(edge1, edge2)
# Combine everything into one polydata object.
combo = vtk.vtkAppendPolyData()
combo.AddInputData(reader.GetOutput())
combo.AddInputData(stitching)
combo.AddInputData(bottom)
combo.Update()
writerFinal = vtk.vtkSTLWriter()
writerFinal.SetFileTypeToBinary()
writerFinal.SetInputData(combo.GetOutput())
writerFinal.SetFileName('output/test2.stl')
writerFinal.Update()
writerFinal.Write()
# Visualize.
renderer = vtk.vtkRenderer()
opacity=1.0
add_to_renderer(renderer=renderer, item=stitching, color='blue', opacity=1.)
add_to_renderer(renderer=renderer, item=bottom, color='red', opacity=1.)
add_to_renderer(renderer=renderer, item=reader, color='white')
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetWindowName("Overlapping cylinders example")
render_window.SetSize(1000,1000)
renderer.SetBackground([0.5]*3)
render_window_interactor = vtk.vtkRenderWindowInteractor()
render_window_interactor.SetRenderWindow(render_window)
render_window.Render()
render_window_interactor.Start()
if __name__ == '__main__':
run()