# ContoursToSurface

VTKExamples/Cxx/PolyData/ContoursToSurface

### Description

This example creates a stack of 21 circles and creates a closed surface from them.

### Code

ContoursToSurface.cxx

    #include <vtkVersion.h>
    #include <vtkActor.h>
    #include <vtkAppendPolyData.h>
    #include <vtkCellArray.h>
    #include <vtkMath.h>
    #include <vtkPolyData.h>
    #include <vtkPolyDataMapper.h>
    #include <vtkProperty.h>
    #include <vtkRenderer.h>
    #include <vtkRenderWindow.h>
    #include <vtkRenderWindowInteractor.h>
    #include <vtkSmartPointer.h>
    #include <vtkTransform.h>
    #include <vtkTransformPolyDataFilter.h>
    #include <vtkVoxelContoursToSurfaceFilter.h>

    void CreateCircle(const double& z, const double& radius, const int& resolution, vtkPolyData* polyData);

    int main(int, char *[])
    {
      // Create the data: a series of discs representing the intersections of x-y planes through a unit sphere
      // centered at 0, 0, 0
      //
      int numDivisions = 20;
      int resolution = 100;
      double lastz = 0.;
      double z = 0.;
      double radius = 0.;
      double sphereRadius = 1.;
      double zmin = -0.9*sphereRadius;
      double zmax = 0.9*sphereRadius;

      // Append all the discs into one polydata
      //
      vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();

      for( int i = 0; i <= numDivisions; ++i )
      {
        lastz = z;
        double u = i / double(numDivisions);
        z = ( 1. - u )*zmin + u*zmax;
        radius = sqrt( sphereRadius*sphereRadius - z*z );
        vtkSmartPointer<vtkPolyData> circle = vtkSmartPointer<vtkPolyData>::New();
        CreateCircle( z, radius, resolution, circle );
    #if VTK_MAJOR_VERSION <= 5
        appendFilter->AddInput( circle );
    #else
        appendFilter->AddInputData( circle );
    #endif
      }

      double deltaz = z - lastz;

      if( !appendFilter->GetNumberOfInputConnections(0) )
      {
        cerr << "error, no contours!" << endl;
        return EXIT_FAILURE;
      }

      appendFilter->Update();

      // Convert to ijk coordinates for the contour to surface filter
      //
      double bounds[6];
      vtkPolyData* contours = appendFilter->GetOutput();
      contours->GetBounds( bounds );
      double origin[3]  = { bounds[0], bounds[2], bounds[4] };
      double spacing[3] = { (bounds[1] - bounds[0]) / 40,
                            (bounds[3] - bounds[2]) / 40,
                             deltaz };

      vtkSmartPointer<vtkPolyData> poly = vtkSmartPointer<vtkPolyData>::New();
      vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
      vtkPoints* contourPoints = contours->GetPoints();
      int numPoints = contourPoints->GetNumberOfPoints();
      points->SetNumberOfPoints( numPoints );
      for( int i = 0; i < numPoints; ++i )
      {
        double pt[3];
        contourPoints->GetPoint( i, pt );
        pt[0] = static_cast<int>( (pt[0] - origin[0]) / spacing[0] + 0.5 );
        pt[1] = static_cast<int>( (pt[1] - origin[1]) / spacing[1] + 0.5 );
        pt[2] = static_cast<int>( (pt[2] - origin[2]) / spacing[2] + 0.5 );
        points->SetPoint( i, pt );
      }
      poly->SetPolys( contours->GetPolys() );
      poly->SetPoints( points );

      // Create the contour to surface filter
      //
      vtkSmartPointer<vtkVoxelContoursToSurfaceFilter> contoursToSurface = vtkSmartPointer<vtkVoxelContoursToSurfaceFilter>::New();
    #if VTK_MAJOR_VERSION <= 5
      contoursToSurface->SetInput( poly );
    #else
      contoursToSurface->SetInputData( poly );
    #endif
      contoursToSurface->SetSpacing( spacing[0], spacing[1], spacing[2] );
      contoursToSurface->Update();

      // Rescale the output back into world coordinates and center it
      //
      double scaleCenter[3];
      contoursToSurface->GetOutput()->GetCenter( scaleCenter );
      double scaleBounds[6];
      contoursToSurface->GetOutput()->GetBounds( scaleBounds );
      double center[3];
      contours->GetCenter( center );

      vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
      transformFilter->SetInputConnection( contoursToSurface->GetOutputPort() );
      vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
      transformFilter->SetTransform( transform );
      transform->Translate( -scaleCenter[0], -scaleCenter[1], -scaleCenter[2] );
      transform->Scale(
        (bounds[1] - bounds[0])/(scaleBounds[1] - scaleBounds[0]),
        (bounds[3] - bounds[2])/(scaleBounds[3] - scaleBounds[2]),
        (bounds[5] - bounds[4])/(scaleBounds[5] - scaleBounds[4]) );
      transform->Translate( center[0], center[1], center[2] );

      // Visualize the contours
      //
      vtkSmartPointer<vtkPolyDataMapper> contoursMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    #if VTK_MAJOR_VERSION <= 5
      contoursMapper->SetInput( contours );
    #else
      contoursMapper->SetInputData( contours );
    #endif
      contoursMapper->ScalarVisibilityOff();

      vtkSmartPointer<vtkActor> contoursActor = vtkSmartPointer<vtkActor>::New();
      contoursActor->SetMapper( contoursMapper );
      contoursActor->GetProperty()->SetRepresentationToWireframe();
      contoursActor->GetProperty()->ShadingOff();

      // Visualize the surface
      //
      vtkSmartPointer<vtkPolyDataMapper> surfaceMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
      surfaceMapper->SetInputConnection( transformFilter->GetOutputPort() );
      surfaceMapper->ScalarVisibilityOff();

      vtkSmartPointer<vtkActor> surfaceActor = vtkSmartPointer<vtkActor>::New();
      surfaceActor->SetMapper( surfaceMapper );
      surfaceActor->GetProperty()->SetRepresentationToWireframe();
      surfaceActor->GetProperty()->ShadingOff();

      // Create two renderers side by side to show the contours and the surface separately
      //
      // Press 't' for trackball interaction
      // Press 'r' to reset the camera
      // Press 'w' for wireframe representation
      // Press 's' for surface representation
      //
      vtkSmartPointer<vtkRenderer> renderer1 = vtkSmartPointer<vtkRenderer>::New();
      renderer1->SetViewport( 0., 0., 0.5, 1. );
      renderer1->SetBackground( 0.2, 0.2, 0.8 );

      vtkSmartPointer<vtkRenderer> renderer2 = vtkSmartPointer<vtkRenderer>::New();
      renderer2->SetViewport( 0.5, 0., 1., 1. );
      renderer2->SetBackground( 0.8, 0.2, 0.2 );

      vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
      renderWindow->SetSize( 800, 400 );

      renderWindow->AddRenderer( renderer1 );
      renderWindow->AddRenderer( renderer2 );

      vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
      interactor->SetRenderWindow( renderWindow );

      renderer1->AddViewProp( surfaceActor );
      renderer2->AddViewProp( contoursActor );
      renderWindow->Render();

      interactor->Start();

      return EXIT_SUCCESS;
    }

    void CreateCircle( const double& z, const double& radius, const int& resolution, vtkPolyData* polyData )
    {
      vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
      vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();

      points->SetNumberOfPoints( resolution );
      cells->Allocate( 1, resolution );
      cells->InsertNextCell( resolution );

      for( int i = 0 ; i < resolution; ++i )
      {
        double theta = vtkMath::RadiansFromDegrees(360.*i/double(resolution));
        double x = radius*cos(theta);
        double y = radius*sin(theta);
        points->SetPoint( i, x, y, z );
        cells->InsertCellPoint( i );
      }

      polyData->Initialize();
      polyData->SetPolys( cells );
      polyData->SetPoints( points );
    }

### CMakeLists.txt

    cmake_minimum_required(VERSION 2.8)

    PROJECT(ContoursToSurface)

    find_package(VTK REQUIRED)
    include(${VTK_USE_FILE})

    add_executable(ContoursToSurface MACOSX_BUNDLE ContoursToSurface.cxx )

    target_link_libraries(ContoursToSurface ${VTK_LIBRARIES})

### Download and Build ContoursToSurface

Click here to download ContoursToSurface and its CMakeLists.txt file. Once the tarball ContoursToSurface.tar has been downloaded and extracted,

    cd ContoursToSurface/build

If VTK is installed:

    cmake ..

If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:

    cmake -DVTK_DIR:PATH=/home/me/vtk_build ..

Build the project:

    make

and run it:

    ./ContoursToSurface

WINDOWS USERS PLEASE NOTE: Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.