I tried to use vtkRuledSurfaceFilter to extrude a circle along a spline curve, but some error unexpected happened as shown in the figure below.Some triangle cells are just missed after this option and I have tried all the parametres but got nothing.After looking up the source code, I thought that should be a bug in the code that miss the cell that connects the last and the first point in a loop.
And I beg for some solutions to help solve this.
Can you please send some data and a simple program?
the code:
vtkNew<vtkNamedColors> colors;
vtkNew<vtkRegularPolygonSource> polygonSource;
polygonSource->GeneratePolygonOff();
polygonSource->SetNumberOfSides(50);
polygonSource->SetRadius(2);
polygonSource->SetCenter(0, 0, 0);
polygonSource->Update();
vtkSmartPointer<vtkPolyData> polyData = polygonSource->GetOutput();
int numberOfContours = polyData->GetNumberOfLines();
std::cout << "Number of contours: " << numberOfContours << std::endl;
// Generate some random points
double start[3] = {-1.2, 0.0, 0.2};
double p0[3] = {-1.0, 0.0, 0.0};
double p1[3] = {0.0, 0.0, 0.0};
// Create a vtkPoints object and store the points in it
vtkNew<vtkPoints> points;
points->InsertNextPoint(start);
points->InsertNextPoint(p0);
points->InsertNextPoint(p1);
vtkNew<vtkParametricSpline> spline;
spline->SetPoints(points);
vtkNew<vtkParametricFunctionSource> functionSource;
functionSource->SetParametricFunction(spline);
functionSource->SetUResolution(100);
functionSource->SetVResolution(100);
functionSource->SetWResolution(100);
functionSource->Update();
// Create the frame
vtkNew<vtkFrenetSerretFrame> frame;
frame->SetInputConnection(functionSource->GetOutputPort());
frame->ConsistentNormalsOn();
frame->Update();
frame->GetOutput()->GetPointData()->SetActiveVectors("FSNormals");
frame->GetOutput()->GetPointData()->SetActiveVectors("FSTangents");
frame->GetOutput()->GetPointData()->SetActiveVectors("FSBinormals");
vtkPoints* linePoints = frame->GetOutput()->GetPoints();
std::vector<vtkSmartPointer<vtkAppendPolyData>> skeletons;
for (int i = 0; i < numberOfContours; ++i) {
skeletons.push_back(vtkSmartPointer<vtkAppendPolyData>::New());
}
for (int i = 0; i < linePoints->GetNumberOfPoints(); ++i) {
vtkNew<vtkTransform> transform;
// Compute a basis
double normalizedX[3];
frame->GetOutput()->GetPointData()->SetActiveVectors("FSNormals");
frame->GetOutput()->GetPointData()->GetVectors()->GetTuple(i, normalizedX);
double normalizedY[3];
frame->GetOutput()->GetPointData()->SetActiveVectors("FSBinormals");
frame->GetOutput()->GetPointData()->GetVectors()->GetTuple(i, normalizedY);
double normalizedZ[3];
frame->GetOutput()->GetPointData()->SetActiveVectors("FSTangents");
frame->GetOutput()->GetPointData()->GetVectors()->GetTuple(i, normalizedZ);
// Create the direction cosine matrix
vtkNew<vtkMatrix4x4> matrix;
matrix->Identity();
for (unsigned int j = 0; j < 3; ++j) {
matrix->SetElement(j, 0, normalizedX[j]);
matrix->SetElement(j, 1, normalizedY[j]);
matrix->SetElement(j, 2, normalizedZ[j]);
}
transform->Translate(linePoints->GetPoint(i)[0], linePoints->GetPoint(i)[1],
linePoints->GetPoint(i)[2]);
transform->Scale(.02, .02, .02);
transform->Concatenate(matrix);
vtkNew<vtkTransformPolyDataFilter> transformPD;
vtkNew<vtkPolyData> polyDataCopy;
polyDataCopy->DeepCopy(polyData);
transformPD->SetTransform(transform);
transformPD->SetInputData(polyDataCopy);
transformPD->Update();
vtkNew<vtkPolyDataConnectivityFilter> contours;
contours->SetInputConnection(transformPD->GetOutputPort());
contours->Update();
for (int r = 0; r < contours->GetNumberOfExtractedRegions(); ++r)
{
contours->SetExtractionModeToSpecifiedRegions();
contours->InitializeSpecifiedRegionList();
contours->AddSpecifiedRegion(r);
contours->Update();
vtkNew<vtkPolyData> skeleton;
skeleton->DeepCopy(contours->GetOutput());
skeletons[r]->AddInputData(skeleton);
}
}
for (int i = 0; i < numberOfContours; ++i) {
vtkNew<vtkRuledSurfaceFilter> ruled;
ruled->SetRuledModeToPointWalk();
ruled->CloseSurfaceOff();
ruled->SetOnRatio(0);
ruled->SetOffset(10);
ruled->OrientLoopsOn();
ruled->SetDistanceFactor(10000000);
ruled->SetInputConnection(skeletons[i]->GetOutputPort());
std::cout << ruled->GetOffset() << endl;
vtkNew<vtkPolyDataNormals> normals;
normals->SetInputConnection(ruled->GetOutputPort());
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(normals->GetOutputPort());
vtkNew<vtkActor> actor;
actor->GetProperty()->SetColor(colors->GetColor3d("Snow").GetData());
actor->SetMapper(mapper);
modelStore.renderer->AddActor(actor);
}
modelStore.renderer->SetBackground(.4, .5, .7);
modelStore.renderWindow->AddRenderer(modelStore.renderer);
ui.openGLWidget->setRenderWindow(modelStore.renderWindow);
ui.openGLWidget->setVisible(true);
Hi 段凡,
I am having some problems when applying the vtkFrenetSerretFrame class in a qt c++ vtk program. Do you have any tips when you implemented your codes?
Kind regards,
Yuxuan
Hi,
I have made a code example that shows exactly the same problem reported by the original poster using vtkRuledSurfaceFilter
with PointWalk
mode
All the code is vtk, except I had to replace vtk.vtkFrenetSerretFrame()
with slicer.vtkParallelTransportFrame()
# Create profile
vtk.vtkMath.RandomSeed(7859821)
diskSource = vtk.vtkDiskSource()
diskSource.SetCircumferentialResolution(5)
clean = vtk.vtkCleanPolyData()
clean.SetInputConnection(diskSource.GetOutputPort())
edges = vtk.vtkFeatureEdges()
edges.SetInputConnection(clean.GetOutputPort())
edges.NonManifoldEdgesOff()
edges.ManifoldEdgesOff()
edges.BoundaryEdgesOn()
edges.FeatureEdgesOff()
stripper = vtk.vtkStripper()
stripper.SetInputConnection(edges.GetOutputPort())
stripper.Update()
profilePolyData = stripper.GetOutput()
# Create a parametric spline
## Generate some random points
numberOfPoints = 5
pointSource = vtk.vtkPointSource()
pointSource.SetNumberOfPoints(numberOfPoints)
pointSource.Update()
points = pointSource.GetOutput().GetPoints()
## Generate the spline
spline = vtk.vtkParametricSpline()
spline.SetPoints(points)
functionSource = vtk.vtkParametricFunctionSource()
functionSource.SetParametricFunction(spline)
functionSource.SetUResolution(50 * numberOfPoints)
functionSource.SetVResolution(50 * numberOfPoints)
functionSource.SetWResolution(50 * numberOfPoints)
functionSource.Update()
splinePolyData = functionSource.GetOutput()
# Create the frame
frame = slicer.vtkParallelTransportFrame() # equivalent to vtk.vtkFrenetSerretFrame()
frame.SetInputData(splinePolyData)
frame.Update()
frame.GetOutput().GetPointData().SetActiveVectors("Normals")
frame.GetOutput().GetPointData().SetActiveVectors("Tangents")
frame.GetOutput().GetPointData().SetActiveVectors("Binormals")
linePoints = frame.GetOutput().GetPoints()
skeleton = vtk.vtkAppendPolyData()
for i in range(linePoints.GetNumberOfPoints()):
transform = vtk.vtkTransform()
# Compute a basis
normalizedX = [0, 0, 0]
frame.GetOutput().GetPointData().SetActiveVectors("Normals")
frame.GetOutput().GetPointData().GetVectors().GetTuple(i, normalizedX)
normalizedY = [0, 0, 0]
frame.GetOutput().GetPointData().SetActiveVectors("Binormals")
frame.GetOutput().GetPointData().GetVectors().GetTuple(i, normalizedY)
normalizedZ = [0, 0, 0]
frame.GetOutput().GetPointData().SetActiveVectors("Tangents")
frame.GetOutput().GetPointData().GetVectors().GetTuple(i, normalizedZ)
# Create the direction cosine matrix
matrix = vtk.vtkMatrix4x4()
matrix.Identity()
for j in range(3):
matrix.SetElement(j, 0, normalizedX[j])
matrix.SetElement(j, 1, normalizedY[j])
matrix.SetElement(j, 2, normalizedZ[j])
transform.Translate(linePoints.GetPoint(i)[0], linePoints.GetPoint(i)[1],
linePoints.GetPoint(i)[2])
transform.Scale(.02, .02, .02)
transform.Concatenate(matrix)
transformPD = vtk.vtkTransformPolyDataFilter()
polyDataCopy = vtk.vtkPolyData()
polyDataCopy.DeepCopy(profilePolyData)
transformPD.SetTransform(transform)
transformPD.SetInputData(polyDataCopy)
transformPD.Update()
contours = vtk.vtkPolyDataConnectivityFilter()
contours.SetInputConnection(transformPD.GetOutputPort())
contours.SetExtractionModeToLargestRegion()
contours.Update()
skeleton.AddInputData(contours.GetOutput())
ruled = vtk.vtkRuledSurfaceFilter()
ruled.SetRuledModeToPointWalk()
ruled.CloseSurfaceOff()
ruled.SetOnRatio(1)
ruled.SetDistanceFactor(10000000)
ruled.SetOrientLoops(True)
ruled.SetInputConnection(skeleton.GetOutputPort())
ruled.Update()
# Slicer code
modelsLogic = slicer.modules.models.logic()
profileModel = modelsLogic.AddModel(profilePolyData)
splineModel = modelsLogic.AddModel(splinePolyData)
skeletonModel = modelsLogic.AddModel(skeleton.GetOutput())
ruledExtrusionModel = modelsLogic.AddModel(ruled.GetOutput())
Please see figures below that show the missing triangle between each neighboring loops triangles creation
Thank you