I have the following list of points in 3D and would like to find the points which are located on the lower edge of the object and on (or closest distance to) the X-Y or Y-Z plane of the symmetry. (Please see yellow points in fig 1). What I did was generating a point which has the X average with Y and Z min and then finding a point of the list which has the closest distance to the generated point. However, it was not correct as the generated point was not a member of the list point so the closest point was sometimes in the front and sometimes on the back of the object for different lists of points.


fig. 1 fig.2

  • $\begingroup$ If you have a plane region (e.g a xyplane = HalfPlane[......]), you could get some of the closest points to that plane within some acceptable distance e.g xyclosepoints = Select[Data3D, RegionDistance[#,xyplane] < 5 &] Then of these points find the one with the smallest coordinate MinimalBy[xyclosepoints, #[[3]]&] $\endgroup$
    – flinty
    Jul 3, 2020 at 23:15
  • $\begingroup$ Thanks a lot flinty! Unfortunately, I do not have a plane region. Is it possible to define that? $\endgroup$ Jul 3, 2020 at 23:33
  • 1
    $\begingroup$ I am looking into it - if you do a KarhunenLoeveDecomposition you can get the data in a nicer frame and then transform back later. Also I meant InfinitePlane not HalfPlane, and my RegionDistance arguments were the wrong way around. $\endgroup$
    – flinty
    Jul 3, 2020 at 23:35

1 Answer 1


This is a little involved but I hope you can follow this step-by-step:

(* load the data *)

(* get the centroid and the KLDecomposition *)
kld = KarhunenLoeveDecomposition[Transpose[Data3D]];

(* get the transformed points, new basis, and new centroid *)
transformed = Transpose[kld[[1]]];
basis = kld[[2]];
trcentr = Mean[transformed];
(* offset to {0,0,0} *)
transformed = (# - trcentr) & /@ transformed;

(* create some planes *)
xyplane = InfinitePlane[{0, 0, 0}, {{1, 0, 0}, {0, 1, 0}}];
xzplane = InfinitePlane[{0, 0, 0}, {{1, 0, 0}, {0, 0, 1}}];
yzplane = InfinitePlane[{0, 0, 0}, {{0, 1, 0}, {0, 0, 1}}];

(* find the points near to each plane, and of those points find the one lowest down *)
yzclosepoints = Select[transformed, RegionDistance[yzplane, #] < 0.5 &];
yzsmallestz = First@MinimalBy[yzclosepoints, Last];
xzclosepoints = Select[transformed, RegionDistance[xzplane, #] < 0.5 &];
xzsmallestz = First@MinimalBy[xzclosepoints, Last];

(* show the transformed points, the planes, the points near the planes *)
 ListPointPlot3D[transformed, PlotRange -> Full, BoxRatios -> 1, PlotStyle -> Black],
 Graphics3D[{Opacity[.1], Red, xyplane, Green, xzplane, Blue, yzplane}], 
   Blue, Point[yzclosepoints],
   Darker@Green, Point[xzclosepoints],
   Orange, PointSize[Large],
   Point[yzsmallestz], Point[xzsmallestz]}]

points kld planes

We now have the desired points but we need to transform them back into the original space:

invkld = Inverse[basis];
untransform[point_] := invkld.(point + trcentr)

(* show the two points in the original space *)
 Graphics3D[{Red, PointSize[Large],

points in original space

  • $\begingroup$ Thank you very much flinty! You are awesome. $\endgroup$ Jul 3, 2020 at 23:58
  • $\begingroup$ I have a question and appreciate your response! I tried it on my whole object. Actually, I could not upload whole points because of the limitation on the Pastebin capacity. To get the side point, I added the XY plane to your script. It shows the correct list of side points; However, It does not give the first point of the list. (i.e the edge point locates a bit higher than the bottom edge). It is weird as your script works well for the points on the Yz plane. (i.e. point on the bake) $\endgroup$ Jul 4, 2020 at 1:11
  • 1
    $\begingroup$ Try adjusting the < 0.5 where I do the Select to something a bit larger. It's possible it's ignoring too many points. $\endgroup$
    – flinty
    Jul 4, 2020 at 1:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.