#include <vtkBooleanOperationPolyDataFilter.h>
#include <vtkSphereSource.h>
#include <vtkSTLWriter.h>
#include <vtkAppendPolyData.h>
#include <vtkTriangleFilter.h>
#include <vtkCleanPolyData.h>
#include <vtkLoopBooleanPolyDataFilter.h>

int main(int argc, char **argv)
{
	double center1[3] = { 0.0, 0.0, 0.0 };
	double center3[3] = { 4.0, 0.0, 0.0 };

	double radius1 = 3.0;
	double radius3 = 3.0;

	vtkSmartPointer<vtkSphereSource> sphere1 = vtkSmartPointer<vtkSphereSource>::New();
	sphere1->SetCenter(center1);
	sphere1->SetRadius(radius1);
	sphere1->Update();

	vtkSmartPointer<vtkSphereSource> sphere3 = vtkSmartPointer<vtkSphereSource>::New();
	sphere3->SetCenter(center3);
	sphere3->SetRadius(radius3);
	sphere3->Update();

	// boolOp1 := sphere3 \ sphere1
	vtkSmartPointer<vtkBooleanOperationPolyDataFilter> boolOp1 = vtkSmartPointer<vtkBooleanOperationPolyDataFilter>::New();
	boolOp1->SetOperationToDifference();
	boolOp1->AddInputConnection(0, sphere3->GetOutputPort());
	boolOp1->AddInputConnection(1, sphere1->GetOutputPort());
	boolOp1->Update();

	// triangulate and clean output from boolOp1
	vtkSmartPointer<vtkTriangleFilter> triangleFilter1 = vtkSmartPointer<vtkTriangleFilter>::New();
	triangleFilter1->AddInputConnection(boolOp1->GetOutputPort());
	triangleFilter1->Update();

	vtkSmartPointer<vtkCleanPolyData> cleanFilter1 = vtkSmartPointer<vtkCleanPolyData>::New();
	cleanFilter1->AddInputConnection(triangleFilter1->GetOutputPort());
	cleanFilter1->Update();
	
	// append boolOp1 and sphere1
	vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
	appendFilter->AddInputConnection(cleanFilter1->GetOutputPort());
	appendFilter->AddInputConnection(sphere1->GetOutputPort());
	appendFilter->Update();
	
	// write result to hdd
	vtkSmartPointer<vtkSTLWriter> writer = vtkSmartPointer<vtkSTLWriter>::New();
	writer->SetFileName("D:/boolOp.stl");
	writer->AddInputConnection(appendFilter->GetOutputPort());
	writer->Update();

	return 0;
}