Hello,
I’m trying to extract triangles from a PolyData object depending on the direction in which the triangle faces. These PolyData objects are shaped like a slice of pineapple. Round with a hole in the middle and much wider than high. This shape I want to divide into four areas. The top plane, the bottom plane, the inside wall and the outside wall. The triangles from the top and bottom I get through checking if the triangle’s normal vector faces up or downward. The triangles on the side I get through calculating the distance between on of the triangle points and the center of the slice. If this distance is greater than a threshold the triangle is part of the outer wall. If the distance is smaller than the threshold it is part of the inner wall.
When I try to push the resulting triangles back into a polydata structure the resulting meshes don’t look like anything I would expect. It seems as if the triangles just get stacked on one another. Any ideas what I do wrong, or what I can do?
Best regards, Armin
vtkSmartPointer<vtkPolyData> areaDataTop = vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkPolyData> areaDataBottom = vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkPolyData> areaDataOuter = vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkPolyData> areaDataInner = vtkSmartPointer<vtkPolyData>::New();
void divideIntoAreas(vtkSmartPointer<vtkPolyData> slice, double3 sliceMainAxis, double threshold) {
vtkSmartPointer<vtkCellArray> trianglesTop = vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkCellArray> trianglesBottom = vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkCellArray> trianglesOuter = vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkCellArray> trianglesInner = vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkPoints> pointsTop = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPoints> pointsBottom = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPoints> pointsOuter = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPoints> pointsInner = vtkSmartPointer<vtkPoints>::New();
double3 sliceMidPoint;
double pointFromSlice[3];
// calculate the middle of the slice
for (int i = 0; i < slice->GetNumberOfPoints(); i++) {
slice->GetPoint(i, pointFromSlice);
sliceMidPoint.x += pointFromSlice[0];
sliceMidPoint.y += pointFromSlice[1];
sliceMidPoint.z += pointFromSlice[2];
}
sliceMidPoint.x /= slice->GetNumberOfPoints();
sliceMidPoint.y /= slice->GetNumberOfPoints();
sliceMidPoint.z /= slice->GetNumberOfPoints();
// iterate over all cells in the slice
for (int i = 0; i < slice->GetNumberOfCells(); i++) {
double normal[3], angle, p0[3], p1[3], p2[3];
// get normal from points of the triangle
normal = getNormalFromCell(slice->GetCell(i));
// calculate the angle between the normal of a cell and the heart main axis
angle = vtkMath::DegreesFromRadians(vtkMath::AngleBetweenVectors(sliceMainAxis, normal));
// fetch cell and cast it to a triangle
vtkSmartPointer<vtkCell> cell = slice->GetCell(i);
vtkSmartPointer<vtkTriangle> triangle = vtkTriangle::SafeDownCast(cell);
// get the points of the current cell (a triangle)
triangle->GetPoints()->GetPoint(0, p0);
triangle->GetPoints()->GetPoint(1, p1);
triangle->GetPoints()->GetPoint(2, p2);
// decide to which area the cell belongs
if ((angle >= -15.0) && (angle <= 15.0)) {
// point is on the top of the slice
// insert into a cellArray
trianglesTop->InsertNextCell(cell);
// insert points into a points-collection
pointsTop->InsertNextPoint(p0);
pointsTop->InsertNextPoint(p1);
pointsTop->InsertNextPoint(p2);
} else if ((angle >= 165.0) || (angle <= -165.0)) {
// point is on the bottom of the slice
// insert triangle into a cellArray
trianglesBottom->InsertNextCell(cell);
// insert points into a points-collection
pointsBottom->InsertNextPoint(p0);
pointsBottom->InsertNextPoint(p1);
pointsBottom->InsertNextPoint(p2);
} else if (std::isnan(angle)) {
// angle is "nan"
throw std::runtime_error("divideIntoAreas(): The angle is NaN.\n");
} else {
// point is on the sides
// decide if inner or outer wall based on distance to the sliceMidPoint
// convert one of the edge-points to double3
double3 edgePoint;
edgePoint.x = p0[0];
edgePoint.y = p0[1];
edgePoint.z = p0[2];
if (calcDistance(edgePoint, sliceMidPoint) > treshold) {
// cell is part of the outer wall
// insert triangle into a cellArray
trianglesOuter->InsertNextCell(cell);
// insert points into a points-collection
pointsOuter->InsertNextPoint(p0);
pointsOuter->InsertNextPoint(p1);
pointsOuter->InsertNextPoint(p2);
} else {
// cell is part of the inner wall
// insert triangle into a cellArray
trianglesInner->InsertNextCell(cell);
// insert points into a points-collection
pointsInner->InsertNextPoint(p0);
pointsInner->InsertNextPoint(p1);
pointsInner->InsertNextPoint(p2);
}
} //end if
} //end for
// add the geometry and topology to the areas
areaDataTop->SetPoints(pointsTop);
areaDataTop->SetPolys(trianglesTop);
areaDataBottom->SetPoints(pointsBottom);
areaDataBottom->SetPolys(trianglesBottom);
areaDataOuter->SetPoints(pointsOuter);
areaDataOuter->SetPolys(trianglesOuter);
areaDataInner->SetPoints(pointsInner);
areaDataInner->SetPolys(trianglesInner);
}
A input slice file and the resulting areas (written to file with a vtkXMLPolyDataWriter) are found here: https://filebin.net/u4fjq7by5cqeucps