VTK中的布尔运算——vtkBooleanOperationPolyDataFilter

【类简介】

该类主要是计算两个输入面定义的容器的并、交、差运算的边缘,需要输入面是流形的,不然结果不可预料。

第一个输出是结果面

第二个输出是两个输入面的交线

具体内容可参考: "Boolean Operations on Surfaces in VTK Without External Libraries" by Cory Quammen, Chris Weigle C., Russ Taylor 

【操作类型】

VTK_UNION  
VTK_INTERSECTION  
VTK_DIFFERENCE
【流程图】  布尔运算也可以用管线流操作,所以本算法的流程类似于下图

VTK中的布尔运算——vtkBooleanOperationPolyDataFilter_第1张图片

【缺陷 limitations】

该类不能很好的处理三角面片共面的情况,应对复杂场景,不适用。


【示例】

#include 
#include 
 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
int main(int argc, char *argv[])
{
  vtkSmartPointer input1;
  vtkSmartPointer input2;
 
  std::string operation("intersection");
 
  if (argc == 4)
    {
    vtkSmartPointer reader1 =
      vtkSmartPointer::New();
    reader1->SetFileName(argv[1]);
    reader1->Update();
    input1 = reader1->GetOutput();
 
    vtkSmartPointer reader2 =
      vtkSmartPointer::New();
    reader2->SetFileName(argv[3]);
    reader2->Update();
    input2 = reader2->GetOutput();
 
    operation = argv[2];
    }
  else
    {
    vtkSmartPointer sphereSource1 =
      vtkSmartPointer::New();
    sphereSource1->SetCenter(.25, 0, 0);
    sphereSource1->Update();
    input1 = sphereSource1->GetOutput();
 
    vtkSmartPointer sphereSource2 =
      vtkSmartPointer::New();
    sphereSource2->Update();
    input2 = sphereSource2->GetOutput();
 
    if (argc == 2)
      {
      operation = argv[1];
      }
    }
 
  vtkSmartPointer input1Mapper =
    vtkSmartPointer::New();
#if VTK_MAJOR_VERSION <= 5
  input1Mapper->SetInputConnection( input1->GetProducerPort() );
#else
  input1Mapper->SetInputData( input1 );
#endif
  input1Mapper->ScalarVisibilityOff();
  vtkSmartPointer input1Actor =
    vtkSmartPointer::New();
  input1Actor->SetMapper( input1Mapper );
  input1Actor->GetProperty()->SetColor(1,0,0);
  input1Actor->SetPosition(
    input1->GetBounds()[1]-input1->GetBounds()[0],
    0, 0);
  vtkSmartPointer input2Mapper =
    vtkSmartPointer::New();
#if VTK_MAJOR_VERSION <= 5
  input2Mapper->SetInputConnection( input2->GetProducerPort() );
#else
  input2Mapper->SetInputData( input2 );
#endif
  input2Mapper->ScalarVisibilityOff();
  vtkSmartPointer input2Actor =
    vtkSmartPointer::New();
  input2Actor->SetMapper( input2Mapper );
  input2Actor->GetProperty()->SetColor(0,1,0);
  input2Actor->SetPosition(
    -(input2->GetBounds()[1]-input2->GetBounds()[0]),
    0, 0);
  vtkSmartPointer booleanOperation =
    vtkSmartPointer::New();
  if (operation == "union")
    {
      booleanOperation->SetOperationToUnion();
    }
  else if (operation == "intersection")
    {
      booleanOperation->SetOperationToIntersection();
    }
  else if (operation == "difference")
    {
      booleanOperation->SetOperationToDifference();
    }
  else
    {
    std::cout << "Unknown operation: " << operation << std::endl;
    return EXIT_FAILURE;
    }
#if VTK_MAJOR_VERSION <= 5
  booleanOperation->SetInputConnection( 0, input1->GetProducerPort() );
  booleanOperation->SetInputConnection( 1, input2->GetProducerPort() );
#else
  booleanOperation->SetInputData( 0, input1 );
  booleanOperation->SetInputData( 1, input2 );
#endif
  vtkSmartPointer booleanOperationMapper =
    vtkSmartPointer::New();
  booleanOperationMapper->SetInputConnection( booleanOperation->GetOutputPort() );
  booleanOperationMapper->ScalarVisibilityOff();
 
  vtkSmartPointer booleanOperationActor =
    vtkSmartPointer::New();
  booleanOperationActor->SetMapper( booleanOperationMapper );
 
  vtkSmartPointer renderer =
    vtkSmartPointer::New();
  renderer->AddViewProp(input1Actor);
  renderer->AddViewProp(input2Actor);
  renderer->AddViewProp(booleanOperationActor);
  renderer->SetBackground(.1, .2, .3);
  vtkSmartPointer renderWindow =
    vtkSmartPointer::New();
  renderWindow->AddRenderer( renderer );
 
  vtkSmartPointer renWinInteractor =
    vtkSmartPointer::New();
  renWinInteractor->SetRenderWindow( renderWindow );
 
  renderWindow->Render();
  renWinInteractor->Start();
 
  return EXIT_SUCCESS;
}

这个例子很简单就不分析了

【类内部实现分析】

int vtkBooleanOperationPolyDataFilter::RequestData(vtkInformation*        vtkNotUsed(request),
	vtkInformationVector** inputVector,
	vtkInformationVector*  outputVector)
{
	vtkInformation* inInfo0 = inputVector[0]->GetInformationObject(0);
	vtkInformation* inInfo1 = inputVector[1]->GetInformationObject(0);
	vtkInformation* outInfo0 = outputVector->GetInformationObject(0);
	vtkInformation* outInfo1 = outputVector->GetInformationObject(1);

	if (!inInfo0 || !inInfo1 || !outInfo0 || !outInfo1)
	{
		return 0;
	}

	vtkPolyData* input0 =
		vtkPolyData::SafeDownCast(inInfo0->Get(vtkDataObject::DATA_OBJECT()));
	vtkPolyData* input1 =
		vtkPolyData::SafeDownCast(inInfo1->Get(vtkDataObject::DATA_OBJECT()));

	vtkPolyData* outputSurface =
		vtkPolyData::SafeDownCast(outInfo0->Get(vtkDataObject::DATA_OBJECT()));     // 输出1: 输出面
	vtkPolyData* outputIntersection =
		vtkPolyData::SafeDownCast(outInfo1->Get(vtkDataObject::DATA_OBJECT()));		// 输出2; 相交线

	if (!input0 || !input1 || !outputSurface || !outputIntersection)				// 无效指针的检查
	{
		return 0;
	}

	// Get intersected versions
	vtkSmartPointer PolyDataIntersection =
		vtkSmartPointer::New();
	PolyDataIntersection->SetInputConnection
		(0, this->GetInputConnection(0, 0));
	PolyDataIntersection->SetInputConnection
		(1, this->GetInputConnection(1, 0));
	PolyDataIntersection->SplitFirstOutputOn();
	PolyDataIntersection->SplitSecondOutputOn();
	PolyDataIntersection->Update();

	outputIntersection->CopyStructure(PolyDataIntersection->GetOutput());
	outputIntersection->GetPointData()->PassData(PolyDataIntersection->GetOutput()->GetPointData());
	outputIntersection->GetCellData()->PassData(PolyDataIntersection->GetOutput()->GetCellData());

	// Compute distances
	vtkSmartPointer PolyDataDistance =
		vtkSmartPointer::New();

	PolyDataDistance->SetInputConnection
		(0, PolyDataIntersection->GetOutputPort( 1 ));								// 求相交线的第二个输出,即第一个输入
	PolyDataDistance->SetInputConnection
		(1, PolyDataIntersection->GetOutputPort( 2 ));								// 求相交线的第三个输出,即第二个输入
	PolyDataDistance->ComputeSecondDistanceOn();									// 计算第二个输入上每个点到第一个输入的有向距离
	PolyDataDistance->Update();

	vtkPolyData* pd0 = PolyDataDistance->GetOutput();								// 第一个输入和对应的scalar
	vtkPolyData* pd1 = PolyDataDistance->GetSecondDistanceOutput();					// a copy of the second input with an additional distance scalar field

	pd0->BuildCells();
	pd0->BuildLinks();
	pd1->BuildCells();
	pd1->BuildLinks();

	// Set up field lists of both points and cells that are shared by
	// the input data sets.
	vtkDataSetAttributes::FieldList pointFields(2);
	pointFields.InitializeFieldList( pd0->GetPointData() );
	pointFields.IntersectFieldList(  pd1->GetPointData() );

	vtkDataSetAttributes::FieldList cellFields(2);
	cellFields.InitializeFieldList( pd0->GetCellData() );
	cellFields.IntersectFieldList(  pd1->GetCellData() );

	// Sort union/intersection.
	vtkSmartPointer< vtkIdList > interList = vtkSmartPointer< vtkIdList >::New(); 
	vtkSmartPointer< vtkIdList > unionList = vtkSmartPointer< vtkIdList >::New();

	this->SortPolyData(pd0, interList, unionList);								  // 面1上的点在面2内, 面1上的点在面2外

	outputSurface->Allocate(pd0);
	outputSurface->GetPointData()->CopyAllocate(pointFields);
	outputSurface->GetCellData()->CopyAllocate(cellFields);

	if ( this->Operation == VTK_UNION || this->Operation == VTK_DIFFERENCE )
	{
		this->CopyCells(pd0, outputSurface, 0, pointFields, cellFields, unionList, false);		// 面1在面2外的点
	}
	else if ( this->Operation == VTK_INTERSECTION )
	{
		this->CopyCells(pd0, outputSurface, 0, pointFields, cellFields, interList, false);		// 面1在面2内的点
	}

	// Label sources for each point and cell.
	vtkSmartPointer< vtkIntArray > pointSourceLabel = vtkSmartPointer< vtkIntArray >::New();
	pointSourceLabel->SetNumberOfComponents(1);
	pointSourceLabel->SetName("PointSource");
	pointSourceLabel->SetNumberOfTuples(outputSurface->GetNumberOfPoints());
	for (vtkIdType ii = 0; ii < outputSurface->GetNumberOfPoints(); ii++)
	{
		pointSourceLabel->InsertValue(ii, 0);
	}	

	vtkSmartPointer< vtkIntArray > cellSourceLabel = vtkSmartPointer< vtkIntArray >::New();
	cellSourceLabel->SetNumberOfComponents(1);
	cellSourceLabel->SetName("CellSource");
	cellSourceLabel->SetNumberOfValues(outputSurface->GetNumberOfCells());
	for (vtkIdType ii = 0; ii < outputSurface->GetNumberOfCells(); ii++)
	{
		cellSourceLabel->InsertValue(ii, 0);
	}

	interList->Reset();
	unionList->Reset();

	this->SortPolyData(pd1, interList, unionList);									 // 面2上的点在面1内, 面2上的点在面1外

	if ( this->Operation == VTK_UNION )
	{
		this->CopyCells(pd1, outputSurface, 1, pointFields, cellFields, unionList, false);			// 面2上的点在面1外
	}
	else if ( this->Operation == VTK_INTERSECTION || this->Operation == VTK_DIFFERENCE )            // 面2上的点在面1内,如果是差会有不同的情况
	{
		this->CopyCells(pd1, outputSurface, 1, pointFields, cellFields, interList,
			(this->ReorientDifferenceCells == 1 &&
			this->Operation == VTK_DIFFERENCE));
	}

	vtkIdType i;
	i = pointSourceLabel->GetNumberOfTuples();
	pointSourceLabel->Resize(outputSurface->GetNumberOfPoints());
	for ( ; i < outputSurface->GetNumberOfPoints(); i++)
	{
		pointSourceLabel->InsertValue(i, 1);
	}

	i = cellSourceLabel->GetNumberOfTuples();
	cellSourceLabel->Resize(outputSurface->GetNumberOfCells());
	for ( ; i < outputSurface->GetNumberOfCells(); i++)
	{
		cellSourceLabel->InsertValue(i, 1);
	}

	outputSurface->GetPointData()->AddArray(pointSourceLabel);
	outputSurface->GetCellData()->AddArray(cellSourceLabel);

	outputSurface->Squeeze();
	outputSurface->GetPointData()->Squeeze();
	outputSurface->GetCellData()->Squeeze();

	return 1;
}

可见内部类的实现主要是参照:


// Labels triangles in mesh as part of the intersection or union surface.
// 标签化 相交或者并面的部分三角形
void vtkBooleanOperationPolyDataFilter::SortPolyData(vtkPolyData* input,
	vtkIdList* interList,
	vtkIdList* unionList)
{
	int numCells = input->GetNumberOfCells();

	vtkDoubleArray *distArray = vtkDoubleArray::SafeDownCast
		( input->GetCellData()->GetArray("Distance") );

	for (int cid = 0; cid < numCells; cid++)
	{

		if ( distArray->GetValue( cid ) > this->Tolerance )
		{
			unionList->InsertNextId( cid );			// 点在面外
		}
		else
		{
			interList->InsertNextId( cid );			// 点在面内
		}
	}
}


你可能感兴趣的:(VTK,vtk,可视化)