Hey folks,
I need to determine the entry and exit points of a line within a bounding box.
In Dynamo, I achieved this using a polysurface generated from the bounding box, but this approach is too heavy for processing 20,000 lines and 6,000 bounding boxes. I would like to implement this in either C# or Python, preferably using a mathematical approach if no built-in methods are available.
The bounding boxes come from an Excel file, stored in a structured list with volume names and min/max XYZ coordinates. These are not actual Revit objects, and since they use survey coordinates, I first translate them to internal coordinates.
I tried using ChatGPT to generate a mathematical solution, which produced some results. However, the function sometimes returns extra points and even detects intersections when a line is entirely inside the box. Additionally, I struggle to understand the mathematical logic behind it.
import clr
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
# Get the document
doc = DocumentManager.Instance.CurrentDBDocument
from math import sqrt
# Function to compute distance between two points
def distance(p1, p2):
return sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2 + (p1[2] - p2[2])**2)
# Function to check if a point is inside a bounding box
def is_inside_bbox(point, bbox_min, bbox_max):
return all(bbox_min[i] <= point[i] <= bbox_max[i] for i in range(3))
# Function to check if an entire line is inside the bounding box
def is_line_inside_bbox(p1, p2, bbox_min, bbox_max):
return (is_inside_bbox(p1, bbox_min, bbox_max) and
is_inside_bbox(p2, bbox_min, bbox_max))
# Function to check line-box intersections
def line_bbox_intersection(p1, p2, bbox_min, bbox_max, epsilon=1e-6):
# Skip the line if it is fully inside the box
if is_line_inside_bbox(p1, p2, bbox_min, bbox_max):
return []
direction = (p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2])
t_min, t_max = 0, 1 # Parameter range for line segment
for i in range(3): # Iterate over x, y, z dimensions
if direction[i] != 0: # Avoid division by zero
t1 = (bbox_min[i] - p1[i]) / direction[i]
t2 = (bbox_max[i] - p1[i]) / direction[i]
t_entry, t_exit = min(t1, t2), max(t1, t2)
t_min, t_max = max(t_min, t_entry), min(t_max, t_exit)
if t_min > t_max: # No valid intersection
return []
intersection_points = []
if 0 < t_min <= 1:
entry_point = XYZ(p1[0] + t_min * direction[0],
p1[1] + t_min * direction[1],
p1[2] + t_min * direction[2])
if distance(entry_point, p1) > epsilon and distance(entry_point, p2) > epsilon:
intersection_points.append(entry_point)
if 0 < t_max <= 1 and t_min != t_max:
exit_point = XYZ(p1[0] + t_max * direction[0],
p1[1] + t_max * direction[1],
p1[2] + t_max * direction[2])
if distance(exit_point, p1) > epsilon and distance(exit_point, p2) > epsilon:
intersection_points.append(exit_point)
return intersection_points
# Input: List of Duct Elements and Bounding Box Data
ducts = UnwrapElement(IN[0]) # List of ducts from Dynamo input
volumes_data = IN[1] # List of bounding box data (7 lists: Name, MinX, MinY, MinZ, MaxX, MaxY, MaxZ)
# Parse bounding boxes
bounding_boxes = []
for i in range(len(volumes_data[0])): # Assuming first list has names
bbox_min = volumes_data[1][i]
bbox_max = volumes_data[2][i]
bounding_boxes.append((bbox_min, bbox_max))
# Process ducts
procesed_ducts = []
results = []
for duct in ducts:
location = duct.Location
if isinstance(location, LocationCurve):
curve = location.Curve
p1 = (curve.GetEndPoint(0).X, curve.GetEndPoint(0).Y, curve.GetEndPoint(0).Z)
p2 = (curve.GetEndPoint(1).X, curve.GetEndPoint(1).Y, curve.GetEndPoint(1).Z)
intersections = []
for bbox_min, bbox_max in bounding_boxes:
points = line_bbox_intersection(p1, p2, bbox_min, bbox_max)
if points:
intersections.append(points)
if intersections:
procesed_ducts.append(duct)
results.append(intersections)
# Output to Dynamo
OUT = procesed_ducts, results
What I Want to Achieve:
- Primary Goal:
- Given a list of ducts and another list containing bounding boxes (with volume names and min/max XYZ coordinates), I need a list of ducts and a list of entry and exit points corresponding to each duct.
- Secondary Goal:
- Structure the bounding box data efficiently.
- Optimize checks to determine entry and exit points only for nearby boxes.
- Explore additional optimizations.
Any suggestions or efficient approaches in C# or Python would be highly appreciated!