Булевы операции VTK с полиданными, производящие пустые наборы

У меня есть STL гироида, и я хочу обрезать его сферой (предыдущий вопрос)

Теперь у меня есть данные, представленные правильным образом, но всякий раз, когда я выполняю логическую операцию над своими двумя объектами, я получаю пустой результат.

import vtk

colors = vtk.vtkNamedColors()

file_name = 'gyroid.stl' 

# Load poly from STL
reader = vtk.vtkSTLReader()
reader.SetFileName(file_name)
reader.Update()
polyData = reader.GetOutput()

# Centre of poly
x = (polyData.GetBounds()[1] - polyData.GetBounds()[0]) / 2.0
y = (polyData.GetBounds()[3] - polyData.GetBounds()[2]) / 2.0
z = (polyData.GetBounds()[5] - polyData.GetBounds()[4]) / 2.0

# Set up cropping sphere
sphereSource = vtk.vtkSphereSource()
sphereSource.SetCenter(x, y, z)
sphereSource.SetPhiResolution(41)
sphereSource.SetThetaResolution(41)
sphereSource.SetRadius(63)
sphereSource.Update()
sphere = sphereSource.GetOutput()

# Boolean operations on poly with sphere
booleanOperation = vtk.vtkBooleanOperationPolyDataFilter()
booleanOperation.SetOperationToIntersection()
# booleanOperation.SetOperationToDifference()
# booleanOperation.SetOperationToUnion()
booleanOperation.SetInputData(0, polyData)
booleanOperation.SetInputData(1, sphere)

# # Output result to STL
# stlWriter = vtk.vtkSTLWriter()
# stlWriter.SetFileName("sphere_cropped.stl")
# stlWriter.SetInputConnection(booleanOperation.GetOutputPort())
# stlWriter.Write()

# Set up poly for display
polyDataMapper = vtk.vtkPolyDataMapper()
polyDataMapper.SetInputData(polyData)
polyDataMapper.ScalarVisibilityOff()
polyDataActor = vtk.vtkActor()
polyDataActor.SetMapper(polyDataMapper)
polyDataActor.GetProperty().SetDiffuseColor(colors.GetColor3d('Tomato'))
polyDataActor.GetProperty().SetSpecular(0.6)
polyDataActor.GetProperty().SetSpecularPower(20)
polyDataActor.SetPosition(polyData.GetBounds()[1] - polyData.GetBounds()[0], 0, 0)

# Set up sphere for display
sphereMapper = vtk.vtkPolyDataMapper()
sphereMapper.SetInputData(sphere)
sphereMapper.ScalarVisibilityOff()
sphereActor = vtk.vtkActor()
sphereActor.SetMapper(sphereMapper)
sphereActor.GetProperty().SetDiffuseColor(colors.GetColor3d('Mint'))
sphereActor.GetProperty().SetSpecular(0.6)
sphereActor.GetProperty().SetSpecularPower(20)
sphereActor.SetPosition(-(polyData.GetBounds()[1] - polyData.GetBounds()[0]), 0, 0)

# Set up Boolean result for display
booleanOperationMapper = vtk.vtkPolyDataMapper()
booleanOperationMapper.SetInputConnection(booleanOperation.GetOutputPort())
booleanOperationMapper.ScalarVisibilityOff()
booleanOperationActor = vtk.vtkActor()
booleanOperationActor.SetMapper(booleanOperationMapper)
booleanOperationActor.GetProperty().SetDiffuseColor(colors.GetColor3d('Banana'))
booleanOperationActor.GetProperty().SetSpecular(0.6)
booleanOperationActor.GetProperty().SetSpecularPower(20)

# Display all
renderer = vtk.vtkRenderer()
renderer.AddViewProp(polyDataActor)
renderer.AddViewProp(sphereActor)
renderer.AddViewProp(booleanOperationActor)
renderer.SetBackground(colors.GetColor3d('Silver'))
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindow.SetSize(640, 480)
renderWindow.SetWindowName('BooleanOperationPolyDataFilter')
renWinInteractor = vtk.vtkRenderWindowInteractor()
renWinInteractor.SetRenderWindow(renderWindow)
renderWindow.Render()
renWinInteractor.Start()

Я понимаю, что гироиды представляют собой сложные поверхности, и мне было интересно, не в этом ли проблема? Нужно ли мне дополнительно обрабатывать полигональные данные, прежде чем я получу разумные ответы, или это просто тот случай, когда логические операторы VTK не работают?

Код для генерации gyroid.stl

import numpy as np
from numpy import sin, cos, pi
from skimage import measure
import stl
from stl import mesh


def gyroid(x, y, z, t):
    return cos(x)*sin(y) + cos(y)*sin(z) + cos(z)*sin(x) + t

lattice_param = 1.5
strut_param = 0 
resolution = 127j 
x, y, z = pi*np.mgrid[-1:1:resolution, -1:1:resolution, -1:1:resolution] * lattice_param
vol = gyroid(x, y, z, strut_param)

verts, faces, normals, values = measure.marching_cubes_lewiner(vol, 0, spacing=(0.1, 0.1, 0.1)) 
                            

data = np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype)
gyr_mesh = mesh.Mesh(data, remove_empty_areas=False)

for i, f in enumerate(faces):
    for j in range(3):
        gyr_mesh.vectors[i][j] = verts[f[j],:] * 10.0
        
gyr_mesh.save('gyroid.stl')

person DrBwts    schedule 03.12.2020    source источник


Ответы (1)


Я опубликовал возможное решение здесь. Вариант с использованием логического фильтра дает разумные результаты:

from vedo import *
import numpy as np

x, y, z = np.mgrid[:30,:30,:30] * 0.4
U = sin(x)*cos(y) + sin(y)*cos(z) + sin(z)*cos(x)

# Create a Volume, take the isosurface at 0 and smooth it
g = Volume(U).isosurface(0).smoothLaplacian()

# Intersect with a sphere
s = Sphere(pos=(15,15,15), r=14, quads=True).triangulate()
gxs = g.boolean('intersect',s).clean().computeNormals()
gxs.color('silver').lighting('metallic')

show([[g,s],gxs], N=2, bg='wheat', bg2='lightblue', axes=5)

введите здесь описание изображения

person mmusy    schedule 04.12.2020