# VTKRuledSurface Bug?

**URL:** https://discourse.vtk.org/t/vtkruledsurface-bug/8102
**Category:** Support
**Created:** [March 22, 2022, 3:18am UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102 "2022-03-22T03:18:38Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![DAsphyxia](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/d/4da419/32.png) [@DAsphyxia](https://discourse.vtk.org/u/DAsphyxia)
#### Post date: [March 22, 2022, 3:18am UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/1 "2022-03-22T03:18:38Z")

</div>

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.

 ![image](https://discourse.vtk.org/uploads/default/original/2X/e/ebf07781227f0c30ee06a6d7685ed8a1c214e984.jpeg)

---

<div class="post-metadata">

### Author: ![will.schroeder](https://discourse.vtk.org/user_avatar/discourse.vtk.org/will.schroeder/32/233_2.png) [@will.schroeder](https://discourse.vtk.org/u/will.schroeder)
#### Post date: [March 22, 2022, 11:32am UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/2 "2022-03-22T11:32:40Z")

</div>

Can you please send some data and a simple program?

---

<div class="post-metadata">

### Author: ![DAsphyxia](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/d/4da419/32.png) [@DAsphyxia](https://discourse.vtk.org/u/DAsphyxia)
#### Post date: [March 22, 2022, 1:29pm UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/3 "2022-03-22T13:29:44Z")

</div>

the code:

```auto
 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);

```

---

<div class="post-metadata">

### Author: ![YuxuanHuang](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/y/f9ae1b/32.png) [@YuxuanHuang](https://discourse.vtk.org/u/YuxuanHuang)
#### Post date: [November 21, 2023, 9:04am UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/4 "2023-11-21T09:04:28Z")

</div>

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

---

<div class="post-metadata">

### Author: ![mau\_igna\_06](https://discourse.vtk.org/user_avatar/discourse.vtk.org/mau_igna_06/32/8064_2.png) [@mau\_igna\_06](https://discourse.vtk.org/u/mau_igna_06)
#### Post date: [January 13, 2025, 6:46pm UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/5 "2025-01-13T18:46:54Z")

</div>

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()`

```auto
# 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

 ![Screenshot from 2025-01-13 15-44-19](https://discourse.vtk.org/uploads/default/original/2X/7/7bfb8e3f29c84f23dce26166f96b14e344b06043.png)  
 ![Screenshot from 2025-01-13 15-44-28](https://discourse.vtk.org/uploads/default/original/2X/c/cfb3f3a64218fbb0e4ab917600b9072a11b22c7c.png)

Thank you 🙂 🙂 🙂

---

<div class="post-metadata">

### Author: ![mau\_igna\_06](https://discourse.vtk.org/user_avatar/discourse.vtk.org/mau_igna_06/32/8064_2.png) [@mau\_igna\_06](https://discourse.vtk.org/u/mau_igna_06)
#### Post date: [January 21, 2025, 3:52pm UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/6 "2025-01-21T15:52:19Z")

</div>

Hi,

I just wanted to write again to see if someone has feedback on this problem

Thank you

---

<div class="post-metadata">

### Author: ![mau\_igna\_06](https://discourse.vtk.org/user_avatar/discourse.vtk.org/mau_igna_06/32/8064_2.png) [@mau\_igna\_06](https://discourse.vtk.org/u/mau_igna_06)
#### Post date: [February 12, 2025, 6:06pm UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/7 "2025-02-12T18:06:38Z")

</div>

Does anyone have any hints in how to solve it? I may be able to put time into fixing it

---

<div class="post-metadata">

### Author: ![will.schroeder](https://discourse.vtk.org/user_avatar/discourse.vtk.org/will.schroeder/32/233_2.png) [@will.schroeder](https://discourse.vtk.org/u/will.schroeder)
#### Post date: [February 13, 2025, 2:23pm UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/8 "2025-02-13T14:23:00Z")

</div>

It’s likely that there is an indexing problem that causes triangles to be dropped, or even possibly degenerate triangles created. etc. I suggest that you create a minimal example, and then walk through the code to see what’s going on. We’ve seen this problem before, so if you can help solve it that would be great.

---

<div class="post-metadata">

### Author: ![mau\_igna\_06](https://discourse.vtk.org/user_avatar/discourse.vtk.org/mau_igna_06/32/8064_2.png) [@mau\_igna\_06](https://discourse.vtk.org/u/mau_igna_06)
#### Post date: [June 3, 2025, 9:09pm UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/9 "2025-06-03T21:09:17Z")

</div>

Hi

Here is a straight-forward example with python’s vtk

 ![image](https://discourse.vtk.org/uploads/default/original/2X/e/ebebabb74f9d276b161a722444dacf026971c9f3.png)  
(Please note the missing triangle in front of the picture)

Code below:

```python
def polylineSource(numberOfSides):
    polygonSource = vtk.vtkRegularPolygonSource()
    polygonSource.SetNumberOfSides(numberOfSides)
    polygonSource.SetRadius(1.0)
    polygonSource.SetCenter(0, 0, 0)
    polygonSource.GeneratePolygonOff()
    polygonSource.GeneratePolylineOn()
    polygonSource.Update()
    return polygonSource.GetOutput()

polyline = polylineSource(numberOfSides=7)

transform = vtk.vtkTransform()
transform.PostMultiply()
transform.RotateX(15)
transform.RotateY(45)
transform.RotateZ(30)
transform.Translate(0, 0, -2)

transformFilter = vtk.vtkTransformPolyDataFilter()
transformFilter.SetTransform(transform)
transformFilter.SetInputData(polyline)
transformFilter.Update()
transformedPolyline = transformFilter.GetOutput()

appendedPolylines = vtk.vtkAppendPolyData()
appendedPolylines.AddInputData(polyline)
appendedPolylines.AddInputData(transformedPolyline)
appendedPolylines.Update()

ruledSurfaceFilter = vtk.vtkRuledSurfaceFilter()
ruledSurfaceFilter.SetRuledModeToPointWalk()
ruledSurfaceFilter.CloseSurfaceOff()
ruledSurfaceFilter.SetOnRatio(1)
ruledSurfaceFilter.SetDistanceFactor(10000000)
ruledSurfaceFilter.SetOrientLoops(True)
ruledSurfaceFilter.SetInputData(appendedPolylines.GetOutput())
ruledSurfaceFilter.Update()

# From this rendering example:
# https://examples.vtk.org/site/Python/Tutorial/Tutorial_Step1/
coneMapper = vtk.vtkPolyDataMapper()
coneMapper.SetInputConnection(ruledSurfaceFilter.GetOutputPort())

coneActor = vtk.vtkActor()
coneActor.SetMapper(coneMapper)
colors = vtk.vtkNamedColors()
coneActor.GetProperty().SetColor(colors.GetColor3d('MistyRose'))

ren1 = vtk.vtkRenderer()
ren1.AddActor(coneActor)
ren1.SetBackground(colors.GetColor3d('MidnightBlue'))

renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren1)
renWin.SetSize(600, 600)
renWin.SetWindowName('Tutorial_Step1')

for i in range(0, 270):
    # Render the image
    renWin.Render()
    # Rotate the active camera by one degree.
    ren1.GetActiveCamera().Azimuth(1)

# Slicer code to visualize the models
#modelsLogic = slicer.modules.models.logic()
#triangleModel = modelsLogic.AddModel(polyline)
#pentagonModel = modelsLogic.AddModel(transformedPolyline)
#bothModel = modelsLogic.AddModel(appendedPolylines.GetOutput())
#ruledExtrusionModel = modelsLogic.AddModel(ruledSurfaceFilter.GetOutput())

```

As a side note, I tried adding some logging statements to the vtkRuledSurfaceFilter and I noted some things using different input data:

- A very high number of times [the first if statement](https://github.com/Kitware/VTK/blob/6dea97ad619c8483d27235ce8a05b2b94d504aa7/Filters/Modeling/vtkRuledSurfaceFilter.cxx#L454) is never entered while executing the filter
- Sometimes [the second if statement](https://github.com/Kitware/VTK/blob/6dea97ad619c8483d27235ce8a05b2b94d504aa7/Filters/Modeling/vtkRuledSurfaceFilter.cxx#L470) is never entered while executing the filter
- The [third and forth if blocks](https://github.com/Kitware/VTK/blob/6dea97ad619c8483d27235ce8a05b2b94d504aa7/Filters/Modeling/vtkRuledSurfaceFilter.cxx#L486-L517) are always entered by executing the filter

In my opinion this implies that the [while loop that controls the creation of new triangles](https://github.com/Kitware/VTK/blob/6dea97ad619c8483d27235ce8a05b2b94d504aa7/Filters/Modeling/vtkRuledSurfaceFilter.cxx#L427) has some faulty logic.

Hope you can help

Mauro

---

<div class="post-metadata">

### Author: ![mau\_igna\_06](https://discourse.vtk.org/user_avatar/discourse.vtk.org/mau_igna_06/32/8064_2.png) [@mau\_igna\_06](https://discourse.vtk.org/u/mau_igna_06)
#### Post date: [September 21, 2026, 5:48pm UTC](https://discourse.vtk.org/t/vtkruledsurface-bug/8102/10 "2026-09-21T17:48:50Z")

</div>

I was able to write a test for the ruledsurface filter based on the reproduction steps above. Then I was able to fix the incorrect behavior on point walk mode.

[https://gitlab.kitware.com/vtk/vtk/-/merge\_requests/13731](https://gitlab.kitware.com/vtk/vtk/-/merge_requests/13731)
