Skip to content
Snippets Groups Projects
Commit fe815fb7 authored by David Thompson's avatar David Thompson
Browse files

Add a "golden ball" source.

This source algorithm uses a Fibonacci spiral (generated using
the "Golden Angle" of π*(sqrt(5) - 1)) which is then projected
out of the plane onto a sphere and Delaunay-tetrahedralized into
a ball. It includes a normal vector field by default which is
zero-length at the center of the ball.
parent af303ddd
No related branches found
No related tags found
No related merge requests found
# Golden Ball Source
A `vtkGoldenBallSource` algorithm has been added to provide
a method to construct a solid, tetrahedralized ball. It uses
a Fibonacci spiral (generated using the "Golden Angle" of
π(sqrt(5) - 1)) which is then projected out of the plane onto
a sphere and Delaunay-tetrahedralized into a ball. It
includes a "normal" vector field by default which is zero-length
at the center of the ball.
Besides the spiral construction this algorithm is also distinct
from the existing sphere source because it produces a solid
rather than a bounding surface.
......@@ -13,6 +13,7 @@ set(classes
vtkEllipticalButtonSource
vtkFrustumSource
vtkGlyphSource2D
vtkGoldenBallSource
vtkGraphToPolyData
vtkHandleSource
vtkHyperTreeGridPreConfiguredSource
......
vtk_module_test_data(
Data/mbwavelet_ascii.q
Data/mbwavelet_ascii.xyz
Data/goldenBallBaseline200.vtu
)
if (NOT vtk_testing_cxx_disabled)
......
......@@ -12,6 +12,7 @@ vtk_add_test_cxx(vtkFiltersSourcesCxxTests tests
TestFrustumSource.cxx,NO_VALID
TestGlyphSource2D.cxx,NO_VALID
TestGlyphSource2DResolution.cxx,
TestGoldenBallSource.cxx,NO_VALID
TestHyperTreeGridPreConfiguredSource.cxx
TestLineSource.cxx,NO_VALID
TestMultiBlock.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestGoldenBallSource.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include <vtkActor.h>
#include <vtkGoldenBallSource.h>
#include <vtkMath.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkTestUtilities.h>
#include <vtkTesting.h>
#include <vtkXMLUnstructuredGridReader.h>
#include <vtkXMLUnstructuredGridWriter.h>
namespace
{
int writeData(vtkTesting* helper, vtkAlgorithm* algo)
{
if (!helper->IsFlagSpecified("-T"))
{
vtkGenericWarningMacro("Error: -T /path/to/scratch was not specified.");
return EXIT_FAILURE;
}
std::string tmpDir = helper->GetTempDirectory();
vtkNew<vtkXMLUnstructuredGridWriter> writer;
writer->SetFileName((tmpDir + "/goldenBallBaseline200.vtu").c_str());
writer->SetInputConnection(algo->GetOutputPort());
writer->Write();
vtkGenericWarningMacro("Writing algorithm data to " << (tmpDir + "/goldenBallBaseline200.vtu"));
return EXIT_FAILURE;
}
} // anonymous namespace
int TestGoldenBallSource(int argc, char* argv[])
{
vtkNew<vtkTesting> testHelper;
testHelper->AddArguments(argc, argv);
if (!testHelper->IsFlagSpecified("-D"))
{
vtkGenericWarningMacro("Error: -D /path/to/data was not specified.");
return EXIT_FAILURE;
}
std::string dataRoot = testHelper->GetDataRoot();
vtkNew<vtkGoldenBallSource> ballSource;
ballSource->SetResolution(200);
ballSource->SetRadius(5.0);
ballSource->GenerateNormalsOn();
ballSource->IncludeCenterPointOn();
ballSource->Update();
if (!vtksys::SystemTools::FileExists(dataRoot + "/Data/goldenBallBaseline200.vtu"))
{
vtkGenericWarningMacro("Error: Baseline data does not exist.");
return writeData(testHelper, ballSource);
}
vtkNew<vtkXMLUnstructuredGridReader> reader;
reader->SetFileName((dataRoot + "/Data/goldenBallBaseline200.vtu").c_str());
reader->Update();
if (!vtkTestUtilities::CompareDataObjects(ballSource->GetOutputDataObject(0),
reader->GetOutputDataObject(0), /* toleranceFactor */ 1.0))
{
vtkGenericWarningMacro("Error: Baseline data does not match.");
return writeData(testHelper, ballSource);
}
return EXIT_SUCCESS;
}
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
// This must be first in order to avoid problems with MSVC; anything
// below that includes <cmath> without this defined will prevent M_PI
// from being defined.
#define _USE_MATH_DEFINES 1
#include "vtkGoldenBallSource.h"
#include "vtkCellArray.h"
#include "vtkDelaunay3D.h"
#include "vtkDoubleArray.h"
#include "vtkFloatArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkUnstructuredGrid.h"
#include "vtkVector.h"
#include "vtkVectorOperators.h"
#include <cmath>
VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkGoldenBallSource);
vtkGoldenBallSource::vtkGoldenBallSource()
: Radius{ 0.5 }
, Center{ 0.0, 0.0, 0.0 }
, Resolution(20)
, IncludeCenterPoint{ 0 }
, GenerateNormals{ 1 }
, OutputPointsPrecision(vtkAlgorithm::SINGLE_PRECISION)
{
this->SetNumberOfInputPorts(0);
}
int vtkGoldenBallSource::RequestData(vtkInformation* vtkNotUsed(request),
vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
{
// get the info object
vtkInformation* outInfo = outputVector->GetInformationObject(0);
// get the output
vtkUnstructuredGrid* output =
vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkNew<vtkPoints> coords;
vtkSmartPointer<vtkDataArray> normals;
if (OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
{
normals = vtkSmartPointer<vtkDoubleArray>::New();
}
else
{
normals = vtkSmartPointer<vtkFloatArray>::New();
}
coords->SetDataType(
this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION ? VTK_DOUBLE : VTK_FLOAT);
coords->SetNumberOfPoints(this->Resolution + (this->IncludeCenterPoint ? 1 : 0));
if (this->GenerateNormals)
{
normals->SetName("normals");
normals->SetNumberOfComponents(3);
normals->SetNumberOfTuples(this->Resolution + (this->IncludeCenterPoint ? 1 : 0));
}
vtkNew<vtkPolyData> vtmp;
vtkNew<vtkCellArray> verts;
if (this->IncludeCenterPoint)
{
verts->AllocateExact(this->Resolution + 1, 2 * (this->Resolution + 1));
}
else
{
verts->AllocateExact(this->Resolution, 2 * this->Resolution);
}
vtmp->SetPoints(coords);
vtmp->SetVerts(verts);
const double phi = M_PI * (std::sqrt(5.) - 1.);
const double nm1 = this->Resolution - 1.0;
const vtkIdType nn = this->Resolution;
for (vtkIdType ii = 0; ii < nn; ++ii)
{
double th = ii * phi;
double y = (1.0 - 2. * (ii / nm1));
double rr = this->Radius * std::sqrt(1. - y * y);
double x = rr * std::cos(th);
double z = rr * std::sin(th);
coords->SetPoint(ii, x, this->Radius * y, z);
if (this->GenerateNormals)
{
vtkVector3d norm(x, this->Radius * y, z);
norm = norm - vtkVector3d(this->Center);
normals->SetTuple(ii, norm.Normalized().GetData());
}
verts->InsertNextCell(1, &ii);
}
if (this->IncludeCenterPoint)
{
coords->SetPoint(nn, this->Center);
verts->InsertNextCell(1, &nn);
if (this->GenerateNormals)
{
normals->SetTuple3(nn, 0, 0, 0);
}
}
vtkNew<vtkDelaunay3D> delaunay;
delaunay->SetInputDataObject(vtmp);
delaunay->Update();
output->ShallowCopy(delaunay->GetOutputDataObject(0));
if (this->GenerateNormals)
{
output->GetPointData()->SetNormals(normals);
}
return 1;
}
void vtkGoldenBallSource::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
os << indent << "Radius: " << this->Radius << "\n";
os << indent << "Center: (" << this->Center[0] << ", " << this->Center[1] << ", "
<< this->Center[2] << ")\n";
os << indent << "Resolution: " << this->Resolution << "\n";
os << indent << "IncludeCenterPoint: " << (this->IncludeCenterPoint ? "ON" : "OFF") << "\n";
os << indent << "Output Points Precision: " << this->OutputPointsPrecision << "\n";
}
VTK_ABI_NAMESPACE_END
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
* @class vtkGoldenBallSource
* @brief Create a faceted approximation to a ball (i.e., a solid sphere).
*
* vtkGoldenBallSource creates a ball (represented by tetrahedra) of specified
* radius and center. The resolution (number of points) can be specified
* and will be equal to the number of tetrahedra in the output approximation.
*
* The name derives from the golden angle (pi * (sqrt(5) - 1)) used to space points
* circumferentially so they are approximately equidistant from their neighbors.
* For this reason, the technique is sometimes called the "Fibonacci spiral,"
* after the planar spiral shape which gets projected to the sphere.
*/
#ifndef vtkGoldenBallSource_h
#define vtkGoldenBallSource_h
#include "vtkFiltersSourcesModule.h" // For export macro
#include "vtkUnstructuredGridAlgorithm.h"
VTK_ABI_NAMESPACE_BEGIN
class VTKFILTERSSOURCES_EXPORT vtkGoldenBallSource : public vtkUnstructuredGridAlgorithm
{
public:
vtkTypeMacro(vtkGoldenBallSource, vtkUnstructuredGridAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent) override;
/**
* Construct sphere with radius=0.5 and default resolution 20.
*/
static vtkGoldenBallSource* New();
//@{
/**
* Set radius of sphere. Default is .5.
*/
vtkSetClampMacro(Radius, double, 0.0, VTK_DOUBLE_MAX);
vtkGetMacro(Radius, double);
//@}
//@{
/**
* Set the center of the sphere. Default is 0,0,0.
*/
vtkSetVector3Macro(Center, double);
vtkGetVectorMacro(Center, double, 3);
//@}
//@{
/**
* Set the number of points used to approximate the sphere.
* The minimum is 4, the default is 20, and there is no maximum.
*/
vtkSetClampMacro(Resolution, int, 4, VTK_INT_MAX);
vtkGetMacro(Resolution, int);
//@}
//@{
/**
* Set/get whether to include a point at the center of the ball.
* The default is not to include the center.
*/
vtkSetMacro(IncludeCenterPoint, int);
vtkGetMacro(IncludeCenterPoint, int);
vtkBooleanMacro(IncludeCenterPoint, int);
//@}
//@{
/**
* Set/get whether to include "normal" vectors at each point.
* The default is to include normals. These are vectors of unit
* length which point outward from the center of the ball. The
* center point (if included) has a zero-length vector.
*/
vtkSetMacro(GenerateNormals, int);
vtkGetMacro(GenerateNormals, int);
vtkBooleanMacro(GenerateNormals, int);
//@}
//@{
/**
* Set/get the desired precision for the output points.
* vtkAlgorithm::SINGLE_PRECISION - Output single-precision floating point.
* vtkAlgorithm::DOUBLE_PRECISION - Output double-precision floating point.
*/
vtkSetMacro(OutputPointsPrecision, int);
vtkGetMacro(OutputPointsPrecision, int);
//@}
protected:
vtkGoldenBallSource();
~vtkGoldenBallSource() override = default;
int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
double Radius;
double Center[3];
int Resolution;
int IncludeCenterPoint;
int GenerateNormals;
int OutputPointsPrecision;
private:
vtkGoldenBallSource(const vtkGoldenBallSource&) = delete;
void operator=(const vtkGoldenBallSource&) = delete;
};
VTK_ABI_NAMESPACE_END
#endif
79bbbd9d422fc2b3535fbce59c1daa2ab70e863d38fc8adb81bd8aaec421de9fb09a48894fc8a3263feec669f504e326c3bd2ef5822032eb17b4d1e1e6c65200
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment