Finding Groove Bottoms on a curve

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).

Here illustrating that an outward “bulge” can be closer to the center of the outer circle than the bottoms of the “dents”:

// Rolf

One way of doing could be that.


Cross product between tangent and curvature direction.

1 Like

A better version


Peak and valley of curves.gh (18.0 KB)

6 Likes

You’re just incredible. :slight_smile: 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:
    candidate_grooves.Add(current_pt);
}

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). :blush:

Again, many thanks!

// Rolf

No problem. I needed a recreation tonight. The exercise was :sunglasses:.there is also a discretization of the curve. You could suppress the first or last value of range component.

1 Like

Gorgeous.

You could also use the derivative of the curvature. When the derivative of curvature is zero there is a peak or a valley.
You will have to use
http://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Geometry_Curve_CurvatureAt.htm
http://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Geometry_Curve_TangentAt.htm

I’m interested to see your script
Thanks

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 :

// Rolf

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)
  {
    candidate_grooves.Add(current_pt);
  }
}

Grooves = candidate_grooves;

//
// That's all regarding "inward bulges"
//

CurveDepressions_Forum_00.gh (695.1 KB)

Edit: The two dents or “inward bulges” I’m actually interested in are the following two :

// Rolf

1 Like

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):

ConvexCurve_Forum_00.gh (18.7 KB)

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):

From this I can now pick the two deepest “inward dents” based on longest distance (deepest “dent”) from the ConvexCurve.

Thanks for help and inspiration, this is fun! :slight_smile:

// Rolf