CappedSphere
VTKExamples/Cxx/Modelling/CappedSphere
Description¶
Demonstrates how to create a capped sphere.
Firstly a line is created in the x-z plane corresponding to an arc from +z to -z in the +x direction in the x-z plane, the length of the arc is specified in degrees.
Then the line is extended by dropping a perpendicular to the x-axis.
The points generated are then converted to a line and passed through to the vtkRotationalExtrusionFilter to generate the resultant 3D surface.
The parameters are:
- angle - the arc length in degrees default 90° (a hemisphere)
- step -the step size of the arc in degrees, default 1°
- radius - the radius of the arc default 1
Options are provided to:
- Uncap the sphere (-u, --uncapped)
- Display the line that was rotationally extruded (-s, --show_line)
Note
The coordinate system for specifying the arc is left-handed with 0° aligned with the positive z-axis, 90° aligned with the positive x-axis.
Note
You can substitute different parametric equations for x and z in the line generating function to get other shapes.
Other Languages
See (Python)
Code¶
CappedSphere.cxx
#include <vtkActor.h> #include <vtkCamera.h> #include <vtkCellArray.h> #include <vtkLine.h> #include <vtkNamedColors.h> #include <vtkPoints.h> #include <vtkPolyData.h> #include <vtkPolyDataMapper.h> #include <vtkProperty.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkRenderer.h> #include <vtkRotationalExtrusionFilter.h> #include <vtkSmartPointer.h> #include <array> #include <cmath> #include <iomanip> #include <iostream> #include <regex> #include <sstream> #include <string> #include <vector> namespace { /** * Get the points for a line. * * @param angle: Length of the arc in degrees. * @param step: Step size in degrees. * @param radius: Radius of the arc. * @param uncapped: True if uncapped. * @param start: Starting angle. * @return: A vector of points. */ std::vector<std::array<double, 3>> GetLine(double const& angle, double const& step, double const& radius, bool const& noCap, double const& start); /** * Show the command line parameters. * * @param fn: The program name. */ std::string ShowUsage(std::string fn); } // namespace int main(int argc, char* argv[]) { // Our degree/radian conversions constexpr auto pi = 3.141592653589793238462643383279502884L; /* pi */ auto d_r = [pi](long double d) { return pi * d / 180.0; }; // auto r_d = [pi](long double r) { return 180 * r / pi; }; auto isNumber = [](std::string& token) { return std::regex_match( token, std::regex(("((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?"))); }; auto angle = 90.0; auto step = 1.0; auto radius = 1.0; auto uncapped = false; auto showLine = false; // The command line arguments std::vector<std::string> cmdVec; for (auto i = 1; i < argc; ++i) { cmdVec.push_back(argv[i]); } if (!cmdVec.empty()) { // Look for parmeters auto posCnt = 0; for (auto token : cmdVec) { if (token == "-h" || token == "--help") { std::cout << ShowUsage(argv[0]) << std::endl; return EXIT_SUCCESS; } if (token == "-u" || token == "--uncapped") { uncapped = true; } if (token == "-s" || token == "--show_line") { showLine = true; } if (isNumber(token) && posCnt < 3) { switch (posCnt) { case 0: angle = std::stod(token); break; case 1: step = std::stod(token); break; case 2: radius = std::stod(token); break; default: break; } posCnt++; } } } angle = d_r(std::abs(angle)); step = d_r(std::abs(step)); radius = std::abs(radius); // With default settings set this to 45 and you get a bowl with a flat bottom. auto start = d_r(90); auto pts = GetLine(angle, step, radius, uncapped, start); // Setup points and lines auto points = vtkSmartPointer<vtkPoints>::New(); auto lines = vtkSmartPointer<vtkCellArray>::New(); for (auto pt : pts) { unsigned long pt_id = points->InsertNextPoint(pt.data()); if (pt_id < pts.size() - 1) { auto line = vtkSmartPointer<vtkLine>::New(); line->GetPointIds()->SetId(0, pt_id); line->GetPointIds()->SetId(1, pt_id + 1); lines->InsertNextCell(line); } } auto polydata = vtkSmartPointer<vtkPolyData>::New(); polydata->SetPoints(points); polydata->SetLines(lines); // Extrude the profile to make the capped sphere auto extrude = vtkSmartPointer<vtkRotationalExtrusionFilter>::New(); extrude->SetInputData(polydata); extrude->SetResolution(60); // Visualize auto colors = vtkSmartPointer<vtkNamedColors>::New(); // To see the line auto lineMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); lineMapper->SetInputData(polydata); auto lineActor = vtkSmartPointer<vtkActor>::New(); lineActor->SetMapper(lineMapper); lineActor->GetProperty()->SetLineWidth(4); lineActor->GetProperty()->SetColor(colors->GetColor3d("Red").GetData()); // To see the surface auto surfaceMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); surfaceMapper->SetInputConnection(extrude->GetOutputPort()); auto surfaceActor = vtkSmartPointer<vtkActor>::New(); surfaceActor->SetMapper(surfaceMapper); surfaceActor->GetProperty()->SetColor(colors->GetColor3d("Khaki").GetData()); auto ren = vtkSmartPointer<vtkRenderer>::New(); auto renWin = vtkSmartPointer<vtkRenderWindow>::New(); renWin->AddRenderer(ren); auto iren = vtkSmartPointer<vtkRenderWindowInteractor>::New(); iren->SetRenderWindow(renWin); ren->AddActor(surfaceActor); if (showLine) { ren->AddActor(lineActor); } ren->SetBackground(colors->GetColor3d("LightSlateGray").GetData()); ren->ResetCamera(); ren->GetActiveCamera()->Azimuth(0); ren->GetActiveCamera()->Elevation(60); ren->ResetCameraClippingRange(); renWin->SetSize(600, 600); renWin->Render(); renWin->SetWindowName("CappedSphere"); iren->Start(); return EXIT_SUCCESS; } namespace { std::vector<std::array<double, 3>> GetLine(double const& angle, double const& step, double const& radius, bool const& uncapped, double const& start) { auto constexpr precision = 1.0e-06; std::vector<std::array<double, 3>> pts; // Do the curved line auto theta = 0.0; while (theta <= angle) { std::array<double, 3> p{{0.0, 0.0, 0.0}}; p[0] = radius * std::cos(start - theta); p[2] = radius * std::sin(theta - start); if (p[0] < 0) { p[0] = 0; pts.push_back(p); break; } if (std::abs(p[0]) < precision) { p[0] = 0; } if (std::abs(p[2]) < precision) { p[2] = 0; } pts.push_back(p); theta += step; } if (!uncapped) { // Drop a perpendicular from the last point to the x-axis if (pts.size() > 1) { std::array<double, 3> lastPoint = pts.back(); if (lastPoint[0] > 0) { auto numPts = 10; auto interval = double(numPts) / radius; auto i = 1; while (i < numPts) { std::array<double, 3> p{{0.0, 0.0, lastPoint[2]}}; p[0] = lastPoint[0] - i / interval; if (p[0] < 0) { p[0] = 0; pts.push_back(p); break; } if (std::abs(p[0]) < precision) { p[0] = 0; } if (std::abs(p[2]) < precision) { p[2] = 0; } pts.push_back(p); ++i; } } lastPoint = pts.back(); if (lastPoint[0] > precision) { std::array<double, 3> p{{0.0, 0.0, lastPoint[2]}}; pts.push_back(p); } } } return pts; } std::string ShowUsage(std::string fn) { // Remove the folder (if present) then emove the extension in this order // since the folder name may contain perionds. auto last_slash_idx = fn.find_last_of("\\/"); if (std::string::npos != last_slash_idx) { fn.erase(0, last_slash_idx + 1); } // auto period_idx = fn.rfind('.'); // if (std::string::npos != period_idx) //{ // fn.erase(period_idx); //} std::ostringstream os; os << "\nusage: " << fn << " [-h] [-u] [-s] [angle] [step] [radius]\n"; os << "\n"; os << "Display a capped sphere.\n"; os << "\n"; os << "positional arguments:\n"; os << " angle The length of the arc in degrees from +z to -z in " "the +x\n"; os << " direction in the x-z plane.\n"; os << " step Step size in degrees.\n"; os << " radius Radius of the arc.\n"; os << "\n"; os << "optional arguments:\n"; os << " -h, --help show this help message and exit\n"; os << " -u, --uncapped Uncap the sphere.\n"; os << " -s, --show_line Show the line that is rotationally extruded to " "make the\n"; os << " surface."; os << std::endl; return os.str(); } } // namespace
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(CappedSphere) find_package(VTK COMPONENTS vtkCommonColor vtkCommonCore vtkCommonDataModel vtkFiltersModeling vtkInteractionStyle vtkRenderingContextOpenGL2 vtkRenderingCore vtkRenderingFreeType vtkRenderingGL2PSOpenGL2 vtkRenderingOpenGL2 QUIET) if (NOT VTK_FOUND) message("Skipping CappedSphere: ${VTK_NOT_FOUND_MESSAGE}") return () endif() message (STATUS "VTK_VERSION: ${VTK_VERSION}") if (VTK_VERSION VERSION_LESS "8.90.0") # old system include(${VTK_USE_FILE}) add_executable(CappedSphere MACOSX_BUNDLE CappedSphere.cxx ) target_link_libraries(CappedSphere PRIVATE ${VTK_LIBRARIES}) else () # include all components add_executable(CappedSphere MACOSX_BUNDLE CappedSphere.cxx ) target_link_libraries(CappedSphere PRIVATE ${VTK_LIBRARIES}) # vtk_module_autoinit is needed vtk_module_autoinit( TARGETS CappedSphere MODULES ${VTK_LIBRARIES} ) endif ()
Download and Build CappedSphere¶
Click here to download CappedSphere and its CMakeLists.txt file. Once the tarball CappedSphere.tar has been downloaded and extracted,
cd CappedSphere/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:
./CappedSphere
WINDOWS USERS
Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.