Clash Detection

@dale,

Based on our tests with this we can’t get outpoints to return anything in the following cases:

  1. The breps are overlapping (‘true clash’)
  2. The breps are touching (following a boolean split, for example)
  3. The breps are touching at only a single point in space.

We’re trying to solve for cases where we have ‘true clashes’ vs. just touching. Is Rhino.Geometry.Intersect.Intersection.BrepBrep() this correct method for doing this? If not, can you suggest another method that would accomplish this goal?

Thanks,

Dan

@lignindes - rather than reopen a four year old thread, I’ve started a news one.

You don’t mention what you are trying to and why. You might start there.

You also don’t provide any source code or geometry. Not sure how we can help.

– Dale

@dale,

Thanks for the reply.

We’re trying to solve for cases where we have ‘true clashes’ vs. just touching.

CLASH.3dm (369.7 KB)

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc
import System
import Rhino.Geometry as rg

def create_layer(layer_name, color):
    """
    Creates a layer with the specified name and color if it doesn't already exist.
    """
    if not rs.IsLayer(layer_name):
        rs.AddLayer(layer_name, color)
    else:
        rs.LayerColor(layer_name, color)

def is_brep_valid(brep_id):
    """
    Checks if the BRep object is valid.
    """
    brep = rs.coercebrep(brep_id)
    return brep.IsValid if brep else False

def add_invalid_dots(brep_id):
    """
    Adds a text dot at the location of the invalid BRep object.
    """
    bbox = rs.BoundingBox(brep_id)
    if bbox:
        center_point = rs.PointAdd(bbox[0], bbox[6]) / 2  # Calculate the center of the bounding box
        rs.AddTextDot("Invalid Object", center_point)

def add_dot_with_layer(dot_text, point, layer_name):
    """
    Adds a text dot at the specified point and sets it to the specified layer.
    """
    current_layer = rs.CurrentLayer()
    rs.CurrentLayer(layer_name)
    dot_id = rs.AddTextDot(dot_text, point)
    rs.CurrentLayer(current_layer)
    return dot_id

def clash_detection_optimized():
    # Setup layers for TOUCHING and CLASHING dots
    create_layer("DOTS::TOUCHING", (255, 255, 0))  # Yellow for touching
    create_layer("DOTS::CLASHING", (255, 0, 0))  # Red for clashing

    brep_ids = rs.GetObjects("Select multiple Brep objects for clash detection", rs.filter.polysurface, minimum_count=2)
    if brep_ids is None or len(brep_ids) < 2:
        print("You must select at least two Brep objects.")
        return

    valid_breps = []
    brep_names = []
    centerpoints = []
    no_clash_instances = []
    clashes = []
    clash_breps = []

    for brep_id in brep_ids:
        if is_brep_valid(brep_id):
            brep = rs.coercebrep(brep_id)
            valid_breps.append((brep, brep_id))
            name = rs.ObjectName(brep_id) if rs.ObjectName(brep_id) else str(brep_id)
            centroid_result = rs.SurfaceVolumeCentroid(brep_id)
            if centroid_result:
                centerpoint = centroid_result[0]
                centerpoints.append(centerpoint)
                brep_names.append(name)
            else:
                print("Warning: Could not compute centroid for object '{}'. This object will be excluded from clash detection.".format(name))
        else:
            add_invalid_dots(brep_id)

    if len(valid_breps) < 2:
        print("Valid BRep objects not found or less than two valid objects selected.")
        return

    #tolerance = sc.doc.ModelAbsoluteTolerance
    tolerance = 0.001
    model_units = rs.UnitSystem()
    max_distance = 40 * 12 if model_units == 8 else None  # Assumes inches if not, manual change required.

    if max_distance is None:
        rs.MessageBox("This script requires the model units to be in inches. Please change the unit system.")
        return

    for i in range(len(valid_breps)):
        for j in range(i + 1, len(valid_breps)):
            distance = centerpoints[i].DistanceTo(centerpoints[j])
            if distance <= max_distance:
                intersection = Rhino.Geometry.Intersect.Intersection.BrepBrep(valid_breps[i][0], valid_breps[j][0], tolerance)
                if intersection[0] and len(intersection[1]) > 0:
                    #print len(intersection[2])
                    #print len(intersection[1])
                    points = intersection[2]
                    curves = intersection[1]
                    #print curves
                    #print points
                    #print intersection[0]
                    joined = rg.Curve.JoinCurves(curves)
                    #print joined
                    #print len(joined)
                    #for curve in joined:
                        #print curve.IsClosed
                        #sc.doc.Objects.AddCurve(curve)
                        #print curve.Geometry
                    #for point in points:
                        #print curve.IsClosed
                        #sc.doc.Objects.AddPoint(point)
                        #print curve.Geometry
                    feedback = "Touching" if len(intersection[1]) <= 5 else "True Clash" #based on qty of curves returned, very rudimentary.  
                    layer_name = "DOTS::TOUCHING" if feedback == "Touching" else "DOTS::CLASHING"
                    point = centerpoints[i]
                    clash_text = "{} between '{}' and '{}'".format(feedback, brep_names[i], brep_names[j])
                    add_dot_with_layer(clash_text, point, layer_name)
                    #print(clash_text)
                    if feedback == "True Clash":
                        clashes.append(feedback) 
                        clash_breps.append(valid_breps[i][1])
                        clash_breps.append(valid_breps[j][1])
                else:
                    no_clash_instances.append((brep_names[i], brep_names[j]))

    if clashes:
        message = "{} True Clahses detected.".format(len(clashes))
        rs.MessageBox(message, 0, "Clash Detection Summary")
        rs.SelectObjects(clash_breps)

if __name__ == "__main__":
    clash_detection_optimized()

@dale

I don’t want to be a bother, but I would like your feedback on an approach to determine if Breps are touching vs. clashing (within a tolerance).

Thanks,

Dan

Hi @lignindes,

Intersect.BrepBrep is very useful. So is MeshClash.

Tolerance is important, of course. You the tolerance in your model is 0.01 and the overlap is smaller, 0.001. Thus, you’ll need to use a smaller tolerance than what the document provides to detect the intersection.

Not sure I’ve helped.

– Dale

@dale

Thank you, yes that helps!

Dan