kopia lustrzana https://github.com/vilemduha/blendercam
Merge remote-tracking branch 'origin/master'
commit
9d50b82402
|
|
@ -685,7 +685,7 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
# movement and ramps
|
||||
use_layers: bpy.props.BoolProperty(name="Use Layers", description="Use layers for roughing", default=True,
|
||||
update=updateRest)
|
||||
stepdown: bpy.props.FloatProperty(name="Step down", default=0.01, min=0.00001, max=32, precision=PRECISION,
|
||||
stepdown: bpy.props.FloatProperty(name="", description="Layer height", default=0.01, min=0.00001, max=32, precision=PRECISION,
|
||||
unit="LENGTH", update=updateRest)
|
||||
first_down: bpy.props.BoolProperty(name="First down",
|
||||
description="First go down on a contour, then go to the next one",
|
||||
|
|
@ -1527,7 +1527,7 @@ def unregister():
|
|||
for p in classes:
|
||||
bpy.utils.unregister_class(p)
|
||||
s = bpy.types.Scene
|
||||
|
||||
|
||||
# cam chains are defined hardly now.
|
||||
del s.cam_chains
|
||||
del s.cam_active_chain
|
||||
|
|
|
|||
|
|
@ -46,9 +46,8 @@ def getCutterBullet(o):
|
|||
if type == 'END':
|
||||
bpy.ops.mesh.primitive_cylinder_add(vertices=32, radius= o.cutter_diameter / 2,
|
||||
depth= o.cutter_diameter, end_fill_type='NGON',
|
||||
align='WORLD', enter_editmode=False, location=(0 , 0, o.cutter_diameter / 2),
|
||||
align='WORLD', enter_editmode=False, location = CUTTER_OFFSET,
|
||||
rotation=(0, 0, 0))
|
||||
#bpy.ops.object.duplicate() # show bit
|
||||
cutter = bpy.context.active_object
|
||||
cutter.scale *= BULLET_SCALE
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
|
|
@ -62,8 +61,7 @@ def getCutterBullet(o):
|
|||
# the actual collision shape is capsule in this case.
|
||||
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, radius = o.cutter_diameter / 2,
|
||||
align='WORLD', enter_editmode=False,
|
||||
location=(0, 0, o.cutter_diameter / 2), rotation=(0, 0, 0))
|
||||
#bpy.ops.object.duplicate() # show bit
|
||||
location = CUTTER_OFFSET, rotation=(0, 0, 0))
|
||||
cutter = bpy.context.active_object
|
||||
cutter.scale *= BULLET_SCALE
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
|
|
@ -81,9 +79,8 @@ def getCutterBullet(o):
|
|||
cone_d = o.cutter_diameter * s
|
||||
bpy.ops.mesh.primitive_cone_add(vertices=32, radius1 = o.cutter_diameter / 2, radius2=0,
|
||||
depth = cone_d, end_fill_type='NGON',
|
||||
align='WORLD', enter_editmode=False, location = (0, 0, cone_d / 2),
|
||||
align='WORLD', enter_editmode=False, location = CUTTER_OFFSET,
|
||||
rotation=(math.pi, 0, 0))
|
||||
#bpy.ops.object.duplicate() # show bit
|
||||
cutter = bpy.context.active_object
|
||||
cutter.scale *= BULLET_SCALE
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
|
|
@ -100,8 +97,7 @@ def getCutterBullet(o):
|
|||
radius2 = o.cylcone_diameter / 2,
|
||||
depth = cylcone_d, end_fill_type='NGON',
|
||||
align = 'WORLD', enter_editmode = False,
|
||||
location = (0 , 0 , cylcone_d / 2),rotation = (math.pi, 0, 0))
|
||||
#bpy.ops.object.duplicate() # show bit
|
||||
location = CUTTER_OFFSET,rotation = (math.pi, 0, 0))
|
||||
cutter = bpy.context.active_object
|
||||
cutter.scale *= BULLET_SCALE
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
|
|
@ -109,6 +105,7 @@ def getCutterBullet(o):
|
|||
bpy.ops.rigidbody.object_add(type='ACTIVE')
|
||||
cutter = bpy.context.active_object
|
||||
cutter.rigid_body.collision_shape = 'CONVEX_HULL'
|
||||
cutter.location = CUTTER_OFFSET
|
||||
elif type == 'BALLCONE':
|
||||
angle = math.radians(o.cutter_tip_angle)/2
|
||||
cutter_R = o.cutter_diameter/2
|
||||
|
|
@ -137,8 +134,7 @@ def getCutterBullet(o):
|
|||
ob_scr.merge_threshold = 0
|
||||
ob_scr.use_merge_vertices = True
|
||||
bpy.ops.object.modifier_apply(modifier='scr')
|
||||
bpy.data.objects['BallConeTool'].select_set(True)
|
||||
#bpy.ops.object.duplicate() # show bit
|
||||
bpy.data.objects['BallConeTool'].select_set(True)
|
||||
cutter = bpy.context.active_object
|
||||
cutter.scale *= BULLET_SCALE
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
|
|
@ -146,7 +142,7 @@ def getCutterBullet(o):
|
|||
bpy.ops.rigidbody.object_add(type='ACTIVE')
|
||||
cutter.location = CUTTER_OFFSET
|
||||
cutter.rigid_body.collision_shape = 'CONVEX_HULL'
|
||||
|
||||
cutter.location = CUTTER_OFFSET
|
||||
elif type == 'CUSTOM':
|
||||
cutob = bpy.data.objects[o.cutter_object_name]
|
||||
activate(cutob)
|
||||
|
|
|
|||
|
|
@ -591,21 +591,26 @@ class CamOperationAdd(bpy.types.Operator):
|
|||
s = bpy.context.scene
|
||||
fixUnits()
|
||||
|
||||
if s.objects.get('CAM_machine') is None:
|
||||
utils.addMachineAreaObject()
|
||||
# if len(s.cam_material)==0:
|
||||
# s.cam_material.add()
|
||||
|
||||
s.cam_operations.add()
|
||||
o = s.cam_operations[-1]
|
||||
s.cam_active_operation = len(s.cam_operations) - 1
|
||||
o.name = 'Operation_' + str(s.cam_active_operation + 1)
|
||||
o.filename = o.name
|
||||
ob = bpy.context.active_object
|
||||
if ob is not None:
|
||||
o.object_name = ob.name
|
||||
minx, miny, minz, maxx, maxy, maxz = utils.getBoundsWorldspace([ob])
|
||||
o.minz = minz
|
||||
else:
|
||||
# FIXME Creating an operation without any object selected
|
||||
# This should actually display a modal dialog
|
||||
# and cancel the operation creation
|
||||
o.object_name = "none"
|
||||
o.minz = 0
|
||||
|
||||
s.cam_active_operation = len(s.cam_operations) - 1
|
||||
o.name = f"Op_{o.object_name}_{s.cam_active_operation + 1}"
|
||||
o.filename = o.name
|
||||
|
||||
if s.objects.get('CAM_machine') is None:
|
||||
utils.addMachineAreaObject()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ from cam.ui_panels.material import CAM_MATERIAL_Panel
|
|||
from cam.ui_panels.chains import CAM_UL_operations, CAM_UL_chains, CAM_CHAINS_Panel
|
||||
from cam.ui_panels.op_properties import CAM_OPERATION_PROPERTIES_Panel
|
||||
from cam.ui_panels.movement import CAM_MOVEMENT_Panel
|
||||
from cam.ui_panels.feedrate import CAM_FEEDRATE_Panel
|
||||
from cam.ui_panels.optimisation import CAM_OPTIMISATION_Panel
|
||||
from cam.ui_panels.area import CAM_AREA_Panel
|
||||
|
||||
|
||||
class CAM_UL_orientations(UIList):
|
||||
|
|
@ -55,139 +58,6 @@ class CAM_UL_orientations(UIList):
|
|||
|
||||
|
||||
|
||||
class CAM_FEEDRATE_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM feedrate panel"""
|
||||
bl_label = "CAM feedrate"
|
||||
bl_idname = "WORLD_PT_CAM_FEEDRATE"
|
||||
|
||||
COMPAT_ENGINES = {'BLENDERCAM_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = bpy.context.scene
|
||||
if len(scene.cam_operations) == 0:
|
||||
layout.label(text='Add operation first')
|
||||
if len(scene.cam_operations) > 0:
|
||||
ao = scene.cam_operations[scene.cam_active_operation]
|
||||
if ao.valid:
|
||||
layout.prop(ao, 'feedrate')
|
||||
layout.prop(ao, 'do_simulation_feedrate')
|
||||
layout.prop(ao, 'plunge_feedrate')
|
||||
layout.prop(ao, 'plunge_angle')
|
||||
layout.prop(ao, 'spindle_rpm')
|
||||
|
||||
|
||||
class CAM_OPTIMISATION_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM optimisation panel"""
|
||||
bl_label = "CAM optimisation"
|
||||
bl_idname = "WORLD_PT_CAM_OPTIMISATION"
|
||||
|
||||
COMPAT_ENGINES = {'BLENDERCAM_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = bpy.context.scene
|
||||
|
||||
if len(scene.cam_operations) == 0:
|
||||
layout.label(text='Add operation first')
|
||||
if len(scene.cam_operations) > 0:
|
||||
ao = scene.cam_operations[scene.cam_active_operation]
|
||||
if ao.valid:
|
||||
layout.prop(ao, 'optimize')
|
||||
if ao.optimize:
|
||||
layout.prop(ao, 'optimize_threshold')
|
||||
if ao.geometry_source == 'OBJECT' or ao.geometry_source == 'COLLECTION':
|
||||
exclude_exact = ao.strategy in ['MEDIAL_AXIS', 'POCKET', 'WATERLINE', 'CUTOUT', 'DRILL', 'PENCIL',
|
||||
'CURVE']
|
||||
if not exclude_exact:
|
||||
if not ao.use_exact:
|
||||
layout.prop(ao, 'use_exact')
|
||||
layout.label(text="Exact mode must be set for opencamlib to work ")
|
||||
|
||||
if "ocl" in sys.modules:
|
||||
layout.label(text="Opencamlib is available ")
|
||||
layout.prop(ao, 'use_opencamlib')
|
||||
else:
|
||||
layout.label(text="Opencamlib is NOT available ")
|
||||
layout.prop(ao, 'exact_subdivide_edges')
|
||||
|
||||
if exclude_exact or not ao.use_exact:
|
||||
layout.prop(ao, 'pixsize')
|
||||
layout.prop(ao, 'imgres_limit')
|
||||
|
||||
sx = ao.max.x - ao.min.x
|
||||
sy = ao.max.y - ao.min.y
|
||||
resx = int(sx / ao.pixsize)
|
||||
resy = int(sy / ao.pixsize)
|
||||
l = 'resolution: ' + str(resx) + ' x ' + str(resy)
|
||||
layout.label(text=l)
|
||||
|
||||
layout.prop(ao, 'simulation_detail')
|
||||
layout.prop(ao, 'circle_detail')
|
||||
|
||||
|
||||
class CAM_AREA_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM operation area panel"""
|
||||
bl_label = "CAM operation area "
|
||||
bl_idname = "WORLD_PT_CAM_OPERATION_AREA"
|
||||
|
||||
COMPAT_ENGINES = {'BLENDERCAM_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = bpy.context.scene
|
||||
if len(scene.cam_operations) == 0:
|
||||
layout.label(text='Add operation first')
|
||||
if len(scene.cam_operations) > 0:
|
||||
ao = scene.cam_operations[scene.cam_active_operation]
|
||||
if ao.valid:
|
||||
layout.prop(ao, 'use_layers')
|
||||
if ao.use_layers:
|
||||
layout.prop(ao, 'stepdown')
|
||||
|
||||
layout.prop(ao, 'ambient_behaviour')
|
||||
if ao.ambient_behaviour == 'AROUND':
|
||||
layout.prop(ao, 'ambient_radius')
|
||||
|
||||
layout.prop(ao, 'maxz') # experimental
|
||||
if ao.maxz > ao.free_movement_height:
|
||||
layout.prop(ao, 'free_movement_height')
|
||||
layout.label(text='Depth start > Free movement')
|
||||
layout.label(text='POSSIBLE COLLISION')
|
||||
if ao.geometry_source in ['OBJECT', 'COLLECTION']:
|
||||
if ao.strategy == 'CURVE':
|
||||
layout.label(text="cannot use depth from object using CURVES")
|
||||
|
||||
if not ao.minz_from_ob:
|
||||
if not ao.minz_from_material:
|
||||
layout.prop(ao, 'minz')
|
||||
layout.prop(ao, 'minz_from_material')
|
||||
if not ao.minz_from_material:
|
||||
layout.prop(ao, 'minz_from_ob')
|
||||
else:
|
||||
layout.prop(ao, 'source_image_scale_z')
|
||||
layout.prop(ao, 'source_image_size_x')
|
||||
if ao.source_image_name != '':
|
||||
i = bpy.data.images[ao.source_image_name]
|
||||
if i is not None:
|
||||
sy = int((ao.source_image_size_x / i.size[0]) * i.size[1] * 1000000) / 1000
|
||||
|
||||
layout.label(text='image size on y axis: ' + strInUnits(sy, 8))
|
||||
layout.separator()
|
||||
layout.prop(ao, 'source_image_offset')
|
||||
col = layout.column(align=True)
|
||||
col.prop(ao, 'source_image_crop', text='Crop source image')
|
||||
if ao.source_image_crop:
|
||||
col.prop(ao, 'source_image_crop_start_x', text='start x')
|
||||
col.prop(ao, 'source_image_crop_start_y', text='start y')
|
||||
col.prop(ao, 'source_image_crop_end_x', text='end x')
|
||||
col.prop(ao, 'source_image_crop_end_y', text='end y')
|
||||
layout.prop(ao, 'use_limit_curve')
|
||||
if ao.use_limit_curve:
|
||||
layout.prop_search(ao, "limit_curve", bpy.data, "objects")
|
||||
layout.prop(ao, "ambient_cutter_restrict")
|
||||
|
||||
|
||||
class CAM_GCODE_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM operation g-code options panel"""
|
||||
bl_label = "CAM g-code options "
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
import bpy
|
||||
from cam.ui_panels.buttons_panel import CAMButtonsPanel
|
||||
|
||||
class CAM_AREA_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM operation area panel"""
|
||||
bl_label = "CAM operation area "
|
||||
bl_idname = "WORLD_PT_CAM_OPERATION_AREA"
|
||||
|
||||
COMPAT_ENGINES = {'BLENDERCAM_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
self.scene = bpy.context.scene
|
||||
if not self.has_operations():
|
||||
self.layout.label(text='Add operation first')
|
||||
return
|
||||
|
||||
self.ao = self.active_operation()
|
||||
|
||||
if not self.ao.valid:
|
||||
return
|
||||
|
||||
self.draw_z_limits()
|
||||
self.draw_xy_limits()
|
||||
|
||||
# Draw layers option: use layers(y/n) and choose the stepdown
|
||||
def draw_z_limits(self):
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(self.ao, 'use_layers')
|
||||
if self.ao.use_layers:
|
||||
row.prop(self.ao, 'stepdown')
|
||||
|
||||
self.layout.prop(self.ao, 'maxz')
|
||||
|
||||
if self.ao.maxz > self.ao.free_movement_height:
|
||||
self.layout.prop(self.ao, 'free_movement_height')
|
||||
self.layout.label(text='Depth start > Free movement')
|
||||
self.layout.label(text='POSSIBLE COLLISION')
|
||||
|
||||
if self.ao.geometry_source in ['OBJECT', 'COLLECTION']:
|
||||
if self.ao.strategy == 'CURVE':
|
||||
self.layout.label(text="cannot use depth from object using CURVES")
|
||||
|
||||
if not self.ao.minz_from_ob:
|
||||
if not self.ao.minz_from_material:
|
||||
self.layout.prop(self.ao, 'minz')
|
||||
self.layout.prop(self.ao, 'minz_from_material')
|
||||
if not self.ao.minz_from_material:
|
||||
self.layout.prop(self.ao, 'minz_from_ob')
|
||||
else:
|
||||
self.layout.prop(self.ao, 'source_image_scale_z')
|
||||
self.layout.prop(self.ao, 'source_image_size_x')
|
||||
if self.ao.source_image_name != '':
|
||||
i = bpy.data.images[self.ao.source_image_name]
|
||||
if i is not None:
|
||||
sy = int((self.ao.source_image_size_x / i.size[0]) * i.size[1] * 1000000) / 1000
|
||||
self.layout.label(text='image size on y axis: ' + strInUnits(sy, 8))
|
||||
self.layout.separator()
|
||||
self.layout.prop(self.ao, 'source_image_offset')
|
||||
col = self.layout.column(align=True)
|
||||
col.prop(self.ao, 'source_image_crop', text='Crop source image')
|
||||
if self.ao.source_image_crop:
|
||||
col.prop(self.ao, 'source_image_crop_start_x', text='start x')
|
||||
col.prop(self.ao, 'source_image_crop_start_y', text='start y')
|
||||
col.prop(self.ao, 'source_image_crop_end_x', text='end x')
|
||||
col.prop(self.ao, 'source_image_crop_end_y', text='end y')
|
||||
|
||||
def draw_xy_limits(self):
|
||||
self.layout.prop(self.ao, 'ambient_behaviour')
|
||||
if self.ao.ambient_behaviour == 'AROUND':
|
||||
self.layout.prop(self.ao, 'ambient_radius')
|
||||
|
||||
self.layout.prop(self.ao, 'use_limit_curve')
|
||||
|
||||
if self.ao.use_limit_curve:
|
||||
self.layout.prop_search(self.ao, "limit_curve", bpy.data, "objects")
|
||||
|
||||
self.layout.prop(self.ao, "ambient_cutter_restrict")
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import bpy
|
||||
import sys
|
||||
|
||||
# Panel definitions
|
||||
class CAMButtonsPanel:
|
||||
|
|
@ -16,6 +17,7 @@ class CAMButtonsPanel:
|
|||
def __init__(self):
|
||||
self.scene = bpy.context.scene
|
||||
|
||||
|
||||
def active_operation_index(self):
|
||||
return(self.scene.cam_active_operation)
|
||||
|
||||
|
|
@ -33,3 +35,10 @@ class CAMButtonsPanel:
|
|||
|
||||
def has_operations(self):
|
||||
return (self.operations_count() > 0)
|
||||
|
||||
def opencamlib_version(self):
|
||||
try:
|
||||
import ocl
|
||||
return(ocl.version())
|
||||
except ImportError as e:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import bpy
|
||||
from cam.ui_panels.buttons_panel import CAMButtonsPanel
|
||||
|
||||
class CAM_FEEDRATE_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM feedrate panel"""
|
||||
bl_label = "CAM feedrate"
|
||||
bl_idname = "WORLD_PT_CAM_FEEDRATE"
|
||||
|
||||
COMPAT_ENGINES = {'BLENDERCAM_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
if not self.has_operations():
|
||||
self.layout.label(text='Add operation first')
|
||||
return
|
||||
|
||||
ao = self.active_operation()
|
||||
if not ao.valid: return
|
||||
|
||||
self.layout.prop(ao, 'feedrate')
|
||||
self.layout.prop(ao, 'do_simulation_feedrate')
|
||||
self.layout.prop(ao, 'plunge_feedrate')
|
||||
self.layout.prop(ao, 'plunge_angle')
|
||||
self.layout.prop(ao, 'spindle_rpm')
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
import sys
|
||||
import ocl
|
||||
import bpy
|
||||
|
||||
from cam.simple import strInUnits
|
||||
|
|
@ -27,10 +25,11 @@ class CAM_INFO_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
self.layout.label(text='No CAM operation created')
|
||||
|
||||
def draw_opencamlib_version(self):
|
||||
if "ocl" in sys.modules:
|
||||
self.layout.label(text = f"Opencamlib v{ocl.version()} installed")
|
||||
else:
|
||||
opencamlib_version = self.opencamlib_version()
|
||||
if opencamlib_version is None:
|
||||
self.layout.label(text = "Opencamlib is not installed")
|
||||
else:
|
||||
self.layout.label(text = f"Opencamlib v{opencamlib_version} installed")
|
||||
|
||||
def draw_active_op_warnings(self):
|
||||
active_op = self.active_operation()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,14 @@
|
|||
import bpy
|
||||
from cam.ui_panels.buttons_panel import CAMButtonsPanel
|
||||
|
||||
# Operations panel
|
||||
# This panel displays the list of operations created by the user
|
||||
# Functionnalities are:
|
||||
# - list Operations
|
||||
# - create/delete/duplicate/reorder operations
|
||||
# - display preset operations
|
||||
#
|
||||
# For each operation, generate the corresponding gcode and export the gcode file
|
||||
|
||||
class CAM_OPERATIONS_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM operations panel"""
|
||||
|
|
@ -10,10 +18,38 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
|
||||
COMPAT_ENGINES = {'BLENDERCAM_RENDER'}
|
||||
|
||||
# Main draw function
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
self.context = context
|
||||
self.draw_operations_list()
|
||||
|
||||
row = layout.row()
|
||||
# FIXME: is this ever used ?
|
||||
use_experimental = bpy.context.preferences.addons['cam'].preferences.experimental
|
||||
|
||||
if (not self.has_operations()): return
|
||||
ao = self.active_operation()
|
||||
if ao is None: return
|
||||
|
||||
self.draw_presets()
|
||||
|
||||
self.draw_output_buttons()
|
||||
|
||||
layout = self.layout
|
||||
sub = layout.column()
|
||||
sub.active = not ao.computing
|
||||
|
||||
# Draw operation name and filename
|
||||
sub.prop(ao, 'name')
|
||||
sub.prop(ao, 'filename')
|
||||
|
||||
self.draw_operation_source()
|
||||
self.draw_operation_options()
|
||||
|
||||
|
||||
# Draw the list of operations and the associated buttons:
|
||||
# create, delete, duplicate, reorder
|
||||
def draw_operations_list(self):
|
||||
row = self.layout.row()
|
||||
row.template_list("CAM_UL_operations", '', self.scene, "cam_operations", self.scene, 'cam_active_operation')
|
||||
col = row.column(align=True)
|
||||
col.operator("scene.cam_operation_add", icon='ADD', text="")
|
||||
|
|
@ -23,18 +59,27 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
col.operator("scene.cam_operation_move", icon='TRIA_UP', text="").direction = 'UP'
|
||||
col.operator("scene.cam_operation_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||
|
||||
use_experimental = bpy.context.preferences.addons['cam'].preferences.experimental
|
||||
|
||||
if (not self.has_operations()): return
|
||||
ao = self.active_operation()
|
||||
if ao is None: return
|
||||
|
||||
row = layout.row(align=True)
|
||||
# Draw the list of preset operations, and preset add and remove buttons
|
||||
def draw_presets(self):
|
||||
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
|
||||
|
||||
if not ao.computing:
|
||||
|
||||
# Draw buttons "Calculate path & export Gcode", "Export Gcode ", and "Simulate this operation"
|
||||
def draw_output_buttons(self):
|
||||
layout = self.layout
|
||||
ao = self.active_operation()
|
||||
|
||||
# FIXME This does not seem to work - there is never a "Computing" label displayed
|
||||
# while an operation is being calculated
|
||||
if ao.computing:
|
||||
row = layout.row(align=True)
|
||||
row.label(text='computing')
|
||||
row.operator('object.kill_calculate_cam_paths_background', text="", icon='CANCEL')
|
||||
else:
|
||||
if ao.valid:
|
||||
layout.operator("object.calculate_cam_path", text="Calculate path & export Gcode")
|
||||
if ao.name is not None:
|
||||
|
|
@ -44,16 +89,14 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
layout.operator("object.cam_simulate", text="Simulate this operation")
|
||||
else:
|
||||
layout.label(text="operation invalid, can't compute")
|
||||
else:
|
||||
row = layout.row(align=True)
|
||||
row.label(text='computing')
|
||||
row.operator('object.kill_calculate_cam_paths_background', text="", icon='CANCEL')
|
||||
|
||||
sub = layout.column()
|
||||
sub.active = not ao.computing
|
||||
|
||||
sub.prop(ao, 'name')
|
||||
sub.prop(ao, 'filename')
|
||||
# Draw a list of objects which will be used as the source of the operation
|
||||
# FIXME Right now, cameras or lights may be used, which crashes
|
||||
# The user should only be able to choose meshes and curves
|
||||
def draw_operation_source(self):
|
||||
layout = self.layout
|
||||
ao = self.active_operation()
|
||||
|
||||
layout.prop(ao, 'geometry_source')
|
||||
|
||||
|
|
@ -75,18 +118,29 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
else:
|
||||
layout.prop_search(ao, "source_image_name", bpy.data, "images")
|
||||
|
||||
|
||||
if ao.strategy in ['CARVE', 'PROJECTED_CURVE']:
|
||||
layout.prop_search(ao, "curve_object", bpy.data, "objects")
|
||||
if ao.strategy == 'PROJECTED_CURVE':
|
||||
layout.prop_search(ao, "curve_object1", bpy.data, "objects")
|
||||
|
||||
# Draw Operation options:
|
||||
# Remove redundant points (optimizes operation)
|
||||
# Use modifiers of the object
|
||||
# Hide all other paths
|
||||
# Parent path to object (?)
|
||||
|
||||
def draw_operation_options(self):
|
||||
layout = self.layout
|
||||
ao = self.active_operation()
|
||||
|
||||
# TODO This should be in some optimization menu
|
||||
layout.prop(ao, 'remove_redundant_points')
|
||||
if ao.remove_redundant_points:
|
||||
layout.label(text='Revise your Code before running!')
|
||||
layout.label(text='Quality will suffer if tolerance')
|
||||
layout.label(text='is high')
|
||||
layout.prop(ao, 'simplify_tol')
|
||||
|
||||
if ao.geometry_source in ['OBJECT', 'COLLECTION']:
|
||||
layout.prop(ao, 'use_modifiers')
|
||||
layout.prop(ao, 'hide_all_others')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
import bpy
|
||||
from cam.ui_panels.buttons_panel import CAMButtonsPanel
|
||||
|
||||
class CAM_OPTIMISATION_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM optimisation panel"""
|
||||
bl_label = "CAM optimisation"
|
||||
bl_idname = "WORLD_PT_CAM_OPTIMISATION"
|
||||
|
||||
COMPAT_ENGINES = {'BLENDERCAM_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = bpy.context.scene
|
||||
|
||||
if len(scene.cam_operations) == 0:
|
||||
layout.label(text='Add operation first')
|
||||
if len(scene.cam_operations) > 0:
|
||||
ao = scene.cam_operations[scene.cam_active_operation]
|
||||
if ao.valid:
|
||||
layout.prop(ao, 'optimize')
|
||||
if ao.optimize:
|
||||
layout.prop(ao, 'optimize_threshold')
|
||||
if ao.geometry_source == 'OBJECT' or ao.geometry_source == 'COLLECTION':
|
||||
exclude_exact = ao.strategy in ['MEDIAL_AXIS', 'POCKET', 'WATERLINE', 'CUTOUT', 'DRILL', 'PENCIL',
|
||||
'CURVE']
|
||||
if not exclude_exact:
|
||||
if not ao.use_exact:
|
||||
layout.prop(ao, 'use_exact')
|
||||
layout.label(text="Exact mode must be set for opencamlib to work ")
|
||||
|
||||
opencamlib_version = self.opencamlib_version()
|
||||
if opencamlib_version is None:
|
||||
layout.label(text="Opencamlib is NOT available ")
|
||||
layout.prop(ao, 'exact_subdivide_edges')
|
||||
else:
|
||||
layout.label(text=f"Opencamlib v{opencamlib_version} installed")
|
||||
layout.prop(ao, 'use_opencamlib')
|
||||
|
||||
if exclude_exact or not ao.use_exact:
|
||||
layout.prop(ao, 'pixsize')
|
||||
layout.prop(ao, 'imgres_limit')
|
||||
|
||||
sx = ao.max.x - ao.min.x
|
||||
sy = ao.max.y - ao.min.y
|
||||
resx = int(sx / ao.pixsize)
|
||||
resy = int(sy / ao.pixsize)
|
||||
l = 'resolution: ' + str(resx) + ' x ' + str(resy)
|
||||
layout.label(text=l)
|
||||
|
||||
layout.prop(ao, 'simulation_detail')
|
||||
layout.prop(ao, 'circle_detail')
|
||||
|
|
@ -1316,7 +1316,13 @@ def getObjectOutline(radius, o, Offset): # FIXME: make this one operation indep
|
|||
join = 2
|
||||
else:
|
||||
join = 1
|
||||
for p1 in polygons.geoms: # sort by size before this???
|
||||
|
||||
if isinstance(polygons, list):
|
||||
polygon_list = polygons
|
||||
else:
|
||||
polygon_list = polygons.geoms
|
||||
|
||||
for p1 in polygon_list: # sort by size before this???
|
||||
# print(p1.type, len(polygons))
|
||||
i += 1
|
||||
if radius > 0:
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue