Maximum (minimum) point of surface

Hi everyone
For
1- find surface ClosestPoint to other Surface

Or for:
2-find Maximum (minimum) point of surface

Is there a command or api in Grasshopper or C #?

For the maximum and minimum of a Surface, I intersect with its BoundingBox, but their common Intersection is not a Point and is null.!!


max of surface.gh (196.2 KB)

Maybe something like this?

The higher the number of points the higher the accuracy!

I don’t know if there is a more exact method, but from my understanding you can always just find an approximation. I might be wrong?

You could do the same procedure with a script and for instance start with a certain number of point samples, and increase it gradually until you get the same two points as with the preview previous number of samples. This way you’d probably always get the “best” accuracy.

max of surface 2.gh (200.2 KB)

thanks for reply Looks like some of the time, for example, the subject below this algorithm can not find the point of maximum !
(Same when the entrance is a Sphere and…)


max of surface 3.gh (9.1 KB)

Maybe
SrfMinMax
SrfMinMax.gh (133.6 KB)

1 Like

Here’s a Python script that should work for most surfaces.

Screenshot 2021-11-12 at 14.26.54

Keep in mind that the found extreme points are always just an approximation.

import Rhino.Geometry as rg
import Grasshopper as gh
import scriptcontext as sc


def divide_surface(srf, udiv, vdiv, nested=False):
    """Divides a surface into a grid of uv-points.
    
    Args:
      srf (Rhino.Geometry.Surface): Surface to divide
      udiv (int): Number of divisions in surface u-direction
      vdiv (int): Number of divisions in surface v-direction
      nested (bool): Optionally True to return a nested list [column][row], 
        by default False to return a flat list.
    
    Returns:
      The division points."""
    
    num_rows = udiv + 1
    num_cols = udiv + 1
    
    udom = rg.Interval(0, udiv)
    vdom = rg.Interval(0, vdiv)
    S.SetDomain(0, udom)
    S.SetDomain(1, vdom)
    
    div_pts = []
    for i in xrange(num_rows):
        for j in xrange(num_cols):
            div_pts.append(rg.Surface.PointAt(srf, i, j))
    
    if nested:
        return [div_pts[i:i+num_rows] for i in xrange(0, len(div_pts), num_rows)]
    return div_pts
    


def find_extremes_z(srf, udiv=10, vdiv=10, step=10, max_div=250, __pts=[], __vals=[]):
    """Recursively finds the approximated extremes - highest and lowest point in z - on a surface.
    
    Args:
      srf (Rhino.Geometry.Surface): Surface to evaluate the z-extremes for
      udiv (int): Optional number of start divisions in surface u-direction, by default 15
      vdiv (int): Optional number of start divisions in surface v-direction, by default 15
      step (int): Optional step value that increments udiv and vdiv each recursion level, by default 15
      max_div (int): Optional maximum number of divisions to in uv-direction of the surface
     
    Returns:
      The approximated lowest [0] and hightest point [1] on the surface."""
    
    if udiv >= max_div or vdiv >= max_div:
        return __pts
    
    sample_pts = divide_surface(srf, udiv, vdiv)
    sample_pts.sort(key=lambda pt: pt.Z)
    extremes = [sample_pts[0], sample_pts[-1]]
    # print "U:", udiv, "V:", vdiv, "-> Extremes:", [pt.Z for pt in __pts]

    if len(__pts) == 0:
        __vals = [[] for _ in xrange(len(extremes))]
        return find_extremes_z(srf, udiv+step, vdiv+step, step, max_div, extremes, __vals)
    
    for i in xrange(len(extremes)):
        difference = abs(extremes[i].Z) - abs(__pts[i].Z)
        if difference > 0.0:
            __pts[i] = extremes[i]
        __vals[i].append(difference)
    
    
    if len(__vals[0]) == 10:
        dsum = sum([sum(lt) for lt in __vals])
        if dsum < sc.doc.ModelAbsoluteTolerance:
            return __pts
    
    return find_extremes_z(srf, udiv+step, vdiv+step, step, max_div, __pts, __vals)
  
            
        

if __name__ == "__main__":
    if S:
        if not D:
            D = 250
        E = find_extremes_z(S, max_div=D)
    else:
        ghenv.Component.AddRuntimeMessage(
            gh.Kernel.GH_RuntimeMessageLevel.Warning,
            "Input parameter S failed to collect data"
        )

The surface gets recursively more and more divided, until for at least 10 steps there was no change for both extremes found.
At each step all the division points are sorted and the extreme points compared to those found at the previous step.
This doesn’t exclude that for a later, even finer division, there would have been an even better result! This and the fact that the surface can infinitely be subdivided, makes the resulting extremes always an approximation.

max of surface 4.gh (199.6 KB)

1 Like

thanks very useful