缩小网格和平面之间的间隙

时间:2018-07-13 08:58:54

标签: vtk

我已将.obj网格文件转换为.stl。我还创建了一个平面几何体作为网格对象的支架,然后合并它们。但是,它存在差距。 有什么建议如何垂直地缩小差距,使其成为一个坚实的对象,我已经尝试过vtkFillHolesFilter和手动方式,但不会填补差距?

我已经附上了屏幕截图,屏幕截图中的红线是我要关闭的位置。enter image description here

创建平面的代码:

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()

1 个答案:

答案 0 :(得分:1)

vtkFillHolesFilter旨在填充孔,而不是填充两个可能断开连接的表面补丁之间的任意间隙。

可能对您有用的是,在我的自由曲面和平面补丁之间缝合一个“缝”,正如我在本文中所概述的:How to triangulate two non-intersecting polylines in 3D。这个想法是沿着边缘走,并根据一些简单的启发式方法创建新的接缝边缘。尽管如果边缘不在同一平面上,则拼接效果很好,但如果边缘分开得太大或太突然,则拼接可能会失败。另外,我建议沿边缘的点数大致相同数量级。

enter image description here


更新:我添加了一个功能示例,演示了您的示例的用法。

重要:拼接算法要求边缘以相同的方式定向!这对于我们为您的表面构造底部的方式很自然。

enter image description here

# 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()