【Rhino】【Python】adjust ends of secondary beam lines to the closest main beam line

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

  1. Layer Processing

    • Identifies main and secondary beam layers
    • Collects beam objects from layers
  2. Beam Analysis

    • Checks each secondary beam for axis alignment
    • Determines adjustment needs
  3. 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(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hmywillstronger

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值