# MarchingCases

VTKExamples/Cxx/VisualizationAlgorithms/MarchingCases

### Description

This example will help you understand the Marching Cubes Algorithm. The example takes one optional argument, a case number. There are 14 Marching Cubes cases, 1-14. There are also 14 complementary cases where the inside/outside value is flipped. To see a complementray case, supply a negative case number. For example, -7 is the complementary case of 7.

Note

According to the ACM Digital Library, the Marching Cubes paper is the most cited Siggraph paper.

### Code

MarchingCases.cxx

    #include <vtkContourFilter.h>
    #include <vtkCubeSource.h>
    #include <vtkExtractEdges.h>
    #include <vtkFloatArray.h>
    #include <vtkGlyph3D.h>
    #include <vtkIdList.h>
    #include <vtkNamedColors.h>
    #include <vtkPoints.h>
    #include <vtkPointData.h>

    #include <vtkActor.h>
    #include <vtkCamera.h>
    #include <vtkPolyDataMapper.h>
    #include <vtkProperty.h>
    #include <vtkRenderWindow.h>
    #include <vtkRenderWindowInteractor.h>
    #include <vtkRenderer.h>
    #include <vtkShrinkPolyData.h>
    #include <vtkSphereSource.h>
    #include <vtkThresholdPoints.h>
    #include <vtkTransform.h>
    #include <vtkTransformPolyDataFilter.h>
    #include <vtkTubeFilter.h>
    #include <vtkUnstructuredGrid.h>
    #include <vtkVectorText.h>

    #include <map>

    void case1 (vtkFloatArray *, vtkVectorText *, int, int);
    void case2 (vtkFloatArray *, vtkVectorText *, int, int);
    void case3 (vtkFloatArray *, vtkVectorText *, int, int);
    void case4 (vtkFloatArray *, vtkVectorText *, int, int);
    void case5 (vtkFloatArray *, vtkVectorText *, int, int);
    void case6 (vtkFloatArray *, vtkVectorText *, int, int);
    void case7 (vtkFloatArray *, vtkVectorText *, int, int);
    void case8 (vtkFloatArray *, vtkVectorText *, int, int);
    void case9 (vtkFloatArray *, vtkVectorText *, int, int);
    void case10(vtkFloatArray *, vtkVectorText *, int, int);
    void case11(vtkFloatArray *, vtkVectorText *, int, int);
    void case12(vtkFloatArray *, vtkVectorText *, int, int);
    void case13(vtkFloatArray *, vtkVectorText *, int, int);
    void case14(vtkFloatArray *, vtkVectorText *, int, int);

    int main (int argc, char *argv[])
    {
      std::map<int, void (*)(vtkFloatArray*, vtkVectorText*, int, int)> cases;
      cases[1]  = &case1;
      cases[2]  = &case2;
      cases[3]  = &case3;
      cases[4]  = &case4;
      cases[5]  = &case5;
      cases[6]  = &case6;
      cases[7]  = &case7;
      cases[8]  = &case8;
      cases[9]  = &case9;
      cases[10] = &case10;
      cases[11] = &case11;
      cases[12] = &case12;
      cases[13] = &case13;
      cases[14] = &case14;

      int mcCase = 12;
      if (argc > 1)
      {
      mcCase = atoi(argv[1]);
      }
      if (std::abs(mcCase) < 1 || std::abs(mcCase) > 14)
        {
          std::cout << argv[0] << " bad case number " << mcCase << std::endl;
          return EXIT_FAILURE;
        }
      vtkSmartPointer<vtkNamedColors> color =
        vtkSmartPointer<vtkNamedColors>::New();

    // Define a Single Cube
      vtkSmartPointer<vtkFloatArray> Scalars =
        vtkSmartPointer<vtkFloatArray>::New();
      Scalars->InsertNextValue(1.0);
      Scalars->InsertNextValue(0.0);
      Scalars->InsertNextValue(0.0);
      Scalars->InsertNextValue(1.0);
      Scalars->InsertNextValue(0.0);
      Scalars->InsertNextValue(0.0);
      Scalars->InsertNextValue(0.0);
      Scalars->InsertNextValue(0.0);

      vtkSmartPointer<vtkPoints> Points =
        vtkSmartPointer<vtkPoints>::New();
      Points->InsertNextPoint(0, 0, 0);
      Points->InsertNextPoint(1, 0, 0);
      Points->InsertNextPoint(1, 1, 0);
      Points->InsertNextPoint(0, 1, 0);
      Points->InsertNextPoint(0, 0, 1);
      Points->InsertNextPoint(1, 0, 1);
      Points->InsertNextPoint(1, 1, 1);
      Points->InsertNextPoint(0, 1, 1);

      vtkSmartPointer<vtkIdList> Ids =
        vtkSmartPointer<vtkIdList>::New();
      Ids->InsertNextId(0);
      Ids->InsertNextId(1);
      Ids->InsertNextId(2);
      Ids->InsertNextId(3);
      Ids->InsertNextId(4);
      Ids->InsertNextId(5);
      Ids->InsertNextId(6);
      Ids->InsertNextId(7);

      vtkSmartPointer<vtkUnstructuredGrid> Grid =
        vtkSmartPointer<vtkUnstructuredGrid>::New();
      Grid->Allocate(10, 10);
      Grid->InsertNextCell(12, Ids);
      Grid->SetPoints(Points);
      Grid->GetPointData()->SetScalars(Scalars);

    // Find the triangles that lie along the 0.5 contour in this cube.
      vtkSmartPointer<vtkContourFilter> Marching =
        vtkSmartPointer<vtkContourFilter>::New();
      Marching->SetInputData(Grid);
      Marching->SetValue(0, 0.5);
      Marching->Update();

    // Extract the edges of the triangles just found.
      vtkSmartPointer<vtkExtractEdges> triangleEdges =
        vtkSmartPointer<vtkExtractEdges>::New();
      triangleEdges->SetInputConnection(Marching->GetOutputPort());

    // Draw the edges as tubes instead of lines.  Also create the associated
    // mapper and actor to display the tubes.
      vtkSmartPointer<vtkTubeFilter> triangleEdgeTubes =
        vtkSmartPointer<vtkTubeFilter>::New();
      triangleEdgeTubes->SetInputConnection(triangleEdges->GetOutputPort());
      triangleEdgeTubes->SetRadius(.005);
      triangleEdgeTubes->SetNumberOfSides(6);
      triangleEdgeTubes->UseDefaultNormalOn();
      triangleEdgeTubes->SetDefaultNormal(.577, .577, .577);
      vtkSmartPointer<vtkPolyDataMapper> triangleEdgeMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
      triangleEdgeMapper->SetInputConnection(triangleEdgeTubes->GetOutputPort());
      triangleEdgeMapper->ScalarVisibilityOff();
      vtkSmartPointer<vtkActor> triangleEdgeActor =
        vtkSmartPointer<vtkActor>::New();
      triangleEdgeActor->SetMapper(triangleEdgeMapper);
      triangleEdgeActor->GetProperty()->SetDiffuseColor(
        color->GetColor3d("lamp_black").GetData());
      triangleEdgeActor->GetProperty()->SetSpecular(.4);
      triangleEdgeActor->GetProperty()->SetSpecularPower(10);

    // Shrink the triangles we found earlier.  Create the associated mapper
    // and actor.  Set the opacity of the shrunken triangles.
      vtkSmartPointer<vtkShrinkPolyData> aShrinker =
        vtkSmartPointer<vtkShrinkPolyData>::New();
      aShrinker->SetShrinkFactor(1);
      aShrinker->SetInputConnection(Marching->GetOutputPort());
      vtkSmartPointer<vtkPolyDataMapper> aMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
      aMapper->ScalarVisibilityOff();
      aMapper->SetInputConnection(aShrinker->GetOutputPort());
      vtkSmartPointer<vtkActor> Triangles =
        vtkSmartPointer<vtkActor>::New();
      Triangles->SetMapper(aMapper);
      Triangles->GetProperty()->SetDiffuseColor(
        color->GetColor3d("banana").GetData());
      Triangles->GetProperty()->SetOpacity(.6);

    // Draw a cube the same size and at the same position as the one
    // created previously.  Extract the edges because we only want to see
    // the outline of the cube.  Pass the edges through a vtkTubeFilter so
    // they are displayed as tubes rather than lines.
      vtkSmartPointer<vtkCubeSource> CubeModel =
        vtkSmartPointer<vtkCubeSource>::New();
      CubeModel->SetCenter(.5, .5, .5);
      vtkSmartPointer<vtkExtractEdges> Edges =
        vtkSmartPointer<vtkExtractEdges>::New();
      Edges->SetInputConnection(CubeModel->GetOutputPort());
      vtkSmartPointer<vtkTubeFilter> Tubes =
        vtkSmartPointer<vtkTubeFilter>::New();
      Tubes->SetInputConnection(Edges->GetOutputPort());
      Tubes->SetRadius(.01);
      Tubes->SetNumberOfSides(6);
      Tubes->UseDefaultNormalOn();
      Tubes->SetDefaultNormal(.577, .577, .577);
    // Create the mapper and actor to display the cube edges.
      vtkSmartPointer<vtkPolyDataMapper> TubeMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
      TubeMapper->SetInputConnection(Tubes->GetOutputPort());
      vtkSmartPointer<vtkActor> CubeEdges =
        vtkSmartPointer<vtkActor>::New();
      CubeEdges->SetMapper(TubeMapper);
      CubeEdges->GetProperty()->SetDiffuseColor(
        color->GetColor3d("khaki").GetData());
      CubeEdges->GetProperty()->SetSpecular(.4);
      CubeEdges->GetProperty()->SetSpecularPower(10);

    // Create a sphere to use as a glyph source for vtkGlyph3D.
      vtkSmartPointer<vtkSphereSource> Sphere =
        vtkSmartPointer<vtkSphereSource>::New();
      Sphere->SetRadius(0.04);
      Sphere->SetPhiResolution(20);
      Sphere->SetThetaResolution(20);
    // Remove the part of the cube with data values below 0.5.
      vtkSmartPointer<vtkThresholdPoints> ThresholdIn =
        vtkSmartPointer<vtkThresholdPoints>::New();
      ThresholdIn->SetInputData(Grid);
      ThresholdIn->ThresholdByUpper(.5);
    // Display spheres at the vertices remaining in the cube data set after
    // it was passed through vtkThresholdPoints.
      vtkSmartPointer<vtkGlyph3D> Vertices =
        vtkSmartPointer<vtkGlyph3D>::New();
      Vertices->SetInputConnection(ThresholdIn->GetOutputPort());
      Vertices->SetSourceConnection(Sphere->GetOutputPort());
    // Create a mapper and actor to display the glyphs.
      vtkSmartPointer<vtkPolyDataMapper> SphereMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
      SphereMapper->SetInputConnection(Vertices->GetOutputPort());
      SphereMapper->ScalarVisibilityOff();
      vtkSmartPointer<vtkActor> CubeVertices =
        vtkSmartPointer<vtkActor>::New();
      CubeVertices->SetMapper(SphereMapper);
      CubeVertices->GetProperty()->SetDiffuseColor(
        color->GetColor3d("tomato").GetData());

    // Define the text for the label
      vtkSmartPointer<vtkVectorText> caseLabel =
        vtkSmartPointer<vtkVectorText>::New();
      caseLabel->SetText("Case 1");

    // Set up a transform to move the label to a new position.
      vtkSmartPointer<vtkTransform> aLabelTransform =
        vtkSmartPointer<vtkTransform>::New();
      aLabelTransform->Identity();
      aLabelTransform->Translate(-0.2, 0, 1.25);
      aLabelTransform->Scale(.05, .05, .05);

    // Move the label to a new position.
      vtkSmartPointer<vtkTransformPolyDataFilter> labelTransform =
        vtkSmartPointer<vtkTransformPolyDataFilter>::New();
      labelTransform->SetTransform(aLabelTransform);
      labelTransform->SetInputConnection(caseLabel->GetOutputPort());

    // Create a mapper and actor to display the text.
      vtkSmartPointer<vtkPolyDataMapper> labelMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
      labelMapper->SetInputConnection(labelTransform->GetOutputPort());

      vtkSmartPointer<vtkActor> labelActor =
        vtkSmartPointer<vtkActor>::New();
      labelActor->SetMapper(labelMapper);

    // Define the base that the cube sits on.  Create its associated mapper
    // and actor.  Set the position of the actor.
      vtkSmartPointer<vtkCubeSource> baseModel =
        vtkSmartPointer<vtkCubeSource>::New();
      baseModel->SetXLength(1.5);
      baseModel->SetYLength(.01);
      baseModel->SetZLength(1.5);
      vtkSmartPointer<vtkPolyDataMapper> baseMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
      baseMapper->SetInputConnection(baseModel->GetOutputPort());
      vtkSmartPointer<vtkActor> base =
        vtkSmartPointer<vtkActor>::New();
      base->SetMapper(baseMapper);
      base->SetPosition(.5, -0.09, .5);

    // Create the Renderer, RenderWindow, and RenderWindowInteractor
      vtkSmartPointer<vtkRenderer> ren =
        vtkSmartPointer<vtkRenderer>::New();
      vtkSmartPointer<vtkRenderWindow> renWin =
        vtkSmartPointer<vtkRenderWindow>::New();
      renWin->AddRenderer(ren);
      renWin->SetSize(640, 480);
      vtkSmartPointer<vtkRenderWindowInteractor> iren =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
      iren->SetRenderWindow(renWin);

    // Add the actors to the renderer
      ren->AddActor(triangleEdgeActor);
      ren->AddActor(base);
      ren->AddActor(labelActor);
      ren->AddActor(CubeEdges);
      ren->AddActor(CubeVertices);
      ren->AddActor(Triangles);

    // Set the background color.
      ren->SetBackground(color->GetColor3d("slate_grey").GetData());

    // Set the scalar values for this case of marching cubes.
      // A negative case number will generate a complementary case
      if (mcCase < 0)
      {
        cases[-mcCase](Scalars, caseLabel, 0, 1);
      }
      else
      {
        cases[mcCase](Scalars, caseLabel, 1, 0);
      }
    // Force the grid to update.
      Grid->Modified();

    // Position the camera.
      ren->GetActiveCamera()->Dolly(1.2);
      ren->GetActiveCamera()->Azimuth(30);
      ren->GetActiveCamera()->Elevation(20);
      ren->ResetCamera();
      ren->ResetCameraClippingRange();

      iren->Initialize();
      renWin->Render();
      iren->Start();
      return EXIT_SUCCESS;
    }

    void case1(vtkFloatArray *scalars,
               vtkVectorText *caseLabel,
               int IN, int OUT)
    {
      scalars->InsertValue(0, IN);
      scalars->InsertValue(1, OUT);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, OUT);
      scalars->InsertValue(4, OUT);
      scalars->InsertValue(5, OUT);
      scalars->InsertValue(6, OUT);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 1 - 00000001");
      }
      else
      {
        caseLabel->SetText("Case 1c - 11111110");
      }
    }

    void case2(vtkFloatArray *scalars,
               vtkVectorText *caseLabel,
               int IN, int OUT)
    {
      scalars->InsertValue(0, IN);
      scalars->InsertValue(1, IN);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, OUT);
      scalars->InsertValue(4, OUT);
      scalars->InsertValue(5, OUT);
      scalars->InsertValue(6, OUT);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 2 - 00000011");
      }
      else
      {
        caseLabel->SetText("Case 2c - 11111100");
      }
    }

    void case3(vtkFloatArray *scalars,
               vtkVectorText *caseLabel,
               int IN, int OUT)
    {
      scalars->InsertValue(0, IN);
      scalars->InsertValue(1, OUT);
      scalars->InsertValue(2, IN);
      scalars->InsertValue(3, OUT);
      scalars->InsertValue(4, OUT);
      scalars->InsertValue(5, OUT);
      scalars->InsertValue(6, OUT);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 3 - 00000101");
      }
      else
      {
        caseLabel->SetText("Case 3c - 11111010");
      }
    }

    void case4(vtkFloatArray *scalars,
               vtkVectorText *caseLabel,
               int IN, int OUT)
    {
      scalars->InsertValue(0, IN);
      scalars->InsertValue(1, OUT);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, OUT);
      scalars->InsertValue(4, OUT);
      scalars->InsertValue(5, OUT);
      scalars->InsertValue(6, IN);
      scalars->InsertValue(7, OUT);
      if (IN == 1) {
        caseLabel->SetText("Case 4 - 01000001");
      }
      else
      {
        caseLabel->SetText("Case 4c - 10111110");
      }
    }

    void case5(vtkFloatArray *scalars,
               vtkVectorText *caseLabel,
               int IN, int OUT)
    {
      scalars->InsertValue(0, OUT);
      scalars->InsertValue(1, IN);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, OUT);
      scalars->InsertValue(4, IN);
      scalars->InsertValue(5, IN);
      scalars->InsertValue(6, OUT);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 5 - 00110010");
      }
      else
      {
        caseLabel->SetText("Case 5c - 11001101");
      }
    }

    void case6(vtkFloatArray *scalars,
               vtkVectorText *caseLabel,
               int IN, int OUT)
    {
      scalars->InsertValue(0, OUT);
      scalars->InsertValue(1, IN);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, IN);
      scalars->InsertValue(4, IN);
      scalars->InsertValue(5, OUT);
      scalars->InsertValue(6, OUT);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 6 - 00011010");
      }
      else
      {
        caseLabel->SetText("Case 6c - 11100101");
      }
    }

    void case7(vtkFloatArray *scalars,
               vtkVectorText *caseLabel,
               int IN, int OUT)
    {
      scalars->InsertValue(0, IN);
      scalars->InsertValue(1, IN);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, OUT);
      scalars->InsertValue(4, OUT);
      scalars->InsertValue(5, OUT);
      scalars->InsertValue(6, IN);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 7 - 01000011");
      }
      else
      {
        caseLabel->SetText("Case 7c - 10111100");
      }
    }

    void case8(vtkFloatArray *scalars,
               vtkVectorText *caseLabel,
               int IN, int OUT)
    {
      scalars->InsertValue(0, IN);
      scalars->InsertValue(1, IN);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, OUT);
      scalars->InsertValue(4, IN);
      scalars->InsertValue(5, IN);
      scalars->InsertValue(6, OUT);
      scalars->InsertValue(7, OUT);
        if (IN == 1)
        {
          caseLabel->SetText("Case 8 - 00110011");
        }
        else
        {
          caseLabel->SetText("Case 8c - 11001100");
        }
    }

    void case9(vtkFloatArray *scalars,
               vtkVectorText *caseLabel,
               int IN, int OUT)
    {
      scalars->InsertValue(0, OUT);
      scalars->InsertValue(1, IN);
      scalars->InsertValue(2, IN);
      scalars->InsertValue(3, IN);
      scalars->InsertValue(4, OUT);
      scalars->InsertValue(5, OUT);
      scalars->InsertValue(6, IN);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 9 - 01001110");
      }
      else
      {
        caseLabel->SetText("Case 9c - 10110001");
      }
    }
    void case10(vtkFloatArray *scalars,
                vtkVectorText *caseLabel,
                int IN, int OUT)
    {
      scalars->InsertValue(0, IN);
      scalars->InsertValue(1, OUT);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, IN);
      scalars->InsertValue(4, OUT);
      scalars->InsertValue(5, IN);
      scalars->InsertValue(6, IN);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 10 - 01101001");
      }
      else
      {
        caseLabel->SetText("Case 10c - 10010110");
      }
    }

    void case11(vtkFloatArray *scalars,
                vtkVectorText *caseLabel,
                int IN, int OUT)
    {
      scalars->InsertValue(0, IN);
      scalars->InsertValue(1, OUT);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, OUT);
      scalars->InsertValue(4, IN);
      scalars->InsertValue(5, IN);
      scalars->InsertValue(6, IN);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 11 - 01110001");
      }
      else
      {
        caseLabel->SetText("Case 11c - 10001110");
      }
    }

    void case12(vtkFloatArray *scalars,
                vtkVectorText *caseLabel,
                int IN, int OUT)
    {
      scalars->InsertValue(0, OUT);
      scalars->InsertValue(1, IN);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, IN);
      scalars->InsertValue(4, IN);
      scalars->InsertValue(5, IN);
      scalars->InsertValue(6, OUT);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 12 - 00111010");
      }
      else
      {
        caseLabel->SetText("Case 12c - 11000101");
      }
    }

    void case13(vtkFloatArray *scalars,
                vtkVectorText *caseLabel,
                int IN, int OUT)
    {
      scalars->InsertValue(0, OUT);
      scalars->InsertValue(1, IN);
      scalars->InsertValue(2, OUT);
      scalars->InsertValue(3, IN);
      scalars->InsertValue(4, IN);
      scalars->InsertValue(5, OUT);
      scalars->InsertValue(6, IN);
      scalars->InsertValue(7, OUT);
      if (IN == 1)
      {
        caseLabel->SetText("Case 13 - 01011010");
      }
      else
      {
        caseLabel->SetText("Case 13c - 10100101");
      }
    }

    void case14(vtkFloatArray *scalars,
                vtkVectorText *caseLabel,
                int IN, int OUT)
    {
      scalars->InsertValue(0, IN);
      scalars->InsertValue(1, OUT);
      scalars->InsertValue(2, IN);
      scalars->InsertValue(3, IN);
      scalars->InsertValue(4, OUT);
      scalars->InsertValue(5, IN);
      scalars->InsertValue(6, IN);
      scalars->InsertValue(7, IN);
      if (IN == 1)
      {
        caseLabel->SetText("Case 14 - 11101101");
      }
      else
      {
        caseLabel->SetText("Case 14c - 00010010");
      }
    }

### CMakeLists.txt

    cmake_minimum_required(VERSION 2.8)

    PROJECT(MarchingCases)

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

    add_executable(MarchingCases MACOSX_BUNDLE MarchingCases.cxx )

    target_link_libraries(MarchingCases ${VTK_LIBRARIES})

### Download and Build MarchingCases

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

    cd MarchingCases/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:

    ./MarchingCases

WINDOWS USERS

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