Untitled

 avatar
unknown
plain_text
8 months ago
9.0 kB
10
Indexable
def generate_bend_tabs(part_edge, bend_line, material_props, press_brake_config, user_params=None):
    """
    Generate temporary bend tabs for sheet metal forming operations
    
    Args:
        part_edge: List of edge segments [(x1,y1,x2,y2, type), ...] where type is 'line' or 'arc'
        bend_line: ((x1,y1), (x2,y2)) - start and end points of bend axis
        material_props: {thickness, yield_strength, bend_radius, springback_factor}
        press_brake_config: {min_flange_length, backgauge_clearance, die_width}
        user_params: Optional override for tab parameters
    
    Returns:
        {
            flat_pattern: Modified geometry with tabs,
            tab_locations: List of tab objects,
            removal_instructions: Text guide for post-forming
        }
    """
    
    # Default parameters (can be overridden)
    params = {
        'tab_width': 15.0,              # mm
        'tab_spacing': 75.0,            # mm
        'offset_multiplier': 3.0,       # times material thickness
        'perforation_diameter': 3.0,    # mm
        'perforation_spacing': 6.0,     # mm
        'web_thickness_ratio': 0.4,     # fraction of material thickness
        'min_tab_strength': 50.0,       # N minimum holding force
        'safety_factor': 1.5
    }
    if user_params:
        params.update(user_params)
    
    # Step 1: Analyze edge geometry relative to bend line
    problem_edges = []
    for edge in part_edge:
        edge_analysis = analyze_edge_to_bend_relationship(edge, bend_line)
        
        if edge_analysis['needs_tab']:
            problem_edges.append({
                'edge': edge,
                'min_distance': edge_analysis['min_distance'],
                'closest_point': edge_analysis['closest_point'],
                'edge_type': edge_analysis['type'],  # 'curved', 'angled', 'close'
                'angle_to_bend': edge_analysis['angle']
            })
    
    # Step 2: Determine tab placement locations
    tab_locations = []
    for prob_edge in problem_edges:
        # Calculate how many tabs needed based on edge length
        edge_length = calculate_edge_length(prob_edge['edge'])
        num_tabs = max(1, int(edge_length / params['tab_spacing']))
        
        # Space tabs evenly along problem edge
        for i in range(num_tabs):
            t = (i + 0.5) / num_tabs  # Parameter along edge (0 to 1)
            tab_point = interpolate_on_edge(prob_edge['edge'], t)
            
            # Calculate optimal tab offset from bend line
            base_offset = params['offset_multiplier'] * material_props['thickness']
            clearance = press_brake_config['backgauge_clearance']
            total_offset = base_offset + clearance + material_props['bend_radius']
            
            # Check for collisions with other geometry
            if not check_tab_collision(tab_point, total_offset, part_edge, tab_locations):
                tab_locations.append({
                    'position': tab_point,
                    'offset_distance': total_offset,
                    'orientation': calculate_perpendicular_to_bend(bend_line, tab_point),
                    'parent_edge': prob_edge['edge']
                })
    
    # Step 3: Generate tab geometry for each location
    tabs = []
    for loc in tab_locations:
        tab_geom = create_tab_geometry(
            base_point=loc['position'],
            orientation=loc['orientation'],
            width=params['tab_width'],
            length=loc['offset_distance'],
            shape='rectangular'  # or 'trapezoidal' for less material
        )
        
        # Step 4: Add break-off features
        breakoff_features = create_breakoff_joint(
            tab_geom=tab_geom,
            attachment_edge=loc['parent_edge'],
            perforation_dia=params['perforation_diameter'],
            perforation_spacing=params['perforation_spacing'],
            web_thickness=material_props['thickness'] * params['web_thickness_ratio']
        )
        
        # Step 5: Validate tab strength
        required_force = calculate_bending_force(
            material_props['yield_strength'],
            material_props['thickness'],
            loc['offset_distance']
        )
        
        tab_strength = calculate_tab_strength(
            tab_geom,
            breakoff_features,
            material_props
        )
        
        if tab_strength / params['safety_factor'] >= required_force:
            tabs.append({
                'geometry': tab_geom,
                'breakoff': breakoff_features,
                'location': loc,
                'strength': tab_strength
            })
        else:
            # Increase tab width or adjust breakoff features
            tabs.append(reinforce_tab(tab_geom, breakoff_features, required_force, params))
    
    # Step 6: Generate modified flat pattern
    flat_pattern = merge_tabs_with_part(part_edge, tabs)
    
    # Add metadata for manufacturing
    flat_pattern = add_layer_separation(flat_pattern, {
        'part_outline': 'PART',
        'tab_geometry': 'TABS',
        'cut_lines': 'CUT',
        'bend_lines': 'BEND',
        'perforations': 'PERFORATION'
    })
    
    # Generate removal instructions
    removal_instructions = generate_removal_guide(tabs, material_props)
    
    return {
        'flat_pattern': flat_pattern,
        'tab_locations': tabs,
        'removal_instructions': removal_instructions,
        'bend_sequence': calculate_optimal_bend_sequence(bend_line, tabs)
    }


# Supporting functions (implementations would follow)

def analyze_edge_to_bend_relationship(edge, bend_line):
    """Determine if edge needs support during bending"""
    min_dist = calculate_min_distance_to_line(edge, bend_line)
    angle = calculate_angle_between(edge, bend_line)
    edge_type = determine_edge_type(edge)
    
    needs_tab = (
        edge_type == 'arc' or                    # Curves always problematic
        min_dist < 50.0 or                       # Too close to bend line
        (angle > 15 and angle < 165)             # Not parallel/perpendicular
    )
    
    return {
        'needs_tab': needs_tab,
        'min_distance': min_dist,
        'closest_point': find_closest_point(edge, bend_line),
        'angle': angle,
        'type': classify_problem_type(edge_type, min_dist, angle)
    }


def create_breakoff_joint(tab_geom, attachment_edge, perforation_dia, perforation_spacing, web_thickness):
    """Create perforations or score lines for easy tab removal"""
    attachment_line = find_intersection_line(tab_geom, attachment_edge)
    
    # Create perforation pattern
    perforations = []
    line_length = calculate_length(attachment_line)
    num_perfs = int(line_length / perforation_spacing)
    
    for i in range(num_perfs):
        t = i / (num_perfs - 1) if num_perfs > 1 else 0.5
        perf_center = interpolate_line(attachment_line, t)
        perforations.append({
            'type': 'circle',
            'center': perf_center,
            'diameter': perforation_dia,
            'depth': 'through'  # or calculate partial depth for living hinge
        })
    
    return {
        'perforations': perforations,
        'web_thickness': web_thickness,
        'connection_type': 'snap-off'
    }


def calculate_tab_strength(tab_geom, breakoff_features, material_props):
    """Calculate holding force of tab before it breaks off"""
    web_width = calculate_total_web_width(breakoff_features['perforations'])
    web_thickness = breakoff_features['web_thickness']
    
    # Simplified strength calculation (actual would include stress concentrations)
    cross_section_area = web_width * web_thickness
    breaking_force = material_props['yield_strength'] * cross_section_area
    
    return breaking_force


def merge_tabs_with_part(part_edge, tabs):
    """Combine part geometry with tab geometry into single flat pattern"""
    combined_geometry = []
    
    # Add main part outline
    combined_geometry.extend(part_edge)
    
    # Add each tab
    for tab in tabs:
        combined_geometry.extend(tab['geometry'])
        combined_geometry.extend(tab['breakoff']['perforations'])
    
    # Resolve overlaps and create clean connections
    merged = resolve_intersections(combined_geometry)
    
    return merged


def generate_removal_guide(tabs, material_props):
    """Create human-readable instructions for tab removal"""
    instructions = []
    instructions.append(f"After bending, remove {len(tabs)} temporary support tabs:")
    instructions.append("1. Tabs are perforated for easy snap-off")
    instructions.append("2. Use pliers to grip tab end and twist/pull perpendicular to part")
    instructions.append("3. Deburr attachment points with file or sandpaper")
    
    if material_props['thickness'] > 2.0:
        instructions.append("Note: Thicker material may require cutting tools for removal")
    
    return "\n".join(instructions)
Editor is loading...
Leave a Comment