I’m using vtkFeatureEdges to extract boundary edges, but I would like to know if there is a simple way to extract only the edges where the contour of these edges has a size limit. It looks like feature edges treats every edge independently, but I need to select only the edges from small holes.
For example, in the image below I want to extract only the edges from the small holes (indicated by the yellow arrow), but I dont want the edges from the big hole and the “external” edges.
Well, I had found a solution for this. Probably not the most elegant solution, but solved my problem for now. I basically loop through all the regions and their edges to manually calculate the total length of each region, add the valid regions to a list, and then I loop through the regions again using only the ones from the list.
//extract boundary edges
vtkFeatureEdges *featureEdges = vtkFeatureEdges::New();
featureEdges->SetInputData(meshPolydata);
featureEdges->BoundaryEdgesOn();
featureEdges->FeatureEdgesOff();
featureEdges->ManifoldEdgesOff();
featureEdges->NonManifoldEdgesOff();
featureEdges->Update();
/*int numberOfLines = featureEdges->GetOutput()->GetNumberOfLines();
std::cout << "Number of lines:" << numberOfLines << std::endl;*/
vtkSmartPointer<vtkPolyDataConnectivityFilter> regions = vtkSmartPointer<vtkPolyDataConnectivityFilter>::New();
regions->SetInputData(featureEdges->GetOutput());
regions->SetExtractionModeToAllRegions();
regions->Update();
int regionCount = regions->GetNumberOfExtractedRegions();
double maximumRegionLength = 1.0; //set the maximum length of the region
std::vector<int> validRegionsList; //define a list of valid regions
//loop through all the regions
for (int i = 0; i < regionCount; i++)
{
//for each specific region...
regions->SetInputData(featureEdges->GetOutput());
regions->SetExtractionModeToSpecifiedRegions();
regions->InitializeSpecifiedRegionList();
regions->AddSpecifiedRegion(i);
regions->ScalarConnectivityOff();
regions->Update();
//std::cout << "Region " << i << "size: " << regions->GetOutput()->GetNumberOfLines() << std::endl;
//create a polydata to store the information of the region
vtkSmartPointer<vtkPolyData> linesPolyData = vtkSmartPointer<vtkPolyData>::New();
linesPolyData->SetPoints(regions->GetOutput()->GetPoints());
linesPolyData->SetLines(regions->GetOutput()->GetLines());
linesPolyData->GetLines()->InitTraversal();
vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New();
double regionLength = 0;
//now loop through the data accumulating the length of each line of the region
while (linesPolyData->GetLines()->GetNextCell(idList))
{
//std::cout << idList->GetNumberOfIds() << " vertices: ";
std::vector<std::vector<double>> lineVertices; //size always 2
for (vtkIdType pointId = 0; pointId < idList->GetNumberOfIds(); pointId++)
{
double point[3];
linesPolyData->GetPoint(idList->GetId(pointId), point);
//Show id and coordinates of the vertices for each line
//std::cout << "[" << idList->GetId(pointId) << "]" << "(" << point[0] << ", "<< point[1] << ", " << point[2] << ") ";
//add the two points of each line into a vector
std::vector<double> pointArray;
pointArray.push_back(point[0]);
pointArray.push_back(point[1]);
pointArray.push_back(point[2]);
lineVertices.push_back(pointArray);
}
//calculate the length of the line and accumulates it in regionLengh
double lineLength = sqrt(pow(lineVertices[0][0] - lineVertices[1][0], 2) + pow(lineVertices[0][1] - lineVertices[1][1], 2) + pow(lineVertices[0][2] - lineVertices[1][2], 2));
//std::cout << "- length: " << lineLength;
regionLength += lineLength;
//std::cout << std::endl;
}
//std::cout << "Total region length: " << regionLength << std::endl;
//add the region to the list of valid regions if length is appropriated
if (regionLength <= maximumRegionLength)
validRegionsList.push_back(i);
}
std::cout << "Valid regions saved!" << std::endl;
//loop through the regions again, now selecting the ones with the required length
for (int i = 0; i < regionCount; i++)
{
regions->SetInputData(featureEdges->GetOutput());
regions->SetExtractionModeToSpecifiedRegions();
regions->InitializeSpecifiedRegionList();
regions->AddSpecifiedRegion(i);
regions->ScalarConnectivityOff();
regions->Update();
//verify if current region is on the list of valid regions
if (std::find(validRegionsList.begin(), validRegionsList.end(), i) != validRegionsList.end())
{
//use your valid regions with connectivityRegions->GetOutput() here!
}
else
continue;
}