Skip to content

Commit

Permalink
Merge pull request #135 from joemarshall/silly_warnings
Browse files Browse the repository at this point in the history
Add warnings for when you (I) do silly things
  • Loading branch information
pppalain authored Jan 17, 2024
2 parents fba5459 + 2e6ad35 commit 737870b
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 44 deletions.
54 changes: 35 additions & 19 deletions scripts/addons/cam/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def updateMaterial(self, context):
def updateOperation(self, context):
scene = context.scene
ao = scene.cam_operations[scene.cam_active_operation]
operationValid(self, context)

if ao.hide_all_others:
for _ao in scene.cam_operations:
Expand Down Expand Up @@ -350,41 +351,56 @@ class import_settings(bpy.types.PropertyGroup):
max_segment_size: FloatProperty(name="", description="Only Segments bigger then this value get subdivided",
default=0.001, min=0.0001, max=1.0, unit="LENGTH")


def operationValid(self, context):
o = self
o.changed = True
o.valid = True
invalidmsg = "Operation has no valid data input\n"
o.info.warnings = ""
o = bpy.context.scene.cam_operations[bpy.context.scene.cam_active_operation]
def isValid(o,context):
valid=True
if o.geometry_source == 'OBJECT':
if o.object_name not in bpy.data.objects:
o.valid = False
o.info.warnings = invalidmsg
valid = False
if o.geometry_source == 'COLLECTION':
if o.collection_name not in bpy.data.collections:
o.valid = False
o.info.warnings = invalidmsg
valid = False
elif len(bpy.data.collections[o.collection_name].objects) == 0:
o.valid = False
o.info.warnings = invalidmsg
valid = False

if o.geometry_source == 'IMAGE':
if o.source_image_name not in bpy.data.images:
o.valid = False
o.info.warnings = invalidmsg
valid = False
return valid

def operationValid(self, context):
scene=context.scene
o = scene.cam_operations[scene.cam_active_operation]
o.changed = True
o.valid = isValid(o,context)
invalidmsg = "Invalid source object for operation.\n"
if o.valid:
o.info.warnings = ""
else:
o.info.warnings = invalidmsg

if o.geometry_source == 'IMAGE':
o.optimisation.use_exact = False
o.update_offsetimage_tag = True
o.update_zbufferimage_tag = True
print('validity ')

def isChainValid(chain,context):
s = context.scene
if len(chain.operations)==0:
return (False,"")
for cho in chain.operations:
found_op = None
for so in s.cam_operations:
if so.name == cho.name:
found_op= so
if found_op == None:
return (False,f"Couldn't find operation {cho.name}")
if cam.isValid(found_op,context) is False:
return (False,f"Operation {found_op.name} is not valid")
return (True,"")

# print(o.valid)

def updateOperationValid(self, context):
operationValid(self, context)
updateOperation(self, context)


Expand Down Expand Up @@ -868,7 +884,7 @@ class camOperation(bpy.types.PropertyGroup):
update=updateRest)

# feeds
feedrate: FloatProperty(name="Feedrate", description="Feedrate", min=0.00005, max=50.0, default=1.0,
feedrate: FloatProperty(name="Feedrate", description="Feedrate in units per minute", min=0.00005, max=50.0, default=1.0,
precision=cam.constants.PRECISION, unit="LENGTH", update=updateChipload)
plunge_feedrate: FloatProperty(name="Plunge speed ", description="% of feedrate", min=0.1, max=100.0, default=50.0,
precision=1, subtype='PERCENTAGE', update=updateRest)
Expand Down
5 changes: 4 additions & 1 deletion scripts/addons/cam/chunk.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from shapely import geometry as sgeometry
from cam import polygon_utils_cam
from cam.simple import *
from cam.exception import CamException
import math


Expand Down Expand Up @@ -970,7 +971,6 @@ def restoreVisibility(o, storage):


def meshFromCurve(o, use_modifiers=False):
# print(o.name,o)
activate(o)
bpy.ops.object.duplicate()

Expand All @@ -980,6 +980,9 @@ def meshFromCurve(o, use_modifiers=False):

if co.type == 'FONT': # support for text objects is only and only here, just convert them to curves.
bpy.ops.object.convert(target='CURVE', keep_original=False)
elif co.type != 'CURVE': # curve must be a curve...
bpy.ops.object.delete() # delete temporary object
raise CamException("Source curve object must be of type CURVE")
co.data.dimensions = '3D'
co.data.bevel_depth = 0
co.data.extrude = 0
Expand Down
36 changes: 31 additions & 5 deletions scripts/addons/cam/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import shapely
import mathutils
import math
import textwrap
import traceback

import cam
Expand Down Expand Up @@ -194,7 +195,8 @@ async def _calc_path(operator,context):
print("Got path:",context)
except CamException as e:
traceback.print_tb(e.__traceback__)
operator.report({'ERROR'},str(e))
error_str="\n".join(textwrap.wrap(str(e),width=80))
operator.report({'ERROR'},error_str)
return {'FINISHED',False}
except AsyncCancelledException as e:
return {'CANCELLED',False}
Expand All @@ -215,9 +217,15 @@ class CalculatePath(bpy.types.Operator,AsyncOperatorMixin):
bl_idname = "object.calculate_cam_path"
bl_label = "Calculate CAM paths"
bl_options = {'REGISTER', 'UNDO','BLOCKING'}

# this property was actually ignored, so removing it in 0.3
# operation= StringProperty(name="Operation", description="Specify the operation to calculate",default='Operation')

@classmethod
def poll(cls,context):
s = context.scene
o = s.cam_operations[s.cam_active_operation]
if o is not None:
if cam.isValid(o,context):
return True
return False

async def execute_async(self, context):
(retval,success) = await _calc_path(self,context)
Expand Down Expand Up @@ -296,8 +304,14 @@ class PathsChain(bpy.types.Operator,AsyncOperatorMixin):
bl_label = "Calculate CAM paths in current chain and export chain gcode"
bl_options = {'REGISTER', 'UNDO','BLOCKING'}

@classmethod
def poll(cls, context):
s = context.scene
chain = s.cam_chains[s.cam_active_chain]
return cam.isChainValid(chain,context)[0]

async def execute_async(self, context):
s = bpy.context.scene
s = context.scene
bpy.ops.object.mode_set(mode='OBJECT') # force object mode
chain = s.cam_chains[s.cam_active_chain]
chainops = getChainOperations(chain)
Expand Down Expand Up @@ -327,6 +341,12 @@ class PathExportChain(bpy.types.Operator):
bl_label = "Export CAM paths in current chain as gcode"
bl_options = {'REGISTER', 'UNDO'}

@classmethod
def poll(cls, context):
s = context.scene
chain = s.cam_chains[s.cam_active_chain]
return cam.isChainValid(chain,context)[0]

def execute(self, context):
s = bpy.context.scene

Expand Down Expand Up @@ -400,6 +420,12 @@ class CAMSimulateChain(bpy.types.Operator, AsyncOperatorMixin):
bl_label = "CAM simulation"
bl_options = {'REGISTER', 'UNDO','BLOCKING'}

@classmethod
def poll(cls, context):
s = context.scene
chain = s.cam_chains[s.cam_active_chain]
return cam.isChainValid(chain,context)[0]

operation: StringProperty(name="Operation",
description="Specify the operation to calculate", default='Operation')

Expand Down
12 changes: 7 additions & 5 deletions scripts/addons/cam/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ async def curve(o):
pathSamples = []
utils.getOperationSources(o)
if not o.onlycurves:
o.info.warnings += 'at least one of assigned objects is not a curve\n'
raise CamException("All objects must be curves for this operation.")

for ob in o.objects:
pathSamples.extend(curveToChunks(ob)) # make the chunks from curve here
Expand Down Expand Up @@ -257,8 +257,7 @@ async def proj_curve(s, o):

from cam import chunk
if targetCurve.type != 'CURVE':
o.info.warnings += 'Projection target and source have to be curve objects!\n '
return
raise CamException('Projection target and source have to be curve objects!')

if 1:
extend_up = 0.1
Expand Down Expand Up @@ -610,8 +609,7 @@ async def medial_axis(o):
elif o.cutter_type == 'BALLNOSE':
maxdepth = - new_cutter_diameter / 2 - o.skin
else:
o.info.warnings += 'Only Ballnose, V-carve cutters\n are supported'
return
raise CamException("Only Ballnose and V-carve cutters are supported for meial axis.")
# remember resolutions of curves, to refine them,
# otherwise medial axis computation yields too many branches in curved parts
resolutions_before = []
Expand Down Expand Up @@ -771,6 +769,10 @@ def getLayers(operation, startdepth, enddepth):
"""returns a list of layers bounded by startdepth and enddepth
uses operation.stepdown to determine number of layers.
"""
if startdepth < enddepth:
raise CamException("Start depth is lower than end depth. "
"If you have set a custom depth end, it must be lower than depth start, "
"and should usually be negative. Set this in the CAM Operation Area panel.")
if operation.use_layers:
layers = []
n = math.ceil((startdepth - enddepth) / operation.stepdown)
Expand Down
18 changes: 11 additions & 7 deletions scripts/addons/cam/ui_panels/chains.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from bpy.types import UIList
from cam.ui_panels.buttons_panel import CAMButtonsPanel

import cam


class CAM_UL_operations(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
Expand Down Expand Up @@ -37,6 +39,7 @@ class CAM_CHAINS_Panel(CAMButtonsPanel, bpy.types.Panel):
bl_label = "CAM chains"
bl_idname = "WORLD_PT_CAM_CHAINS"
panel_interface_level = 1
always_show_panel = True

def draw(self, context):
layout = self.layout
Expand All @@ -63,13 +66,14 @@ def draw(self, context):
col.operator("scene.cam_chain_operation_down", icon='TRIA_DOWN', text="")

if not chain.computing:
if chain.valid:
pass
layout.operator("object.calculate_cam_paths_chain", text="Calculate chain paths & Export Gcode")
layout.operator("object.cam_export_paths_chain", text="Export chain gcode")
layout.operator("object.cam_simulate_chain", text="Simulate this chain")
else:
layout.label(text="chain invalid, can't compute")
layout.operator("object.calculate_cam_paths_chain", text="Calculate chain paths & Export Gcode")
layout.operator("object.cam_export_paths_chain", text="Export chain gcode")
layout.operator("object.cam_simulate_chain", text="Simulate this chain")

valid,reason=cam.isChainValid(chain,context)
if not valid:
layout.label(icon="ERROR",text=f"Can't compute chain - reason:\n")
layout.label(text=reason)
else:
layout.label(text='chain is currently computing')

Expand Down
8 changes: 5 additions & 3 deletions scripts/addons/cam/ui_panels/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class CAM_INFO_Panel(CAMButtonsPanel, bpy.types.Panel):
bl_label = "CAM info & warnings"
bl_idname = "WORLD_PT_CAM_INFO"
panel_interface_level = 0
always_show_panel = True

prop_level = {
'draw_blendercam_version': 0,
Expand Down Expand Up @@ -115,6 +116,7 @@ def draw(self, context):
self.context = context
self.draw_blendercam_version()
self.draw_opencamlib_version()
self.draw_op_warnings()
self.draw_op_time()
self.draw_op_money_cost()
if self.op:
self.draw_op_warnings()
self.draw_op_time()
self.draw_op_money_cost()
8 changes: 4 additions & 4 deletions scripts/addons/cam/ui_panels/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ def draw_calculate_path(self):
self.layout.label(text='!ERROR! COLLISION!')
self.layout.prop(self.op.movement, 'free_height')

if self.op.valid:
self.layout.operator("object.calculate_cam_path", text="Calculate path & export Gcode")
else:
self.layout.label(text="operation invalid, can't compute")
if not self.op.valid:
self.layout.label(text="Select a valid object to calculate the path.")
# will be disable if not valid
self.layout.operator("object.calculate_cam_path", text="Calculate path & export Gcode")

def draw_export_gcode(self):
if not self.has_correct_level(): return
Expand Down
2 changes: 2 additions & 0 deletions scripts/addons/cam/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ def getBounds(o):
o.max.z = o.source_image_offset.z
s = bpy.context.scene
m = s.cam_machine
# make sure this message only shows once and goes away once fixed
o.info.warnings.replace('Operation exceeds your machine limits\n','')
if o.max.x - o.min.x > m.working_area.x or o.max.y - o.min.y > m.working_area.y \
or o.max.z - o.min.z > m.working_area.z:
o.info.warnings += 'Operation exceeds your machine limits\n'
Expand Down

0 comments on commit 737870b

Please sign in to comment.