# Finding lower boundary of a 3D object in list format

I have the following point list and would like to find the points located in the lower boundary of the 3D object (It is part of a body torso).

https://pastebin.com/L12n0Gfr

I am using the following script. However, in the end it shows just one point which is not correct. I think the reason is that the lower boundary points are not aligned with a straight line. Any help is really appreciated.

B3 = Select[data3D, MemberQ[#, Min[ data3D[[All, 2]]]] &];

• You have to specify how you define the lower boundary. It could be threshold = Mean[Data3D[[All, 3]]]; lb = Select[Data3D, #[[3]] < threshold &]; Or some other threshold that you define. Also, a minimal working example does not consist of more than 9600 points. Jun 30 '20 at 20:43
• Thank you! Exactly, I do not know how I can define the threshold that Mathematica automatically selects the points located on the lower edge of the torso. If they were in one line then maybe Min (along Y axes) would work but it seems they are not aligned along a straight line. Jun 30 '20 at 21:33

I think I've found a method that could work. The idea is to make a MeshRegion out of your points and then find all of the polygons with similar face normal vectors. The normal vectors can be computed with MeshCellNormals as described in this answer:

mesh = ConvexHullMesh[Data3D];
poly = MeshPrimitives[ConvexHullMesh[Data3D], 2];
clusters = ClusteringComponents[
RegionMeshMeshCellNormals[mesh, 2],
Automatic,
1
];
nClusters = Max[clusters]


6

So now we have all of the polygons and clustered them into groups and we just need to figure out which clusters correspond to the top and bottom of the torso. In my case, it turns out that clusters 1 and 3 are the ones I need:

Show[
ListPointPlot3D[Data3D],
Graphics3D[Pick[poly, clusters, 1 | 3]]
]


To get the points defined by these polygons (say, the ones from cluster 1):

pts = Union @@ Pick[poly, clusters, 1][[All, 1]];
Length[pts]


408

Check that these points are all members of Data3D:

Length[Intersection[pts, Data3D]]


408

edit

The OP indicated that there seems to be some issue with the computation of the normals. It's possible that some of the polygons of the mesh are very tiny and the normals cannot be computed or something. The first suggestion I have for this is to try

mesh = RepairMesh[mesh]


to see if that helps. If that doesn't work, it's worth investigating the normals computed:

normals = RegionMeshMeshCellNormals[mesh, 2];
Count[normals, Except[{__?NumericQ}]]
Length[normals]


If the number of non-numeric vectors in normals is fairly low, you could consider throwing out the problematic polygons:

goodPolyPos = Flatten @ Position[normals, {__?NumericQ}, {1}, Heads -> False];
normals = normals[[goodPolyPos]];
poly = poly[[goodPolyPos]]


From there you could continue with:

clusters = ClusteringComponents[normals, Automatic, 1];


and see how you get on.

• Thank you, Sjoerd! I tried your script on my whole torso. What I have uploaded here was part of Torso because of the limitation on Pastebin capacity (i.e number off points). Unfortunately, when I apply it on the whole torso it gives the following error" ClusteringComponents does not support this type of data." Any idea why? Jul 1 '20 at 18:40
• @MehdiEbadi That's difficult to say in advance. Check that your data is a numeric matrix (i.e., MatrixQ[Data3D, NumericQ] is True) and also check it for the computed normals that you throw into ClusteringComponents. I wouldn't be surprised if there's a corrupted point in there somewhere. Jul 1 '20 at 21:49
• Thank you Sjoerd! I checked it. Data 3D is a numeric matrix but the ClusteringComponents is not a numeric matrix (i.e give False ) Jul 2 '20 at 7:17
• @MehdiEbadi I updated the post with some suggestions you could try for this problem. Jul 2 '20 at 8:09