# CappedSphere

Repository source: 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), (PythonicAPI)

Question

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

### Code¶

CappedSphere.cxx

#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCellArray.h>
#include <vtkLine.h>
#include <vtkNamedColors.h>
#include <vtkNew.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 <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 const& 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 parameters
auto posCnt = 0;
for (auto const& 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:
break;
default:
break;
}
posCnt++;
}
}
}
angle = d_r(std::abs(angle));
step = d_r(std::abs(step));
// 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
vtkNew<vtkPoints> points;
vtkNew<vtkCellArray> lines;
for (auto pt : pts)
{
unsigned long pt_id = points->InsertNextPoint(pt.data());
if (pt_id < pts.size() - 1)
{
vtkNew<vtkLine> line;
line->GetPointIds()->SetId(0, pt_id);
line->GetPointIds()->SetId(1, pt_id + 1);
lines->InsertNextCell(line);
}
}

vtkNew<vtkPolyData> polydata;
polydata->SetPoints(points);
polydata->SetLines(lines);

// Extrude the profile to make the capped sphere
vtkNew<vtkRotationalExtrusionFilter> extrude;
extrude->SetInputData(polydata);
extrude->SetResolution(60);

//  Visualize
vtkNew<vtkNamedColors> colors;

// To see the line
vtkNew<vtkPolyDataMapper> lineMapper;
lineMapper->SetInputData(polydata);

vtkNew<vtkActor> lineActor;
lineActor->SetMapper(lineMapper);
lineActor->GetProperty()->SetLineWidth(4);
lineActor->GetProperty()->SetColor(colors->GetColor3d("Red").GetData());

// To see the surface
vtkNew<vtkPolyDataMapper> surfaceMapper;
surfaceMapper->SetInputConnection(extrude->GetOutputPort());

vtkNew<vtkActor> surfaceActor;
surfaceActor->SetMapper(surfaceMapper);
surfaceActor->GetProperty()->SetColor(colors->GetColor3d("Khaki").GetData());

vtkNew<vtkRenderer> ren;
vtkNew<vtkRenderWindow> renWin;
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin);

if (showLine)
{
}
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.12 FATAL_ERROR)

project(CappedSphere)

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

if (NOT VTK_FOUND)
message(FATAL_ERROR "CappedSphere: 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(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}
)

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.