I have a 3D model which is clipped by a flat surface. It looks like:

The boundary of the cutting is complex, it may contain many lists. The list is closed or opened, there are also possible knots on the list. So we can’t cut and fill the original model by vtkClipClosedSurface successfully.

we can use vtkFillHolesFilter to fill the clipped model easily. But I want to fill the clipped model in a simple way.
For every single list, sort the points on the list and connect the last point and the first one if it’s opened. Take the first point on the list and find its two neighboring points, construct a triangle by them. Then we get a new list whose length becomes shorter, take the first point on the list, and find neighboring points to form a new triangle. Repeat the same steps until there are only three points left. Finally, we create a triangle base on the rest three points.

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(Explore)

set(CMAKE_CXX_STANDARD 14)

find_package( VTK REQUIRED )
include( ${VTK_USE_FILE} )
find_package( Qt5 COMPONENTS Widgets REQUIRED )

add_executable(vtkIOExplore main.cpp ListsFilter.cpp ListsFilter.h log.h)
qt5_use_modules( ${PROJECT_NAME} Core )
target_link_libraries( ${PROJECT_NAME} ${VTK_LIBRARIES} )

main.cpp

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtk3DSImporter.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkPolyData.h>
#include <vtkProperty.h>
#include <vtkSTLReader.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkMapper.h>
#include <vtkAppendPolyData.h>
#include <vtkContourFilter.h>
#include <vtkGaussianCubeReader.h>
#include <vtkImageData.h>
#include <vtkCutter.h>
#include <vtkPlane.h>
#include <vtkClipPolyData.h>

#include "ListsFilter.h"
#include "log.h"

#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();

int main() {
    vtkSPtrNew( reader, vtkSTLReader );
    reader->SetFileName( "/Users/weiyang/Desktop/test.stl" );
    reader->Update();
    auto data = reader->GetOutput();

    vtkSPtrNew( cutPlane, vtkPlane );
    cutPlane->SetOrigin( 21.0257, 0.481699, -1.06998 );
    cutPlane->SetNormal( -0.0512398, -0.996148, 0.0711591 );
    vtkSPtrNew( cutter, vtkCutter );
    cutter->SetCutFunction( cutPlane );
    cutter->SetInputData( data );
    cutter->Update();
    auto cutLinePd = cutter->GetOutput();
    ListsFilter listF( cutLinePd->GetLines() );
    listF.Init();
    listF.Update();

    vtkSPtrNew( appendFilter, vtkAppendPolyData );
    for( int i = 0; i < listF.GetListsCount(); ++i )
    {
        vtkSPtrNew( list, vtkIdList );
        list->DeepCopy( listF.GetList( i ) );

        if( list->GetNumberOfIds() > 2 && list->GetId( 0 ) != list->GetId( list->GetNumberOfIds() - 1 ) )
        {
            list->InsertNextId( list->GetId( 0 ) );
            Log( IInfo, "make it closed" );
        }

        // closed circle
        if( list->GetNumberOfIds() > 2 && list->GetId( 0 ) == list->GetId( list->GetNumberOfIds() - 1 ) )
        {
            Log(IInfo, "in", ", list length: ", list->GetNumberOfIds());
            vtkSPtrNew( cover, vtkPolyData );
            vtkSPtrNew( coverPoints, vtkPoints );
            coverPoints->DeepCopy( cutLinePd->GetPoints() );
            vtkSPtrNew( coverCells, vtkCellArray );

            vtkSPtrNew( circle, vtkIdList );
            circle->DeepCopy( list );

            while( circle->GetNumberOfIds() > 3 )
            {
                auto id0 = circle->GetId( circle->GetNumberOfIds() - 1 );
                auto id1 = circle->GetId( 0 );
                auto id2 = circle->GetId( 1 );
                vtkIdType ids[3] = { id0, id1, id2 };
                //vtkIdType ids[3] = { circle->GetNumberOfIds() - 1, 0, 1 };
                coverCells->InsertNextCell( 3, ids );
                //Log( IDebug, "new cell: ", id0, ", ", id1, ", ", id2 );
                vtkSPtrNew( oldCircle, vtkIdList );
                oldCircle->DeepCopy( circle );
                circle->Initialize();
                for( int j = 1; j < oldCircle->GetNumberOfIds(); ++j )
                {
                    circle->InsertNextId( oldCircle->GetId( j ) );
                }
            }
            if( circle->GetNumberOfIds() == 3 )
            {
                auto id0 = circle->GetId( circle->GetNumberOfIds() - 1 );
                auto id1 = circle->GetId( 0 );
                auto id2 = circle->GetId( 1 );
                vtkIdType ids[3] = { id0, id1, id2 };
                coverCells->InsertNextCell( 3, ids );
            }
            cover->SetPolys( coverCells );
            cover->SetPoints( coverPoints );
            cover->Modified();

            appendFilter->AddInputData( cover );
        }
    }
    appendFilter->Update();

    vtkSPtrNew( capMapper, vtkPolyDataMapper );
    capMapper->SetInputData( appendFilter->GetOutput() );
    Log( IInfo, "cell count: ", appendFilter->GetOutput()->GetNumberOfCells() );

    vtkSPtrNew( capActor, vtkActor );
    capActor->SetMapper( capMapper );
    capActor->GetProperty()->SetColor( 1, 1, 0 );

    vtkSPtrNew( linesMapper, vtkPolyDataMapper );
    linesMapper->SetInputData( cutLinePd );

    vtkSPtrNew( linesActor, vtkActor );
    linesActor->SetMapper( linesMapper );
    linesActor->GetProperty()->SetColor( 1, 0, 0 );

    vtkSPtrNew( clipper, vtkClipPolyData );
    clipper->SetInputData( data );
    clipper->SetClipFunction( cutPlane );
    clipper->Update();

    auto clippedData = clipper->GetOutput();

    vtkSPtrNew( mapper, vtkPolyDataMapper );
    mapper->SetInputData( clippedData );

    vtkSPtrNew( actor, vtkActor );
    actor->SetMapper( mapper );

    vtkSPtrNew( renderer, vtkRenderer );
    renderer->AddActor( actor );
    renderer->AddActor( linesActor );
    renderer->AddActor( capActor );
    renderer->SetBackground( 0, 0, 0 );

    vtkSPtrNew( renderWindow, vtkRenderWindow );
    renderWindow->AddRenderer( renderer );

    vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
    renderWindowInteractor->SetRenderWindow( renderWindow );

    renderer->ResetCamera();
    renderWindow->Render();
    renderWindowInteractor->Start();

    return 0;
}

The implementation details of the CPlusPlus class ListsFilter can be found in VTK – Find Connected Lists And Sort All Points In Them, the relevant files are ListsFilter.h and ListsFilter.cpp.

The file log.h can found in the article Create Log Output Function Based On Variable-parameter List
.

Our algorithm is not suitable for all different situations. If there are many closed lists and they are far away from each other, we may get the following result.

Use vtkFillHolesFilter to fill the hole.

    vtkSPtrNew( fillFilter, vtkFillHolesFilter );
    fillFilter->SetInputData( reader->GetOutput() );
    fillFilter->SetHoleSize( 10 );
    fillFilter->Update();
Categories: VTK

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

3D Files Converter: Support to write X3D file and VRML file.

X
A prohibited operation
0
Would love your thoughts, please comment.x
()
x