OK, so I’m looking to find N number of “grooves” or dents on a curve, and the “bottom-most” point in each of them (illustrated below are two “dents”). How can I find these “deepest points” in the simplest manner, even regarding that points along the “bulges” can be closer to the deepest points in the dents?
The search for the “deepest points” must start from the center of the outer circle, although no constraints exist for how to further calculate the final solution(s).
You’re just incredible. Thank you very much, I’ll study it trying to re-interpret the definition into a for-loop in a script.
After I posted I had only tried splitting the curve in segments, finding the point-centroid of the whole curve, and testing for shortest radius of the following (in a for-loop):
var prev_dist = centroid.DistanceTo(prev_pt); // i-1
var current_dist = centroid.DistanceTo(pts[i]); // i
var next_dist = centroid.DistanceTo(next_pt); // i+1
if (centroid.DistanceTo(prev_pt) > current_dist &&
centroid.DistanceTo(next_pt) > current_dist)
// Yup, this is the nearest (bottom-most)
// point on this curve segment, keep it:
Your solution seems to have better precision (since my solution is based on splitting the curve into N segments) and also not picking up points “near the bottom-most” (which my clumpsy for-loop does).
Absolutely no problem. I’ll arrange so that the definition will work when stripping (an awful lots of) crap from it.
The problem I have is that I actually reconstruct my curve from intersection points of a mesh. And that makes my curve a bit “bumpy” between the points (360 points in this case). This leads to very many “dents” detected unless applying a tolerance on the deviations (In my case I only compare distances from the curve’s centroid).
The white circles are my results (I will upload the script very soon) and the red circles are yours, on essentially the same curve.
I had to bake and smooth the curve for your definition though, because I ended up with too many inward dents due to the spiky curve. You may have a better way of defining the contour curve from the points. Anyway, here are the results :
OK, here’s the script. I hope the definition works standalone. The following code sequence is relevant :
// Find inward Bulges
var centroid = GetCentroidForPoints(points_hits.ToList());
var candidate_grooves = new List<Point3d>();
var len = points_hits.Length;
for (var i = 0; i < len; i++)
// Ensure that prev / next points flip to array
// start or array end so as to not exceed the bounds
var prev_ix = i - 1;
if (prev_ix < 0)
prev_ix = len - 1;
var next_ix = i + 1;
if (next_ix > len - 1)
next_ix = 0;
// Do the math
var prev_pt = points_hits[prev_ix];
var current_pt = points_hits[i];
var next_pt = points_hits[next_ix];
var current_dist = centroid.DistanceTo(current_pt);
var prev_dist = centroid.DistanceTo(prev_pt);
var next_dist = centroid.DistanceTo(next_pt);
if (prev_dist - tolerance > current_dist &&
next_dist - tolerance > current_dist)
Grooves = candidate_grooves;
// That's all regarding "inward bulges"
If you want to filter by distance you could also use a convex curve and calculate a distance or vector from the convex curve and points on your initial curve.
Not on my PC at the moment but it seems that convex is not in rhinocommon. There is surely a library with that.
Yes, that’s probably the simplest approach. I designed the following algorithm which seems to provide with a ConvexCurve. Someone smarter than me can probably simplify the algorithm (Edit: What puzzles me is why I couldn’t make the for-loop clean up all the “inward” points in its first round):
I haven’t tried it on extreme curvatures but it seems to work for this case. Edit: Illustration of the strategy in the algorithm which is to remove Point(B - mid) if the VectorAngle(a) is less than the VectorAngle(b) compared to the Vector(Centroid):