Add files via upload

pull/276/head
SpectralVectors 2024-10-23 17:37:33 -04:00 zatwierdzone przez GitHub
rodzic a4c393849b
commit 11444b957f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
16 zmienionych plików z 798 dodań i 1249 usunięć

Wyświetl plik

@ -15,69 +15,56 @@ class CAM_AREA_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Operation Area" bl_label = "CAM Operation Area"
bl_idname = "WORLD_PT_CAM_OPERATION_AREA" bl_idname = "WORLD_PT_CAM_OPERATION_AREA"
panel_interface_level = 0
prop_level = { def draw(self, context):
"draw_use_layers": 0, layout = self.layout
"draw_maxz": 1, if self.op is not None:
"draw_minz": 1, # Use Layers
"draw_ambient": 1, col = layout.column(align=True)
"draw_limit_curve": 1,
"draw_first_down": 1,
}
def draw_use_layers(self):
if not self.has_correct_level():
return
col = self.layout.column(align=True)
row = col.row(align=True) row = col.row(align=True)
row.prop(self.op, "use_layers") row.prop(self.op, "use_layers")
if self.op.use_layers: if self.op.use_layers:
row.prop(self.op, "stepdown") row.prop(self.op, "stepdown")
self.draw_first_down(col)
def draw_first_down(self, col): # First Down
if not self.has_correct_level(): if self.level >= 1 and self.op.strategy in ["CUTOUT", "POCKET", "MEDIAL_AXIS"]:
return
if self.op.strategy in ["CUTOUT", "POCKET", "MEDIAL_AXIS"]:
row = col.row(align=True) row = col.row(align=True)
row.label(text="") row.label(text="")
row.prop(self.op, "first_down") row.prop(self.op, "first_down")
def draw_maxz(self): # Max Z
if not self.has_correct_level(): if self.level >= 1:
return col = layout.column(align=True)
self.layout.prop(self.op, "maxz") col.prop(self.op, "maxz")
self.layout.prop(self.op.movement, "free_height") col.prop(self.op.movement, "free_height")
if self.op.maxz > self.op.movement.free_height: if self.op.maxz > self.op.movement.free_height:
self.layout.label(text="!ERROR! COLLISION!") col.label(text="!ERROR! COLLISION!")
self.layout.label(text="Depth Start > Free Movement Height") col.label(text="Depth Start > Free Movement Height")
self.layout.label(text="!ERROR! COLLISION!") col.label(text="!ERROR! COLLISION!")
def draw_minz(self): # Min Z
if not self.has_correct_level(): if self.level >= 1:
return
if self.op.geometry_source in ["OBJECT", "COLLECTION"]: if self.op.geometry_source in ["OBJECT", "COLLECTION"]:
if self.op.strategy == "CURVE": if self.op.strategy == "CURVE":
self.layout.label(text="Cannot Use Depth from Object Using Curves") col.label(text="Cannot Use Depth from Object Using Curves")
row = self.layout.row(align=True) row = col.row(align=True)
row.label(text="Set Max Depth from") row.label(text="Set Max Depth from")
row.prop(self.op, "minz_from", text="") row.prop(self.op, "minz_from", text="")
if self.op.minz_from == "CUSTOM": if self.op.minz_from == "CUSTOM":
self.layout.prop(self.op, "minz") row.prop(self.op, "minz")
else: else:
self.layout.prop(self.op, "source_image_scale_z") col.prop(self.op, "source_image_scale_z")
self.layout.prop(self.op, "source_image_size_x") col.prop(self.op, "source_image_size_x")
if self.op.source_image_name != "": if self.op.source_image_name != "":
i = bpy.data.images[self.op.source_image_name] i = bpy.data.images[self.op.source_image_name]
if i is not None: if i is not None:
sy = int((self.op.source_image_size_x / i.size[0]) * i.size[1] * 1000000) / 1000 size_x = self.op.source_image_size_x / i.size[0]
self.layout.label(text="Image Size on Y Axis: " + strInUnits(sy, 8)) size_y = int(x_size * i.size[1] * 1000000) / 1000
self.layout.separator() col.label(text="Image Size on Y Axis: " + strInUnits(size_y, 8))
self.layout.prop(self.op, "source_image_offset") col.separator()
col = self.layout.column(align=True) col.prop(self.op, "source_image_offset")
col.prop(self.op, "source_image_crop", text="Crop Source Image") col.prop(self.op, "source_image_crop", text="Crop Source Image")
if self.op.source_image_crop: if self.op.source_image_crop:
col.prop(self.op, "source_image_crop_start_x", text="Start X") col.prop(self.op, "source_image_crop_start_x", text="Start X")
@ -85,28 +72,17 @@ class CAM_AREA_Panel(CAMButtonsPanel, Panel):
col.prop(self.op, "source_image_crop_end_x", text="End X") col.prop(self.op, "source_image_crop_end_x", text="End X")
col.prop(self.op, "source_image_crop_end_y", text="End Y") col.prop(self.op, "source_image_crop_end_y", text="End Y")
def draw_ambient(self): # Draw Ambient
if not self.has_correct_level(): if self.level >= 1:
return
if self.op.strategy in ["BLOCK", "SPIRAL", "CIRCLES", "PARALLEL", "CROSS"]: if self.op.strategy in ["BLOCK", "SPIRAL", "CIRCLES", "PARALLEL", "CROSS"]:
self.layout.prop(self.op, "ambient_behaviour") col.prop(self.op, "ambient_behaviour")
if self.op.ambient_behaviour == "AROUND": if self.op.ambient_behaviour == "AROUND":
self.layout.prop(self.op, "ambient_radius") col.prop(self.op, "ambient_radius")
self.layout.prop(self.op, "ambient_cutter_restrict") col.prop(self.op, "ambient_cutter_restrict")
def draw_limit_curve(self): # Draw Limit Curve
if not self.has_correct_level(): if self.level >= 1:
return
if self.op.strategy in ["BLOCK", "SPIRAL", "CIRCLES", "PARALLEL", "CROSS"]: if self.op.strategy in ["BLOCK", "SPIRAL", "CIRCLES", "PARALLEL", "CROSS"]:
self.layout.prop(self.op, "use_limit_curve") col.prop(self.op, "use_limit_curve")
if self.op.use_limit_curve: if self.op.use_limit_curve:
self.layout.prop_search(self.op, "limit_curve", bpy.data, "objects") col.prop_search(self.op, "limit_curve", bpy.data, "objects")
def draw(self, context):
self.context = context
self.draw_use_layers()
self.draw_maxz()
self.draw_minz()
self.draw_ambient()
self.draw_limit_curve()

Wyświetl plik

@ -14,56 +14,23 @@ class CAMButtonsPanel:
bl_space_type = "PROPERTIES" bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW" bl_region_type = "WINDOW"
bl_context = "render" bl_context = "render"
always_show_panel = False
COMPAT_ENGINES = {"CNCCAM_RENDER"} COMPAT_ENGINES = {"CNCCAM_RENDER"}
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
rd = bpy.context.scene.render engine = context.scene.render.engine
if rd.engine in cls.COMPAT_ENGINES: return [True if engine in cls.COMPAT_ENGINES else False]
if cls.always_show_panel:
return True
op = cls.active_operation()
if op and op.valid:
if hasattr(cls, "panel_interface_level"):
return cls.panel_interface_level <= int(context.scene.interface.level)
else:
return True
return False
@classmethod
def active_operation_index(cls):
return bpy.context.scene.cam_active_operation
@classmethod
def active_operation(cls):
active_op = None
try:
active_op = bpy.context.scene.cam_operations[cls.active_operation_index()]
except IndexError:
pass
return active_op
def __init__(self): def __init__(self):
self.op = self.active_operation() context = bpy.context
addon_prefs = bpy.context.preferences.addons["bl_ext.user_default.blendercam"].preferences
self.level = int(context.scene.interface.level)
self.machine = context.scene.cam_machine
addon_prefs = context.preferences.addons["bl_ext.user_default.blendercam"].preferences
self.use_experimental = addon_prefs.experimental self.use_experimental = addon_prefs.experimental
def operations_count(self): operations = context.scene.cam_operations
return len(bpy.context.scene.cam_operations) operations_count = len(operations)
operation_index = context.scene.cam_active_operation
def has_operations(self): self.op = operations[operation_index] if operations_count > 0 else None
return self.operations_count() > 0
def has_correct_level(self):
if not hasattr(self, "prop_level"):
return True
caller_function = inspect.stack()[1][3]
if caller_function not in self.prop_level:
return True
return self.prop_level[caller_function] <= int(self.context.scene.interface.level)

Wyświetl plik

@ -43,10 +43,9 @@ class CAM_CHAINS_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Chains" bl_label = "CAM Chains"
bl_idname = "WORLD_PT_CAM_CHAINS" bl_idname = "WORLD_PT_CAM_CHAINS"
panel_interface_level = 1
always_show_panel = True
def draw(self, context): def draw(self, context):
if self.level >= 1 and self.op is not None:
layout = self.layout layout = self.layout
row = layout.row() row = layout.row()

Wyświetl plik

@ -14,118 +14,80 @@ class CAM_CUTTER_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Cutter" bl_label = "CAM Cutter"
bl_idname = "WORLD_PT_CAM_CUTTER" bl_idname = "WORLD_PT_CAM_CUTTER"
panel_interface_level = 0
prop_level = { def draw(self, context):
"draw_cutter_preset_menu": 1, layout = self.layout
"draw_cutter_id": 2, if self.op is not None:
"draw_cutter_type": 0, # Cutter Preset Menu
"draw_ball_radius": 0, if self.level >= 1:
"draw_bull_radius": 0, row = layout.row(align=True)
"draw_cylcone_diameter": 0,
"draw_cutter_tip_angle": 0,
"draw_laser": 0,
"draw_plasma": 0,
"draw_custom": 0,
"draw_cutter_diameter": 0,
"draw_cutter_flutes": 1,
"draw_cutter_description": 1,
"draw_engagement": 0,
}
def draw_cutter_preset_menu(self):
if not self.has_correct_level():
return
row = self.layout.row(align=True)
row.menu("CAM_CUTTER_MT_presets", text=bpy.types.CAM_CUTTER_MT_presets.bl_label) row.menu("CAM_CUTTER_MT_presets", text=bpy.types.CAM_CUTTER_MT_presets.bl_label)
row.operator("render.cam_preset_cutter_add", text="", icon="ADD") row.operator("render.cam_preset_cutter_add", text="", icon="ADD")
row.operator("render.cam_preset_cutter_add", text="", icon="REMOVE").remove_active = True row.operator(
"render.cam_preset_cutter_add", text="", icon="REMOVE"
).remove_active = True
def draw_cutter_id(self): # Cutter ID
if not self.has_correct_level(): if self.level >= 2:
return layout.prop(self.op, "cutter_id")
self.layout.prop(self.op, "cutter_id")
def draw_cutter_type(self): # Cutter Type
if not self.has_correct_level(): layout.prop(self.op, "cutter_type")
return
self.layout.prop(self.op, "cutter_type")
def draw_ball_radius(self): # Ball Radius
if not self.has_correct_level():
return
if self.op.cutter_type in ["BALLCONE"]: if self.op.cutter_type in ["BALLCONE"]:
self.layout.prop(self.op, "ball_radius") layout.prop(self.op, "ball_radius")
def draw_bull_radius(self): # Bullnose Radius
if not self.has_correct_level():
return
if self.op.cutter_type in ["BULLNOSE"]: if self.op.cutter_type in ["BULLNOSE"]:
self.layout.prop(self.op, "bull_corner_radius") layout.prop(self.op, "bull_corner_radius")
def draw_cylcone_diameter(self): # Cyclone Diameter
if not self.has_correct_level():
return
if self.op.cutter_type in ["CYLCONE"]: if self.op.cutter_type in ["CYLCONE"]:
self.layout.prop(self.op, "cylcone_diameter") layout.prop(self.op, "cylcone_diameter")
def draw_cutter_tip_angle(self): # Cutter Tip Angle
if not self.has_correct_level():
return
if self.op.cutter_type in ["VCARVE", "BALLCONE", "BULLNOSE", "CYLCONE"]: if self.op.cutter_type in ["VCARVE", "BALLCONE", "BULLNOSE", "CYLCONE"]:
self.layout.prop(self.op, "cutter_tip_angle") layout.prop(self.op, "cutter_tip_angle")
def draw_laser(self): # Laser
if not self.has_correct_level():
return
if self.op.cutter_type in ["LASER"]: if self.op.cutter_type in ["LASER"]:
self.layout.prop(self.op, "Laser_on") layout.prop(self.op, "Laser_on")
self.layout.prop(self.op, "Laser_off") layout.prop(self.op, "Laser_off")
self.layout.prop(self.op, "Laser_cmd") layout.prop(self.op, "Laser_cmd")
self.layout.prop(self.op, "Laser_delay") layout.prop(self.op, "Laser_delay")
def draw_plasma(self): # Plasma
if not self.has_correct_level():
return
if self.op.cutter_type in ["PLASMA"]: if self.op.cutter_type in ["PLASMA"]:
self.layout.prop(self.op, "Plasma_on") layout.prop(self.op, "Plasma_on")
self.layout.prop(self.op, "Plasma_off") layout.prop(self.op, "Plasma_off")
self.layout.prop(self.op, "Plasma_delay") layout.prop(self.op, "Plasma_delay")
self.layout.prop(self.op, "Plasma_dwell") layout.prop(self.op, "Plasma_dwell")
self.layout.prop(self.op, "lead_in") layout.prop(self.op, "lead_in")
self.layout.prop(self.op, "lead_out") layout.prop(self.op, "lead_out")
def draw_custom(self): # Custom
if not self.has_correct_level():
return
if self.op.cutter_type in ["CUSTOM"]: if self.op.cutter_type in ["CUSTOM"]:
if self.op.optimisation.use_exact: if self.op.optimisation.use_exact:
self.layout.label( layout.label(
text="Warning - only Convex Shapes Are Supported. ", icon="COLOR_RED" text="Warning - only Convex Shapes Are Supported. ", icon="COLOR_RED"
) )
self.layout.label(text="If Your Custom Cutter Is Concave,") layout.label(text="If Your Custom Cutter Is Concave,")
self.layout.label(text="Switch Exact Mode Off.") layout.label(text="Switch Exact Mode Off.")
self.layout.prop_search(self.op, "cutter_object_name", bpy.data, "objects") layout.prop_search(self.op, "cutter_object_name", bpy.data, "objects")
def draw_cutter_diameter(self): # Cutter Diameter
if not self.has_correct_level(): layout.prop(self.op, "cutter_diameter")
return
self.layout.prop(self.op, "cutter_diameter")
def draw_cutter_flutes(self): # Cutter Flutes
if not self.has_correct_level(): if self.level >= 1:
return
if self.op.cutter_type not in ["LASER", "PLASMA"]: if self.op.cutter_type not in ["LASER", "PLASMA"]:
self.layout.prop(self.op, "cutter_flutes") layout.prop(self.op, "cutter_flutes")
def draw_cutter_description(self): # Cutter Description
if not self.has_correct_level(): layout.prop(self.op, "cutter_description")
return
self.layout.prop(self.op, "cutter_description")
def draw_engagement(self): # Cutter Engagement
if not self.has_correct_level():
return
if self.op.cutter_type in ["LASER", "PLASMA"]: if self.op.cutter_type in ["LASER", "PLASMA"]:
return return
if self.op.strategy in ["CUTOUT"]: if self.op.strategy in ["CUTOUT"]:
@ -136,25 +98,7 @@ class CAM_CUTTER_Panel(CAMButtonsPanel, Panel):
else: else:
engagement = round(100 * self.op.dist_between_paths / self.op.cutter_diameter, 1) engagement = round(100 * self.op.dist_between_paths / self.op.cutter_diameter, 1)
self.layout.label(text=f"Cutter Engagement: {engagement}%") layout.label(text=f"Cutter Engagement: {engagement}%")
if engagement > 50: if engagement > 50:
self.layout.label(text="WARNING: CUTTER ENGAGEMENT > 50%") layout.label(text="WARNING: CUTTER ENGAGEMENT > 50%")
def draw(self, context):
self.context = context
self.draw_cutter_preset_menu()
self.draw_cutter_id()
self.draw_cutter_type()
self.draw_ball_radius()
self.draw_bull_radius()
self.draw_cylcone_diameter()
self.draw_cutter_tip_angle()
self.draw_laser()
self.draw_plasma()
self.draw_custom()
self.draw_cutter_diameter()
self.draw_cutter_flutes()
self.draw_cutter_description()
self.draw_engagement()

Wyświetl plik

@ -14,46 +14,22 @@ class CAM_FEEDRATE_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Feedrate" bl_label = "CAM Feedrate"
bl_idname = "WORLD_PT_CAM_FEEDRATE" bl_idname = "WORLD_PT_CAM_FEEDRATE"
panel_interface_level = 0
prop_level = {
"draw_feedrate": 0,
"draw_sim_feedrate": 2,
"draw_plunge_feedrate": 1,
"draw_plunge_angle": 1,
"draw_spindle_rpm": 0,
}
def draw_feedrate(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "feedrate")
def draw_sim_feedrate(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "do_simulation_feedrate")
def draw_plunge_feedrate(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "plunge_feedrate")
def draw_plunge_angle(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "plunge_angle")
def draw_spindle_rpm(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "spindle_rpm")
def draw(self, context): def draw(self, context):
self.context = context layout = self.layout
if self.op is not None:
# Feedrate
layout.prop(self.op, "feedrate")
self.draw_feedrate() # Sim Feedrate
self.draw_sim_feedrate() if self.level >= 2:
self.draw_plunge_feedrate() layout.prop(self.op, "do_simulation_feedrate")
self.draw_plunge_angle()
self.draw_spindle_rpm() # Plunge Feedrate
if self.level >= 1:
layout.prop(self.op, "plunge_feedrate")
# Plunge Angle
layout.prop(self.op, "plunge_angle")
# Spindle RPM
layout.prop(self.op, "spindle_rpm")

Wyświetl plik

@ -14,59 +14,36 @@ class CAM_GCODE_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM G-code Options" bl_label = "CAM G-code Options"
bl_idname = "WORLD_PT_CAM_GCODE" bl_idname = "WORLD_PT_CAM_GCODE"
panel_interface_level = 1
prop_level = {
"draw_output_header": 1,
"draw_output_trailer": 1,
"draw_enable_dust": 1,
"draw_enable_hold": 1,
"draw_enable_mist": 1,
}
def draw_output_header(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "output_header")
if self.op.output_header:
self.layout.prop(self.op, "gcode_header")
def draw_output_trailer(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "output_trailer")
if self.op.output_trailer:
self.layout.prop(self.op, "gcode_trailer")
def draw_enable_dust(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "enable_dust")
if self.op.enable_dust:
self.layout.prop(self.op, "gcode_start_dust_cmd")
self.layout.prop(self.op, "gcode_stop_dust_cmd")
def draw_enable_hold(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "enable_hold")
if self.op.enable_hold:
self.layout.prop(self.op, "gcode_start_hold_cmd")
self.layout.prop(self.op, "gcode_stop_hold_cmd")
def draw_enable_mist(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "enable_mist")
if self.op.enable_mist:
self.layout.prop(self.op, "gcode_start_mist_cmd")
self.layout.prop(self.op, "gcode_stop_mist_cmd")
def draw(self, context): def draw(self, context):
self.context = context layout = self.layout
self.draw_output_header() if self.level >= 1 and self.op is not None:
self.draw_output_trailer()
self.draw_enable_dust() # Output Header
self.draw_enable_hold() layout.prop(self.op, "output_header")
self.draw_enable_mist() if self.op.output_header:
layout.prop(self.op, "gcode_header")
# Output Trailer
layout.prop(self.op, "output_trailer")
if self.op.output_trailer:
layout.prop(self.op, "gcode_trailer")
# Enable Dust
layout.prop(self.op, "enable_dust")
if self.op.enable_dust:
layout.prop(self.op, "gcode_start_dust_cmd")
layout.prop(self.op, "gcode_stop_dust_cmd")
# Enable Hold
layout.prop(self.op, "enable_hold")
if self.op.enable_hold:
layout.prop(self.op, "gcode_start_hold_cmd")
layout.prop(self.op, "gcode_stop_hold_cmd")
# Enable Mist
layout.prop(self.op, "enable_mist")
if self.op.enable_mist:
layout.prop(self.op, "gcode_start_mist_cmd")
layout.prop(self.op, "gcode_stop_mist_cmd")

Wyświetl plik

@ -60,51 +60,28 @@ class CAM_INFO_Properties(PropertyGroup):
class CAM_INFO_Panel(CAMButtonsPanel, Panel): class CAM_INFO_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Info & Warnings" bl_label = "CAM Info & Warnings"
bl_idname = "WORLD_PT_CAM_INFO" bl_idname = "WORLD_PT_CAM_INFO"
panel_interface_level = 0
always_show_panel = True
prop_level = { # Display the Info Panel
"draw_cnccam_version": 0, def draw(self, context):
"draw_opencamlib_version": 1, layout = self.layout
"draw_op_warnings": 0, if self.op is not None:
"draw_op_time": 0, # CNC CAM Version
"draw_op_chipload": 0, layout.label(text=f'CNC CAM v{".".join([str(x) for x in cam_version])}')
"draw_op_money_cost": 1,
}
# Draw CNC CAM version (and whether there are updates available) # OpenCAMLib Version
def draw_cnccam_version(self): if self.level >= 1:
addon_prefs = bpy.context.preferences.addons["bl_ext.user_default.blendercam"].preferences
if not self.has_correct_level():
return
self.layout.label(text=f'CNC CAM v{".".join([str(x) for x in cam_version])}')
if len(addon_prefs.new_version_available) > 0:
self.layout.label(text=f"New Version Available:")
self.layout.label(text=f" {addon_prefs.new_version_available}")
self.layout.operator("render.cam_update_now")
# Display the OpenCamLib version
def draw_opencamlib_version(self):
if not self.has_correct_level():
return
ocl_version = opencamlib_version() ocl_version = opencamlib_version()
if ocl_version is None: if ocl_version is None:
self.layout.label(text="OpenCAMLib is not Installed") layout.label(text="OpenCAMLib is not Installed")
else: else:
self.layout.label(text=f"OpenCAMLib v{ocl_version}") layout.label(text=f"OpenCAMLib v{ocl_version}")
# Display warnings related to the current operation # Operation Warnings
def draw_op_warnings(self):
if not self.has_correct_level():
return
for line in self.op.info.warnings.rstrip("\n").split("\n"): for line in self.op.info.warnings.rstrip("\n").split("\n"):
if len(line) > 0: if len(line) > 0:
self.layout.label(text=line, icon="ERROR") layout.label(text=line, icon="ERROR")
# Display the time estimation for the current operation # Operation Time Estimate
def draw_op_time(self):
if not self.has_correct_level():
return
if not int(self.op.info.duration * 60) > 0: if not int(self.op.info.duration * 60) > 0:
return return
@ -115,22 +92,17 @@ class CAM_INFO_Panel(CAMButtonsPanel, Panel):
elif self.op.info.duration > 1: elif self.op.info.duration > 1:
time_estimate += f" ({round(self.op.info.duration % 60)}min)" time_estimate += f" ({round(self.op.info.duration % 60)}min)"
self.layout.label(text=time_estimate) layout.label(text=time_estimate)
# Display the chipload (does this work ?) # Operation Chipload
def draw_op_chipload(self):
if not self.has_correct_level():
return
if not self.op.info.chipload > 0: if not self.op.info.chipload > 0:
return return
chipload = f"Chipload: {strInUnits(self.op.info.chipload, 4)}/tooth" chipload = f"Chipload: {strInUnits(self.op.info.chipload, 4)}/tooth"
self.layout.label(text=chipload) layout.label(text=chipload)
# Display the current operation money cost # Operation Money Cost
def draw_op_money_cost(self): if self.level >= 1:
if not self.has_correct_level():
return
if not int(self.op.info.duration * 60) > 0: if not int(self.op.info.duration * 60) > 0:
return return
@ -144,14 +116,4 @@ class CAM_INFO_Panel(CAMButtonsPanel, Panel):
cost_per_second = bpy.context.scene.cam_machine.hourly_rate / 3600 cost_per_second = bpy.context.scene.cam_machine.hourly_rate / 3600
total_cost = self.op.info.duration * 60 * cost_per_second total_cost = self.op.info.duration * 60 * cost_per_second
op_cost = f"Operation Cost: ${total_cost:.2f} (${cost_per_second:.2f}/s)" op_cost = f"Operation Cost: ${total_cost:.2f} (${cost_per_second:.2f}/s)"
self.layout.label(text=op_cost) layout.label(text=op_cost)
# Display the Info Panel
def draw(self, context):
self.context = context
self.draw_cnccam_version()
self.draw_opencamlib_version()
if self.op:
self.draw_op_warnings()
self.draw_op_time()
self.draw_op_money_cost()

Wyświetl plik

@ -35,11 +35,7 @@ class CAM_INTERFACE_Properties(PropertyGroup):
class CAM_INTERFACE_Panel(CAMButtonsPanel, Panel): class CAM_INTERFACE_Panel(CAMButtonsPanel, Panel):
bl_label = "Interface" bl_label = "Interface"
bl_idname = "WORLD_PT_CAM_INTERFACE" bl_idname = "WORLD_PT_CAM_INTERFACE"
always_show_panel = True
def draw_interface_level(self):
self.layout.prop(self.context.scene.interface, "level", text="")
def draw(self, context): def draw(self, context):
self.context = context layout = self.layout
self.draw_interface_level() layout.prop(context.scene.interface, "level", text="")

Wyświetl plik

@ -14,126 +14,84 @@ class CAM_MACHINE_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Machine" bl_label = "CAM Machine"
bl_idname = "WORLD_PT_CAM_MACHINE" bl_idname = "WORLD_PT_CAM_MACHINE"
always_show_panel = True
panel_interface_level = 0
prop_level = {
"draw_presets": 1,
"draw_post_processor": 0,
"draw_split_files": 2,
"draw_system": 0,
"draw_position_definitions": 2,
"draw_working_area": 0,
"draw_feedrates": 1,
"draw_splindle_speeds": 0,
"draw_tool_options": 2,
"draw_suplemental_axis": 3,
"draw_collet_size": 2,
"draw_block_numbers": 2,
"draw_hourly_rate": 1,
}
def draw_presets(self):
if not self.has_correct_level():
return
row = self.layout.row(align=True)
row.menu("CAM_MACHINE_MT_presets", text=bpy.types.CAM_MACHINE_MT_presets.bl_label)
row.operator("render.cam_preset_machine_add", text="", icon="ADD")
row.operator("render.cam_preset_machine_add", text="", icon="REMOVE").remove_active = True
def draw_post_processor(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "post_processor")
def draw_split_files(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "eval_splitting")
if self.machine.eval_splitting:
self.layout.prop(self.machine, "split_limit")
def draw_system(self):
if not self.has_correct_level():
return
self.layout.prop(bpy.context.scene.unit_settings, "system")
def draw_position_definitions(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "use_position_definitions")
if self.machine.use_position_definitions:
self.layout.prop(self.machine, "starting_position")
self.layout.prop(self.machine, "mtc_position")
self.layout.prop(self.machine, "ending_position")
def draw_working_area(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "working_area")
def draw_feedrates(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "feedrate_min")
self.layout.prop(self.machine, "feedrate_max")
self.layout.prop(self.machine, "feedrate_default")
def draw_splindle_speeds(self):
if not self.has_correct_level():
return
# TODO: spindle default and feedrate default should become part of the cutter definition...
self.layout.prop(self.machine, "spindle_min")
self.layout.prop(self.machine, "spindle_max")
self.layout.prop(self.machine, "spindle_start_time")
self.layout.prop(self.machine, "spindle_default")
def draw_tool_options(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "output_tool_definitions")
self.layout.prop(self.machine, "output_tool_change")
if self.machine.output_tool_change:
self.layout.prop(self.machine, "output_g43_on_tool_change")
def draw_suplemental_axis(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "axis4")
self.layout.prop(self.machine, "axis5")
def draw_collet_size(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "collet_size")
def draw_block_numbers(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "output_block_numbers")
if self.machine.output_block_numbers:
self.layout.prop(self.machine, "start_block_number")
self.layout.prop(self.machine, "block_number_increment")
def draw_hourly_rate(self):
if not self.has_correct_level():
return
self.layout.prop(self.machine, "hourly_rate")
def draw(self, context): def draw(self, context):
self.context = context layout = self.layout
self.machine = bpy.context.scene.cam_machine
self.draw_presets() # Presets
self.draw_post_processor() if self.level >= 1:
self.draw_split_files() row = layout.row(align=True)
self.draw_system() row.menu("CAM_MACHINE_MT_presets", text=bpy.types.CAM_MACHINE_MT_presets.bl_label)
self.draw_position_definitions() row.operator(
self.draw_working_area() "render.cam_preset_machine_add",
self.draw_feedrates() text="",
self.draw_splindle_speeds() icon="ADD",
self.draw_tool_options() )
self.draw_suplemental_axis() row.operator(
self.draw_collet_size() "render.cam_preset_machine_add",
self.draw_block_numbers() text="",
self.draw_hourly_rate() icon="REMOVE",
).remove_active = True
# Post Processor
layout.prop(self.machine, "post_processor")
# Split Files
if self.level >= 2:
layout.prop(self.machine, "eval_splitting")
if self.machine.eval_splitting:
layout.prop(self.machine, "split_limit")
# System
layout.prop(bpy.context.scene.unit_settings, "system")
# Position Definitions
if self.level >= 2:
layout.prop(self.machine, "use_position_definitions")
if self.machine.use_position_definitions:
layout.prop(self.machine, "starting_position")
layout.prop(self.machine, "mtc_position")
layout.prop(self.machine, "ending_position")
# Working Area
layout.prop(self.machine, "working_area")
# Feedrates
if self.level >= 1:
layout.prop(self.machine, "feedrate_min")
layout.prop(self.machine, "feedrate_max")
layout.prop(self.machine, "feedrate_default")
# Spindle Speeds
# TODO: spindle default and feedrate default should become part of the cutter definition...
layout.prop(self.machine, "spindle_min")
layout.prop(self.machine, "spindle_max")
layout.prop(self.machine, "spindle_start_time")
layout.prop(self.machine, "spindle_default")
# Tool Options
if self.level >= 2:
layout.prop(self.machine, "output_tool_definitions")
layout.prop(self.machine, "output_tool_change")
if self.machine.output_tool_change:
layout.prop(self.machine, "output_g43_on_tool_change")
# Supplemental Axis
if self.level >= 3:
layout.prop(self.machine, "axis4")
layout.prop(self.machine, "axis5")
# Collet Size
if self.level >= 2:
layout.prop(self.machine, "collet_size")
# Block Numbers
if self.level >= 2:
layout.prop(self.machine, "output_block_numbers")
if self.machine.output_block_numbers:
layout.prop(self.machine, "start_block_number")
layout.prop(self.machine, "block_number_increment")
# Hourly Rate
if self.level >= 1:
layout.prop(self.machine, "hourly_rate")

Wyświetl plik

@ -68,7 +68,6 @@ class CAM_MATERIAL_Properties(PropertyGroup):
update=update_material, update=update_material,
) )
# material_origin
origin: FloatVectorProperty( origin: FloatVectorProperty(
name="Material Origin", name="Material Origin",
default=(0, 0, 0), default=(0, 0, 0),
@ -78,7 +77,6 @@ class CAM_MATERIAL_Properties(PropertyGroup):
update=update_material, update=update_material,
) )
# material_size
size: FloatVectorProperty( size: FloatVectorProperty(
name="Material Size", name="Material Size",
default=(0.200, 0.200, 0.100), default=(0.200, 0.200, 0.100),
@ -97,11 +95,10 @@ class CAM_MATERIAL_PositionObject(Operator):
bl_idname = "object.material_cam_position" bl_idname = "object.material_cam_position"
bl_label = "Position Object for CAM Operation" bl_label = "Position Object for CAM Operation"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
interface_level = 0
def execute(self, context): def execute(self, context):
s = bpy.context.scene scene = context.scene
operation = s.cam_operations[s.cam_active_operation] operation = scene.cam_operations[scene.cam_active_operation]
if operation.object_name in bpy.data.objects: if operation.object_name in bpy.data.objects:
positionObject(operation) positionObject(operation)
else: else:
@ -109,60 +106,37 @@ class CAM_MATERIAL_PositionObject(Operator):
return {"FINISHED"} return {"FINISHED"}
def draw(self, context): def draw(self, context):
if not self.interface_level <= int(self.context.scene.interface.level): layout = self.layout
return layout.prop_search(self, "operation", context.scene, "cam_operations")
self.layout.prop_search(self, "operation", bpy.context.scene, "cam_operations")
class CAM_MATERIAL_Panel(CAMButtonsPanel, Panel): class CAM_MATERIAL_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Material Size and Position" bl_label = "CAM Material Size and Position"
bl_idname = "WORLD_PT_CAM_MATERIAL" bl_idname = "WORLD_PT_CAM_MATERIAL"
panel_interface_level = 0
prop_level = { def draw(self, context):
"draw_estimate_from_image": 0, layout = self.layout
"draw_estimate_from_object": 1, if self.op is not None:
"draw_axis_alignment": 0, # Estimate from Image
}
def draw_estimate_from_image(self):
if not self.has_correct_level():
return
if self.op.geometry_source not in ["OBJECT", "COLLECTION"]: if self.op.geometry_source not in ["OBJECT", "COLLECTION"]:
self.layout.label(text="Estimated from Image") layout.label(text="Estimated from Image")
def draw_estimate_from_object(self): # Estimate from Object
if not self.has_correct_level(): if self.level >= 1:
return
if self.op.geometry_source in ["OBJECT", "COLLECTION"]: if self.op.geometry_source in ["OBJECT", "COLLECTION"]:
self.layout.prop(self.op.material, "estimate_from_model") layout.prop(self.op.material, "estimate_from_model")
if self.op.material.estimate_from_model: if self.op.material.estimate_from_model:
row_radius = self.layout.row() row_radius = layout.row()
row_radius.label(text="Additional Radius") row_radius.label(text="Additional Radius")
row_radius.prop(self.op.material, "radius_around_model", text="") row_radius.prop(self.op.material, "radius_around_model", text="")
else: else:
self.layout.prop(self.op.material, "origin") layout.prop(self.op.material, "origin")
self.layout.prop(self.op.material, "size") layout.prop(self.op.material, "size")
# Display Axis alignment section # Axis Alignment
def draw_axis_alignment(self):
if not self.has_correct_level():
return
if self.op.geometry_source in ["OBJECT", "COLLECTION"]: if self.op.geometry_source in ["OBJECT", "COLLECTION"]:
row_axis = self.layout.row() row_axis = layout.row()
row_axis.prop(self.op.material, "center_x") row_axis.prop(self.op.material, "center_x")
row_axis.prop(self.op.material, "center_y") row_axis.prop(self.op.material, "center_y")
self.layout.prop(self.op.material, "z_position") layout.prop(self.op.material, "z_position")
self.layout.operator("object.material_cam_position", text="Position Object") layout.operator("object.material_cam_position", text="Position Object")
def draw(self, context):
self.context = context
# FIXME: This function displays the progression of a job with a progress bar
# Commenting because it makes no sense here
# Consider removing it entirely
# self.layout.template_running_jobs()
self.draw_estimate_from_image()
self.draw_estimate_from_object()
self.draw_axis_alignment()

Wyświetl plik

@ -31,7 +31,11 @@ class CAM_MOVEMENT_Properties(PropertyGroup):
"Conventional / Up milling", "Conventional / Up milling",
"Cutter rotates against the direction of the feed", "Cutter rotates against the direction of the feed",
), ),
("CLIMB", "Climb / Down milling", "Cutter rotates with the direction of the feed"), (
"CLIMB",
"Climb / Down milling",
"Cutter rotates with the direction of the feed",
),
( (
"MEANDER", "MEANDER",
"Meander / Zig Zag", "Meander / Zig Zag",
@ -45,7 +49,10 @@ class CAM_MOVEMENT_Properties(PropertyGroup):
insideout: EnumProperty( insideout: EnumProperty(
name="Direction", name="Direction",
items=(("INSIDEOUT", "Inside out", "a"), ("OUTSIDEIN", "Outside in", "a")), items=(
("INSIDEOUT", "Inside out", "a"),
("OUTSIDEIN", "Outside in", "a"),
),
description="Approach to the piece", description="Approach to the piece",
default="INSIDEOUT", default="INSIDEOUT",
update=update_operation, update=update_operation,
@ -53,7 +60,10 @@ class CAM_MOVEMENT_Properties(PropertyGroup):
spindle_rotation: EnumProperty( spindle_rotation: EnumProperty(
name="Spindle Rotation", name="Spindle Rotation",
items=(("CW", "Clockwise", "a"), ("CCW", "Counter clockwise", "a")), items=(
("CW", "Clockwise", "a"),
("CCW", "Counter clockwise", "a"),
),
description="Spindle rotation direction", description="Spindle rotation direction",
default="CW", default="CW",
update=update_operation, update=update_operation,
@ -216,109 +226,73 @@ class CAM_MOVEMENT_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Movement" bl_label = "CAM Movement"
bl_idname = "WORLD_PT_CAM_MOVEMENT" bl_idname = "WORLD_PT_CAM_MOVEMENT"
panel_interface_level = 0
prop_level = {
"draw_cut_type": 1,
"draw_spindle_rotation": 2,
"draw_free_height": 0,
"draw_use_g64": 2,
"draw_parallel_stepback": 1,
"draw_helix_enter": 2,
"draw_ramp": 1,
"draw_retract_tangential": 2,
"draw_stay_low": 1,
"draw_protect_vertical": 1,
}
def draw_cut_type(self):
if not self.has_correct_level():
return
self.layout.prop(self.op.movement, "type")
if self.op.movement.type in ["BLOCK", "SPIRAL", "CIRCLES"]:
self.layout.prop(self.op.movement, "insideout")
def draw_spindle_rotation(self):
if not self.has_correct_level():
return
self.layout.prop(self.op.movement, "spindle_rotation")
def draw_free_height(self):
if not self.has_correct_level():
return
self.layout.prop(self.op.movement, "free_height")
if self.op.maxz > self.op.movement.free_height:
self.layout.label(text="Depth Start > Free Movement")
self.layout.label(text="POSSIBLE COLLISION")
def draw_use_g64(self):
if not self.has_correct_level():
return
if self.context.scene.cam_machine.post_processor not in G64_INCOMPATIBLE_MACHINES:
self.layout.prop(self.op.movement, "useG64")
if self.op.movement.useG64:
self.layout.prop(self.op.movement, "G64")
def draw_parallel_stepback(self):
if not self.has_correct_level():
return
if self.op.strategy in ["PARALLEL", "CROSS"]:
if not self.op.movement.ramp:
self.layout.prop(self.op.movement, "parallel_step_back")
def draw_helix_enter(self):
if not self.has_correct_level():
return
if self.op.strategy in ["POCKET"]:
self.layout.prop(self.op.movement, "helix_enter")
if self.op.movement.helix_enter:
self.layout.prop(self.op.movement, "ramp_in_angle")
self.layout.prop(self.op.movement, "helix_diameter")
def draw_ramp(self):
if not self.has_correct_level():
return
self.layout.prop(self.op.movement, "ramp")
if self.op.movement.ramp:
self.layout.prop(self.op.movement, "ramp_in_angle")
self.layout.prop(self.op.movement, "ramp_out")
if self.op.movement.ramp_out:
self.layout.prop(self.op.movement, "ramp_out_angle")
def draw_retract_tangential(self):
if not self.has_correct_level():
return
if self.op.strategy in ["POCKET"]:
self.layout.prop(self.op.movement, "retract_tangential")
if self.op.movement.retract_tangential:
self.layout.prop(self.op.movement, "retract_radius")
self.layout.prop(self.op.movement, "retract_height")
def draw_stay_low(self):
if not self.has_correct_level():
return
self.layout.prop(self.op.movement, "stay_low")
if self.op.movement.stay_low:
self.layout.prop(self.op.movement, "merge_dist")
def draw_protect_vertical(self):
if not self.has_correct_level():
return
if self.op.cutter_type not in ["BALLCONE"]:
self.layout.prop(self.op.movement, "protect_vertical")
if self.op.movement.protect_vertical:
self.layout.prop(self.op.movement, "protect_vertical_limit")
def draw(self, context): def draw(self, context):
self.context = context layout = self.layout
if self.op is not None:
# Cut Type
if self.level >= 1:
layout.prop(self.op.movement, "type")
if self.op.movement.type in ["BLOCK", "SPIRAL", "CIRCLES"]:
layout.prop(self.op.movement, "insideout")
self.draw_cut_type() # Spindle Rotation
self.draw_spindle_rotation() if self.level >= 2:
self.draw_free_height() layout.prop(self.op.movement, "spindle_rotation")
self.draw_use_g64()
self.draw_parallel_stepback() # Free Height
self.draw_ramp() layout.prop(self.op.movement, "free_height")
self.draw_helix_enter() if self.op.maxz > self.op.movement.free_height:
self.draw_retract_tangential() layout.label(text="Depth Start > Free Movement")
self.draw_stay_low() layout.label(text="POSSIBLE COLLISION")
self.draw_protect_vertical()
# Use G64
if self.level >= 2:
if context.scene.cam_machine.post_processor not in G64_INCOMPATIBLE_MACHINES:
layout.prop(self.op.movement, "useG64")
if self.op.movement.useG64:
layout.prop(self.op.movement, "G64")
# Parallel Stepback
if self.level >= 1:
if self.op.strategy in ["PARALLEL", "CROSS"]:
if not self.op.movement.ramp:
layout.prop(self.op.movement, "parallel_step_back")
# Helix Enter
if self.level >= 2:
if self.op.strategy in ["POCKET"]:
layout.prop(self.op.movement, "helix_enter")
if self.op.movement.helix_enter:
layout.prop(self.op.movement, "ramp_in_angle")
layout.prop(self.op.movement, "helix_diameter")
# Ramp
if self.level >= 1:
layout.prop(self.op.movement, "ramp")
if self.op.movement.ramp:
layout.prop(self.op.movement, "ramp_in_angle")
layout.prop(self.op.movement, "ramp_out")
if self.op.movement.ramp_out:
layout.prop(self.op.movement, "ramp_out_angle")
# Retract Tangential
if self.level >= 2:
if self.op.strategy in ["POCKET"]:
layout.prop(self.op.movement, "retract_tangential")
if self.op.movement.retract_tangential:
layout.prop(self.op.movement, "retract_radius")
layout.prop(self.op.movement, "retract_height")
# Stay Low
if self.level >= 1:
layout.prop(self.op.movement, "stay_low")
if self.op.movement.stay_low:
layout.prop(self.op.movement, "merge_dist")
# Protect Vertical
if self.level >= 1:
if self.op.cutter_type not in ["BALLCONE"]:
layout.prop(self.op.movement, "protect_vertical")
if self.op.movement.protect_vertical:
layout.prop(self.op.movement, "protect_vertical_limit")

Wyświetl plik

@ -14,191 +14,136 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Operation Setup" bl_label = "CAM Operation Setup"
bl_idname = "WORLD_PT_CAM_OPERATION" bl_idname = "WORLD_PT_CAM_OPERATION"
panel_interface_level = 0
prop_level = {
"draw_cutter_engagement": 0,
"draw_machine_axis": 2,
"draw_strategy": 0,
"draw_enable_A_B_axis": 1,
"draw_cutout_options": 0,
"draw_waterline_options": 0,
"draw_medial_axis_options": 0,
"draw_drill_options": 0,
"draw_pocket_options": 0,
"draw_default_options": 0,
"draw_bridges_options": 1,
"draw_skin": 1,
"draw_array": 1,
"draw_cutout_type": 0,
"draw_overshoot": 1,
"draw_startpoint": 1,
"draw_lead_in_out": 3,
"draw_outlines": 2,
"draw_merge": 2,
}
# Displays percentage of the cutter which is engaged with the material
# Displays a warning for engagements greater than 50%
def draw_cutter_engagement(self): def draw_cutter_engagement(self):
if not self.has_correct_level(): layout = self.layout
return if self.op is not None:
# Cutter Engagement
# Warns if cutter engagement is greater than 50%
if self.op.cutter_type in ["BALLCONE"]: if self.op.cutter_type in ["BALLCONE"]:
engagement = round(100 * self.op.dist_between_paths / self.op.ball_radius, 1) engagement = round(100 * self.op.dist_between_paths / self.op.ball_radius, 1)
else: else:
engagement = round(100 * self.op.dist_between_paths / self.op.cutter_diameter, 1) engagement = round(100 * self.op.dist_between_paths / self.op.cutter_diameter, 1)
if engagement > 50: if engagement > 50:
self.layout.label(text="Warning: High Cutter Engagement") layout.label(text="Warning: High Cutter Engagement")
self.layout.label(text=f"Cutter Engagement: {engagement}%") layout.label(text=f"Cutter Engagement: {engagement}%")
def draw_machine_axis(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "machine_axes")
def draw_strategy(self):
if not self.has_correct_level():
return
if self.op.machine_axes == "4":
self.layout.prop(self.op, "strategy4axis")
if self.op.strategy4axis == "INDEXED":
self.layout.prop(self.op, "strategy")
self.layout.prop(self.op, "rotary_axis_1")
elif self.op.machine_axes == "5":
self.layout.prop(self.op, "strategy5axis")
if self.op.strategy5axis == "INDEXED":
self.layout.prop(self.op, "strategy")
self.layout.prop(self.op, "rotary_axis_1")
self.layout.prop(self.op, "rotary_axis_2")
else:
self.layout.prop(self.op, "strategy")
def draw_enable_A_B_axis(self): def draw_enable_A_B_axis(self):
if not self.has_correct_level(): layout = self.layout
return
self.layout.prop(self.op, "enable_A") # Enable A & B Axes
if self.level >= 1:
layout.prop(self.op, "enable_A")
if self.op.enable_A: if self.op.enable_A:
self.layout.prop(self.op, "rotation_A") layout.prop(self.op, "rotation_A")
self.layout.prop(self.op, "A_along_x") layout.prop(self.op, "A_along_x")
if self.op.A_along_x: if self.op.A_along_x:
self.layout.label(text="A || X - B || Y") layout.label(text="A || X - B || Y")
else: else:
self.layout.label(text="A || Y - B ||X") layout.label(text="A || Y - B || X")
self.layout.prop(self.op, "enable_B") layout.prop(self.op, "enable_B")
if self.op.enable_B: if self.op.enable_B:
self.layout.prop(self.op, "rotation_B") layout.prop(self.op, "rotation_B")
def draw_cutout_type(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "cut_type")
def draw_overshoot(self): def draw_overshoot(self):
if not self.has_correct_level(): layout = self.layout
return
self.layout.prop(self.op, "straight")
def draw_startpoint(self): # Overshoot
if not self.has_correct_level(): layout.prop(self.op, "straight")
return
self.layout.prop(self.op, "profile_start")
def draw_lead_in_out(self): def draw(self, context):
if not self.has_correct_level(): layout = self.layout
return if self.op is not None:
self.layout.prop(self.op, "lead_in") # Machine Axis
self.layout.prop(self.op, "lead_out") if self.level >= 2:
layout.prop(self.op, "machine_axes")
def draw_outlines(self): # Strategy
if not self.has_correct_level(): if self.op.machine_axes == "4":
return layout.prop(self.op, "strategy4axis")
self.layout.prop(self.op, "outlines_count") if self.op.strategy4axis == "INDEXED":
if self.op.outlines_count > 1: layout.prop(self.op, "strategy")
self.layout.prop(self.op, "dist_between_paths") layout.prop(self.op, "rotary_axis_1")
self.draw_cutter_engagement() elif self.op.machine_axes == "5":
self.layout.prop(self.op.movement, "insideout") layout.prop(self.op, "strategy5axis")
if self.op.strategy5axis == "INDEXED":
layout.prop(self.op, "strategy")
layout.prop(self.op, "rotary_axis_1")
layout.prop(self.op, "rotary_axis_2")
else:
layout.prop(self.op, "strategy")
def draw_merge(self): # Cutout Options
if not self.has_correct_level():
return
self.layout.prop(self.op, "dont_merge")
def draw_cutout_options(self):
if not self.has_correct_level():
return
if self.op.strategy in ["CUTOUT"]: if self.op.strategy in ["CUTOUT"]:
self.draw_cutout_type() # Cutout Type
layout.prop(self.op, "cut_type")
if self.op.cut_type in ["OUTSIDE", "INSIDE"]: if self.op.cut_type in ["OUTSIDE", "INSIDE"]:
self.draw_overshoot() self.draw_overshoot()
self.draw_startpoint() # Startpoint
self.draw_lead_in_out() layout.prop(self.op, "profile_start")
# Lead In & Out
layout.prop(self.op, "lead_in")
layout.prop(self.op, "lead_out")
if self.op.strategy in ["CUTOUT", "CURVE"]: if self.op.strategy in ["CUTOUT", "CURVE"]:
self.draw_enable_A_B_axis() self.draw_enable_A_B_axis()
self.draw_outlines() # Outlines
self.draw_merge() layout.prop(self.op, "outlines_count")
if self.op.outlines_count > 1:
layout.prop(self.op, "dist_between_paths")
self.draw_cutter_engagement()
layout.prop(self.op.movement, "insideout")
# Merge
layout.prop(self.op, "dont_merge")
def draw_waterline_options(self): # Waterline Options
if not self.has_correct_level():
return
if self.op.strategy in ["WATERLINE"]: if self.op.strategy in ["WATERLINE"]:
self.layout.label(text="Ocl Doesn't Support Fill Areas") layout.label(text="Ocl Doesn't Support Fill Areas")
if not self.op.optimisation.use_opencamlib: if not self.op.optimisation.use_opencamlib:
self.layout.prop(self.op, "slice_detail") layout.prop(self.op, "slice_detail")
self.layout.prop(self.op, "waterline_fill") layout.prop(self.op, "waterline_fill")
if self.op.waterline_fill: if self.op.waterline_fill:
self.layout.prop(self.op, "dist_between_paths") layout.prop(self.op, "dist_between_paths")
self.layout.prop(self.op, "waterline_project") layout.prop(self.op, "waterline_project")
self.layout.label(text="Waterline Needs a Skin Margin") layout.label(text="Waterline Needs a Skin Margin")
def draw_carve_options(self): # Carve Options
if not self.has_correct_level():
return
if self.op.strategy in ["CARVE"]: if self.op.strategy in ["CARVE"]:
self.layout.prop(self.op, "carve_depth") layout.prop(self.op, "carve_depth")
self.layout.prop(self.op, "dist_along_paths") layout.prop(self.op, "dist_along_paths")
def draw_medial_axis_options(self): # Medial Axis Options
if not self.has_correct_level():
return
if self.op.strategy in ["MEDIAL_AXIS"]: if self.op.strategy in ["MEDIAL_AXIS"]:
self.layout.prop(self.op, "medial_axis_threshold") layout.prop(self.op, "medial_axis_threshold")
self.layout.prop(self.op, "medial_axis_subdivision") layout.prop(self.op, "medial_axis_subdivision")
self.layout.prop(self.op, "add_pocket_for_medial") layout.prop(self.op, "add_pocket_for_medial")
self.layout.prop(self.op, "add_mesh_for_medial") layout.prop(self.op, "add_mesh_for_medial")
def draw_drill_options(self): # Drill Options
if not self.has_correct_level():
return
if self.op.strategy in ["DRILL"]: if self.op.strategy in ["DRILL"]:
self.layout.prop(self.op, "drill_type") layout.prop(self.op, "drill_type")
self.draw_enable_A_B_axis() self.draw_enable_A_B_axis()
def draw_pocket_options(self): # Pocket Options
if not self.has_correct_level():
return
if self.op.strategy in ["POCKET"]: if self.op.strategy in ["POCKET"]:
self.draw_overshoot() self.draw_overshoot()
self.layout.prop(self.op, "pocketType") layout.prop(self.op, "pocketType")
if self.op.pocketType == "PARALLEL": if self.op.pocketType == "PARALLEL":
self.layout.label(text="Warning:Parallel pocket Experimental", icon="ERROR") layout.label(text="Warning:Parallel pocket Experimental", icon="ERROR")
self.layout.prop(self.op, "parallelPocketCrosshatch") layout.prop(self.op, "parallelPocketCrosshatch")
self.layout.prop(self.op, "parallelPocketContour") layout.prop(self.op, "parallelPocketContour")
self.layout.prop(self.op, "parallelPocketAngle") layout.prop(self.op, "parallelPocketAngle")
else: else:
self.layout.prop(self.op, "pocket_option") layout.prop(self.op, "pocket_option")
self.layout.prop(self.op, "pocketToCurve") layout.prop(self.op, "pocketToCurve")
self.layout.prop(self.op, "dist_between_paths") layout.prop(self.op, "dist_between_paths")
self.draw_cutter_engagement() self.draw_cutter_engagement()
self.draw_enable_A_B_axis() self.draw_enable_A_B_axis()
def draw_default_options(self): # Default Options
if not self.has_correct_level():
return
if self.op.strategy not in [ if self.op.strategy not in [
"CUTOUT", "CUTOUT",
"CURVE", "CURVE",
@ -208,56 +153,35 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, Panel):
"DRILL", "DRILL",
"POCKET", "POCKET",
]: ]:
self.layout.prop(self.op, "dist_between_paths") layout.prop(self.op, "dist_between_paths")
self.draw_cutter_engagement() self.draw_cutter_engagement()
self.layout.prop(self.op, "dist_along_paths") layout.prop(self.op, "dist_along_paths")
if self.op.strategy in ["PARALLEL", "CROSS"]: if self.op.strategy in ["PARALLEL", "CROSS"]:
self.layout.prop(self.op, "parallel_angle") layout.prop(self.op, "parallel_angle")
self.draw_enable_A_B_axis() self.draw_enable_A_B_axis()
self.layout.prop(self.op, "inverse") layout.prop(self.op, "inverse")
def draw_bridges_options(self): # Bridges Options
if not self.has_correct_level(): if self.level >= 1:
return
if self.op.strategy not in ["POCKET", "DRILL", "CURVE", "MEDIAL_AXIS"]: if self.op.strategy not in ["POCKET", "DRILL", "CURVE", "MEDIAL_AXIS"]:
self.layout.prop(self.op, "use_bridges") layout.prop(self.op, "use_bridges")
if self.op.use_bridges: if self.op.use_bridges:
self.layout.prop(self.op, "bridges_width") layout.prop(self.op, "bridges_width")
self.layout.prop(self.op, "bridges_height") layout.prop(self.op, "bridges_height")
self.layout.prop_search(self.op, "bridges_collection_name", bpy.data, "collections") layout.prop_search(
self.layout.prop(self.op, "use_bridge_modifiers") self.op, "bridges_collection_name", bpy.data, "collections"
self.layout.operator("scene.cam_bridges_add", text="Autogenerate Bridges / Tabs") )
layout.prop(self.op, "use_bridge_modifiers")
layout.operator("scene.cam_bridges_add", text="Autogenerate Bridges / Tabs")
def draw_skin(self): # Skin
if not self.has_correct_level():
return
self.layout.prop(self.op, "skin") self.layout.prop(self.op, "skin")
def draw_array(self): # Array
if not self.has_correct_level():
return
if self.op.machine_axes == "3": if self.op.machine_axes == "3":
self.layout.prop(self.op, "array") layout.prop(self.op, "array")
if self.op.array: if self.op.array:
self.layout.prop(self.op, "array_x_count") layout.prop(self.op, "array_x_count")
self.layout.prop(self.op, "array_x_distance") layout.prop(self.op, "array_x_distance")
self.layout.prop(self.op, "array_y_count") layout.prop(self.op, "array_y_count")
self.layout.prop(self.op, "array_y_distance") layout.prop(self.op, "array_y_distance")
def draw(self, context):
self.context = context
self.draw_machine_axis()
self.draw_strategy()
self.draw_cutout_options()
self.draw_waterline_options()
self.draw_carve_options()
self.draw_medial_axis_options()
self.draw_drill_options()
self.draw_pocket_options()
self.draw_default_options()
self.draw_bridges_options()
self.draw_skin()
self.draw_array()

Wyświetl plik

@ -9,8 +9,8 @@ from bpy.types import Panel
from .buttons_panel import CAMButtonsPanel from .buttons_panel import CAMButtonsPanel
# Operations panel # Operations panel
# This panel displays the list of operations created by the user # Displays the list of operations created by the user
# Functionnalities are: # Functionality:
# - list Operations # - list Operations
# - create/delete/duplicate/reorder operations # - create/delete/duplicate/reorder operations
# - display preset operations # - display preset operations
@ -23,24 +23,21 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, Panel):
bl_label = "CAM Operations" bl_label = "CAM Operations"
bl_idname = "WORLD_PT_CAM_OPERATIONS" bl_idname = "WORLD_PT_CAM_OPERATIONS"
always_show_panel = True
panel_interface_level = 0
prop_level = { def draw(self, context):
"draw_presets": 1, layout = self.layout
"draw_operations_list": 0, # Presets
"draw_calculate_path": 0, if self.level >= 1:
"draw_export_gcode": 1, row = layout.row(align=True)
"draw_simulate_op": 1, row.menu("CAM_OPERATION_MT_presets", text=bpy.types.CAM_OPERATION_MT_presets.bl_label)
"draw_op_name": 1, row.operator("render.cam_preset_operation_add", text="", icon="ADD")
"draw_op_filename": 0, row.operator(
"draw_operation_source": 0, "render.cam_preset_operation_add", text="", icon="REMOVE"
} ).remove_active = True
# Draw the list of operations and the associated buttons: # Operations List
# create, delete, duplicate, reorder # create, delete, duplicate, reorder
def draw_operations_list(self): row = layout.row()
row = self.layout.row()
row.template_list( row.template_list(
"CAM_UL_operations", "CAM_UL_operations",
"", "",
@ -57,99 +54,60 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, Panel):
col.operator("scene.cam_operation_move", icon="TRIA_UP", text="").direction = "UP" col.operator("scene.cam_operation_move", icon="TRIA_UP", text="").direction = "UP"
col.operator("scene.cam_operation_move", icon="TRIA_DOWN", text="").direction = "DOWN" col.operator("scene.cam_operation_move", icon="TRIA_DOWN", text="").direction = "DOWN"
# Draw the list of preset operations, and preset add and remove buttons if self.op is None:
def draw_presets(self):
if not self.has_correct_level():
return return
row = self.layout.row(align=True)
row.menu("CAM_OPERATION_MT_presets", text=bpy.types.CAM_OPERATION_MT_presets.bl_label)
row.operator("render.cam_preset_operation_add", text="", icon="ADD")
row.operator("render.cam_preset_operation_add", text="", icon="REMOVE").remove_active = True
def draw_calculate_path(self): # Calculate Path
if not self.has_correct_level():
return
if self.op.maxz > self.op.movement.free_height: if self.op.maxz > self.op.movement.free_height:
self.layout.label(text="!ERROR! COLLISION!") layout.label(text="!ERROR! COLLISION!")
self.layout.label(text="Depth Start > Free Movement Height") layout.label(text="Depth Start > Free Movement Height")
self.layout.label(text="!ERROR! COLLISION!") layout.label(text="!ERROR! COLLISION!")
self.layout.prop(self.op.movement, "free_height") layout.prop(self.op.movement, "free_height")
if not self.op.valid: if not self.op.valid:
self.layout.label(text="Select a Valid Object to Calculate the Path.") layout.label(text="Select a Valid Object to Calculate the Path.")
# will be disable if not valid # will be disabled if not valid
self.layout.operator("object.calculate_cam_path", text="Calculate Path & Export Gcode") layout.operator("object.calculate_cam_path", text="Calculate Path & Export Gcode")
def draw_export_gcode(self): # Export Gcode
if not self.has_correct_level(): if self.level >= 1:
return
if self.op.valid: if self.op.valid:
if self.op.name is not None: if self.op.name is not None:
name = f"cam_path_{self.op.name}" name = f"cam_path_{self.op.name}"
if bpy.context.scene.objects.get(name) is not None: if bpy.context.scene.objects.get(name) is not None:
self.layout.operator("object.cam_export", text="Export Gcode ") layout.operator("object.cam_export", text="Export Gcode ")
def draw_simulate_op(self): # Simulate Op
if not self.has_correct_level(): layout.operator("object.cam_simulate", text="Simulate This Operation")
return
if self.op.valid:
self.layout.operator("object.cam_simulate", text="Simulate This Operation")
def draw_op_name(self): # Op Name
if not self.has_correct_level(): layout.prop(self.op, "name")
return
self.layout.prop(self.op, "name")
def draw_op_filename(self): # Op Filename
if not self.has_correct_level(): layout.prop(self.op, "filename")
return
self.layout.prop(self.op, "filename")
# Draw a list of objects which will be used as the source of the operation # Op Source
# FIXME Right now, cameras or lights may be used, which crashes layout.prop(self.op, "geometry_source")
# The user should only be able to choose meshes and curves
def draw_operation_source(self):
if not self.has_correct_level():
return
self.layout.prop(self.op, "geometry_source")
if self.op.strategy == "CURVE": if self.op.strategy == "CURVE":
if self.op.geometry_source == "OBJECT": if self.op.geometry_source == "OBJECT":
self.layout.prop_search(self.op, "object_name", bpy.data, "objects") layout.prop_search(self.op, "object_name", bpy.data, "objects")
elif self.op.geometry_source == "COLLECTION": elif self.op.geometry_source == "COLLECTION":
self.layout.prop_search(self.op, "collection_name", bpy.data, "collections") layout.prop_search(self.op, "collection_name", bpy.data, "collections")
else: else:
if self.op.geometry_source == "OBJECT": if self.op.geometry_source == "OBJECT":
self.layout.prop_search(self.op, "object_name", bpy.data, "objects") layout.prop_search(self.op, "object_name", bpy.data, "objects")
if self.op.enable_A: if self.op.enable_A:
self.layout.prop(self.op, "rotation_A") layout.prop(self.op, "rotation_A")
if self.op.enable_B: if self.op.enable_B:
self.layout.prop(self.op, "rotation_B") layout.prop(self.op, "rotation_B")
elif self.op.geometry_source == "COLLECTION": elif self.op.geometry_source == "COLLECTION":
self.layout.prop_search(self.op, "collection_name", bpy.data, "collections") layout.prop_search(self.op, "collection_name", bpy.data, "collections")
else: else:
self.layout.prop_search(self.op, "source_image_name", bpy.data, "images") layout.prop_search(self.op, "source_image_name", bpy.data, "images")
if self.op.strategy in ["CARVE", "PROJECTED_CURVE"]: if self.op.strategy in ["CARVE", "PROJECTED_CURVE"]:
self.layout.prop_search(self.op, "curve_object", bpy.data, "objects") layout.prop_search(self.op, "curve_object", bpy.data, "objects")
if self.op.strategy == "PROJECTED_CURVE": if self.op.strategy == "PROJECTED_CURVE":
self.layout.prop_search(self.op, "curve_object1", bpy.data, "objects") layout.prop_search(self.op, "curve_object1", bpy.data, "objects")
def draw(self, context):
self.context = context
self.draw_presets()
self.draw_operations_list()
if self.op is None:
return
self.draw_calculate_path()
self.draw_export_gcode()
self.draw_simulate_op()
self.draw_op_name()
self.draw_op_filename()
self.draw_operation_source()

Wyświetl plik

@ -110,18 +110,17 @@ class CAM_OPTIMISATION_Panel(CAMButtonsPanel, Panel):
bl_idname = "WORLD_PT_CAM_OPTIMISATION" bl_idname = "WORLD_PT_CAM_OPTIMISATION"
panel_interface_level = 2 panel_interface_level = 2
def draw_optimize(self): def draw(self, context):
if not self.has_correct_level(): layout = self.layout
return
self.layout.prop(self.op.optimisation, "optimize") if self.level >= 2 and self.op is not None:
# Optimize
layout.prop(self.op.optimisation, "optimize")
if self.op.optimisation.optimize: if self.op.optimisation.optimize:
self.layout.prop(self.op.optimisation, "optimize_threshold") layout.prop(self.op.optimisation, "optimize_threshold")
layout.separator()
def draw_exact_mode(self):
if not self.has_correct_level():
return
# Exact Mode
if not self.op.geometry_source == "OBJECT" or self.op.geometry_source == "COLLECTION": if not self.op.geometry_source == "OBJECT" or self.op.geometry_source == "COLLECTION":
return return
@ -135,11 +134,11 @@ class CAM_OPTIMISATION_Panel(CAMButtonsPanel, Panel):
] ]
if self.exact_possible: if self.exact_possible:
self.layout.prop(self.op.optimisation, "use_exact") layout.prop(self.op.optimisation, "use_exact")
if not self.exact_possible or not self.op.optimisation.use_exact: if not self.exact_possible or not self.op.optimisation.use_exact:
self.layout.prop(self.op.optimisation, "pixsize") layout.prop(self.op.optimisation, "pixsize")
self.layout.prop(self.op.optimisation, "imgres_limit") layout.prop(self.op.optimisation, "imgres_limit")
sx = self.op.max.x - self.op.min.x sx = self.op.max.x - self.op.min.x
sy = self.op.max.y - self.op.min.y sy = self.op.max.y - self.op.min.y
@ -148,66 +147,38 @@ class CAM_OPTIMISATION_Panel(CAMButtonsPanel, Panel):
if resx > 0 and resy > 0: if resx > 0 and resy > 0:
resolution = "Resolution: " + str(resx) + " x " + str(resy) resolution = "Resolution: " + str(resx) + " x " + str(resy)
self.layout.label(text=resolution) layout.label(text=resolution)
def draw_use_opencamlib(self):
if not self.has_correct_level():
return
# Use OpenCAMLib
if not (self.exact_possible and self.op.optimisation.use_exact): if not (self.exact_possible and self.op.optimisation.use_exact):
return return
ocl_version = opencamlib_version() ocl_version = opencamlib_version()
if ocl_version is None: if ocl_version is None:
self.layout.label(text="OpenCAMLib is not Available ") layout.label(text="OpenCAMLib is not Available ")
self.layout.prop(self.op.optimisation, "exact_subdivide_edges") layout.prop(self.op.optimisation, "exact_subdivide_edges")
else: else:
self.layout.prop(self.op.optimisation, "use_opencamlib") layout.prop(self.op.optimisation, "use_opencamlib")
layout.separator()
def draw_simulation_detail(self): # Simulation Detail
if not self.has_correct_level(): layout.prop(self.op.optimisation, "simulation_detail")
return layout.prop(self.op.optimisation, "circle_detail")
self.layout.prop(self.op.optimisation, "simulation_detail")
self.layout.prop(self.op.optimisation, "circle_detail")
def draw_simplify_gcode(self):
if not self.has_correct_level():
return
# Simplify Gcode
if self.op.strategy not in ["DRILL"]: if self.op.strategy not in ["DRILL"]:
self.layout.prop(self.op, "remove_redundant_points") layout.prop(self.op, "remove_redundant_points")
if self.op.remove_redundant_points: if self.op.remove_redundant_points:
self.layout.prop(self.op, "simplify_tol") layout.prop(self.op, "simplify_tol")
def draw_use_modifiers(self): # Use Modifiers
if not self.has_correct_level():
return
if self.op.geometry_source in ["OBJECT", "COLLECTION"]: if self.op.geometry_source in ["OBJECT", "COLLECTION"]:
self.layout.prop(self.op, "use_modifiers") layout.prop(self.op, "use_modifiers")
def draw_hide_all_others(self): # Hide All Others
if not self.has_correct_level(): layout.prop(self.op, "hide_all_others")
return
self.layout.prop(self.op, "hide_all_others")
def draw_parent_path_to_object(self): # Parent Path to Object
if not self.has_correct_level(): layout.prop(self.op, "parent_path_to_object")
return
self.layout.prop(self.op, "parent_path_to_object")
def draw(self, context):
self.context = context
self.draw_optimize()
self.layout.separator()
self.draw_exact_mode()
self.draw_use_opencamlib()
self.layout.separator()
self.draw_simulation_detail()
self.draw_simplify_gcode()
self.draw_use_modifiers()
self.draw_hide_all_others()
self.draw_parent_path_to_object()

Wyświetl plik

@ -14,17 +14,12 @@ class CAM_PACK_Panel(CAMButtonsPanel, Panel):
bl_label = "Pack Curves on Sheet" bl_label = "Pack Curves on Sheet"
bl_idname = "WORLD_PT_CAM_PACK" bl_idname = "WORLD_PT_CAM_PACK"
panel_interface_level = 2
COMPAT_ENGINES = {"CNCCAM_RENDER"}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
scene = bpy.context.scene scene = bpy.context.scene
settings = scene.cam_pack settings = scene.cam_pack
layout.label(text="Warning - Algorithm Is Slow.") if self.level >= 2:
layout.label(text="Only for Curves Now.")
layout.operator("object.cam_pack_objects") layout.operator("object.cam_pack_objects")
layout.prop(settings, "sheet_fill_direction") layout.prop(settings, "sheet_fill_direction")
layout.prop(settings, "sheet_x") layout.prop(settings, "sheet_x")

Wyświetl plik

@ -14,15 +14,13 @@ class CAM_SLICE_Panel(CAMButtonsPanel, Panel):
bl_label = "Slice Model to Plywood Sheets" bl_label = "Slice Model to Plywood Sheets"
bl_idname = "WORLD_PT_CAM_SLICE" bl_idname = "WORLD_PT_CAM_SLICE"
panel_interface_level = 2
COMPAT_ENGINES = {"CNCCAM_RENDER"}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
scene = bpy.context.scene scene = bpy.context.scene
settings = scene.cam_slice settings = scene.cam_slice
if self.level >= 2:
layout.operator("object.cam_slice_objects") layout.operator("object.cam_slice_objects")
layout.prop(settings, "slice_distance") layout.prop(settings, "slice_distance")
layout.prop(settings, "slice_above0") layout.prop(settings, "slice_above0")