文章目录
Core Technique
The script employs three main technical approaches:
1. Parallel Detection
def is_parallel_to_axis(line):
dx = abs(end[0] - start[0])
dy = abs(end[1] - start[1])
if dx > tolerance and dy <= tolerance:
return 'X'
elif dy > tolerance and dx <= tolerance:
return 'Y'
- Uses vector comparison to determine if beams are parallel to X or Y axis
- Implements tolerance checking for real-world imperfections
2. Proximity Analysis
def find_closest_main_line(point, main_lines, direction):
# For X-direction beams
if direction == 'X':
if min(start[1], end[1]) - 2000 <= point[1] <= max(start[1], end[1]) + 2000:
dist = abs(point[0] - start[0])
- Searches within 2000-unit radius
- Separates X and Y direction analysis
- Uses point-to-line distance calculations
3. Point Projection
# Projection calculation
closest_proj = [start[0], point[1], point[2]] # For X direction
closest_proj = [point[0], start[1], point[2]] # For Y direction
- Maintains Z-coordinate
- Projects endpoints onto main beam lines
Processing Thread
-
Layer Processing
- Identifies main and secondary beam layers
- Collects beam objects from layers
-
Beam Analysis
- Checks each secondary beam for axis alignment
- Determines adjustment needs
-
Adjustment Execution
- Projects endpoints to main beams
- Creates new adjusted beams
- Maintains original layer assignment
overview
import rhinoscriptsyntax as rs
import math
def is_parallel_to_axis(line):
"""Check if line is parallel to X or Y axis and return axis type"""
if not rs.IsCurve(line):
return None
start = rs.CurveStartPoint(line)
end = rs.CurveEndPoint(line)
if not start or not end:
return None
dx = abs(end[0] - start[0])
dy = abs(end[1] - start[1])
tolerance = 0.1 # tolerance for determining if parallel
if dx > tolerance and dy <= tolerance:
return 'X'
elif dy > tolerance and dx <= tolerance:
return 'Y'
else:
return None
def get_line_vector(line):
"""Get normalized direction vector of a line"""
start = rs.CurveStartPoint(line)
end = rs.CurveEndPoint(line)
if not start or not end:
return None
vector = [end[0] - start[0], end[1] - start[1], end[2] - start[2]]
length = math.sqrt(vector[0]**2 + vector[1]**2 + vector[2]**2)
if length == 0:
return None
return [v/length for v in vector]
def find_closest_main_line(point, main_lines, direction):
"""Find the closest main line that could potentially intersect"""
closest_line = None
min_dist = float('inf')
closest_proj = None
for main_line in main_lines:
if not rs.IsCurve(main_line):
continue
start = rs.CurveStartPoint(main_line)
end = rs.CurveEndPoint(main_line)
if not start or not end:
continue
# Project point onto main line's infinite extension
if direction == 'X':
# For X-direction secondary beams, compare Y coordinates
if min(start[1], end[1]) - 2000 <= point[1] <= max(start[1], end[1]) + 2000:
dist = abs(point[0] - start[0])
if dist < min_dist:
min_dist = dist
closest_line = main_line
closest_proj = [start[0], point[1], point[2]]
else: # Y direction
# For Y-direction secondary beams, compare X coordinates
if min(start[0], end[0]) - 2000 <= point[0] <= max(start[0], end[0]) + 2000:
dist = abs(point[1] - start[1])
if dist < min_dist:
min_dist = dist
closest_line = main_line
closest_proj = [point[0], start[1], point[2]]
return closest_line, closest_proj, min_dist
def adjust_secondary_beams():
# Get all main beam lines
all_layers = rs.LayerNames()
if not all_layers:
print("No layers found")
return
main_layers = [layer for layer in all_layers if layer.startswith("BEAM LINE::MAIN::")]
secondary_layers = [layer for layer in all_layers if layer.startswith("BEAM LINE::SECONDARY::")]
print("Found main layers: %s" % ", ".join(main_layers))
print("Found secondary layers: %s" % ", ".join(secondary_layers))
main_lines = []
for layer in main_layers:
objects = rs.ObjectsByLayer(layer)
if objects:
main_lines.extend([obj for obj in objects if rs.IsCurve(obj)])
if not main_lines:
print("No main beam lines found")
return
print("Found %d main beam lines" % len(main_lines))
secondary_lines = []
for layer in secondary_layers:
objects = rs.ObjectsByLayer(layer)
if objects:
secondary_lines.extend([obj for obj in objects if rs.IsCurve(obj)])
if not secondary_lines:
print("No secondary beam lines found")
return
print("Found %d secondary beam lines" % len(secondary_lines))
max_distance = 2000 # Maximum adjustment distance
adjusted_count = 0
skipped_not_parallel = 0
skipped_no_intersection = 0
debug_count = min(5, len(secondary_lines))
print("\nDebugging first %d secondary lines:" % debug_count)
rs.EnableRedraw(False)
try:
for i, sec_line in enumerate(secondary_lines):
debugging = i < debug_count
if not rs.IsCurve(sec_line):
continue
direction = is_parallel_to_axis(sec_line)
if not direction:
skipped_not_parallel += 1
if debugging:
print("Line %d: Not parallel to axis" % i)
continue
if debugging:
print("Line %d: Parallel to %s axis" % (i, direction))
start_point = rs.CurveStartPoint(sec_line)
end_point = rs.CurveEndPoint(sec_line)
if debugging:
print("Line %d: Start point %s, End point %s" % (i, str(start_point), str(end_point)))
if not start_point or not end_point:
continue
# Find closest main lines and projection points for both ends
start_main, start_proj, start_dist = find_closest_main_line(start_point, main_lines, direction)
end_main, end_proj, end_dist = find_closest_main_line(end_point, main_lines, direction)
modified = False
new_start = start_point
new_end = end_point
if start_main and start_dist <= max_distance:
if debugging:
print("Line %d: Start point can be adjusted, distance: %f" % (i, start_dist))
new_start = start_proj
modified = True
if end_main and end_dist <= max_distance:
if debugging:
print("Line %d: End point can be adjusted, distance: %f" % (i, end_dist))
new_end = end_proj
modified = True
if not (start_main or end_main):
skipped_no_intersection += 1
if debugging:
print("Line %d: No suitable main lines found" % i)
continue
if modified:
try:
old_layer = rs.ObjectLayer(sec_line)
new_line = rs.AddLine(new_start, new_end)
if new_line:
rs.DeleteObject(sec_line)
rs.ObjectLayer(new_line, old_layer)
adjusted_count += 1
if debugging:
print("Line %d: Successfully adjusted" % i)
except Exception as e:
print("Error creating new line: " + str(e))
continue
print("\nResults:")
print("Total secondary lines processed: %d" % len(secondary_lines))
print(