Based on our tests with this we can’t get outpoints to return anything in the following cases:
The breps are overlapping (‘true clash’)
The breps are touching (following a boolean split, for example)
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?
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()
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.