Untitled
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