Access regions data of stl subregions after using vtkSTLReader

Hello,
I have spent a ton of time trying to figure this out, but I have to admit defeat, so hopefully I can get some guidance here. I am trying to process stl files that are composed of multiple parts, called “solids” in the stl files. In an ASCII stl, we find a structure like this:

solid <name1>
    <facet data>
...
endsolid
solid <name2>
    <facet data>
...
endsolid

So we have basically a list of solids. I can readily read the stl with the vtkSTLReader, I can and do also show it in my renderer, this works fine. What I have NOT figured out yet:
How can I then access the data of the individual regions? I would like for example to know the bounding box of each individual region. I would like to be able to extract a certain region by its name and store it as an individual stl file. I would be extremely thankful for any pointers …
The closest thing I found is for Paraview: Extract region sizes from .stl file ($613) · Snippets · GitLab but I do not really understand how it works or how it can be translated to pure vtk with Python.
Thank you!
PS: I am working in Python and it would be great to know the correct calls there, but c++ might work as well as it can be adapted quite easily most of the time.

Hello,

Here, this is a C++ example illustrating on how to process regions with vtkConnectivityFilter: https://examples.vtk.org/site/Cxx/Filtering/ConnectivityFilterDemo/

There is also a simpler example in Python using vtkConnectivityFilter that you can use as a start up: https://examples.vtk.org/site/Python/Filtering/ConnectivityFilter/

regards,

PC

Thank you for your reply Paulo,
As the vtkConnectivityFilter is mentioned in the linked example I posted, I already tried this with no success so far. Reading a 8-region stl with reader = vtkSTLReader() and using ConnectivityFilter like this

conn = vtkConnectivityFilter()
conn.SetInputConnection(reader.GetOutputPort())
conn.SetExtractionModeToAllRegions()
conn.ColorRegionsOn()
conn.Update()
tst = conn.GetNumberOfExtractedRegions()

Results in tst = 1. So the regions are not extracted correctly as it seems. I do not know where this fails, it appears to work usually as shown by these examples.
I found here vtk - Splitting a 3D mesh based on sharpness - Stack Overflow that he/she uses connectivity.SetExtractionModeToSpecifiedRegions() and (kind of) then access them with connectivity.AddSpecifiedRegion(i), but if I only have 1 extracted region, this does not help me to access it individually.

This multi-solid STL file is a desperate attempt to keep the extremely limited STL file format relevant. It is time to move on and instead of spending any more time with STL use that file to get to know and develop support for more modern 3D printing file formats.

Hello Andras,
I agree in part with your thoughts about limitations of stl files, however, some tools use this format and I am kind of limited to and operation on it because of external dependency. It is not my choice.

If we load such an stl file in Paraview, the solids are also recognized, because by default the regions are colored by “STLSolidLabelling” which appears to be integers representing the amount of regions. I just do not know what the additional steps Paraview uses to get the regions are.

An alternative would be to have the STL reader output a partitioned dataset instead of a polydata.

You can use vtkThreshold filter to extract each region by the STLSolidLabelling data array (that is used for coloring).

If you are a paying customer of the software that forces you to use STL then please complain to the company (tell the sales representative, file a problem report, feature request, etc). If all their users complain about STL then maybe they will do something about it.

Thank you again for your responses. I am currently a bit out of time to test the suggestions, but will report back once I have. In the meantime I stumbled upon thes functions
‘stlReader.MergingOn()’ which might lead to merging of the solids? Also there is ‘stlReader.ScalarTagsOn()’ which is described as ‘Turn on/off tagging of solids with scalars’ and might be what I am looking for, especially combinded with ‘stlReader.GetScalarTags()’ which has a wrong description in the documentation, but could be helpful to get access to the individual solids. I will try out these. I assume this gives me the sought after STLSolidLabelling we see in PV.
@mwestphal could you be a bit more specific on how to get the stl reader to put out a partionioned dataset?
Thank you.

Well, you would have to add the feature in the vtkSTLReader, by writing C++ code.

Bad news: I have a hard time even understanding C++ code. Not only would I need to implement that but also to compile and make it somehow accessible by my Python project. All of which is beyond my knowledge. But …
Good news: I did it. The methods I found earlier for the stlReader help and in combination with the vtkThreshold I can isolate the parts.

headers = reader.GetHeader()  # this actually gives us the solid names right away
reader.ScalarTagsOn()   # causes output of an Array "STLSolidLabeling" in the CELLDATA
# this is how we can access it
polydata = reader.GetOutput()
celldata = polydata.GetCellData()
scalar_stlLabeling = celldata.GetScalars().GetArray("STLSolidLabeling")
# and here we can get the number of regions as the range of scalar (0 ... n)
range = scalar_stlLabeling.GetValueRange(0)

# and then we can use vtkThreshold to isolate parts
threshold = vtkThreshold()
threshold.SetInputConnection(0, reader.GetOutputPort())
threshold.SetThresholdFunction(vtkThreshold.THRESHOLD_UPPER)
threshold.SetInputArrayToProcess(0, 0, 0, vtkDataObject.FIELD_ASSOCIATION_CELLS, "STLSolidLabeling")
threshold.SetUpperThreshold(1)

I have not implemented it all the way through, I hope the scalar numbering does match the order in the headers list, so when I later extract bounding boxes and stuff, I know which named regions they belong to and not just which scalar values.