// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkConeSource.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkTransform.h" #include VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkConeSource); //------------------------------------------------------------------------------ // Construct with default resolution 6, height 1.0, radius 0.5, and capping // on. vtkConeSource::vtkConeSource(int res) { res = (res < 0 ? 0 : res); this->Resolution = res; this->Height = 1.0; this->Radius = 0.5; this->Capping = 1; this->Center[0] = 0.0; this->Center[1] = 0.0; this->Center[2] = 0.0; this->Direction[0] = 1.0; this->Direction[1] = 0.0; this->Direction[2] = 0.0; this->OutputPointsPrecision = SINGLE_PRECISION; this->SetNumberOfInputPorts(0); } //------------------------------------------------------------------------------ int vtkConeSource::RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector) { // get the info objects vtkInformation* outInfo = outputVector->GetInformationObject(0); double angle; int numLines, numPolys, numPts; double x[3], xbot; int i; vtkIdType pts[VTK_CELL_SIZE]; vtkPoints* newPoints; vtkCellArray* newLines = nullptr; vtkCellArray* newPolys = nullptr; vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); // for streaming int piece; int numPieces; int maxPieces; int start, end; int createBottom; piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()); if (piece >= this->Resolution && !(piece == 0 && this->Resolution == 0)) { return 1; } numPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()); maxPieces = this->Resolution != 0 ? this->Resolution : 1; numPieces = std::min(numPieces, maxPieces); if (piece >= maxPieces) { // Super class should do this for us, // but I put this condition in any way. return 1; } start = maxPieces * piece / numPieces; end = (maxPieces * (piece + 1) / numPieces) - 1; createBottom = (this->Capping && (start == 0)); vtkDebugMacro("ConeSource Executing"); if (this->Resolution) { angle = 2.0 * vtkMath::Pi() / this->Resolution; } else { angle = 0.0; } // Set things up; allocate memory // switch (this->Resolution) { case 0: numPts = 2; numLines = 1; newLines = vtkCellArray::New(); newLines->AllocateEstimate(numLines, numPts); break; case 1: case 2: numPts = 2 * this->Resolution + 1; numPolys = this->Resolution; newPolys = vtkCellArray::New(); newPolys->AllocateEstimate(numPolys, 3); break; default: if (createBottom) { // piece 0 has cap. numPts = this->Resolution + 1; numPolys = end - start + 2; } else { numPts = end - start + 3; numPolys = end - start + 2; } newPolys = vtkCellArray::New(); newPolys->AllocateEstimate(numPolys, this->Resolution); break; } newPoints = vtkPoints::New(); // Set the desired precision for the points in the output. if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION) { newPoints->SetDataType(VTK_DOUBLE); } else { newPoints->SetDataType(VTK_FLOAT); } newPoints->Allocate(numPts); // Create cone // x[0] = this->Height / 2.0; // zero-centered x[1] = 0.0; x[2] = 0.0; pts[0] = newPoints->InsertNextPoint(x); xbot = -this->Height / 2.0; switch (this->Resolution) { case 0: x[0] = xbot; x[1] = 0.0; x[2] = 0.0; pts[1] = newPoints->InsertNextPoint(x); newLines->InsertNextCell(2, pts); break; case 2: // fall through this case to use the code in case 1 x[0] = xbot; x[1] = 0.0; x[2] = -this->Radius; pts[1] = newPoints->InsertNextPoint(x); x[0] = xbot; x[1] = 0.0; x[2] = this->Radius; pts[2] = newPoints->InsertNextPoint(x); newPolys->InsertNextCell(3, pts); [[fallthrough]]; case 1: x[0] = xbot; x[1] = -this->Radius; x[2] = 0.0; pts[1] = newPoints->InsertNextPoint(x); x[0] = xbot; x[1] = this->Radius; x[2] = 0.0; pts[2] = newPoints->InsertNextPoint(x); newPolys->InsertNextCell(3, pts); break; default: // General case: create Resolution triangles and single cap // create the bottom. if (createBottom) { for (i = 0; i < this->Resolution; i++) { x[0] = xbot; x[1] = this->Radius * cos(i * angle); x[2] = this->Radius * sin(i * angle); // Reverse the order pts[this->Resolution - i - 1] = newPoints->InsertNextPoint(x); } newPolys->InsertNextCell(this->Resolution, pts); } pts[0] = 0; if (!createBottom) { // we need to create the points also x[0] = xbot; x[1] = this->Radius * cos(start * angle); x[2] = this->Radius * sin(start * angle); pts[1] = newPoints->InsertNextPoint(x); for (i = start; i <= end; ++i) { x[1] = this->Radius * cos((i + 1) * angle); x[2] = this->Radius * sin((i + 1) * angle); pts[2] = newPoints->InsertNextPoint(x); newPolys->InsertNextCell(3, pts); pts[1] = pts[2]; } } else { // bottom and points have already been created. for (i = start; i <= end; i++) { pts[1] = i + 1; pts[2] = i + 2; if (pts[2] > this->Resolution) { pts[2] = 1; } newPolys->InsertNextCell(3, pts); } } // createBottom } // switch // A non-default origin and/or direction requires transformation // if (this->Center[0] != 0.0 || this->Center[1] != 0.0 || this->Center[2] != 0.0 || this->Direction[0] != 1.0 || this->Direction[1] != 0.0 || this->Direction[2] != 0.0) { vtkTransform* t = vtkTransform::New(); t->Translate(this->Center[0], this->Center[1], this->Center[2]); double vMag = vtkMath::Norm(this->Direction); if (this->Direction[0] < 0.0) { // flip x -> -x to avoid instability t->RotateWXYZ(180.0, (this->Direction[0] - vMag) / 2.0, this->Direction[1] / 2.0, this->Direction[2] / 2.0); t->RotateWXYZ(180.0, 0, 1, 0); } else { t->RotateWXYZ(180.0, (this->Direction[0] + vMag) / 2.0, this->Direction[1] / 2.0, this->Direction[2] / 2.0); } if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION) { double* ipts = static_cast(newPoints->GetData())->GetPointer(0); for (i = 0; i < numPts; i++, ipts += 3) { t->TransformPoint(ipts, ipts); } } else { float* ipts = static_cast(newPoints->GetData())->GetPointer(0); for (i = 0; i < numPts; i++, ipts += 3) { t->TransformPoint(ipts, ipts); } } t->Delete(); } // Update ourselves // output->SetPoints(newPoints); newPoints->Delete(); if (newPolys) { newPolys->Squeeze(); // we may have estimated size; reclaim some space output->SetPolys(newPolys); newPolys->Delete(); } else { output->SetLines(newLines); newLines->Delete(); } return 1; } //------------------------------------------------------------------------------ int vtkConeSource::RequestInformation(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector) { vtkInformation* outInfo = outputVector->GetInformationObject(0); outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1); return 1; } //------------------------------------------------------------------------------ void vtkConeSource::SetAngle(double angle) { this->SetRadius(this->Height * tan(vtkMath::RadiansFromDegrees(angle))); } //------------------------------------------------------------------------------ double vtkConeSource::GetAngle() { return vtkMath::DegreesFromRadians(atan2(this->Radius, this->Height)); } //------------------------------------------------------------------------------ void vtkConeSource::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Resolution: " << this->Resolution << "\n"; os << indent << "Height: " << this->Height << "\n"; os << indent << "Radius: " << this->Radius << "\n"; os << indent << "Capping: " << (this->Capping ? "On\n" : "Off\n"); os << indent << "Center: (" << this->Center[0] << ", " << this->Center[1] << ", " << this->Center[2] << ")\n"; os << indent << "Direction: (" << this->Direction[0] << ", " << this->Direction[1] << ", " << this->Direction[2] << ")\n"; os << indent << "Output Points Precision: " << this->OutputPointsPrecision << "\n"; } VTK_ABI_NAMESPACE_END