(Java) Использование функционального (предикатного) интерфейса, который выводит логическое значение из двоичного дерева

vtkFillHolesFilter предназначен для заполнения отверстий, а не произвольных промежутков между двумя, возможно, отключенными поверхностными пластырями.

Что может быть сработает для вас - это сшить «шов» между вашей свободной формой и плоским патчем, как я набросал в этом посте: Как триангулировать две непересекающиеся полилинии в 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()

0
задан Xore 19 January 2019 в 19:57
поделиться

1 ответ

Объект overTwenty, который вы создали, является функцией. Если вы хотите использовать его в узле вашего дерева, вы должны вызвать его единственный метод в узле вашего дерева. Например, вы можете назвать это так:

boolean result = overTwenty.forAll(root);

Кстати, ваш NodeOperation интерфейс вполне эквивалентен Function<Tree, Boolean> с той небольшой разницей, что он возвращает примитив boolean вместо класс Boolean.

0
ответ дан Ricola 19 January 2019 в 19:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: