Skip to content

Blow

vtk-examples/Cxx/Visualization/Blow


Description

Extrusion blow molding process.

In the extrusion blow molding process, a material is extruded through an annular die to form a hollow cylinder. This cylinder is called a parison. Two mold halves are then closed on the parison, while at the same time the parison is inflated with air. Some of the parison material remains within the mold while some becomes waste material. The material is typically a polymer plastic softened with heat, but blow molding has been used to form metal parts. Plastic bottles are often manufactured using a blow molding process.

In this example the polymer was molded using an isothermal, nonlinear-elastic, incompressible (rubber-like) material. Triangular membrane finite elements were used to model the parison, while a combination of triangular and quadrilateral finite elements were used to model the mold. The mold surface is assumed to be rigid, and the parison is assumed to attach to the mold upon contact. Thus the thinning of the parison is controlled by its stretching during inflation and the sequence in which it contacts the mold.

Ten steps of the analysis are illustrated. The color of the parison indicates its thickness. Using a rainbow scale, red areas are thinnest while blue regions are thickest. Our visualization shows clearly one problem with the analysis technique we are using. Note that while the nodes (i.e., points) of the finite element mesh are prevented from passing through the mold, the interior of the triangular elements are not. This is apparent from the occlusion of the mold wireframe by the parison mesh.

You can also view the individual steps.

Other languages

See (Python)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

Blow.cxx

#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkConnectivityFilter.h>
#include <vtkContourFilter.h>
#include <vtkDataSetMapper.h>
#include <vtkDataSetReader.h>
#include <vtkGeometryFilter.h>
#include <vtkLookupTable.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkPolyDataNormals.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkUnstructuredGrid.h>
#include <vtkWarpVector.h>

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    std::cout << "Usage: " << argv[0] << " filename [data_point] e.g. blow.vtk"
              << std::endl;
    std::cout << "where: filename is blow.vtk." << std::endl;
    std::cout << "       data_point allows you to specify which frame is to be "
                 "displayed."
              << std::endl;
    std::cout << "       If data_point < 0 or data_point > 9 all ten "
                 "frames are then displayed."
              << std::endl;
    return EXIT_FAILURE;
  }

  // Default is to display all ten frames.
  auto dataPoint = -1;
  std::string fileName = argv[1];
  if (argc > 2)
  {
    dataPoint = atoi(argv[2]);
  }

  vtkNew<vtkNamedColors> colors;

  std::vector<std::string> thickness;
  std::vector<std::string> displacement;
  for (auto i = 0; i < 10; ++i)
  {
    std::ostringstream os;
    os << i;
    thickness.push_back("thickness" + os.str());
    displacement.push_back("displacement" + os.str());
    os.str("");
  }

  std::vector<vtkSmartPointer<vtkDataSetReader>> reader;
  std::vector<vtkSmartPointer<vtkWarpVector>> warp;
  std::vector<vtkSmartPointer<vtkConnectivityFilter>> connect;
  std::vector<vtkSmartPointer<vtkGeometryFilter>> mold;
  std::vector<vtkSmartPointer<vtkDataSetMapper>> moldMapper;
  std::vector<vtkSmartPointer<vtkActor>> moldActor;
  std::vector<vtkSmartPointer<vtkConnectivityFilter>> connect2;
  std::vector<vtkSmartPointer<vtkGeometryFilter>> parison;
  std::vector<vtkSmartPointer<vtkPolyDataNormals>> normals2;
  std::vector<vtkSmartPointer<vtkPolyDataMapper>> parisonMapper;
  std::vector<vtkSmartPointer<vtkActor>> parisonActor;
  std::vector<vtkSmartPointer<vtkContourFilter>> cf;
  std::vector<vtkSmartPointer<vtkPolyDataMapper>> contourMapper;
  std::vector<vtkSmartPointer<vtkActor>> contours;
  std::vector<vtkSmartPointer<vtkRenderer>> ren;

  vtkNew<vtkLookupTable> lut;
  lut->SetHueRange(0.0, 0.66667);

  for (auto i = 0; i < 10; ++i)
  {
    // Create the reader and warp the data vith vectors.
    reader.push_back(vtkSmartPointer<vtkDataSetReader>::New());
    reader[i]->SetFileName(fileName.c_str());
    reader[i]->SetScalarsName(thickness[i].c_str());
    reader[i]->SetVectorsName(displacement[i].c_str());
    reader[i]->Update();

    warp.push_back(vtkSmartPointer<vtkWarpVector>::New());
    warp[i]->SetInputData(reader[i]->GetUnstructuredGridOutput());

    // Extract the mold from the mesh using connectivity.
    connect.push_back(vtkSmartPointer<vtkConnectivityFilter>::New());
    connect[i]->SetInputConnection(warp[i]->GetOutputPort());
    connect[i]->SetExtractionModeToSpecifiedRegions();
    connect[i]->AddSpecifiedRegion(0);
    connect[i]->AddSpecifiedRegion(1);
    mold.push_back(vtkSmartPointer<vtkGeometryFilter>::New());
    mold[i]->SetInputConnection(connect[i]->GetOutputPort());
    moldMapper.push_back(vtkSmartPointer<vtkDataSetMapper>::New());
    moldMapper[i]->SetInputConnection(mold[i]->GetOutputPort());
    moldMapper[i]->ScalarVisibilityOff();
    moldActor.push_back(vtkSmartPointer<vtkActor>::New());
    moldActor[i]->SetMapper(moldMapper[i]);
    moldActor[i]->GetProperty()->SetColor(
        colors->GetColor3d("ivory_black").GetData());
    moldActor[i]->GetProperty()->SetRepresentationToWireframe();

    // Extract the parison from the mesh using connectivity.
    connect2.push_back(vtkSmartPointer<vtkConnectivityFilter>::New());
    connect2[i]->SetInputConnection(warp[i]->GetOutputPort());
    connect2[i]->SetExtractionModeToSpecifiedRegions();
    connect2[i]->AddSpecifiedRegion(2);
    parison.push_back(vtkSmartPointer<vtkGeometryFilter>::New());
    parison[i]->SetInputConnection(connect2[i]->GetOutputPort());
    normals2.push_back(vtkSmartPointer<vtkPolyDataNormals>::New());
    normals2[i]->SetInputConnection(parison[i]->GetOutputPort());
    normals2[i]->SetFeatureAngle(60);
    parisonMapper.push_back(vtkSmartPointer<vtkPolyDataMapper>::New());
    parisonMapper[i]->SetInputConnection(normals2[i]->GetOutputPort());
    parisonMapper[i]->SetLookupTable(lut);
    parisonMapper[i]->SetScalarRange(0.12, 1.0);
    parisonActor.push_back(vtkSmartPointer<vtkActor>::New());
    parisonActor[i]->SetMapper(parisonMapper[i]);

    cf.push_back(vtkSmartPointer<vtkContourFilter>::New());
    cf[i]->SetInputConnection(connect2[i]->GetOutputPort());
    cf[i]->SetValue(0, 0.5);
    contourMapper.push_back(vtkSmartPointer<vtkPolyDataMapper>::New());
    contourMapper[i]->SetInputConnection(cf[i]->GetOutputPort());
    contours.push_back(vtkSmartPointer<vtkActor>::New());
    contours[i]->SetMapper(contourMapper[i]);

    ren.push_back(vtkSmartPointer<vtkRenderer>::New());
    ren[i]->AddActor(moldActor[i]);
    ren[i]->AddActor(parisonActor[i]);
    ren[i]->AddActor(contours[i]);
    ren[i]->SetBackground(colors->GetColor3d("AliceBlue").GetData());
    ren[i]->GetActiveCamera()->SetPosition(50.973277, 12.298821, 29.102547);
    ren[i]->GetActiveCamera()->SetFocalPoint(0.141547, 12.298821, -0.245166);
    ren[i]->GetActiveCamera()->SetViewUp(-0.500000, 0.000000, 0.866025);
    ren[i]->GetActiveCamera()->SetClippingRange(36.640827, 78.614680);
  }

  // Create the RenderWindow and RenderWindowInteractor.
  vtkNew<vtkRenderWindow> renWin;
  vtkNew<vtkRenderWindowInteractor> iren;
  iren->SetRenderWindow(renWin);
  auto rendererSizeX = 750;
  auto rendererSizeY = 400;
  auto renWinScale = 0.5;
  renWin->SetWindowName("Blow");
  if (dataPoint >= 0 && dataPoint < 10)
  {
    renWin->AddRenderer(ren[dataPoint]);
    renWin->SetSize(rendererSizeX, rendererSizeY);
  }
  else
  {
    auto gridDimensionsX = 2;
    auto gridDimensionsY = 5;
    renWin->SetSize(int(rendererSizeX * gridDimensionsX * renWinScale),
                    int(rendererSizeY * gridDimensionsY * renWinScale));
    // Add and position the renders to the render window.
    for (auto row = 0; row < gridDimensionsY; ++row)
    {
      for (auto col = 0; col < gridDimensionsX; ++col)
      {
        auto idx = row * gridDimensionsX + col;
        auto x0 = double(col) / gridDimensionsX;
        auto y0 = double(gridDimensionsY - row - 1) / gridDimensionsY;
        auto x1 = double(col + 1) / gridDimensionsX;
        auto y1 = double(gridDimensionsY - row) / gridDimensionsY;
        renWin->AddRenderer(ren[idx]);
        ren[idx]->SetViewport(x0, y0, x1, y1);
      }
    }
  }

  renWin->Render();
  iren->Initialize();
  iren->Start();

  return EXIT_SUCCESS;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(Blow)

find_package(VTK COMPONENTS 
  CommonColor
  CommonCore
  CommonDataModel
  FiltersCore
  FiltersGeneral
  FiltersGeometry
  IOLegacy
  InteractionStyle
  RenderingContextOpenGL2
  RenderingCore
  RenderingFreeType
  RenderingGL2PSOpenGL2
  RenderingOpenGL2
)

if (NOT VTK_FOUND)
  message(FATAL_ERROR "Blow: Unable to find the VTK build folder.")
endif()

# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(Blow MACOSX_BUNDLE Blow.cxx )
  target_link_libraries(Blow PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
  TARGETS Blow
  MODULES ${VTK_LIBRARIES}
)

Download and Build Blow

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

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

./Blow

WINDOWS USERS

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