# IsoparametricCellsDemo

Repository source: IsoparametricCellsDemo

### Description¶

This example shows the isoparametric cells supported by the VTK. These cells are nonlinear and contain one or more mid-side vertices. Isoparametric elements are typically used in finite element analysis. The term isoparametric is derived from the use of the same shape functions (or interpolation functions) to define the element's geometric shape as are used to define the displacements within the element.

Options are provided to show a wire frame (-w) or to add a back face color (-b). You can also remove the plinth with the (-n) option. If you want a single object, use -o followed by the object number.

This example illustrates each cell's representation using its parametric coordinates (pcoords) as the vertices of the cell. In practice, the vertices will correspond to physical points in a finite element model. Use vtkTessellatorFilter to better see the shape of the cell. See for example, QuadraticHexahedronDemo and QuadraticTetraDemo.

Other languages

See (Python), (PythonicAPI)

Question

### Code¶

IsoparametricCellsDemo.cxx

#include <vtkActor.h>
#include <vtkActor2D.h>
#include <vtkAxesActor.h>
#include <vtkCamera.h>
#include <vtkCellArray.h>
#include <vtkCubeSource.h>
#include <vtkDataSetMapper.h>
#include <vtkGlyph3DMapper.h>
#include <vtkInteractorStyleSwitch.h>
#include <vtkLabeledDataMapper.h>
#include <vtkLightKit.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkPoints.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkProperty2D.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkTextMapper.h>
#include <vtkTextProperty.h>
#include <vtkTransform.h>
#include <vtkTransformFilter.h>
#include <vtkUnstructuredGrid.h>
#include <vtkVersion.h>

#include <vtkCubicLine.h>

#include <vtk_cli11.h>
#include <vtk_fmt.h>
// clang-format off
#include VTK_FMT(fmt/format.h)
// clang-format on

#if VTK_VERSION_NUMBER >= 90020210809ULL
#define VTK_HAS_COW 1
#endif

#if VTK_HAS_COW
#include <vtkCameraOrientationWidget.h>
#endif

#include <algorithm>
#include <cstdlib>
#include <string>
#include <vector>

using cellPair =
std::pair<vtkSmartPointer<vtkUnstructuredGrid>, std::array<double, 3>>;
using cellMap = std::map<unsigned int, cellPair>;

namespace {
/**
* Link the unstructured grid number to the unstructured grid name.
*
* @return The map : {index number, unstructured grid name}
*/
std::map<unsigned int, std::string> SpecifyObjects();

/**
* Make a map consisting of the unstructured grid name,
*  the unstructured grid and it's orientation as
*  Azimuth, Elevation and Zoom in degrees.
*
* @return The map.
*/
cellMap GetUnstructuredGrids();

// These functions return a vtkUnstructured grid corresponding to the object.
template <typename T> vtkNew<vtkUnstructuredGrid> MakeUG(vtkNew<T>);

/**
* Make a tile slightly larger or smaller than the bounds in the
*   X and Z directions and thinner or thicker in the Y direction.
*
* A thickness_ratio of zero reduces the tile to an XZ plane.
*
* @param bounds - the bounds for the tile.
* @param expansionFactor - the expansion factor in the XZ plane.
* @param thicknessRatio - the thickness ratio in the Y direction, >= 0.
* @param shiftY - used to shift the centre of the plinth in the Y-direction.
* @return An actor corresponding to the tile.
*/
vtkNew<vtkActor> MakeTile(double const bounds[],
double const& expansionFactor = 0.5,
double const& thicknessRatio = 0.05,
double shiftY = -0.05);

vtkNew<vtkTextProperty> GetTextProperty();
vtkNew<vtkTextProperty> GetLabelProperty();
vtkNew<vtkProperty> GetBackFaceProperty();
vtkNew<vtkProperty> GetPointActorProperty();
vtkNew<vtkProperty> GetActorProperty();
vtkNew<vtkProperty> GetTileProperty();

} // namespace

int main(int argc, char** argv)
{
CLI::App app{
"Demonstrate the isoparametric cell types found in VTK. "
"The numbers define the ordering of the points making the cell."};

// Define options
auto wireframeOn{false};
app.add_flag("-w, --wireframe", wireframeOn, "Render a wireframe.");
auto backfaceOn{false};
"Display the back face in a different colour.");
unsigned int objectNum = -1;
"The number corresponding to the object.");
auto plinthOff{false};
app.add_flag("-n, --noPlinth", plinthOff, "Remove the plinth.");
CLI11_PARSE(app, argc, argv);
if (wireframeOn && backfaceOn)
{
std::cerr << "error: argument -b/--backface: not allowed with argument "
"-w/--wireframe"
<< std::endl;
return EXIT_FAILURE;
}

auto objects = SpecifyObjects();
// The order here should match the order in specify_objects().
std::vector<unsigned int> objectOrder{21, 22, 23, 36, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35};

// Check for a single object.
auto singleObject = false;
if (objectNum != -1)
{
if (std::count(objectOrder.cbegin(), objectOrder.cend(), objectNum) > 0)
{
singleObject = true;
}
else
{
"Please enter the number corresponding to the object.\n"
<< "Available objects are:" << std::endl;
for (auto obj : objectOrder)
{
std::cerr << fmt::format("{:s} (={:d})", objects[obj], obj)
<< std::endl;
}
return EXIT_FAILURE;
}
}
else
{
singleObject = false;
}

vtkNew<vtkNamedColors> colors;

// Create one sphere for all.
vtkNew<vtkSphereSource> sphere;
sphere->SetPhiResolution(21);
sphere->SetThetaResolution(21);

auto cells = GetUnstructuredGrids();
// The text to be displayed in the viewport.
std::vector<std::string> names;
//  The keys of the objects selected for display.
std::vector<unsigned int> keys;
if (singleObject)
{
names.push_back(fmt::format("{:s} (={:d})", objects[objectNum], objectNum));
keys.push_back(objectNum);
}
else
{
for (auto obj : objectOrder)
{
names.push_back(fmt::format("{:s} (={:d})", objects[obj], obj));
keys.push_back(obj);
}
}

std::vector<unsigned int> addPlinth{24, 25, 12, 26, 27, 29, 31, 32, 33};
std::vector<unsigned int> lines{21, 35};

// Set up the viewports.
auto gridRowDimensions = 4;
auto gridColumnDimensions = 4;
auto rendererSize = 300;
if (singleObject)
{
gridRowDimensions = 1;
gridColumnDimensions = 1;
rendererSize = 1200;
}
std::array<int, 2> windowSize{gridColumnDimensions * rendererSize,
gridRowDimensions * rendererSize};

auto blank = cells.size();
std::vector<std::string> blankViewports;

std::map<std::string, std::array<double, 4>> viewports;
for (int row = 0; row < gridRowDimensions; row++)
{
for (int col = 0; col < gridColumnDimensions; col++)
{
int index = row * gridColumnDimensions + col;

// Set the renderer's viewport dimensions (xmin, ymin, xmax, ymax)
//  within the render window.
// Note that for the Y values, we need to subtract the row index
//  from grid rows because the viewport Y axis points upwards
//  and we want to draw the grid from top to down.
std::array<double, 4> viewport{
static_cast<double>(col) / gridColumnDimensions,
static_cast<double>(gridRowDimensions - row - 1) / gridRowDimensions,
static_cast<double>(col + 1) / gridColumnDimensions,
static_cast<double>(gridRowDimensions - row) / gridRowDimensions};
// std::cout << viewport[0] << " " << viewport[1]
//           << " " << viewport[2] << " "<< viewport[3] << std::endl;
if (index < blank)
{
viewports[names[index]] = viewport;
}
else
{
auto s = fmt::format("vp_{:d}_{:d}", col, row);
viewports[s] = viewport;
blankViewports.push_back(s);
}
}
}

std::map<std::string, vtkSmartPointer<vtkRenderer>> renderers;

vtkNew<vtkRenderWindow> renWin;
renWin->SetWindowName("IsoparametricCellsDemo");
renWin->SetSize(windowSize.data());

vtkNew<vtkRenderWindowInteractor> iRen;
iRen->SetRenderWindow(renWin);
auto is = vtkInteractorStyleSwitch::SafeDownCast(iRen->GetInteractorStyle());
if (is)
{
is->SetCurrentStyleToTrackballCamera();
}

// Create and link the mappers, actors and renderers together.
std::string singleObjectName{""};
unsigned int idx = 0;
for (const auto& key : keys)
{
std::cout << "Creating: " << names[idx] << std::endl;

if (singleObject)
{
singleObjectName = names[idx];
}

auto textProperty = GetTextProperty();
if (singleObject)
{
textProperty->SetFontSize(int(rendererSize / 28));
}
else
{
textProperty->SetFontSize(int(rendererSize / 24));
}

vtkNew<vtkTextMapper> textMapper;
textMapper->SetTextProperty(textProperty);
textMapper->SetInput(names[idx].c_str());

vtkNew<vtkActor2D> textActor;
textActor->SetMapper(textMapper);
textActor->SetPosition(rendererSize / 2.0, 8);

vtkNew<vtkDataSetMapper> mapper;
mapper->SetInputData(cells[key].first);
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
actor->SetProperty(GetActorProperty());

if (wireframeOn ||
std::find(lines.cbegin(), lines.cend(), key) != lines.cend())
{
actor->GetProperty()->SetRepresentationToWireframe();
actor->GetProperty()->SetLineWidth(2);
actor->GetProperty()->SetOpacity(1);
actor->GetProperty()->SetColor(colors->GetColor3d("Black").GetData());
}
else
{
if (backfaceOn)
{
actor->SetBackfaceProperty(GetBackFaceProperty());
}
}

// Label the points.
auto labelProperty = GetLabelProperty();
if (singleObject)
{
labelProperty->SetFontSize(int(rendererSize / 36));
}
else
{
labelProperty->SetFontSize(int(rendererSize / 16));
}

vtkNew<vtkLabeledDataMapper> labelMapper;
labelMapper->SetInputData(cells[key].first);
labelMapper->SetLabelTextProperty(labelProperty);

vtkNew<vtkActor2D> labelActor;
labelActor->SetMapper(labelMapper);

// Glyph the points.
vtkNew<vtkGlyph3DMapper> pointMapper;
pointMapper->SetInputData(cells[key].first);
pointMapper->SetSourceConnection(sphere->GetOutputPort());
pointMapper->ScalingOff();
pointMapper->ScalarVisibilityOff();

vtkNew<vtkActor> pointActor;
pointActor->SetMapper(pointMapper);
pointActor->SetProperty(GetPointActorProperty());

vtkNew<vtkRenderer> renderer;
renderer->SetBackground(colors->GetColor3d("LightSteelBlue").GetData());
renderer->SetViewport(viewports[names[idx]].data());

vtkNew<vtkLightKit> lightKit;

if (!plinthOff)
{
{
auto tileActor =
MakeTile(cells[key].first->GetBounds(), 0.5, 0.01, -0.05);
tileActor->SetProperty(GetTileProperty());
}
}

renderer->ResetCamera();
renderer->GetActiveCamera()->Azimuth(cells[key].second[0]);
renderer->GetActiveCamera()->Elevation(cells[key].second[1]);
renderer->GetActiveCamera()->Dolly(cells[key].second[2]);
renderer->ResetCameraClippingRange();

renderers[names[idx]] = renderer;

++idx;
}

for (const auto& key : blankViewports)
{
vtkNew<vtkRenderer> renderer;
renderer->SetBackground(colors->GetColor3d("LightSteelBlue").GetData());
renderer->SetViewport(viewports[key].data());

renderers[key] = renderer;
}

#if VTK_HAS_COW
vtkNew<vtkCameraOrientationWidget> camOrientManipulator;
#else
vtkNew<vtkAxesActor> axes;
vtkNew<vtkOrientationMarkerWidget> widget;
#endif

if (singleObject)
{
#if VTK_HAS_COW
camOrientManipulator->SetParentRenderer(renderers[singleObjectName]);
camOrientManipulator->SetInteractor(iRen);
// Enable the widget.
camOrientManipulator->On();
#else
double rgba[4]{0.0, 0.0, 0.0, 0.0};
colors->GetColor("Carrot", rgba);
widget->SetOutlineColor(rgba[0], rgba[1], rgba[2]);
widget->SetOrientationMarker(axes);
widget->SetCurrentRenderer(renderers[singleObjectName]);
widget->SetInteractor(iRen);
widget->SetViewport(0.0, 0.0, 0.2, 0.2);
widget->EnabledOn();
widget->InteractiveOn();
#endif
}

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

return EXIT_SUCCESS;
}

namespace {

std::map<unsigned int, std::string> SpecifyObjects()
{
return std::map<unsigned int, std::string>{
{35, "VTK_CUBIC_LINE"},
};
}

cellMap GetUnstructuredGrids()
{
return cellMap{
{29,
{31,
{32,
{70, 22.5, 1.0})},
{33,
{-15, 15, 0.95})},
{35, cellPair(MakeUG(vtkNew<vtkCubicLine>()), {0, 0, 0.85})},
};
}

template <typename T> vtkNew<vtkUnstructuredGrid> MakeUG(vtkNew<T> aCell)
{
double* pcoords = aCell->GetParametricCoords();
for (int i = 0; i < aCell->GetNumberOfPoints(); ++i)
{
aCell->GetPointIds()->SetId(i, i);
aCell->GetPoints()->SetPoint(i, *(pcoords + 3 * i), *(pcoords + 3 * i + 1),
*(pcoords + 3 * i + 2));
}

vtkNew<vtkUnstructuredGrid> ug;
ug->SetPoints(aCell->GetPoints());
ug->InsertNextCell(aCell->GetCellType(), aCell->GetPointIds());
return ug;
}

{

vtkNew<vtkUnstructuredGrid> ug;
return ug;
}

{

double* pcoords = aCell->GetParametricCoords();
for (int i = 0; i < aCell->GetNumberOfPoints(); ++i)
{
aCell->GetPointIds()->SetId(i, i);
aCell->GetPoints()->SetPoint(i, *(pcoords + 3 * i), *(pcoords + 3 * i + 1),
*(pcoords + 3 * i + 2));
}

vtkNew<vtkUnstructuredGrid> ug;
ug->SetPoints(aCell->GetPoints());
ug->InsertNextCell(aCell->GetCellType(), aCell->GetPointIds());

vtkNew<vtkTransform> t;
t->RotateX(-90);
t->Translate(0, 0, 0);

vtkNew<vtkTransformFilter> tf;
tf->SetTransform(t);
tf->SetInputData(ug);
tf->Update();

// Put the transformed points back.
ug->SetPoints(tf->GetOutput()->GetPoints());

return ug;
}

vtkNew<vtkActor> MakeTile(double const bounds[], double const& expansionFactor,
double const& thicknessRatio, double shiftY)
{
std::vector<double> d_xyz = {bounds[1] - bounds[0], bounds[3] - bounds[2],
bounds[5] - bounds[4]};
auto thickness = d_xyz[2] * std::abs(thicknessRatio);
std::vector<double> center = {(bounds[1] + bounds[0]) / 2.0,
bounds[2] - thickness / 2.0,
(bounds[5] + bounds[4]) / 2.0};
auto x_length = bounds[1] - bounds[0] + (d_xyz[0] * expansionFactor);
auto z_length = bounds[5] - bounds[4] + (d_xyz[2] * expansionFactor);

vtkNew<vtkCubeSource> plane;
plane->SetCenter(center[0], center[1] + shiftY, center[2]);
plane->SetXLength(x_length);
plane->SetYLength(thickness);
plane->SetZLength(z_length);

vtkNew<vtkPolyDataMapper> planeMapper;
planeMapper->SetInputConnection(plane->GetOutputPort());

vtkNew<vtkActor> planeActor;
planeActor->SetMapper(planeMapper);

return planeActor;
}

vtkNew<vtkTextProperty> GetTextProperty()
{
vtkNew<vtkNamedColors> colors;

vtkNew<vtkTextProperty> pty;
pty->BoldOn();
pty->SetJustificationToCentered();
pty->SetColor(colors->GetColor3d("Black").GetData());
return pty;
}

vtkNew<vtkTextProperty> GetLabelProperty()
{
vtkNew<vtkNamedColors> colors;

vtkNew<vtkTextProperty> pty;
pty->BoldOn();
pty->SetJustificationToCentered();
pty->SetColor(colors->GetColor3d("DeepPink").GetData());
return pty;
}

vtkNew<vtkProperty> GetBackFaceProperty()
{
vtkNew<vtkNamedColors> colors;

vtkNew<vtkProperty> pty;
pty->SetAmbientColor(colors->GetColor3d("LightSalmon").GetData());
pty->SetDiffuseColor(colors->GetColor3d("OrangeRed").GetData());
pty->SetSpecularColor(colors->GetColor3d("White").GetData());
pty->SetSpecular(0.2);
pty->SetDiffuse(1.0);
pty->SetAmbient(0.2);
pty->SetSpecularPower(20.0);
pty->SetOpacity(1.0);
return pty;
}

vtkNew<vtkProperty> GetActorProperty()
{
vtkNew<vtkNamedColors> colors;

vtkNew<vtkProperty> pty;
pty->SetAmbientColor(colors->GetColor3d("DarkSalmon").GetData());
pty->SetDiffuseColor(colors->GetColor3d("Seashell").GetData());
pty->SetSpecularColor(colors->GetColor3d("White").GetData());
pty->SetSpecular(0.5);
pty->SetDiffuse(0.7);
pty->SetAmbient(0.5);
pty->SetSpecularPower(20.0);
pty->SetOpacity(0.8);
pty->EdgeVisibilityOn();
pty->SetLineWidth(3);
return pty;
}

vtkNew<vtkProperty> GetPointActorProperty()
{
vtkNew<vtkNamedColors> colors;

vtkNew<vtkProperty> pty;
pty->SetAmbientColor(colors->GetColor3d("Gold").GetData());
pty->SetDiffuseColor(colors->GetColor3d("Yellow").GetData());
pty->SetSpecularColor(colors->GetColor3d("White").GetData());
pty->SetSpecular(0.5);
pty->SetDiffuse(0.7);
pty->SetAmbient(0.5);
pty->SetSpecularPower(20.0);
pty->SetOpacity(1.0);
return pty;
}

vtkNew<vtkProperty> GetTileProperty()
{
vtkNew<vtkNamedColors> colors;

vtkNew<vtkProperty> pty;
pty->SetAmbientColor(colors->GetColor3d("SteelBlue").GetData());
pty->SetDiffuseColor(colors->GetColor3d("LightSteelBlue").GetData());
pty->SetSpecularColor(colors->GetColor3d("White").GetData());
pty->SetSpecular(0.5);
pty->SetDiffuse(0.7);
pty->SetAmbient(0.5);
pty->SetSpecularPower(20.0);
pty->SetOpacity(0.8);
pty->EdgeVisibilityOn();
pty->SetLineWidth(1);
return pty;
}

} // namespace


### CMakeLists.txt¶

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(IsoparametricCellsDemo)

find_package(VTK COMPONENTS
CommonColor
CommonCore
CommonDataModel
InteractionStyle
RenderingContextOpenGL2
RenderingCore
RenderingFreeType
RenderingGL2PSOpenGL2
RenderingLabel
RenderingOpenGL2
)

if (NOT VTK_FOUND)
message(FATAL_ERROR "IsoparametricCellsDemo: 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.")
target_link_libraries(IsoparametricCellsDemo PRIVATE ${VTK_LIBRARIES} ) # vtk_module_autoinit is needed vtk_module_autoinit( TARGETS IsoparametricCellsDemo MODULES${VTK_LIBRARIES}
)


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

./IsoparametricCellsDemo


WINDOWS USERS

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