import bpy import sys import os # --- Parse Arguments --- # structure: [..., 'input.svg', 'output.stl', 'thickness', 'invert_flag', 'padding'] try: argv = sys.argv argv = argv[argv.index("--") + 1:] input_svg = argv[0] output_stl = argv[1] thickness_mm = float(argv[2]) # Read the 4th argument as integer (1 or 0), convert to boolean invert_mode = bool(int(argv[3])) if len(argv) > 3 else False # Read Padding (Default 0.0) padding_mm = float(argv[4]) if len(argv) > 4 else 0.0 except (ValueError, IndexError) as e: print(f"Error parsing arguments: {e}") sys.exit(1) # --- Step 1: Clean & Setup Units --- bpy.ops.wm.read_factory_settings(use_empty=True) scene = bpy.context.scene scene.unit_settings.system = 'METRIC' scene.unit_settings.length_unit = 'MILLIMETERS' scene.unit_settings.scale_length = 0.001 # --- Step 2: Import SVG --- if not os.path.exists(input_svg): print(f"FATAL: File not found: {input_svg}") sys.exit(1) bpy.ops.import_curve.svg(filepath=input_svg) # --- Step 3: Geometry Processing --- bpy.ops.object.select_all(action='SELECT') if bpy.context.selected_objects: bpy.context.view_layer.objects.active = bpy.context.selected_objects[0] # 1. Join all parts bpy.ops.object.join() obj = bpy.context.active_object obj.name = "Pattern" # 2. Convert to Mesh bpy.ops.object.convert(target='MESH') # 3. Center Geometry bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS') obj.location = (0, 0, 0) print(f"Imported Dimensions: {obj.dimensions.x:.2f}mm x {obj.dimensions.y:.2f}mm") def add_solidify(target_obj, thick, offset=0): mod = target_obj.modifiers.new(name='Solidify', type='SOLIDIFY') mod.thickness = thick mod.use_even_offset = True mod.use_rim = True mod.offset = offset bpy.context.view_layer.objects.active = target_obj bpy.ops.object.modifier_apply(modifier=mod.name) # --- Step 4: Logic Branch --- if invert_mode: print(f"--- INVERSION MODE (Negative) ---") if padding_mm > 0: print(f"Applying Padding: {padding_mm}mm (Total Extra Width: {padding_mm*2}mm)") # 1. Cutter (thicker than base) cutter_thickness = thickness_mm * 3.0 add_solidify(obj, cutter_thickness, offset=0) # 2. Base Plate bpy.ops.mesh.primitive_cube_add(location=(0,0,0)) base = bpy.context.active_object base.name = "BasePlate" # Calculate Dimensions with Padding # Padding is added to all sides, so width increases by padding*2 final_x = obj.dimensions.x + (padding_mm * 2) final_y = obj.dimensions.y + (padding_mm * 2) base.dimensions = (final_x, final_y, thickness_mm) # Apply transforms so scale is 1,1,1 bpy.ops.object.transform_apply(scale=True) base.location = (0,0,0) # 3. Boolean Difference print("Applying Boolean Difference...") bool_mod = base.modifiers.new(name='Boolean', type='BOOLEAN') bool_mod.object = obj bool_mod.operation = 'DIFFERENCE' bool_mod.solver = 'EXACT' try: bpy.context.view_layer.objects.active = base bpy.ops.object.modifier_apply(modifier=bool_mod.name) except Exception as e: print(f"Warning: Exact Boolean failed. {e}") bool_mod.solver = 'FAST' bpy.ops.object.modifier_apply(modifier=bool_mod.name) bpy.data.objects.remove(obj, do_unlink=True) obj = base else: print(f"--- STANDARD MODE (Positive) ---") add_solidify(obj, thickness_mm, offset=0) # --- Step 5: Final Placement (Z=0) --- bpy.context.view_layer.update() min_z = min([c[2] for c in obj.bound_box]) obj.location.z -= min_z # --- Step 6: Export --- print(f"Exporting to: {output_stl}") bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') obj.select_set(True) bpy.context.view_layer.objects.active = obj bpy.ops.wm.stl_export(filepath=output_stl, global_scale=1.0) else: print("Error: No objects found in SVG.") sys.exit(1)