kopia lustrzana https://github.com/vilemduha/blendercam
Porównaj commity
37 Commity
79fcd0b920
...
99ae721762
Autor | SHA1 | Data |
---|---|---|
Alain Pelletier | 99ae721762 | |
Alain Pelletier | 502a3bdf8c | |
migo101 | 77b838ddd8 | |
migo101 | 40a4d2b7ba | |
migo101 | ff4a39666e | |
migo101 | f423a5ce0f | |
migo1001 | 415df8eb74 | |
Alain Pelletier | ac5a16c2b4 | |
abosafia | 1438d529ae | |
Alain Pelletier | c85e156efd | |
abosafia | 0270f2195e | |
migo101 | f248e23f72 | |
Alain Pelletier | 4c71b8a224 | |
Alain Pelletier | 10816b3fc7 | |
migo101 | d986c210a5 | |
migo1001 | fb3740fac7 | |
migo101 | 9781d0888a | |
Alain Pelletier | 1c65e51481 | |
abosafia | ab06a37387 | |
Alain Pelletier | 5ef337dc12 | |
migo101 | 27b4ec6e43 | |
migo101 | 5998fffb5a | |
migo101 | 46b3c9e6e8 | |
migo101 | 272dbc6109 | |
Alain Pelletier | 84856fdc11 | |
Alain Pelletier | f7c270e843 | |
abosafia | ac653a84c3 | |
migo101 | 89c123d572 | |
migo1001 | fdc6a7f8ea | |
migo101 | 5cbb538fc2 | |
migo101 | ec9c66a174 | |
Alain Pelletier | 85766a0e26 | |
Alain Pelletier | af77b220ea | |
migo101 | b18e0fdd3c | |
migo101 | 0a1c4326f5 | |
migo101 | fb2c2f227a | |
Stephen Rakonza | 3f365bc4d9 |
|
@ -49,7 +49,7 @@ from cam import ui, ops, curvecamtools, curvecamequation, curvecamcreate, utils,
|
|||
from mathutils import *
|
||||
from shapely import geometry as sgeometry
|
||||
|
||||
|
||||
from cam.ui import *
|
||||
|
||||
bl_info = {
|
||||
"name": "CAM - gcode generation tools",
|
||||
|
@ -63,7 +63,7 @@ bl_info = {
|
|||
"tracker_url": "",
|
||||
"category": "Scene"}
|
||||
|
||||
PRECISION = 5
|
||||
import cam.constants
|
||||
|
||||
was_hidden_dict = {}
|
||||
|
||||
|
@ -163,20 +163,20 @@ class machineSettings(bpy.types.PropertyGroup):
|
|||
"toolchange, ending position",
|
||||
default=False)
|
||||
starting_position: bpy.props.FloatVectorProperty(name='Start position', default=(0, 0, 0), unit='LENGTH',
|
||||
precision=PRECISION, subtype="XYZ", update=updateMachine)
|
||||
precision=cam.constants.PRECISION, subtype="XYZ", update=updateMachine)
|
||||
mtc_position: bpy.props.FloatVectorProperty(name='MTC position', default=(0, 0, 0), unit='LENGTH',
|
||||
precision=PRECISION, subtype="XYZ", update=updateMachine)
|
||||
precision=cam.constants.PRECISION, subtype="XYZ", update=updateMachine)
|
||||
ending_position: bpy.props.FloatVectorProperty(name='End position', default=(0, 0, 0), unit='LENGTH',
|
||||
precision=PRECISION, subtype="XYZ", update=updateMachine)
|
||||
precision=cam.constants.PRECISION, subtype="XYZ", update=updateMachine)
|
||||
|
||||
working_area: bpy.props.FloatVectorProperty(name='Work Area', default=(0.500, 0.500, 0.100), unit='LENGTH',
|
||||
precision=PRECISION, subtype="XYZ", update=updateMachine)
|
||||
precision=cam.constants.PRECISION, subtype="XYZ", update=updateMachine)
|
||||
feedrate_min: bpy.props.FloatProperty(name="Feedrate minimum /min", default=0.0, min=0.00001, max=320000,
|
||||
precision=PRECISION, unit='LENGTH')
|
||||
precision=cam.constants.PRECISION, unit='LENGTH')
|
||||
feedrate_max: bpy.props.FloatProperty(name="Feedrate maximum /min", default=2, min=0.00001, max=320000,
|
||||
precision=PRECISION, unit='LENGTH')
|
||||
precision=cam.constants.PRECISION, unit='LENGTH')
|
||||
feedrate_default: bpy.props.FloatProperty(name="Feedrate default /min", default=1.5, min=0.00001, max=320000,
|
||||
precision=PRECISION, unit='LENGTH')
|
||||
precision=cam.constants.PRECISION, unit='LENGTH')
|
||||
hourly_rate: bpy.props.FloatProperty(name="Price per hour", default=100, min=0.005, precision=2)
|
||||
|
||||
# UNSUPPORTED:
|
||||
|
@ -211,7 +211,7 @@ class machineSettings(bpy.types.PropertyGroup):
|
|||
# default='X', update = updateOffsetImage)
|
||||
|
||||
collet_size: bpy.props.FloatProperty(name="#Collet size", description="Collet size for collision detection",
|
||||
default=33, min=0.00001, max=320000, precision=PRECISION, unit="LENGTH")
|
||||
default=33, min=0.00001, max=320000, precision=cam.constants.PRECISION, unit="LENGTH")
|
||||
# exporter_start = bpy.props.StringProperty(name="exporter start", default="%")
|
||||
|
||||
# post processor options
|
||||
|
@ -244,15 +244,15 @@ class PackObjectsSettings(bpy.types.PropertyGroup):
|
|||
description='Fill direction of the packer algorithm',
|
||||
default='Y')
|
||||
sheet_x: FloatProperty(name="X size", description="Sheet size", min=0.001, max=10, default=0.5,
|
||||
precision=PRECISION, unit="LENGTH")
|
||||
precision=cam.constants.PRECISION, unit="LENGTH")
|
||||
sheet_y: FloatProperty(name="Y size", description="Sheet size", min=0.001, max=10, default=0.5,
|
||||
precision=PRECISION, unit="LENGTH")
|
||||
precision=cam.constants.PRECISION, unit="LENGTH")
|
||||
distance: FloatProperty(name="Minimum distance",
|
||||
description="minimum distance between objects(should be at least cutter diameter!)",
|
||||
min=0.001, max=10, default=0.01, precision=PRECISION, unit="LENGTH")
|
||||
min=0.001, max=10, default=0.01, precision=cam.constants.PRECISION, unit="LENGTH")
|
||||
tolerance: FloatProperty(name="Placement Tolerance",
|
||||
description="Tolerance for placement: smaller value slower placemant",
|
||||
min=0.001, max=0.02, default=0.005, precision=PRECISION, unit="LENGTH")
|
||||
min=0.001, max=0.02, default=0.005, precision=cam.constants.PRECISION, unit="LENGTH")
|
||||
rotate: bpy.props.BoolProperty(name="enable rotation", description="Enable rotation of elements", default=True)
|
||||
rotate_angle: FloatProperty(name="Placement Angle rotation step",
|
||||
description="bigger rotation angle,faster placemant", default=0.19635 * 4,
|
||||
|
@ -265,7 +265,7 @@ class SliceObjectsSettings(bpy.types.PropertyGroup):
|
|||
"""stores all data for machines"""
|
||||
slice_distance: FloatProperty(name="Slicing distance",
|
||||
description="slices distance in z, should be most often thickness of plywood sheet.",
|
||||
min=0.001, max=10, default=0.005, precision=PRECISION, unit="LENGTH")
|
||||
min=0.001, max=10, default=0.005, precision=cam.constants.PRECISION, unit="LENGTH")
|
||||
slice_above0: bpy.props.BoolProperty(name="Slice above 0", description="only slice model above 0", default=False)
|
||||
slice_3d: bpy.props.BoolProperty(name="3d slice", description="for 3d carving", default=False)
|
||||
indexes: bpy.props.BoolProperty(name="add indexes", description="adds index text of layer + index", default=True)
|
||||
|
@ -288,26 +288,26 @@ def operationValid(self, context):
|
|||
o.changed = True
|
||||
o.valid = True
|
||||
invalidmsg = "Operation has no valid data input\n"
|
||||
o.warnings = ""
|
||||
o.info.warnings = ""
|
||||
o = bpy.context.scene.cam_operations[bpy.context.scene.cam_active_operation]
|
||||
if o.geometry_source == 'OBJECT':
|
||||
if o.object_name not in bpy.data.objects:
|
||||
o.valid = False
|
||||
o.warnings = invalidmsg
|
||||
o.info.warnings = invalidmsg
|
||||
if o.geometry_source == 'COLLECTION':
|
||||
if o.collection_name not in bpy.data.collections:
|
||||
o.valid = False
|
||||
o.warnings = invalidmsg
|
||||
o.info.warnings = invalidmsg
|
||||
elif len(bpy.data.collections[o.collection_name].objects) == 0:
|
||||
o.valid = False
|
||||
o.warnings = invalidmsg
|
||||
o.info.warnings = invalidmsg
|
||||
|
||||
if o.geometry_source == 'IMAGE':
|
||||
if o.source_image_name not in bpy.data.images:
|
||||
o.valid = False
|
||||
o.warnings = invalidmsg
|
||||
o.info.warnings = invalidmsg
|
||||
|
||||
o.use_exact = False
|
||||
o.optimisation.use_exact = False
|
||||
o.update_offsetimage_tag = True
|
||||
o.update_zbufferimage_tag = True
|
||||
print('validity ')
|
||||
|
@ -326,7 +326,7 @@ def updateChipload(self, context):
|
|||
print('update chipload ')
|
||||
o = self
|
||||
# Old chipload
|
||||
o.chipload = (o.feedrate / (o.spindle_rpm * o.cutter_flutes))
|
||||
o.info.chipload = (o.feedrate / (o.spindle_rpm * o.cutter_flutes))
|
||||
# New chipload with chip thining compensation.
|
||||
# I have tried to combine these 2 formulas to compinsate for the phenomenon of chip thinning when cutting at less
|
||||
# than 50% cutter engagement with cylindrical end mills. formula 1 Nominal Chipload is
|
||||
|
@ -340,7 +340,7 @@ def updateChipload(self, context):
|
|||
# we will be one tiny step on the way to a slightly better chipload calculating function.
|
||||
|
||||
# self.chipload = ((0.5*(o.cutter_diameter/o.dist_between_paths))/(math.sqrt((o.feedrate*1000)/(o.spindle_rpm*o.cutter_diameter*o.cutter_flutes)*(o.cutter_diameter/o.dist_between_paths)-1)))
|
||||
print(o.chipload)
|
||||
print(o.info.chipload)
|
||||
|
||||
|
||||
def updateOffsetImage(self, context):
|
||||
|
@ -376,28 +376,27 @@ def updateStrategy(o, context):
|
|||
def updateCutout(o, context):
|
||||
pass
|
||||
|
||||
|
||||
def updateExact(o, context):
|
||||
print('update exact ')
|
||||
o.changed = True
|
||||
o.update_zbufferimage_tag = True
|
||||
o.update_offsetimage_tag = True
|
||||
if o.use_exact and (
|
||||
o.strategy == 'POCKET' or o.strategy == 'MEDIAL_AXIS' or o.inverse):
|
||||
# o.use_exact = False
|
||||
o.use_opencamlib = False
|
||||
print(' pocket cannot use opencamlib')
|
||||
if o.optimisation.use_exact:
|
||||
if o.strategy == 'POCKET' or o.strategy == 'MEDIAL_AXIS' or o.inverse:
|
||||
o.optimisation.use_opencamlib = False
|
||||
print('Current operation cannot use exact mode')
|
||||
else:
|
||||
o.optimisation.use_opencamlib = False
|
||||
|
||||
|
||||
def updateOpencamlib(o, context):
|
||||
print('update opencamlib ')
|
||||
o.changed = True
|
||||
if o.use_opencamlib and (
|
||||
if o.optimisation.use_opencamlib and (
|
||||
o.strategy == 'POCKET' or o.strategy == 'MEDIAL_AXIS'):
|
||||
o.use_exact = False
|
||||
o.use_opencamlib = False
|
||||
print('pocket cannot use opencamlib')
|
||||
|
||||
o.optimisation.use_exact = False
|
||||
o.optimisation.use_opencamlib = False
|
||||
print('Current operation cannot use opencamlib')
|
||||
|
||||
def updateBridges(o, context):
|
||||
print('update bridges ')
|
||||
|
@ -466,6 +465,12 @@ def getStrategyList(scene, context):
|
|||
|
||||
|
||||
class camOperation(bpy.types.PropertyGroup):
|
||||
|
||||
material: bpy.props.PointerProperty(type=CAM_MATERIAL_Properties)
|
||||
info: bpy.props.PointerProperty(type=CAM_INFO_Properties)
|
||||
optimisation: bpy.props.PointerProperty(type=CAM_OPTIMISATION_Properties)
|
||||
|
||||
|
||||
name: bpy.props.StringProperty(name="Operation Name", default="Operation", update=updateRest)
|
||||
filename: bpy.props.StringProperty(name="File name", default="Operation", update=updateRest)
|
||||
auto_export: bpy.props.BoolProperty(name="Auto export",
|
||||
|
@ -586,7 +591,7 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
update=updateStrategy)
|
||||
|
||||
skin: FloatProperty(name="Skin", description="Material to leave when roughing ", min=0.0, max=1.0, default=0.0,
|
||||
precision=PRECISION, unit="LENGTH", update=updateOffsetImage)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateOffsetImage)
|
||||
inverse: bpy.props.BoolProperty(name="Inverse milling", description="Male to female model conversion",
|
||||
default=False, update=updateOffsetImage)
|
||||
array: bpy.props.BoolProperty(name="Use array",
|
||||
|
@ -597,9 +602,9 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
array_y_count: bpy.props.IntProperty(name="Y count", description="Y count", default=1, min=1, max=32000,
|
||||
update=updateRest)
|
||||
array_x_distance: FloatProperty(name="X distance", description="distance between operation origins", min=0.00001,
|
||||
max=1.0, default=0.01, precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
max=1.0, default=0.01, precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
array_y_distance: FloatProperty(name="Y distance", description="distance between operation origins", min=0.00001,
|
||||
max=1.0, default=0.01, precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
max=1.0, default=0.01, precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
|
||||
# pocket options
|
||||
pocket_option: EnumProperty(name='Start Position', items=(
|
||||
|
@ -621,23 +626,23 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
cutter_id: IntProperty(name="Tool number", description="For machines which support tool change based on tool id",
|
||||
min=0, max=10000, default=1, update=updateRest)
|
||||
cutter_diameter: FloatProperty(name="Cutter diameter", description="Cutter diameter = 2x cutter radius",
|
||||
min=0.000001, max=10, default=0.003, precision=PRECISION, unit="LENGTH",
|
||||
min=0.000001, max=10, default=0.003, precision=cam.constants.PRECISION, unit="LENGTH",
|
||||
update=updateOffsetImage)
|
||||
cylcone_diameter: FloatProperty(name="Bottom Diameter", description="Bottom diameter",
|
||||
min=0.000001, max=10, default=0.003, precision=PRECISION, unit="LENGTH",
|
||||
min=0.000001, max=10, default=0.003, precision=cam.constants.PRECISION, unit="LENGTH",
|
||||
update=updateOffsetImage)
|
||||
cutter_length: FloatProperty(name="#Cutter length", description="#not supported#Cutter length", min=0.0, max=100.0,
|
||||
default=25.0, precision=PRECISION, unit="LENGTH", update=updateOffsetImage)
|
||||
default=25.0, precision=cam.constants.PRECISION, unit="LENGTH", update=updateOffsetImage)
|
||||
cutter_flutes: IntProperty(name="Cutter flutes", description="Cutter flutes", min=1, max=20, default=2,
|
||||
update=updateChipload)
|
||||
cutter_tip_angle: FloatProperty(name="Cutter v-carve angle", description="Cutter v-carve angle", min=0.0,
|
||||
max=180.0, default=60.0, precision=PRECISION, update=updateOffsetImage)
|
||||
max=180.0, default=60.0, precision=cam.constants.PRECISION, update=updateOffsetImage)
|
||||
ball_radius: FloatProperty(name="Ball radius", description="Radius of", min=0.0,
|
||||
max=0.035, default=0.001, unit="LENGTH", precision=PRECISION, update=updateOffsetImage)
|
||||
max=0.035, default=0.001, unit="LENGTH", precision=cam.constants.PRECISION, update=updateOffsetImage)
|
||||
# ball_cone_flute: FloatProperty(name="BallCone Flute Length", description="length of flute", min=0.0,
|
||||
# max=0.1, default=0.017, unit="LENGTH", precision=PRECISION, update=updateOffsetImage)
|
||||
# max=0.1, default=0.017, unit="LENGTH", precision=cam.constants.PRECISION, update=updateOffsetImage)
|
||||
bull_corner_radius: FloatProperty(name="Bull Corner Radius", description="Radius tool bit corner", min=0.0,
|
||||
max=0.035, default=0.005, unit="LENGTH", precision=PRECISION,
|
||||
max=0.035, default=0.005, unit="LENGTH", precision=cam.constants.PRECISION,
|
||||
update=updateOffsetImage)
|
||||
|
||||
cutter_description: StringProperty(name="Tool Description", default="", update=updateOffsetImage)
|
||||
|
@ -658,9 +663,9 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
|
||||
# steps
|
||||
dist_between_paths: bpy.props.FloatProperty(name="Distance between toolpaths", default=0.001, min=0.00001, max=32,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
dist_along_paths: bpy.props.FloatProperty(name="Distance along toolpaths", default=0.0002, min=0.00001, max=32,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
parallel_angle: bpy.props.FloatProperty(name="Angle of paths", default=0, min=-360, max=360, precision=0,
|
||||
subtype="ANGLE", unit="ROTATION", update=updateRest)
|
||||
old_rotation_A: bpy.props.FloatProperty(name="A axis angle",
|
||||
|
@ -687,7 +692,7 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
update=updateRest)
|
||||
|
||||
# carve only
|
||||
carve_depth: bpy.props.FloatProperty(name="Carve depth", default=0.001, min=-.100, max=32, precision=PRECISION,
|
||||
carve_depth: bpy.props.FloatProperty(name="Carve depth", default=0.001, min=-.100, max=32, precision=cam.constants.PRECISION,
|
||||
unit="LENGTH", update=updateRest)
|
||||
|
||||
# drill only
|
||||
|
@ -697,7 +702,7 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
default='MIDDLE_SYMETRIC', update=updateRest)
|
||||
# waterline only
|
||||
slice_detail: bpy.props.FloatProperty(name="Distance betwen slices", default=0.001, min=0.00001, max=32,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
waterline_fill: bpy.props.BoolProperty(name="Fill areas between slices",
|
||||
description="Fill areas between slices in waterline mode", default=True,
|
||||
update=updateRest)
|
||||
|
@ -708,7 +713,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="", description="Layer height", 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=cam.constants.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",
|
||||
|
@ -727,10 +732,10 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
default=False, update=updateRest)
|
||||
lead_in: bpy.props.FloatProperty(name="Lead in radius",
|
||||
description="Lead out radius for torch or laser to turn off",
|
||||
min=0.00, max=1, default=0.0, precision=PRECISION, unit="LENGTH")
|
||||
min=0.00, max=1, default=0.0, precision=cam.constants.PRECISION, unit="LENGTH")
|
||||
lead_out: bpy.props.FloatProperty(name="Lead out radius",
|
||||
description="Lead out radius for torch or laser to turn off",
|
||||
min=0.00, max=1, default=0.0, precision=PRECISION, unit="LENGTH")
|
||||
min=0.00, max=1, default=0.0, precision=cam.constants.PRECISION, unit="LENGTH")
|
||||
profile_start: bpy.props.IntProperty(name="Start point", description="Start point offset", min=0, default=0,
|
||||
update=updateRest)
|
||||
|
||||
|
@ -741,16 +746,16 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
description="Retract from material in circular motion", default=False,
|
||||
update=updateRest)
|
||||
retract_radius: bpy.props.FloatProperty(name='Retract arc radius', default=0.001, min=0.000001, max=100,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
retract_height: bpy.props.FloatProperty(name='Retract arc height', default=0.001, min=0.00000, max=100,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
|
||||
minz_from_ob: bpy.props.BoolProperty(name="Depth from object", description="Operation ending depth from object",
|
||||
default=True, update=updateRest)
|
||||
minz_from_material: bpy.props.BoolProperty(name="Depth from material",
|
||||
description="Operation ending depth from material",
|
||||
default=False, update=updateRest)
|
||||
minz: bpy.props.FloatProperty(name="Operation depth end", default=-0.01, min=-3, max=3, precision=PRECISION,
|
||||
minz: bpy.props.FloatProperty(name="Operation depth end", default=-0.01, min=-3, max=3, precision=cam.constants.PRECISION,
|
||||
unit="LENGTH",
|
||||
update=updateRest) # this is input minz. True minimum z can be something else, depending on material e.t.c.
|
||||
start_type: bpy.props.EnumProperty(name='Start type',
|
||||
|
@ -764,7 +769,7 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
update=updateStrategy)
|
||||
|
||||
maxz: bpy.props.FloatProperty(name="Operation depth start", description='operation starting depth', default=0,
|
||||
min=-3, max=10, precision=PRECISION, unit="LENGTH",
|
||||
min=-3, max=10, precision=cam.constants.PRECISION, unit="LENGTH",
|
||||
update=updateRest) # EXPERIMENTAL
|
||||
|
||||
#######################################################
|
||||
|
@ -772,25 +777,25 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
####################################################
|
||||
|
||||
source_image_scale_z: bpy.props.FloatProperty(name="Image source depth scale", default=0.01, min=-1, max=1,
|
||||
precision=PRECISION, unit="LENGTH", update=updateZbufferImage)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateZbufferImage)
|
||||
source_image_size_x: bpy.props.FloatProperty(name="Image source x size", default=0.1, min=-10, max=10,
|
||||
precision=PRECISION, unit="LENGTH", update=updateZbufferImage)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateZbufferImage)
|
||||
source_image_offset: bpy.props.FloatVectorProperty(name='Image offset', default=(0, 0, 0), unit='LENGTH',
|
||||
precision=PRECISION, subtype="XYZ", update=updateZbufferImage)
|
||||
precision=cam.constants.PRECISION, subtype="XYZ", update=updateZbufferImage)
|
||||
source_image_crop: bpy.props.BoolProperty(name="Crop source image",
|
||||
description="Crop source image - the position of the sub-rectangle is relative to the whole image, so it can be used for e.g. finishing just a part of an image",
|
||||
default=False, update=updateZbufferImage)
|
||||
source_image_crop_start_x: bpy.props.FloatProperty(name='crop start x', default=0, min=0, max=100,
|
||||
precision=PRECISION, subtype='PERCENTAGE',
|
||||
precision=cam.constants.PRECISION, subtype='PERCENTAGE',
|
||||
update=updateZbufferImage)
|
||||
source_image_crop_start_y: bpy.props.FloatProperty(name='crop start y', default=0, min=0, max=100,
|
||||
precision=PRECISION, subtype='PERCENTAGE',
|
||||
precision=cam.constants.PRECISION, subtype='PERCENTAGE',
|
||||
update=updateZbufferImage)
|
||||
source_image_crop_end_x: bpy.props.FloatProperty(name='crop end x', default=100, min=0, max=100,
|
||||
precision=PRECISION, subtype='PERCENTAGE',
|
||||
precision=cam.constants.PRECISION, subtype='PERCENTAGE',
|
||||
update=updateZbufferImage)
|
||||
source_image_crop_end_y: bpy.props.FloatProperty(name='crop end y', default=100, min=0, max=100,
|
||||
precision=PRECISION, subtype='PERCENTAGE',
|
||||
precision=cam.constants.PRECISION, subtype='PERCENTAGE',
|
||||
update=updateZbufferImage)
|
||||
|
||||
#########################################################
|
||||
|
@ -810,7 +815,7 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
|
||||
ambient_radius: FloatProperty(name="Ambient radius",
|
||||
description="Radius around the part which will be milled if ambient is set to Around",
|
||||
min=0.0, max=100.0, default=0.01, precision=PRECISION, unit="LENGTH",
|
||||
min=0.0, max=100.0, default=0.01, precision=cam.constants.PRECISION, unit="LENGTH",
|
||||
update=updateRest)
|
||||
# ambient_cutter = EnumProperty(name='Borders',items=(('EXTRAFORCUTTER', 'Extra for cutter', "Extra space for cutter is cut around the segment"),('ONBORDER', "Cutter on edge", "Cutter goes exactly on edge of ambient with it's middle") ,('INSIDE', "Inside segment", 'Cutter stays within segment') ),description='handling of ambient and cutter size',default='INSIDE')
|
||||
use_limit_curve: bpy.props.BoolProperty(name="Use limit curve", description="A curve limits the operation area",
|
||||
|
@ -825,7 +830,7 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
|
||||
# feeds
|
||||
feedrate: FloatProperty(name="Feedrate", description="Feedrate", min=0.00005, max=50.0, default=1.0,
|
||||
precision=PRECISION, unit="LENGTH", update=updateChipload)
|
||||
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)
|
||||
plunge_angle: bpy.props.FloatProperty(name="Plunge angle",
|
||||
|
@ -844,13 +849,13 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
items=(('CW', 'Clock wise', 'a'), ('CCW', 'Counter clock wise', 'a')),
|
||||
description='Spindle rotation direction', default='CW', update=updateRest)
|
||||
free_movement_height: bpy.props.FloatProperty(name="Free movement height", default=0.01, min=0.0000, max=32,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
useG64: bpy.props.BoolProperty(name="G64 trajectory",
|
||||
description='Use only if your machie supports G64 code. LinuxCNC and Mach3 do',
|
||||
default=False, update=updateRest)
|
||||
G64: bpy.props.FloatProperty(name="Path Control Mode with Optional Tolerance", default=0.0001, min=0.0000,
|
||||
max=0.005,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
movement_insideout: EnumProperty(name='Direction',
|
||||
items=(('INSIDEOUT', 'Inside out', 'a'), ('OUTSIDEIN', 'Outside in', 'a')),
|
||||
description='approach to the piece', default='INSIDEOUT', update=updateRest)
|
||||
|
@ -859,51 +864,29 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
default=False, update=updateRest)
|
||||
stay_low: bpy.props.BoolProperty(name="Stay low if possible", default=True, update=updateRest)
|
||||
merge_dist: bpy.props.FloatProperty(name="Merge distance - EXPERIMENTAL", default=0.0, min=0.0000, max=0.1,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
# optimization and performance
|
||||
circle_detail: bpy.props.IntProperty(name="Detail of circles used for curve offsets", default=64, min=12, max=512,
|
||||
update=updateRest)
|
||||
use_exact: bpy.props.BoolProperty(name="Use exact mode",
|
||||
description="Exact mode allows greater precision, but is slower with complex meshes",
|
||||
default=True, update=updateExact)
|
||||
exact_subdivide_edges: bpy.props.BoolProperty(name="Auto subdivide long edges",
|
||||
description="This can avoid some collision issues when importing CAD models",
|
||||
default=False, update=updateExact)
|
||||
use_opencamlib: bpy.props.BoolProperty(name="Use OpenCAMLib",
|
||||
description="Use OpenCAMLib to sample paths or get waterline shape",
|
||||
default=False, update=updateOpencamlib)
|
||||
pixsize: bpy.props.FloatProperty(name="sampling raster detail", default=0.0001, min=0.00001, max=0.1,
|
||||
precision=PRECISION, unit="LENGTH", update=updateZbufferImage)
|
||||
simulation_detail: bpy.props.FloatProperty(name="Simulation sampling raster detail", default=0.0002, min=0.00001,
|
||||
max=0.01, precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
|
||||
do_simulation_feedrate: bpy.props.BoolProperty(name="Adjust feedrates with simulation EXPERIMENTAL",
|
||||
description="Adjust feedrates with simulation", default=False,
|
||||
update=updateRest)
|
||||
|
||||
imgres_limit: bpy.props.IntProperty(name="Maximum resolution in megapixels", default=16, min=1, max=512,
|
||||
description="This property limits total memory usage and prevents crashes. Increase it if you know what are doing.",
|
||||
update=updateZbufferImage)
|
||||
optimize: bpy.props.BoolProperty(name="Reduce path points", description="Reduce path points", default=True,
|
||||
update=updateRest)
|
||||
optimize_threshold: bpy.props.FloatProperty(name="Reduction threshold in μm", default=.2, min=0.000000001,
|
||||
max=1000, precision=20, update=updateRest)
|
||||
|
||||
dont_merge: bpy.props.BoolProperty(name="Dont merge outlines when cutting",
|
||||
description="this is usefull when you want to cut around everything",
|
||||
default=False, update=updateRest)
|
||||
|
||||
pencil_threshold: bpy.props.FloatProperty(name="Pencil threshold", default=0.00002, min=0.00000001, max=1,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
crazy_threshold1: bpy.props.FloatProperty(name="min engagement", default=0.02, min=0.00000001, max=100,
|
||||
precision=PRECISION, update=updateRest)
|
||||
precision=cam.constants.PRECISION, update=updateRest)
|
||||
crazy_threshold5: bpy.props.FloatProperty(name="optimal engagement", default=0.3, min=0.00000001, max=100,
|
||||
precision=PRECISION, update=updateRest)
|
||||
precision=cam.constants.PRECISION, update=updateRest)
|
||||
crazy_threshold2: bpy.props.FloatProperty(name="max engagement", default=0.5, min=0.00000001, max=100,
|
||||
precision=PRECISION, update=updateRest)
|
||||
precision=cam.constants.PRECISION, update=updateRest)
|
||||
crazy_threshold3: bpy.props.FloatProperty(name="max angle", default=2, min=0.00000001, max=100,
|
||||
precision=PRECISION, update=updateRest)
|
||||
precision=cam.constants.PRECISION, update=updateRest)
|
||||
crazy_threshold4: bpy.props.FloatProperty(name="test angle step", default=0.05, min=0.00000001, max=100,
|
||||
precision=PRECISION, update=updateRest)
|
||||
precision=cam.constants.PRECISION, update=updateRest)
|
||||
# Add pocket operation to medial axis
|
||||
add_pocket_for_medial: bpy.props.BoolProperty(name="Add pocket operation",
|
||||
description="clean unremoved material after medial axis",
|
||||
|
@ -916,21 +899,19 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
update=updateRest)
|
||||
####
|
||||
medial_axis_threshold: bpy.props.FloatProperty(name="Long vector threshold", default=0.001, min=0.00000001,
|
||||
max=100, precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
max=100, precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
medial_axis_subdivision: bpy.props.FloatProperty(name="Fine subdivision", default=0.0002, min=0.00000001, max=100,
|
||||
precision=PRECISION, unit="LENGTH", update=updateRest)
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=updateRest)
|
||||
# calculations
|
||||
duration: bpy.props.FloatProperty(name="Estimated time", default=0.01, min=0.0000, max=3200000000,
|
||||
precision=PRECISION, unit="TIME")
|
||||
# chip_rate
|
||||
|
||||
# bridges
|
||||
use_bridges: bpy.props.BoolProperty(name="Use bridges", description="use bridges in cutout", default=False,
|
||||
update=updateBridges)
|
||||
bridges_width: bpy.props.FloatProperty(name='width of bridges', default=0.002, unit='LENGTH', precision=PRECISION,
|
||||
bridges_width: bpy.props.FloatProperty(name='width of bridges', default=0.002, unit='LENGTH', precision=cam.constants.PRECISION,
|
||||
update=updateBridges)
|
||||
bridges_height: bpy.props.FloatProperty(name='height of bridges',
|
||||
description="Height from the bottom of the cutting operation",
|
||||
default=0.0005, unit='LENGTH', precision=PRECISION, update=updateBridges)
|
||||
default=0.0005, unit='LENGTH', precision=cam.constants.PRECISION, update=updateBridges)
|
||||
bridges_collection_name: bpy.props.StringProperty(name='Bridges Collection',
|
||||
description='Collection of curves used as bridges',
|
||||
update=operationValid)
|
||||
|
@ -949,7 +930,7 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
# update = updateStrategy)
|
||||
#
|
||||
# bridges_per_curve = bpy.props.IntProperty(name="minimum bridges per curve", description="", default=4, min=1, max=512, update = updateBridges)
|
||||
# bridges_max_distance = bpy.props.FloatProperty(name = 'Maximum distance between bridges', default=0.08, unit='LENGTH', precision=PRECISION, update = updateBridges)
|
||||
# bridges_max_distance = bpy.props.FloatProperty(name = 'Maximum distance between bridges', default=0.08, unit='LENGTH', precision=cam.constants.PRECISION, update = updateBridges)
|
||||
|
||||
use_modifiers: BoolProperty(name="use mesh modifiers",
|
||||
description="include mesh modifiers using render level when calculating operation, does not effect original mesh",
|
||||
|
@ -957,34 +938,21 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
# optimisation panel
|
||||
|
||||
# material settings
|
||||
material_from_model: bpy.props.BoolProperty(name="Estimate from model",
|
||||
description="Estimate material size from model", default=True,
|
||||
update=updateMaterial)
|
||||
material_radius_around_model: bpy.props.FloatProperty(name="radius around model",
|
||||
description="How much to add to model size on all sides",
|
||||
default=0.0, unit='LENGTH', precision=PRECISION,
|
||||
update=updateMaterial)
|
||||
material_center_x: bpy.props.BoolProperty(name="Center with X axis", description="Position model centered on X",
|
||||
default=False, update=updateMaterial)
|
||||
material_center_y: bpy.props.BoolProperty(name="Center with Y axis", description="Position model centered on Y",
|
||||
default=False, update=updateMaterial)
|
||||
|
||||
material_Z: bpy.props.EnumProperty(name="Z placement", items=(
|
||||
('ABOVE', 'Above', 'Place objec above 0'), ('BELOW', 'Below', 'Place object below 0'),
|
||||
('CENTERED', 'Centered', 'Place object centered on 0')), description="Position below Zero", default='BELOW',
|
||||
update=updateMaterial)
|
||||
|
||||
material_origin: bpy.props.FloatVectorProperty(name='Material origin', default=(0, 0, 0), unit='LENGTH',
|
||||
precision=PRECISION, subtype="XYZ", update=updateMaterial)
|
||||
material_size: bpy.props.FloatVectorProperty(name='Material size', default=(0.200, 0.200, 0.100), min=0, unit='LENGTH',
|
||||
precision=PRECISION, subtype="XYZ", update=updateMaterial)
|
||||
min: bpy.props.FloatVectorProperty(name='Operation minimum', default=(0, 0, 0), unit='LENGTH', precision=PRECISION,
|
||||
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
# MATERIAL SETTINGS
|
||||
|
||||
min: bpy.props.FloatVectorProperty(
|
||||
name='Operation minimum', default=(0, 0, 0), unit='LENGTH', precision=cam.constants.PRECISION,
|
||||
subtype="XYZ")
|
||||
max: bpy.props.FloatVectorProperty(name='Operation maximum', default=(0, 0, 0), unit='LENGTH', precision=PRECISION,
|
||||
max: bpy.props.FloatVectorProperty(name='Operation maximum', default=(0, 0, 0), unit='LENGTH', precision=cam.constants.PRECISION,
|
||||
subtype="XYZ")
|
||||
warnings: bpy.props.StringProperty(name='warnings', description='warnings', default='', update=updateRest)
|
||||
chipload: bpy.props.FloatProperty(name="chipload", description="Calculated chipload", default=0.0, unit='LENGTH',
|
||||
precision=10)
|
||||
|
||||
|
||||
# g-code options for operation
|
||||
output_header: BoolProperty(name="output g-code header",
|
||||
|
@ -1155,21 +1123,21 @@ class AddPresetCamOperation(bl_operators.presets.AddPresetBase, Operator):
|
|||
|
||||
preset_defines = ["o = bpy.context.scene.cam_operations[bpy.context.scene.cam_active_operation]"]
|
||||
|
||||
preset_values = ['o.use_layers', 'o.duration', 'o.chipload', 'o.material_from_model', 'o.stay_low', 'o.carve_depth',
|
||||
'o.dist_along_paths', 'o.source_image_crop_end_x', 'o.source_image_crop_end_y', 'o.material_size',
|
||||
'o.material_radius_around_model', 'o.use_limit_curve', 'o.cut_type', 'o.use_exact',
|
||||
'o.exact_subdivide_edges', 'o.minz_from_ob', 'o.free_movement_height',
|
||||
preset_values = ['o.use_layers', 'o.info.duration', 'o.info.chipload', 'o.material.estimate_from_model', 'o.stay_low', 'o.carve_depth',
|
||||
'o.dist_along_paths', 'o.source_image_crop_end_x', 'o.source_image_crop_end_y', 'o.material.size',
|
||||
'o.material.radius_around_model', 'o.use_limit_curve', 'o.cut_type', 'o.optimisation.use_exact',
|
||||
'o.optimisation.exact_subdivide_edges', 'o.minz_from_ob', 'o.free_movement_height',
|
||||
'o.source_image_crop_start_x', 'o.movement_insideout', 'o.spindle_rotation_direction', 'o.skin',
|
||||
'o.source_image_crop_start_y', 'o.movement_type', 'o.source_image_crop', 'o.limit_curve',
|
||||
'o.spindle_rpm', 'o.ambient_behaviour', 'o.cutter_type', 'o.source_image_scale_z',
|
||||
'o.cutter_diameter', 'o.source_image_size_x', 'o.curve_object', 'o.curve_object1',
|
||||
'o.cutter_flutes', 'o.ambient_radius', 'o.simulation_detail', 'o.update_offsetimage_tag',
|
||||
'o.dist_between_paths', 'o.max', 'o.min', 'o.pixsize', 'o.slice_detail', 'o.parallel_step_back',
|
||||
'o.cutter_flutes', 'o.ambient_radius', 'o.optimisation.simulation_detail', 'o.update_offsetimage_tag',
|
||||
'o.dist_between_paths', 'o.max', 'o.min', 'o.optimisation.pixsize', 'o.slice_detail', 'o.parallel_step_back',
|
||||
'o.drill_type', 'o.source_image_name', 'o.dont_merge', 'o.update_silhouete_tag',
|
||||
'o.material_origin', 'o.inverse', 'o.waterline_fill', 'o.source_image_offset', 'o.circle_detail',
|
||||
'o.material.origin', 'o.inverse', 'o.waterline_fill', 'o.source_image_offset', 'o.optimisation.circle_detail',
|
||||
'o.strategy', 'o.update_zbufferimage_tag', 'o.stepdown', 'o.feedrate', 'o.cutter_tip_angle',
|
||||
'o.cutter_id', 'o.path_object_name', 'o.pencil_threshold', 'o.geometry_source',
|
||||
'o.optimize_threshold', 'o.protect_vertical', 'o.plunge_feedrate', 'o.minz', 'o.warnings',
|
||||
'o.optimize_threshold', 'o.protect_vertical', 'o.plunge_feedrate', 'o.minz', 'o.info.warnings',
|
||||
'o.object_name', 'o.optimize', 'o.parallel_angle', 'o.cutter_length',
|
||||
'o.output_header', 'o.gcode_header', 'o.output_trailer', 'o.gcode_trailer', 'o.use_modifiers',
|
||||
'o.minz_from_material', 'o.useG64',
|
||||
|
@ -1225,7 +1193,6 @@ def get_panels(): # convenience function for bot register and unregister functi
|
|||
ui.CAM_UL_operations,
|
||||
# ui.CAM_UL_orientations,
|
||||
ui.CAM_UL_chains,
|
||||
camOperation,
|
||||
opReference,
|
||||
camChain,
|
||||
machineSettings,
|
||||
|
@ -1307,6 +1274,7 @@ def get_panels(): # convenience function for bot register and unregister functi
|
|||
# pack module:
|
||||
PackObjectsSettings,
|
||||
SliceObjectsSettings,
|
||||
camOperation,
|
||||
|
||||
)
|
||||
|
||||
|
@ -1426,7 +1394,6 @@ def compatible_panels():
|
|||
classes = [
|
||||
ui.CAM_UL_operations,
|
||||
ui.CAM_UL_chains,
|
||||
camOperation,
|
||||
opReference,
|
||||
camChain,
|
||||
machineSettings,
|
||||
|
@ -1435,10 +1402,14 @@ classes = [
|
|||
|
||||
ui.CAM_CHAINS_Panel,
|
||||
ui.CAM_OPERATIONS_Panel,
|
||||
ui.CAM_INFO_Properties,
|
||||
ui.CAM_INFO_Panel,
|
||||
ui.CAM_MATERIAL_Panel,
|
||||
ui.CAM_MATERIAL_Properties,
|
||||
ui.CAM_MATERIAL_PositionObject,
|
||||
ui.CAM_OPERATION_PROPERTIES_Panel,
|
||||
ui.CAM_OPTIMISATION_Panel,
|
||||
ui.CAM_OPTIMISATION_Properties,
|
||||
ui.CAM_AREA_Panel,
|
||||
ui.CAM_MOVEMENT_Panel,
|
||||
ui.CAM_FEEDRATE_Panel,
|
||||
|
@ -1459,7 +1430,6 @@ classes = [
|
|||
ops.PathExportChain,
|
||||
ops.PathsAll,
|
||||
ops.PathExport,
|
||||
ops.CAMPositionObject,
|
||||
ops.CAMSimulate,
|
||||
ops.CAMSimulateChain,
|
||||
ops.CamChainAdd,
|
||||
|
@ -1516,10 +1486,13 @@ classes = [
|
|||
# pack module:
|
||||
PackObjectsSettings,
|
||||
SliceObjectsSettings,
|
||||
camOperation,
|
||||
|
||||
]
|
||||
|
||||
|
||||
def register():
|
||||
|
||||
for p in classes:
|
||||
bpy.utils.register_class(p)
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ def getCachePath(o):
|
|||
fn=bpy.data.filepath
|
||||
l=len(bpy.path.basename(fn))
|
||||
bn=bpy.path.basename(fn)[:-6]
|
||||
|
||||
|
||||
try:
|
||||
os.mkdir(fn[:-l]+'temp_cam')
|
||||
except:
|
||||
|
@ -45,10 +45,10 @@ def calculatePath(op):
|
|||
picklepath=getCachePath(o)+'.pickle'
|
||||
f=open(picklepath,'wb')
|
||||
d={}
|
||||
|
||||
d['duration']=o.duration
|
||||
d['warnings']=o.warnings
|
||||
|
||||
|
||||
d['duration']=o.info.duration
|
||||
d['warnings']=o.info.warnings
|
||||
|
||||
#pickle path...
|
||||
oname="cam_path_"+o.name
|
||||
if oname in s.objects:
|
||||
|
@ -73,7 +73,7 @@ def calculatePath(op):
|
|||
time.sleep(1)
|
||||
sys.stdout.write('progress{%s}\n' % ('finished'))
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
#parse arguments here
|
||||
argv = sys.argv
|
||||
|
||||
|
|
|
@ -635,7 +635,7 @@ def optimizeChunk(chunk, operation):
|
|||
protect_vertical = operation.protect_vertical and operation.machine_axes == '3'
|
||||
for vi in range(0, len(points) - 1):
|
||||
|
||||
if not compare(chunk.points[-1], points[vi + 1], points[vi], operation.optimize_threshold * 0.000001):
|
||||
if not compare(chunk.points[-1], points[vi + 1], points[vi], operation.optimisation.optimize_threshold * 0.000001):
|
||||
if naxispoints:
|
||||
chunk.append(points[vi], startpoints[vi], endpoints[vi], rotations[vi])
|
||||
else:
|
||||
|
|
|
@ -65,7 +65,7 @@ def getCutterBullet(o):
|
|||
cutter = bpy.context.active_object
|
||||
cutter.scale *= BULLET_SCALE
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
|
||||
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
|
||||
bpy.ops.rigidbody.object_add(type='ACTIVE')
|
||||
cutter = bpy.context.active_object
|
||||
#cutter.dimensions.z = 0.2 * BULLET_SCALE # should be sufficient for now... 20 cm.
|
||||
|
@ -84,7 +84,7 @@ def getCutterBullet(o):
|
|||
cutter = bpy.context.active_object
|
||||
cutter.scale *= BULLET_SCALE
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
|
||||
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
|
||||
bpy.ops.rigidbody.object_add(type='ACTIVE')
|
||||
cutter = bpy.context.active_object
|
||||
cutter.rigid_body.collision_shape = 'CONE'
|
||||
|
@ -134,7 +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.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)
|
||||
|
@ -247,7 +247,7 @@ def prepareBulletCollision(o):
|
|||
bpy.data.meshes.remove(oldmesh)
|
||||
|
||||
# subdivide long edges here:
|
||||
if o.exact_subdivide_edges:
|
||||
if o.optimisation.exact_subdivide_edges:
|
||||
subdivideLongEdges(collisionob, o.cutter_diameter * 2)
|
||||
|
||||
bpy.ops.rigidbody.object_add(type='ACTIVE')
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
# Package to store all constants of BlenderCAM
|
||||
|
||||
# PRECISION is used in most operations
|
||||
PRECISION = 5
|
||||
|
||||
CHIPLOAD_PRECISION = 10
|
||||
|
||||
MAX_OPERATION_TIME = 3200000000 # seconds
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
|
||||
# here is the Gcode generaton
|
||||
# here is the Gcode generaton
|
||||
|
||||
import bpy
|
||||
import time
|
||||
|
@ -496,7 +496,7 @@ def exportGcodePath(filename, vertslist, operations):
|
|||
for aline in lines:
|
||||
c.write(aline + '\n')
|
||||
|
||||
o.duration = duration * unitcorr
|
||||
o.info.duration = duration * unitcorr
|
||||
if enable_dust:
|
||||
c.write(stop_dust + '\n')
|
||||
if enable_hold:
|
||||
|
@ -532,7 +532,7 @@ def getPath(context, operation): # should do all path calculations.
|
|||
|
||||
utils.getOperationSources(operation)
|
||||
|
||||
operation.warnings = ''
|
||||
operation.info.warnings = ''
|
||||
checkMemoryLimit(operation)
|
||||
|
||||
print(operation.machine_axes)
|
||||
|
@ -585,16 +585,16 @@ def checkMemoryLimit(o):
|
|||
# utils.getBounds(o)
|
||||
sx = o.max.x - o.min.x
|
||||
sy = o.max.y - o.min.y
|
||||
resx = sx / o.pixsize
|
||||
resy = sy / o.pixsize
|
||||
resx = sx / o.optimisation.pixsize
|
||||
resy = sy / o.optimisation.pixsize
|
||||
res = resx * resy
|
||||
limit = o.imgres_limit * 1000000
|
||||
limit = o.optimisation.imgres_limit * 1000000
|
||||
# print('co se to deje')
|
||||
if res > limit:
|
||||
ratio = (res / limit)
|
||||
o.pixsize = o.pixsize * math.sqrt(ratio)
|
||||
o.warnings = o.warnings + 'sampling resolution had to be reduced!\n'
|
||||
print('changing sampling resolution to %f' % o.pixsize)
|
||||
o.optimisation.pixsize = o.optimisation.pixsize * math.sqrt(ratio)
|
||||
o.info.warnings += f"Memory limit: sampling resolution reduced to {o.optimisation.pixsize}\n"
|
||||
print('changing sampling resolution to %f' % o.optimisation.pixsize)
|
||||
|
||||
|
||||
# this is the main function.
|
||||
|
@ -688,7 +688,7 @@ def getPath3axis(context, operation):
|
|||
|
||||
strategy.chunksToMesh(chunks, o)
|
||||
|
||||
elif o.strategy == 'WATERLINE' and o.use_opencamlib:
|
||||
elif o.strategy == 'WATERLINE' and o.optimisation.use_opencamlib:
|
||||
utils.getAmbient(o)
|
||||
chunks = []
|
||||
oclGetWaterline(o, chunks)
|
||||
|
@ -699,7 +699,7 @@ def getPath3axis(context, operation):
|
|||
ch.points.reverse()
|
||||
strategy.chunksToMesh(chunks, o)
|
||||
|
||||
elif o.strategy == 'WATERLINE' and not o.use_opencamlib:
|
||||
elif o.strategy == 'WATERLINE' and not o.optimisation.use_opencamlib:
|
||||
topdown = True
|
||||
tw = time.time()
|
||||
chunks = []
|
||||
|
@ -766,7 +766,7 @@ def getPath3axis(context, operation):
|
|||
o.inverse and not poly.is_empty and slicesfilled == 1): # first slice fill
|
||||
restpoly = lastslice
|
||||
|
||||
restpoly = restpoly.buffer(-o.dist_between_paths, resolution=o.circle_detail)
|
||||
restpoly = restpoly.buffer(-o.dist_between_paths, resolution=o.optimisation.circle_detail)
|
||||
|
||||
fillz = z
|
||||
i = 0
|
||||
|
@ -783,7 +783,7 @@ def getPath3axis(context, operation):
|
|||
parentChildDist(lastchunks, nchunks, o)
|
||||
lastchunks = nchunks
|
||||
# slicechunks.extend(polyToChunks(restpoly,z))
|
||||
restpoly = restpoly.buffer(-o.dist_between_paths, resolution=o.circle_detail)
|
||||
restpoly = restpoly.buffer(-o.dist_between_paths, resolution=o.optimisation.circle_detail)
|
||||
|
||||
i += 1
|
||||
# print(i)
|
||||
|
@ -801,7 +801,7 @@ def getPath3axis(context, operation):
|
|||
if o.inverse and poly.is_empty and slicesfilled > 0:
|
||||
restpoly = bound_rectangle.difference(lastslice)
|
||||
|
||||
restpoly = restpoly.buffer(-o.dist_between_paths, resolution=o.circle_detail)
|
||||
restpoly = restpoly.buffer(-o.dist_between_paths, resolution=o.optimisation.circle_detail)
|
||||
|
||||
i = 0
|
||||
while not restpoly.is_empty: # 'GeometryCollection':#len(restpoly.boundary.coords)>0:
|
||||
|
@ -812,7 +812,7 @@ def getPath3axis(context, operation):
|
|||
slicechunks.extend(nchunks)
|
||||
parentChildDist(lastchunks, nchunks, o)
|
||||
lastchunks = nchunks
|
||||
restpoly = restpoly.buffer(-o.dist_between_paths, resolution=o.circle_detail)
|
||||
restpoly = restpoly.buffer(-o.dist_between_paths, resolution=o.optimisation.circle_detail)
|
||||
i += 1
|
||||
|
||||
percent = int(h / nslices * 100)
|
||||
|
|
|
@ -142,7 +142,7 @@ def offsetArea(o, samples):
|
|||
o.offset_image.fill(-10)
|
||||
|
||||
sourceArray = samples
|
||||
cutterArray = simulation.getCutterArray(o, o.pixsize)
|
||||
cutterArray = simulation.getCutterArray(o, o.optimisation.pixsize)
|
||||
|
||||
# progress('image size', sourceArray.shape)
|
||||
|
||||
|
@ -222,7 +222,7 @@ def getOffsetImageCavities(o, i): # for pencil operation mainly
|
|||
|
||||
def imageEdgeSearch_online(o, ar, zimage): # search edges for pencil strategy, another try.
|
||||
minx, miny, minz, maxx, maxy, maxz = o.min.x, o.min.y, o.min.z, o.max.x, o.max.y, o.max.z
|
||||
r = ceil((o.cutter_diameter/12)/o.pixsize) # was commented
|
||||
r = ceil((o.cutter_diameter/12)/o.optimisation.pixsize) # was commented
|
||||
coef = 0.75
|
||||
maxarx = ar.shape[0]
|
||||
maxary = ar.shape[1]
|
||||
|
@ -340,8 +340,8 @@ def imageEdgeSearch_online(o, ar, zimage): # search edges for pencil strategy,
|
|||
for ch in chunks:
|
||||
ch = ch.points
|
||||
for i in range(0, len(ch)):
|
||||
ch[i] = ((ch[i][0] + coef - o.borderwidth) * o.pixsize + minx,
|
||||
(ch[i][1] + coef - o.borderwidth) * o.pixsize + miny, ch[i][2])
|
||||
ch[i] = ((ch[i][0] + coef - o.borderwidth) * o.optimisation.pixsize + minx,
|
||||
(ch[i][1] + coef - o.borderwidth) * o.optimisation.pixsize + miny, ch[i][2])
|
||||
return chunks
|
||||
|
||||
|
||||
|
@ -352,13 +352,13 @@ def crazyPath(o):
|
|||
sx = o.max.x - o.min.x
|
||||
sy = o.max.y - o.min.y
|
||||
|
||||
resx = ceil(sx / o.simulation_detail) + 2 * o.borderwidth
|
||||
resy = ceil(sy / o.simulation_detail) + 2 * o.borderwidth
|
||||
resx = ceil(sx / o.optimisation.simulation_detail) + 2 * o.borderwidth
|
||||
resy = ceil(sy / o.optimisation.simulation_detail) + 2 * o.borderwidth
|
||||
|
||||
o.millimage = numpy.array((0.1), dtype=float)
|
||||
o.millimage.resize(resx, resy)
|
||||
o.millimage.fill(0)
|
||||
o.cutterArray = -simulation.getCutterArray(o, o.simulation_detail) # getting inverted cutter
|
||||
o.cutterArray = -simulation.getCutterArray(o, o.optimisation.simulation_detail) # getting inverted cutter
|
||||
|
||||
|
||||
def buildStroke(start, end, cutterArray):
|
||||
|
@ -396,7 +396,7 @@ def crazyStrokeImage(o):
|
|||
# this surprisingly works, and can be used as a basis for something similar to adaptive milling strategy.
|
||||
minx, miny, minz, maxx, maxy, maxz = o.min.x, o.min.y, o.min.z, o.max.x, o.max.y, o.max.z
|
||||
|
||||
r = int((o.cutter_diameter / 2.0) / o.pixsize) # ceil((o.cutter_diameter/12)/o.pixsize)
|
||||
r = int((o.cutter_diameter / 2.0) / o.optimisation.pixsize) # ceil((o.cutter_diameter/12)/o.optimisation.pixsize)
|
||||
d = 2 * r
|
||||
coef = 0.75
|
||||
|
||||
|
@ -562,8 +562,8 @@ def crazyStrokeImage(o):
|
|||
for ch in chunks:
|
||||
ch = ch.points
|
||||
for i in range(0, len(ch)):
|
||||
ch[i] = ((ch[i][0] + coef - o.borderwidth) * o.pixsize + minx,
|
||||
(ch[i][1] + coef - o.borderwidth) * o.pixsize + miny, 0)
|
||||
ch[i] = ((ch[i][0] + coef - o.borderwidth) * o.optimisation.pixsize + minx,
|
||||
(ch[i][1] + coef - o.borderwidth) * o.optimisation.pixsize + miny, 0)
|
||||
return chunks
|
||||
|
||||
|
||||
|
@ -581,7 +581,7 @@ def crazyStrokeImageBinary(o, ar, avoidar):
|
|||
ar[:, :o.borderwidth] = 0
|
||||
ar[:, -o.borderwidth:] = 0
|
||||
|
||||
r = int((o.cutter_diameter / 2.0) / o.pixsize) # ceil((o.cutter_diameter/12)/o.pixsize)
|
||||
r = int((o.cutter_diameter / 2.0) / o.optimisation.pixsize) # ceil((o.cutter_diameter/12)/o.optimisation.pixsize)
|
||||
d = 2 * r
|
||||
coef = 0.75
|
||||
maxarx = ar.shape[0]
|
||||
|
@ -821,8 +821,8 @@ def crazyStrokeImageBinary(o, ar, avoidar):
|
|||
for ch in chunks:
|
||||
ch = ch.points
|
||||
for i in range(0, len(ch)):
|
||||
ch[i] = ((ch[i][0] + coef - o.borderwidth) * o.pixsize + minx,
|
||||
(ch[i][1] + coef - o.borderwidth) * o.pixsize + miny, o.minz)
|
||||
ch[i] = ((ch[i][0] + coef - o.borderwidth) * o.optimisation.pixsize + minx,
|
||||
(ch[i][1] + coef - o.borderwidth) * o.optimisation.pixsize + miny, o.minz)
|
||||
|
||||
return chunks
|
||||
|
||||
|
@ -830,7 +830,7 @@ def crazyStrokeImageBinary(o, ar, avoidar):
|
|||
def imageToChunks(o, image, with_border=False):
|
||||
t = time.time()
|
||||
minx, miny, minz, maxx, maxy, maxz = o.min.x, o.min.y, o.min.z, o.max.x, o.max.y, o.max.z
|
||||
pixsize = o.pixsize
|
||||
pixsize = o.optimisation.pixsize
|
||||
|
||||
image = image.astype(numpy.uint8)
|
||||
|
||||
|
@ -840,7 +840,7 @@ def imageToChunks(o, image, with_border=False):
|
|||
|
||||
indices1 = ar.nonzero()
|
||||
borderspread = 2
|
||||
# o.cutter_diameter/o.pixsize#when the border was excluded precisely, sometimes it did remove some silhouette parts
|
||||
# o.cutter_diameter/o.optimisation.pixsize#when the border was excluded precisely, sometimes it did remove some silhouette parts
|
||||
r = o.borderwidth - borderspread
|
||||
# to prevent outline of the border was 3 before and also (o.cutter_diameter/2)/pixsize+o.borderwidth
|
||||
if with_border:
|
||||
|
@ -980,7 +980,7 @@ def imageToChunks(o, image, with_border=False):
|
|||
|
||||
# print('directsimplify')
|
||||
reduxratio = 1.25 # was 1.25
|
||||
soptions = ['distance', 'distance', o.pixsize * reduxratio, 5, o.pixsize * reduxratio]
|
||||
soptions = ['distance', 'distance', o.optimisation.pixsize * reduxratio, 5, o.optimisation.pixsize * reduxratio]
|
||||
nchunks = []
|
||||
for i, ch in enumerate(vecchunks):
|
||||
|
||||
|
@ -1030,8 +1030,8 @@ def getResolution(o):
|
|||
sx = o.max.x - o.min.x
|
||||
sy = o.max.y - o.min.y
|
||||
|
||||
resx = ceil(sx / o.pixsize) + 2 * o.borderwidth
|
||||
resy = ceil(sy / o.pixsize) + 2 * o.borderwidth
|
||||
resx = ceil(sx / o.optimisation.pixsize) + 2 * o.borderwidth
|
||||
resy = ceil(sy / o.optimisation.pixsize) + 2 * o.borderwidth
|
||||
|
||||
# this basically renders blender zbuffer and makes it accessible by saving & loading it again.
|
||||
# that's because blender doesn't allow accessing pixels in render :(
|
||||
|
@ -1043,13 +1043,13 @@ def renderSampleImage(o):
|
|||
# print(o.zbuffer_image)
|
||||
|
||||
if o.geometry_source == 'OBJECT' or o.geometry_source == 'COLLECTION':
|
||||
pixsize = o.pixsize
|
||||
pixsize = o.optimisation.pixsize
|
||||
|
||||
sx = o.max.x - o.min.x
|
||||
sy = o.max.y - o.min.y
|
||||
|
||||
resx = math.ceil(sx / o.pixsize) + 2 * o.borderwidth
|
||||
resy = math.ceil(sy / o.pixsize) + 2 * o.borderwidth
|
||||
resx = math.ceil(sx / o.optimisation.pixsize) + 2 * o.borderwidth
|
||||
resy = math.ceil(sy / o.optimisation.pixsize) + 2 * o.borderwidth
|
||||
|
||||
if not o.update_zbufferimage_tag and len(o.zbuffer_image) == resx and len(o.zbuffer_image[0]) == resy:
|
||||
# if we call this accidentally in more functions, which currently happens...
|
||||
|
@ -1106,7 +1106,7 @@ def renderSampleImage(o):
|
|||
bpy.context.scene.camera = camera
|
||||
|
||||
camera.data.type = 'ORTHO'
|
||||
camera.data.ortho_scale = max(resx * o.pixsize, resy * o.pixsize)
|
||||
camera.data.ortho_scale = max(resx * o.optimisation.pixsize, resy * o.optimisation.pixsize)
|
||||
camera.location = (o.min.x + sx / 2, o.min.y + sy / 2, 1)
|
||||
camera.rotation_euler = (0, 0, 0)
|
||||
# if not o.render_all:#removed in 0.3
|
||||
|
@ -1160,8 +1160,8 @@ def renderSampleImage(o):
|
|||
|
||||
o.offset_image.resize(ex - sx + 2 * o.borderwidth, ey - sy + 2 * o.borderwidth)
|
||||
|
||||
o.pixsize = o.source_image_size_x / i.size[0]
|
||||
simple.progress('pixel size in the image source', o.pixsize)
|
||||
o.optimisation.pixsize = o.source_image_size_x / i.size[0]
|
||||
simple.progress('pixel size in the image source', o.optimisation.pixsize)
|
||||
|
||||
rawimage = imagetonumpy(i)
|
||||
maxa = numpy.max(rawimage)
|
||||
|
|
|
@ -51,29 +51,6 @@ def threadread(tcom):
|
|||
e = inline.find('}')
|
||||
tcom.outtext = inline[s + 9:e]
|
||||
|
||||
|
||||
class CAMPositionObject(bpy.types.Operator):
|
||||
"""position object for CAM operation. Tests object bounds and places them so the object
|
||||
is aligned to be positive from x and y and negative from z."""
|
||||
bl_idname = "object.cam_position"
|
||||
bl_label = "position object for CAM operation"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
s = bpy.context.scene
|
||||
operation = s.cam_operations[s.cam_active_operation]
|
||||
if operation.object_name in bpy.data.objects:
|
||||
utils.positionObject(operation)
|
||||
else:
|
||||
print('no object assigned')
|
||||
return {'FINISHED'}
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop_search(self, "operation", bpy.context.scene, "cam_operations")
|
||||
|
||||
|
||||
@bpy.app.handlers.persistent
|
||||
def timer_update(context):
|
||||
"""monitoring of background processes"""
|
||||
|
@ -568,14 +545,14 @@ def Add_Pocket(self, maxdepth, sname, new_cutter_diameter):
|
|||
if not mpocket_exists: # create a pocket operation if it does not exist already
|
||||
s.cam_operations.add()
|
||||
o = s.cam_operations[-1]
|
||||
o.object_name = 'medial_pocket'
|
||||
o.object_name= 'medial_pocket'
|
||||
s.cam_active_operation = len(s.cam_operations) - 1
|
||||
o.name = 'MedialPocket'
|
||||
o.filename = o.name
|
||||
o.strategy = 'POCKET'
|
||||
o.use_layers = False
|
||||
o.material_from_model = False
|
||||
o.material_size[2] = -maxdepth
|
||||
o.material.estimate_from_model = False
|
||||
o.material.size[2] = -maxdepth
|
||||
o.minz_from_ob = False
|
||||
o.minz_from_material = True
|
||||
|
||||
|
@ -594,22 +571,18 @@ class CamOperationAdd(bpy.types.Operator):
|
|||
s = bpy.context.scene
|
||||
fixUnits()
|
||||
|
||||
ob = bpy.context.active_object
|
||||
if ob is None: raise CamException("No object selected")
|
||||
|
||||
minx, miny, minz, maxx, maxy, maxz = utils.getBoundsWorldspace([ob])
|
||||
s.cam_operations.add()
|
||||
o = s.cam_operations[-1]
|
||||
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
|
||||
o.object_name = ob.name
|
||||
o.minz = minz
|
||||
|
||||
s.cam_active_operation = len(s.cam_operations) - 1
|
||||
o.name = f"Op_{o.object_name}_{s.cam_active_operation + 1}"
|
||||
|
||||
o.name = f"Op_{ob.name}_{s.cam_active_operation + 1}"
|
||||
o.filename = o.name
|
||||
|
||||
if s.objects.get('CAM_machine') is None:
|
||||
|
|
|
@ -320,7 +320,7 @@ def getPathPattern(operation):
|
|||
pathchunks = []
|
||||
chunks = []
|
||||
for p in polys:
|
||||
p = p.buffer(-o.dist_between_paths / 10, o.circle_detail)
|
||||
p = p.buffer(-o.dist_between_paths / 10, o.optimisation.circle_detail)
|
||||
# first, move a bit inside, because otherwise the border samples go crazy very often changin between
|
||||
# hit/non hit and making too many jumps in the path.
|
||||
chunks.extend(shapelyToChunks(p, 0))
|
||||
|
@ -335,7 +335,7 @@ def getPathPattern(operation):
|
|||
for porig in polys:
|
||||
p = porig
|
||||
while not p.is_empty:
|
||||
p = p.buffer(-o.dist_between_paths, o.circle_detail)
|
||||
p = p.buffer(-o.dist_between_paths, o.optimisation.circle_detail)
|
||||
if not p.is_empty:
|
||||
|
||||
nchunks = shapelyToChunks(p, zlevel)
|
||||
|
@ -358,13 +358,13 @@ def getPathPattern(operation):
|
|||
for a in range(0, int(steps)):
|
||||
dist = d
|
||||
if a == int(o.cutter_diameter / 2 / o.dist_between_paths):
|
||||
if o.use_exact:
|
||||
dist += o.pixsize * 0.85
|
||||
if o.optimisation.use_exact:
|
||||
dist += o.optimisation.pixsize * 0.85
|
||||
# this is here only because silhouette is still done with zbuffer method,
|
||||
# even if we use bullet collisions.
|
||||
else:
|
||||
dist += o.pixsize * 2.5
|
||||
p = p.buffer(dist, o.circle_detail)
|
||||
dist += o.optimisation.pixsize * 2.5
|
||||
p = p.buffer(dist, o.optimisation.circle_detail)
|
||||
if not p.is_empty:
|
||||
nchunks = shapelyToChunks(p, zlevel)
|
||||
if o.movement_insideout == 'INSIDEOUT':
|
||||
|
|
|
@ -113,7 +113,7 @@ def generateSimulationImage(operations, limits):
|
|||
sy = maxy - miny
|
||||
|
||||
o = operations[0] # getting sim detail and others from first op.
|
||||
simulation_detail = o.simulation_detail
|
||||
simulation_detail = o.optimisation.simulation_detail
|
||||
borderwidth = o.borderwidth
|
||||
resx = math.ceil(sx / simulation_detail) + 2 * borderwidth
|
||||
resy = math.ceil(sy / simulation_detail) + 2 * borderwidth
|
||||
|
|
|
@ -101,7 +101,7 @@ def cutout(o):
|
|||
if o.outlines_count > 1:
|
||||
for i in range(1, o.outlines_count):
|
||||
chunksFromCurve.extend(shapelyToChunks(p, -1))
|
||||
p = p.buffer(distance=o.dist_between_paths * offset, resolution=o.circle_detail, join_style=join,
|
||||
p = p.buffer(distance=o.dist_between_paths * offset, resolution=o.optimisation.circle_detail, join_style=join,
|
||||
mitre_limit=2)
|
||||
|
||||
chunksFromCurve.extend(shapelyToChunks(p, -1))
|
||||
|
@ -205,7 +205,7 @@ def curve(o):
|
|||
pathSamples = []
|
||||
utils.getOperationSources(o)
|
||||
if not o.onlycurves:
|
||||
o.warnings += 'at least one of assigned objects is not a curve\n'
|
||||
o.info.warnings += 'at least one of assigned objects is not a curve\n'
|
||||
|
||||
for ob in o.objects:
|
||||
pathSamples.extend(curveToChunks(ob)) # make the chunks from curve here
|
||||
|
@ -253,7 +253,7 @@ def proj_curve(s, o):
|
|||
|
||||
from cam import chunk
|
||||
if targetCurve.type != 'CURVE':
|
||||
o.warnings = o.warnings + 'Projection target and source have to be curve objects!\n '
|
||||
o.info.warnings += 'Projection target and source have to be curve objects!\n '
|
||||
return
|
||||
|
||||
if 1:
|
||||
|
@ -322,17 +322,17 @@ def pocket(o):
|
|||
lastchunks = []
|
||||
centers = None
|
||||
firstoutline = p # for testing in the end.
|
||||
prest = p.buffer(-c_offset, o.circle_detail)
|
||||
prest = p.buffer(-c_offset, o.optimisation.circle_detail)
|
||||
while not p.is_empty:
|
||||
if o.pocketToCurve:
|
||||
polygon_utils_cam.shapelyToCurve('3dpocket', p, 0.0) # make a curve starting with _3dpocket
|
||||
|
||||
nchunks = shapelyToChunks(p, o.min.z)
|
||||
# print("nchunks")
|
||||
pnew = p.buffer(-o.dist_between_paths, o.circle_detail)
|
||||
pnew = p.buffer(-o.dist_between_paths, o.optimisation.circle_detail)
|
||||
if pnew.is_empty:
|
||||
|
||||
pt = p.buffer(-c_offset, o.circle_detail) # test if the last curve will leave material
|
||||
|
||||
pt = p.buffer(-c_offset, o.optimisation.circle_detail) # test if the last curve will leave material
|
||||
if not pt.is_empty:
|
||||
pnew = pt
|
||||
# print("pnew")
|
||||
|
@ -376,7 +376,7 @@ def pocket(o):
|
|||
if not chunksFromCurve[chi].children:
|
||||
p = ch.points[0] # TODO:intercept closest next point when it should stay low
|
||||
# first thing to do is to check if helix enter can really enter.
|
||||
checkc = Circle(helix_radius + c_offset, o.circle_detail)
|
||||
checkc = Circle(helix_radius + c_offset, o.optimisation.circle_detail)
|
||||
checkc = affinity.translate(checkc, p[0], p[1])
|
||||
covers = False
|
||||
for poly in o.silhouete:
|
||||
|
@ -387,7 +387,7 @@ def pocket(o):
|
|||
if covers:
|
||||
revolutions = (l[0] - p[2]) / revheight
|
||||
# print(revolutions)
|
||||
h = Helix(helix_radius, o.circle_detail, l[0], p, revolutions)
|
||||
h = Helix(helix_radius, o.optimisation.circle_detail, l[0], p, revolutions)
|
||||
# invert helix if not the typical direction
|
||||
if (o.movement_type == 'CONVENTIONAL' and o.spindle_rotation_direction == 'CW') or (
|
||||
o.movement_type == 'CLIMB' and o.spindle_rotation_direction == 'CCW'):
|
||||
|
@ -397,7 +397,7 @@ def pocket(o):
|
|||
h = nhelix
|
||||
ch.points = h + ch.points
|
||||
else:
|
||||
o.warnings = o.warnings + 'Helix entry did not fit! \n '
|
||||
o.info.warnings += 'Helix entry did not fit! \n '
|
||||
ch.closed = True
|
||||
ch.rampZigZag(l[0], l[1], o)
|
||||
# Arc retract here first try:
|
||||
|
@ -427,7 +427,7 @@ def pocket(o):
|
|||
p = (p.x, p.y, p.z)
|
||||
|
||||
# progress(str((v1,v,p)))
|
||||
h = Helix(o.retract_radius, o.circle_detail, p[2] + o.retract_height, p, revolutions)
|
||||
h = Helix(o.retract_radius, o.optimisation.circle_detail, p[2] + o.retract_height, p, revolutions)
|
||||
|
||||
e = Euler((0, 0, rotangle + pi)) # angle to rotate whole retract move
|
||||
rothelix = []
|
||||
|
@ -445,7 +445,7 @@ def pocket(o):
|
|||
c = sgeometry.Polygon(c)
|
||||
# print('çoutline')
|
||||
# print(c)
|
||||
coutline = c.buffer(c_offset, o.circle_detail)
|
||||
coutline = c.buffer(c_offset, o.optimisation.circle_detail)
|
||||
# print(h)
|
||||
# print('çoutline')
|
||||
# print(coutline)
|
||||
|
@ -585,7 +585,7 @@ def medial_axis(o):
|
|||
slope = math.tan(math.pi * (90 - angle / 2) / 180) # angle in degrees
|
||||
# slope = math.tan((math.pi-angle)/2) #angle in radian
|
||||
new_cutter_diameter = o.cutter_diameter
|
||||
m_o_name = o.object_name
|
||||
m_o_ob = o.object_name
|
||||
if o.cutter_type == 'VCARVE':
|
||||
angle = o.cutter_tip_angle
|
||||
# start the max depth calc from the "start depth" of the operation.
|
||||
|
@ -601,7 +601,7 @@ def medial_axis(o):
|
|||
elif o.cutter_type == 'BALLNOSE':
|
||||
maxdepth = - new_cutter_diameter / 2
|
||||
else:
|
||||
o.warnings += 'Only Ballnose, Ball and V-carve cutters\n are supported'
|
||||
o.info.warnings += 'Only Ballnose, Ball and V-carve cutters\n are supported'
|
||||
return
|
||||
# remember resolutions of curves, to refine them,
|
||||
# otherwise medial axis computation yields too many branches in curved parts
|
||||
|
@ -755,7 +755,7 @@ def medial_axis(o):
|
|||
if o.add_pocket_for_medial:
|
||||
# o.add_pocket_for_medial = False
|
||||
# export medial axis parameter to pocket op
|
||||
ops.Add_Pocket(None, maxdepth, m_o_name, new_cutter_diameter)
|
||||
ops.Add_Pocket(None, maxdepth, m_o_ob, new_cutter_diameter)
|
||||
|
||||
|
||||
def getLayers(operation, startdepth, enddepth):
|
||||
|
@ -828,7 +828,7 @@ def chunksToMesh(chunks, o):
|
|||
if len(ch.points) > 0: # TODO: there is a case where parallel+layers+zigzag ramps send empty chunks here...
|
||||
# print(len(ch.points))
|
||||
nverts = []
|
||||
if o.optimize:
|
||||
if o.optimisation.optimize:
|
||||
ch = optimizeChunk(ch, o)
|
||||
|
||||
# lift and drop
|
||||
|
@ -874,7 +874,7 @@ def chunksToMesh(chunks, o):
|
|||
verts.append(v)
|
||||
lifted = lift
|
||||
# print(verts_rotations)
|
||||
if o.use_exact and not o.use_opencamlib:
|
||||
if o.optimisation.use_exact and not o.optimisation.use_opencamlib:
|
||||
cleanupBulletCollision(o)
|
||||
print(time.time() - t)
|
||||
t = time.time()
|
||||
|
|
|
@ -101,7 +101,7 @@ def testParallel(pos):
|
|||
bpy.ops.scene.cam_operation_add()
|
||||
o = bpy.context.scene.cam_operations[-1]
|
||||
o.ambient_behaviour = 'AROUND'
|
||||
o.material_radius_around_model = 0.01
|
||||
o.material.radius_around_model = 0.01
|
||||
bpy.ops.object.calculate_cam_path()
|
||||
|
||||
|
||||
|
@ -110,7 +110,7 @@ def testWaterline(pos):
|
|||
bpy.ops.scene.cam_operation_add()
|
||||
o = bpy.context.scene.cam_operations[-1]
|
||||
o.strategy = 'WATERLINE'
|
||||
o.pixsize = .0002
|
||||
o.optimisation.pixsize = .0002
|
||||
# o.ambient_behaviour='AROUND'
|
||||
# o.material_radius_around_model=0.01
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
|
||||
import sys
|
||||
import bpy
|
||||
from bpy.types import UIList, Operator
|
||||
|
@ -34,16 +35,16 @@ from cam import gcodeimportparser, simple
|
|||
from cam.simple import *
|
||||
|
||||
from cam.ui_panels.buttons_panel import CAMButtonsPanel
|
||||
from cam.ui_panels.info import CAM_INFO_Panel
|
||||
from cam.ui_panels.info import *
|
||||
from cam.ui_panels.operations import CAM_OPERATIONS_Panel
|
||||
from cam.ui_panels.cutter import CAM_CUTTER_Panel
|
||||
from cam.ui_panels.machine import CAM_MACHINE_Panel
|
||||
from cam.ui_panels.material import CAM_MATERIAL_Panel
|
||||
from cam.ui_panels.material import *
|
||||
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.optimisation import *
|
||||
from cam.ui_panels.area import CAM_AREA_Panel
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import sys
|
||||
|
||||
# Panel definitions
|
||||
class CAMButtonsPanel:
|
||||
|
@ -11,38 +10,27 @@ class CAMButtonsPanel:
|
|||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
rd = context.scene.render
|
||||
rd = bpy.context.scene.render
|
||||
return rd.engine in cls.COMPAT_ENGINES
|
||||
|
||||
def __init__(self):
|
||||
self.scene = bpy.context.scene
|
||||
|
||||
self.active_op = self.active_operation()
|
||||
|
||||
def active_operation_index(self):
|
||||
return(self.scene.cam_active_operation)
|
||||
return(bpy.context.scene.cam_active_operation)
|
||||
|
||||
def active_operation(self):
|
||||
active_op = None
|
||||
try:
|
||||
active_op = self.scene.cam_operations[self.active_operation_index()]
|
||||
active_op = bpy.context.scene.cam_operations[self.active_operation_index()]
|
||||
except IndexError:
|
||||
print(f"Invalid operation index {self.active_operation_index()}")
|
||||
|
||||
pass
|
||||
|
||||
return(active_op)
|
||||
|
||||
def operations_count(self):
|
||||
return(len(self.scene.cam_operations))
|
||||
return(len(bpy.context.scene.cam_operations))
|
||||
|
||||
def has_operations(self):
|
||||
return (self.operations_count() > 0)
|
||||
|
||||
def opencamlib_version(self):
|
||||
try:
|
||||
import ocl
|
||||
except ImportError:
|
||||
try:
|
||||
import opencamlib as ocl
|
||||
except ImportError as e:
|
||||
return
|
||||
return(ocl.version())
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ class CAM_CUTTER_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
layout.prop(ao, 'lead_out')
|
||||
|
||||
if ao.cutter_type == 'CUSTOM':
|
||||
if ao.use_exact:
|
||||
if ao.optimisation.use_exact:
|
||||
layout.label(text='Warning - only convex shapes are supported. ', icon='COLOR_RED')
|
||||
layout.label(text='If your custom cutter is concave,')
|
||||
layout.label(text='switch exact mode off.')
|
||||
|
|
|
@ -1,12 +1,32 @@
|
|||
import sys
|
||||
import bpy
|
||||
|
||||
from cam.simple import strInUnits
|
||||
from cam.ui_panels.buttons_panel import CAMButtonsPanel
|
||||
import cam.utils
|
||||
import cam.constants
|
||||
|
||||
# Info panel
|
||||
# This panel gives general information about the current operation
|
||||
|
||||
class CAM_INFO_Properties(bpy.types.PropertyGroup):
|
||||
|
||||
warnings: bpy.props.StringProperty(
|
||||
name='warnings',
|
||||
description='warnings',
|
||||
default='',
|
||||
update=cam.utils.update_operation)
|
||||
|
||||
chipload: bpy.props.FloatProperty(
|
||||
name="chipload", description="Calculated chipload",
|
||||
default=0.0, unit='LENGTH',
|
||||
precision=cam.constants.CHIPLOAD_PRECISION)
|
||||
|
||||
duration: bpy.props.FloatProperty(
|
||||
name="Estimated time", default=0.01, min=0.0000,
|
||||
max=cam.constants.MAX_OPERATION_TIME,
|
||||
precision=cam.constants.PRECISION, unit="TIME")
|
||||
|
||||
|
||||
class CAM_INFO_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM info panel"""
|
||||
bl_label = "CAM info & warnings"
|
||||
|
@ -14,60 +34,78 @@ class CAM_INFO_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
|
||||
COMPAT_ENGINES = {'BLENDERCAM_RENDER'}
|
||||
|
||||
# Display the Info Panel
|
||||
def draw(self, context):
|
||||
self.draw_opencamlib_version()
|
||||
|
||||
if self.has_operations():
|
||||
self.draw_active_op_warnings()
|
||||
self.draw_active_op_data()
|
||||
self.draw_active_op_time()
|
||||
self.draw_active_op_money_cost()
|
||||
else:
|
||||
self.layout.label(text='No CAM operation created')
|
||||
|
||||
# Display the OpenCamLib version
|
||||
def draw_opencamlib_version(self):
|
||||
opencamlib_version = self.opencamlib_version()
|
||||
opencamlib_version = cam.utils.opencamlib_version()
|
||||
if opencamlib_version is None:
|
||||
self.layout.label(text = "Opencamlib is not installed")
|
||||
self.layout.label(text="Opencamlib is not installed")
|
||||
else:
|
||||
self.layout.label(text = f"Opencamlib v{opencamlib_version} installed")
|
||||
self.layout.label(
|
||||
text=f"Opencamlib v{opencamlib_version} installed")
|
||||
|
||||
# Display warnings related to the current operation
|
||||
def draw_active_op_warnings(self):
|
||||
active_op = self.active_operation()
|
||||
if active_op is None: return
|
||||
if self.active_op is None:
|
||||
return
|
||||
|
||||
for line in active_op.warnings.rstrip("\n").split("\n"):
|
||||
if len(line) > 0 :
|
||||
for line in self.active_op.info.warnings.rstrip("\n").split("\n"):
|
||||
if len(line) > 0:
|
||||
self.layout.label(text=line, icon='ERROR')
|
||||
|
||||
def draw_active_op_data(self):
|
||||
active_op = self.active_operation()
|
||||
if active_op is None: return
|
||||
if not active_op.valid: return
|
||||
if not int(active_op.duration*60) > 0: return
|
||||
# Display the time estimation for the current operation
|
||||
def draw_active_op_time(self):
|
||||
if self.active_op is None:
|
||||
return
|
||||
if not self.active_op.valid:
|
||||
return
|
||||
if not int(self.active_op.info.duration * 60) > 0:
|
||||
return
|
||||
|
||||
active_op_time_text = "Operation Time: %d s " % int(active_op.duration*60)
|
||||
if active_op.duration > 60:
|
||||
active_op_time_text += " (%dh %dmin)" % (int(active_op.duration / 60), round(active_op.duration % 60))
|
||||
elif active_op.duration > 1:
|
||||
active_op_time_text += " (%dmin)" % round(active_op.duration % 60)
|
||||
time_estimate = f"Operation Time: {int(self.active_op.info.duration*60)}s "
|
||||
if self.active_op.info.duration > 60:
|
||||
time_estimate += f" ({int(self.active_op.info.duration / 60)}h"
|
||||
time_estimate += f" {round(self.active_op.info.duration % 60)}min)"
|
||||
elif self.active_op.info.duration > 1:
|
||||
time_estimate += f" ({round(self.active_op.info.duration % 60)}min)"
|
||||
|
||||
self.layout.label(text = active_op_time_text)
|
||||
self.layout.label(text=time_estimate)
|
||||
|
||||
self.layout.label(text="Chipload: %s/tooth" % strInUnits(active_op.chipload, 4))
|
||||
# Display the chipload (does this work ?)
|
||||
def draw_active_op_chipload(self):
|
||||
if self.active_op is None:
|
||||
return
|
||||
if not self.active_op.valid:
|
||||
return
|
||||
if not self.active_op.info.chipload > 0:
|
||||
return
|
||||
|
||||
chipload = f"Chipload: {strInUnits(self.active_op.info.chipload, 4)}/tooth"
|
||||
self.layout.label(text=chipload)
|
||||
|
||||
# Display the current operation money cost
|
||||
def draw_active_op_money_cost(self):
|
||||
active_op = self.active_operation()
|
||||
if active_op is None: return
|
||||
if not active_op.valid: return
|
||||
if not int(active_op.duration*60) > 0: return
|
||||
if self.active_op is None or not self.active_op.valid:
|
||||
return
|
||||
if not int(self.active_op.info.duration * 60) > 0:
|
||||
return
|
||||
|
||||
# TODO: the hourly_rate button properties should be moved here (UI related only)
|
||||
# Right now, trying to do so causes an error
|
||||
self.layout.prop(self.scene.cam_machine, 'hourly_rate')
|
||||
row = self.layout.row()
|
||||
row.label(text='Hourly Rate')
|
||||
row.prop(bpy.context.scene.cam_machine, 'hourly_rate', text='')
|
||||
|
||||
if float(self.scene.cam_machine.hourly_rate) < 0.01: return
|
||||
if float(bpy.context.scene.cam_machine.hourly_rate) < 0.01:
|
||||
return
|
||||
|
||||
cost_per_second = self.scene.cam_machine.hourly_rate / 3600
|
||||
self.layout.label(text = "Operation cost: $%.2f (%.2f $/s)"
|
||||
% (active_op.duration * 60 * cost_per_second, cost_per_second)
|
||||
)
|
||||
cost_per_second = bpy.context.scene.cam_machine.hourly_rate / 3600
|
||||
total_cost = self.active_op.info.duration * 60 * cost_per_second
|
||||
op_cost = f"Operation cost: ${total_cost:.2f} (${cost_per_second:.2f}/s)"
|
||||
self.layout.label(text=op_cost)
|
||||
|
|
|
@ -1,36 +1,127 @@
|
|||
|
||||
import bpy
|
||||
from cam.ui_panels.buttons_panel import CAMButtonsPanel
|
||||
import cam.utils
|
||||
import cam.constants
|
||||
|
||||
|
||||
class CAM_MATERIAL_Properties(bpy.types.PropertyGroup):
|
||||
|
||||
estimate_from_model: bpy.props.BoolProperty(
|
||||
name="Estimate cut area from model",
|
||||
description="Estimate cut area based on model geometry",
|
||||
default=True,
|
||||
update=cam.utils.update_material
|
||||
)
|
||||
|
||||
radius_around_model: bpy.props.FloatProperty(
|
||||
name='Radius around model',
|
||||
description="Increase cut area around the model on X and Y by this amount",
|
||||
default=0.0, unit='LENGTH', precision=cam.constants.PRECISION,
|
||||
update=cam.utils.update_material
|
||||
)
|
||||
|
||||
center_x: bpy.props.BoolProperty(
|
||||
name="Center on X axis",
|
||||
description="Position model centered on X",
|
||||
default=False, update=cam.utils.update_material
|
||||
)
|
||||
|
||||
center_y: bpy.props.BoolProperty(
|
||||
name="Center on Y axis",
|
||||
description="Position model centered on Y",
|
||||
default=False, update=cam.utils.update_material
|
||||
)
|
||||
|
||||
z_position: bpy.props.EnumProperty(
|
||||
name="Z placement", items=(
|
||||
('ABOVE', 'Above', 'Place object vertically above the XY plane'),
|
||||
('BELOW', 'Below', 'Place object vertically below the XY plane'),
|
||||
('CENTERED', 'Centered', 'Place object vertically centered on the XY plane')),
|
||||
description="Position below Zero", default='BELOW',
|
||||
update=cam.utils.update_material
|
||||
)
|
||||
|
||||
# material_origin
|
||||
origin: bpy.props.FloatVectorProperty(
|
||||
name='Material origin', default=(0, 0, 0), unit='LENGTH',
|
||||
precision=cam.constants.PRECISION, subtype="XYZ",
|
||||
update=cam.utils.update_material
|
||||
)
|
||||
|
||||
# material_size
|
||||
size: bpy.props.FloatVectorProperty(
|
||||
name='Material size', default=(0.200, 0.200, 0.100), min=0, unit='LENGTH',
|
||||
precision=cam.constants.PRECISION, subtype="XYZ",
|
||||
update=cam.utils.update_material
|
||||
)
|
||||
|
||||
|
||||
# Position object for CAM operation. Tests object bounds and places them so the object
|
||||
# is aligned to be positive from x and y and negative from z."""
|
||||
class CAM_MATERIAL_PositionObject(bpy.types.Operator):
|
||||
|
||||
bl_idname = "object.material_cam_position"
|
||||
bl_label = "position object for CAM operation"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
s = bpy.context.scene
|
||||
operation = s.cam_operations[s.cam_active_operation]
|
||||
if operation.object_name in bpy.data.objects:
|
||||
cam.utils.positionObject(operation)
|
||||
else:
|
||||
print('no object assigned')
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
self.layout.prop_search(self, "operation", bpy.context.scene, "cam_operations")
|
||||
|
||||
|
||||
class CAM_MATERIAL_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM material panel"""
|
||||
bl_label = "CAM Material size and position"
|
||||
bl_idname = "WORLD_PT_CAM_MATERIAL"
|
||||
|
||||
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:
|
||||
layout.template_running_jobs()
|
||||
if ao.geometry_source in ['OBJECT', 'COLLECTION']:
|
||||
layout.prop(ao, 'material_from_model')
|
||||
if self.active_op is None:
|
||||
return
|
||||
|
||||
if ao.material_from_model:
|
||||
layout.prop(ao, 'material_radius_around_model')
|
||||
else:
|
||||
layout.prop(ao, 'material_origin')
|
||||
layout.prop(ao, 'material_size')
|
||||
# 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()
|
||||
|
||||
layout.prop(ao, 'material_center_x')
|
||||
layout.prop(ao, 'material_center_y')
|
||||
layout.prop(ao, 'material_Z')
|
||||
layout.operator("object.cam_position", text="Position object")
|
||||
else:
|
||||
layout.label(text='Estimated from image')
|
||||
if self.active_op.geometry_source not in ['OBJECT', 'COLLECTION']:
|
||||
self.layout.label(text='Estimated from image')
|
||||
return
|
||||
|
||||
self.layout.prop(self.active_op.material, 'estimate_from_model')
|
||||
|
||||
if self.active_op.material.estimate_from_model:
|
||||
self.draw_estimate_material_from_model()
|
||||
else:
|
||||
self.draw_custom_material_size_and_origin()
|
||||
|
||||
self.draw_axis_alignment()
|
||||
|
||||
# Display section selecting the radius around the model
|
||||
def draw_estimate_material_from_model(self):
|
||||
row_radius = self.layout.row()
|
||||
row_radius.label(text="Additional radius")
|
||||
row_radius.prop(self.active_op.material, 'radius_around_model', text='')
|
||||
|
||||
# Display section showing custom material size
|
||||
def draw_custom_material_size_and_origin(self):
|
||||
self.layout.prop(self.active_op.material, 'origin')
|
||||
self.layout.prop(self.active_op.material, 'size')
|
||||
|
||||
# Display Axis alignment section
|
||||
def draw_axis_alignment(self):
|
||||
row_axis = self.layout.row()
|
||||
row_axis.prop(self.active_op.material, 'center_x')
|
||||
row_axis.prop(self.active_op.material, 'center_y')
|
||||
self.layout.prop(self.active_op.material, 'z_position')
|
||||
self.layout.operator("object.material_cam_position", text="Position object")
|
||||
|
|
|
@ -90,7 +90,7 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
|
||||
elif ao.strategy == 'WATERLINE':
|
||||
layout.label(text="OCL doesn't support fill areas")
|
||||
if not ao.use_opencamlib:
|
||||
if not ao.optimisation.use_opencamlib:
|
||||
layout.prop(ao, 'slice_detail')
|
||||
layout.prop(ao, 'waterline_fill')
|
||||
if ao.waterline_fill:
|
||||
|
|
|
@ -21,27 +21,23 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
|
||||
# Main draw function
|
||||
def draw(self, context):
|
||||
self.context = context
|
||||
self.draw_operations_list()
|
||||
|
||||
# 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
|
||||
if self.active_op is None: return
|
||||
|
||||
self.draw_presets()
|
||||
|
||||
self.draw_output_buttons()
|
||||
|
||||
layout = self.layout
|
||||
sub = layout.column()
|
||||
sub.active = not ao.computing
|
||||
sub = self.layout.column()
|
||||
sub.active = not self.active_op.computing
|
||||
|
||||
# Draw operation name and filename
|
||||
sub.prop(ao, 'name')
|
||||
sub.prop(ao, 'filename')
|
||||
sub.prop(self.active_op, 'name')
|
||||
sub.prop(self.active_op, 'filename')
|
||||
|
||||
self.draw_operation_source()
|
||||
self.draw_operation_options()
|
||||
|
@ -51,7 +47,7 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
# 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')
|
||||
row.template_list("CAM_UL_operations", '', bpy.context.scene, "cam_operations", bpy.context.scene, 'cam_active_operation')
|
||||
col = row.column(align=True)
|
||||
col.operator("scene.cam_operation_add", icon='ADD', text="")
|
||||
col.operator("scene.cam_operation_copy", icon='COPYDOWN', text="")
|
||||
|
@ -71,58 +67,53 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
|
||||
# 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)
|
||||
if self.active_op.computing:
|
||||
row = self.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:
|
||||
name = "cam_path_{}".format(ao.name)
|
||||
if self.scene.objects.get(name) is not None:
|
||||
layout.operator("object.cam_export", text="Export Gcode ")
|
||||
layout.operator("object.cam_simulate", text="Simulate this operation")
|
||||
if self.active_op.valid:
|
||||
self.layout.operator("object.calculate_cam_path", text="Calculate path & export Gcode")
|
||||
if self.active_op.name is not None:
|
||||
name = "cam_path_{}".format(self.active_op.name)
|
||||
if bpy.context.scene.objects.get(name) is not None:
|
||||
self.layout.operator("object.cam_export", text="Export Gcode ")
|
||||
self.layout.operator("object.cam_simulate", text="Simulate this operation")
|
||||
else:
|
||||
layout.label(text="operation invalid, can't compute")
|
||||
self.layout.label(text="operation invalid, can't compute")
|
||||
|
||||
|
||||
# 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')
|
||||
self.layout.prop(self.active_op, 'geometry_source')
|
||||
|
||||
if ao.strategy == 'CURVE':
|
||||
if ao.geometry_source == 'OBJECT':
|
||||
layout.prop_search(ao, "object_name", bpy.data, "objects")
|
||||
elif ao.geometry_source == 'COLLECTION':
|
||||
layout.prop_search(ao, "collection_name", bpy.data, "collections")
|
||||
if self.active_op.strategy == 'CURVE':
|
||||
if self.active_op.geometry_source == 'OBJECT':
|
||||
self.layout.prop_search(self.active_op, "object_name", bpy.data, "objects")
|
||||
elif self.active_op.geometry_source == 'COLLECTION':
|
||||
self.layout.prop_search(self.active_op, "collection_name", bpy.data, "collections")
|
||||
else:
|
||||
if ao.geometry_source == 'OBJECT':
|
||||
layout.prop_search(ao, "object_name", bpy.data, "objects")
|
||||
if ao.enable_A:
|
||||
layout.prop(ao, 'rotation_A')
|
||||
if ao.enable_B:
|
||||
layout.prop(ao, 'rotation_B')
|
||||
if self.active_op.geometry_source == 'OBJECT':
|
||||
self.layout.prop_search(self.active_op, "object_name", bpy.data, "objects")
|
||||
if self.active_op.enable_A:
|
||||
self.layout.prop(self.active_op, 'rotation_A')
|
||||
if self.active_op.enable_B:
|
||||
self.layout.prop(self.active_op, 'rotation_B')
|
||||
|
||||
elif ao.geometry_source == 'COLLECTION':
|
||||
layout.prop_search(ao, "collection_name", bpy.data, "collections")
|
||||
elif self.active_op.geometry_source == 'COLLECTION':
|
||||
self.layout.prop_search(self.active_op, "collection_name", bpy.data, "collections")
|
||||
else:
|
||||
layout.prop_search(ao, "source_image_name", bpy.data, "images")
|
||||
self.layout.prop_search(self.active_op, "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")
|
||||
if self.active_op.strategy in ['CARVE', 'PROJECTED_CURVE']:
|
||||
self.layout.prop_search(self.active_op, "curve_object", bpy.data, "objects")
|
||||
if self.active_op.strategy == 'PROJECTED_CURVE':
|
||||
self.layout.prop_search(self.active_op, "curve_object1", bpy.data, "objects")
|
||||
|
||||
# Draw Operation options:
|
||||
# Remove redundant points (optimizes operation)
|
||||
|
@ -131,20 +122,18 @@ class CAM_OPERATIONS_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
# Parent path to object (?)
|
||||
|
||||
def draw_operation_options(self):
|
||||
layout = self.layout
|
||||
ao = self.active_operation()
|
||||
|
||||
# TODO This should be in some optimization menu
|
||||
if ao.strategy != 'DRILL':
|
||||
layout.prop(ao, 'remove_redundant_points')
|
||||
if self.active_op.strategy != 'DRILL':
|
||||
self.layout.prop(self.active_op, '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 self.active_op.remove_redundant_points:
|
||||
self.layout.label(text='Revise your Code before running!')
|
||||
self.layout.label(text='Quality will suffer if tolerance')
|
||||
self.layout.label(text='is high')
|
||||
self.layout.prop(self.active_op, 'simplify_tol')
|
||||
|
||||
if ao.geometry_source in ['OBJECT', 'COLLECTION']:
|
||||
layout.prop(ao, 'use_modifiers')
|
||||
layout.prop(ao, 'hide_all_others')
|
||||
layout.prop(ao, 'parent_path_to_object')
|
||||
if self.active_op.geometry_source in ['OBJECT', 'COLLECTION']:
|
||||
self.layout.prop(self.active_op, 'use_modifiers')
|
||||
self.layout.prop(self.active_op, 'hide_all_others')
|
||||
self.layout.prop(self.active_op, 'parent_path_to_object')
|
||||
|
|
|
@ -1,5 +1,51 @@
|
|||
import bpy
|
||||
from cam.ui_panels.buttons_panel import CAMButtonsPanel
|
||||
import cam.utils
|
||||
import cam.constants
|
||||
|
||||
|
||||
class CAM_OPTIMISATION_Properties(bpy.types.PropertyGroup):
|
||||
|
||||
optimize: bpy.props.BoolProperty(
|
||||
name="Reduce path points", description="Reduce path points", default=True,
|
||||
update=cam.utils.update_operation)
|
||||
|
||||
optimize_threshold: bpy.props.FloatProperty(
|
||||
name="Reduction threshold in μm", default=.2, min=0.000000001,
|
||||
max=1000, precision=20, update=cam.utils.update_operation)
|
||||
|
||||
use_exact: bpy.props.BoolProperty(
|
||||
name="Use exact mode",
|
||||
description="Exact mode allows greater precision, but is slower with complex meshes",
|
||||
default=True, update=cam.utils.update_exact_mode)
|
||||
|
||||
imgres_limit: bpy.props.IntProperty(
|
||||
name="Maximum resolution in megapixels", default=16, min=1, max=512,
|
||||
description="Limits total memory usage and prevents crashes. Increase it if you know what are doing",
|
||||
update=cam.utils.update_zbuffer_image)
|
||||
|
||||
pixsize: bpy.props.FloatProperty(
|
||||
name="sampling raster detail", default=0.0001, min=0.00001, max=0.1,
|
||||
precision=cam.constants.PRECISION, unit="LENGTH", update=cam.utils.update_zbuffer_image)
|
||||
|
||||
use_opencamlib: bpy.props.BoolProperty(
|
||||
name="Use OpenCAMLib",
|
||||
description="Use OpenCAMLib to sample paths or get waterline shape",
|
||||
default=False, update=cam.utils.update_opencamlib)
|
||||
|
||||
exact_subdivide_edges: bpy.props.BoolProperty(
|
||||
name="Auto subdivide long edges",
|
||||
description="This can avoid some collision issues when importing CAD models",
|
||||
default=False, update=cam.utils.update_exact_mode)
|
||||
|
||||
circle_detail: bpy.props.IntProperty(
|
||||
name="Detail of circles used for curve offsets", default=64, min=12, max=512,
|
||||
update=cam.utils.update_operation)
|
||||
|
||||
simulation_detail: bpy.props.FloatProperty(
|
||||
name="Simulation sampling raster detail", default=0.0002, min=0.00001,
|
||||
max=0.01, precision=cam.constants.PRECISION, unit="LENGTH", update=cam.utils.update_operation)
|
||||
|
||||
|
||||
class CAM_OPTIMISATION_Panel(CAMButtonsPanel, bpy.types.Panel):
|
||||
"""CAM optimisation panel"""
|
||||
|
@ -9,42 +55,77 @@ class CAM_OPTIMISATION_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
COMPAT_ENGINES = {'BLENDERCAM_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = bpy.context.scene
|
||||
if self.active_op is None:
|
||||
return
|
||||
if not self.active_op.valid:
|
||||
return
|
||||
|
||||
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', 'CUTOUT', 'DRILL', 'PENCIL',
|
||||
'CURVE']
|
||||
if not exclude_exact:
|
||||
layout.prop(ao, 'use_exact')
|
||||
layout.label(text="Exact mode must be set for opencamlib to work ")
|
||||
self.draw_optimize()
|
||||
self.layout.separator()
|
||||
self.draw_exact_mode()
|
||||
self.draw_use_opencamlib()
|
||||
self.layout.separator()
|
||||
self.draw_simulation_detail()
|
||||
|
||||
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')
|
||||
def draw_optimize(self):
|
||||
if self.active_op is None:
|
||||
return
|
||||
if not self.active_op.valid:
|
||||
return
|
||||
|
||||
if exclude_exact or not ao.use_exact:
|
||||
layout.prop(ao, 'pixsize')
|
||||
layout.prop(ao, 'imgres_limit')
|
||||
self.layout.prop(self.active_op.optimisation, 'optimize')
|
||||
if self.active_op.optimisation.optimize:
|
||||
self.layout.prop(self.active_op.optimisation, 'optimize_threshold')
|
||||
|
||||
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)
|
||||
def draw_exact_mode(self):
|
||||
if self.active_op is None:
|
||||
return
|
||||
if not self.active_op.valid:
|
||||
return
|
||||
|
||||
layout.prop(ao, 'simulation_detail')
|
||||
layout.prop(ao, 'circle_detail')
|
||||
if not self.active_op.geometry_source == 'OBJECT' or self.active_op.geometry_source == 'COLLECTION':
|
||||
return
|
||||
|
||||
self.exact_possible = self.active_op.strategy not in [
|
||||
'MEDIAL_AXIS', 'POCKET', 'CUTOUT', 'DRILL', 'PENCIL', 'CURVE']
|
||||
|
||||
if self.exact_possible:
|
||||
self.layout.prop(self.active_op.optimisation, 'use_exact')
|
||||
|
||||
if not self.exact_possible or not self.active_op.optimisation.use_exact:
|
||||
self.layout.prop(self.active_op.optimisation, 'pixsize')
|
||||
self.layout.prop(self.active_op.optimisation, 'imgres_limit')
|
||||
|
||||
sx = self.active_op.max.x - self.active_op.min.x
|
||||
sy = self.active_op.max.y - self.active_op.min.y
|
||||
resx = int(sx / self.active_op.optimisation.pixsize)
|
||||
resy = int(sy / self.active_op.optimisation.pixsize)
|
||||
|
||||
if resx > 0 and resy > 0:
|
||||
resolution = 'Resolution: ' + str(resx) + ' x ' + str(resy)
|
||||
self.layout.label(text=resolution)
|
||||
|
||||
def draw_use_opencamlib(self):
|
||||
if self.active_op is None:
|
||||
return
|
||||
if not self.active_op.valid:
|
||||
return
|
||||
if not (self.exact_possible and self.active_op.optimisation.use_exact):
|
||||
return
|
||||
|
||||
opencamlib_version = cam.utils.opencamlib_version()
|
||||
|
||||
if opencamlib_version is None:
|
||||
self.layout.label(text="Opencamlib is not available ")
|
||||
self.layout.prop(self.active_op.optimisation, 'exact_subdivide_edges')
|
||||
else:
|
||||
self.layout.prop(self.active_op.optimisation, 'use_opencamlib')
|
||||
|
||||
def draw_simulation_detail(self):
|
||||
if self.active_op is None:
|
||||
return
|
||||
if not self.active_op.valid:
|
||||
return
|
||||
|
||||
self.layout.prop(self.active_op.optimisation, 'simulation_detail')
|
||||
self.layout.prop(self.active_op.optimisation, 'circle_detail')
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
# blender CAM utils.py (c) 2012 Vilem Novak
|
||||
#
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
|
@ -53,6 +54,49 @@ from shapely import geometry as sgeometry
|
|||
SHAPELY = True
|
||||
|
||||
|
||||
# The following functions are temporary
|
||||
# until all content in __init__.py is cleaned up
|
||||
|
||||
def update_material(self, context):
|
||||
addMaterialAreaObject()
|
||||
|
||||
def update_operation(self, context):
|
||||
from . import updateRest
|
||||
active_op = bpy.context.scene.cam_operations[bpy.context.scene.cam_active_operation]
|
||||
updateRest(active_op, bpy.context)
|
||||
|
||||
def update_exact_mode(self, context):
|
||||
from . import updateExact
|
||||
active_op = bpy.context.scene.cam_operations[bpy.context.scene.cam_active_operation]
|
||||
updateExact(active_op, bpy.context)
|
||||
|
||||
def update_opencamlib(self, context):
|
||||
from . import updateOpencamlib
|
||||
active_op = bpy.context.scene.cam_operations[bpy.context.scene.cam_active_operation]
|
||||
updateOpencamlib(active_op, bpy.context)
|
||||
|
||||
def update_zbuffer_image(self, context):
|
||||
from . import updateZbufferImage
|
||||
active_op = bpy.context.scene.cam_operations[bpy.context.scene.cam_active_operation]
|
||||
updateZbufferImage(active_op, bpy.context)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Import OpencamLib
|
||||
# Return available OpenCamLib version on success, None otherwise
|
||||
def opencamlib_version():
|
||||
try:
|
||||
import ocl
|
||||
except ImportError:
|
||||
try:
|
||||
import opencamlib as ocl
|
||||
except ImportError as e:
|
||||
return
|
||||
return(ocl.version())
|
||||
|
||||
def positionObject(operation):
|
||||
ob = bpy.data.objects[operation.object_name]
|
||||
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS')
|
||||
|
@ -63,21 +107,21 @@ def positionObject(operation):
|
|||
totx = maxx - minx
|
||||
toty = maxy - miny
|
||||
totz = maxz - minz
|
||||
if operation.material_center_x:
|
||||
if operation.material.center_x:
|
||||
ob.location.x -= minx + totx / 2
|
||||
else:
|
||||
ob.location.x -= minx
|
||||
|
||||
if operation.material_center_y:
|
||||
if operation.material.center_y:
|
||||
ob.location.y -= miny + toty / 2
|
||||
else:
|
||||
ob.location.y -= miny
|
||||
|
||||
if operation.material_Z == 'BELOW':
|
||||
if operation.material.z_position == 'BELOW':
|
||||
ob.location.z -= maxz
|
||||
elif operation.material_Z == 'ABOVE':
|
||||
elif operation.material.z_position == 'ABOVE':
|
||||
ob.location.z -= minz
|
||||
elif operation.material_Z == 'CENTERED':
|
||||
elif operation.material.z_position == 'CENTERED':
|
||||
ob.location.z -= minz + totz / 2
|
||||
|
||||
if ob.type != 'CURVE':
|
||||
|
@ -225,7 +269,7 @@ def getOperationSources(o):
|
|||
collection = bpy.data.collections[o.collection_name]
|
||||
o.objects = collection.objects
|
||||
elif o.geometry_source == 'IMAGE':
|
||||
o.use_exact = False
|
||||
o.optimisation.use_exact = False
|
||||
|
||||
if o.geometry_source == 'OBJECT' or o.geometry_source == 'COLLECTION':
|
||||
o.onlycurves = True
|
||||
|
@ -252,23 +296,23 @@ def getBounds(o):
|
|||
o.min.z = o.minz # max(bb[0][2]+l.z,o.minz)#
|
||||
print("not minz from object")
|
||||
|
||||
if o.material_from_model:
|
||||
print("material_from_model")
|
||||
if o.material.estimate_from_model:
|
||||
print("Estimate material from model")
|
||||
|
||||
o.min.x = minx - o.material_radius_around_model
|
||||
o.min.y = miny - o.material_radius_around_model
|
||||
o.min.x = minx - o.material.radius_around_model
|
||||
o.min.y = miny - o.material.radius_around_model
|
||||
o.max.z = max(o.maxz, maxz)
|
||||
|
||||
o.max.x = maxx + o.material_radius_around_model
|
||||
o.max.y = maxy + o.material_radius_around_model
|
||||
o.max.x = maxx + o.material.radius_around_model
|
||||
o.max.y = maxy + o.material.radius_around_model
|
||||
else:
|
||||
print("not material from model")
|
||||
o.min.x = o.material_origin.x
|
||||
o.min.y = o.material_origin.y
|
||||
o.min.z = o.material_origin.z - o.material_size.z
|
||||
o.max.x = o.min.x + o.material_size.x
|
||||
o.max.y = o.min.y + o.material_size.y
|
||||
o.max.z = o.material_origin.z
|
||||
o.min.x = o.material.origin.x
|
||||
o.min.y = o.material.origin.y
|
||||
o.min.z = o.material.origin.z - o.material.size.z
|
||||
o.max.x = o.min.x + o.material.size.x
|
||||
o.max.y = o.min.y + o.material.size.y
|
||||
o.max.z = o.material.origin.z
|
||||
|
||||
else:
|
||||
i = bpy.data.images[o.source_image_name]
|
||||
|
@ -283,19 +327,19 @@ def getBounds(o):
|
|||
sy = 0
|
||||
ey = i.size[1]
|
||||
|
||||
o.pixsize = o.source_image_size_x / i.size[0]
|
||||
o.optimisation.pixsize = o.source_image_size_x / i.size[0]
|
||||
|
||||
o.min.x = o.source_image_offset.x + sx * o.pixsize
|
||||
o.max.x = o.source_image_offset.x + ex * o.pixsize
|
||||
o.min.y = o.source_image_offset.y + sy * o.pixsize
|
||||
o.max.y = o.source_image_offset.y + ey * o.pixsize
|
||||
o.min.x = o.source_image_offset.x + sx * o.optimisation.pixsize
|
||||
o.max.x = o.source_image_offset.x + ex * o.optimisation.pixsize
|
||||
o.min.y = o.source_image_offset.y + sy * o.optimisation.pixsize
|
||||
o.max.y = o.source_image_offset.y + ey * o.optimisation.pixsize
|
||||
o.min.z = o.source_image_offset.z + o.minz
|
||||
o.max.z = o.source_image_offset.z
|
||||
s = bpy.context.scene
|
||||
m = s.cam_machine
|
||||
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.warnings += 'Operation exceeds your machine limits\n'
|
||||
o.info.warnings += 'Operation exceeds your machine limits\n'
|
||||
|
||||
|
||||
def getBoundsMultiple(operations):
|
||||
|
@ -333,10 +377,10 @@ def samplePathLow(o, ch1, ch2, dosample):
|
|||
bpath.points.append([p.x, p.y, p.z])
|
||||
# print('between path')
|
||||
# print(len(bpath))
|
||||
pixsize = o.pixsize
|
||||
pixsize = o.optimisation.pixsize
|
||||
if dosample:
|
||||
if not (o.use_opencamlib and o.use_exact):
|
||||
if o.use_exact:
|
||||
if not (o.optimisation.use_opencamlib and o.optimisation.use_exact):
|
||||
if o.optimisation.use_exact:
|
||||
if o.update_bullet_collision_tag:
|
||||
prepareBulletCollision(o)
|
||||
o.update_bullet_collision_tag = False
|
||||
|
@ -363,8 +407,8 @@ def sampleChunks(o, pathSamples, layers):
|
|||
minx, miny, minz, maxx, maxy, maxz = o.min.x, o.min.y, o.min.z, o.max.x, o.max.y, o.max.z
|
||||
getAmbient(o)
|
||||
|
||||
if o.use_exact: # prepare collision world
|
||||
if o.use_opencamlib:
|
||||
if o.optimisation.use_exact: # prepare collision world
|
||||
if o.optimisation.use_opencamlib:
|
||||
oclSample(o, pathSamples)
|
||||
cutterdepth = 0
|
||||
else:
|
||||
|
@ -379,11 +423,11 @@ def sampleChunks(o, pathSamples, layers):
|
|||
if o.strategy != 'WATERLINE': # or prepare offset image, but not in some strategies.
|
||||
prepareArea(o)
|
||||
|
||||
pixsize = o.pixsize
|
||||
pixsize = o.optimisation.pixsize
|
||||
|
||||
coordoffset = o.borderwidth + pixsize / 2 # -m
|
||||
|
||||
res = ceil(o.cutter_diameter / o.pixsize)
|
||||
res = ceil(o.cutter_diameter / o.optimisation.pixsize)
|
||||
m = res / 2
|
||||
|
||||
t = time.time()
|
||||
|
@ -436,13 +480,13 @@ def sampleChunks(o, pathSamples, layers):
|
|||
if not o.ambient.contains(sgeometry.Point(x, y)):
|
||||
newsample = (x, y, 1)
|
||||
else:
|
||||
if o.use_opencamlib and o.use_exact:
|
||||
if o.optimisation.use_opencamlib and o.optimisation.use_exact:
|
||||
z = s[2]
|
||||
if minz > z:
|
||||
z = minz
|
||||
newsample = (x, y, z)
|
||||
# ampling
|
||||
elif o.use_exact and not o.use_opencamlib:
|
||||
elif o.optimisation.use_exact and not o.optimisation.use_opencamlib:
|
||||
|
||||
if lastsample is not None: # this is an optimalization,
|
||||
# search only for near depths to the last sample. Saves about 30% of sampling time.
|
||||
|
@ -985,7 +1029,7 @@ def connectChunksLow(chunks, o):
|
|||
# print('addbetwee')
|
||||
between = samplePathLow(o, lastch, ch,
|
||||
False) # other paths either dont use sampling or are sorted before it.
|
||||
if o.use_opencamlib and o.use_exact and (
|
||||
if o.optimisation.use_opencamlib and o.optimisation.use_exact and (
|
||||
o.strategy == 'PARALLEL' or o.strategy == 'CROSS' or o.strategy == 'PENCIL'):
|
||||
chunks_to_resample.append(
|
||||
(connectedchunks[-1], len(connectedchunks[-1].points), len(between.points)))
|
||||
|
@ -997,7 +1041,7 @@ def connectChunksLow(chunks, o):
|
|||
lastch = ch
|
||||
pos = lastch.points[-1]
|
||||
|
||||
if o.use_opencamlib and o.use_exact and o.strategy != 'CUTOUT' and o.strategy != 'POCKET':
|
||||
if o.optimisation.use_opencamlib and o.optimisation.use_exact and o.strategy != 'CUTOUT' and o.strategy != 'POCKET':
|
||||
oclResampleChunks(o, chunks_to_resample)
|
||||
|
||||
return connectedchunks
|
||||
|
@ -1296,7 +1340,7 @@ def getAmbient(o):
|
|||
o.limit_poly = shapely.ops.unary_union(polys)
|
||||
|
||||
if o.ambient_cutter_restrict:
|
||||
o.limit_poly = o.limit_poly.buffer(o.cutter_diameter / 2, resolution=o.circle_detail)
|
||||
o.limit_poly = o.limit_poly.buffer(o.cutter_diameter / 2, resolution=o.optimisation.circle_detail)
|
||||
o.ambient = o.ambient.intersection(o.limit_poly)
|
||||
o.update_ambient_tag = False
|
||||
|
||||
|
@ -1330,7 +1374,7 @@ def getObjectOutline(radius, o, Offset): # FIXME: make this one operation indep
|
|||
# print(p1.type, len(polygons))
|
||||
i += 1
|
||||
if radius > 0:
|
||||
p1 = p1.buffer(radius * offset, resolution=o.circle_detail, join_style=join, mitre_limit=2)
|
||||
p1 = p1.buffer(radius * offset, resolution=o.optimisation.circle_detail, join_style=join, mitre_limit=2)
|
||||
outlines.append(p1)
|
||||
|
||||
# print(outlines)
|
||||
|
@ -1405,6 +1449,7 @@ def addMachineAreaObject():
|
|||
o = s.objects['CAM_machine']
|
||||
else:
|
||||
oldunits = s.unit_settings.system
|
||||
oldLengthUnit = s.unit_settings.length_unit
|
||||
# need to be in metric units when adding machine mesh object
|
||||
# in order for location to work properly
|
||||
s.unit_settings.system = 'METRIC'
|
||||
|
@ -1431,6 +1476,7 @@ def addMachineAreaObject():
|
|||
o.hide_select = True
|
||||
# o.select = False
|
||||
s.unit_settings.system = oldunits
|
||||
s.unit_settings.length_unit = oldLengthUnit
|
||||
|
||||
# bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
|
||||
|
||||
|
@ -1440,7 +1486,6 @@ def addMachineAreaObject():
|
|||
# else:
|
||||
# bpy.context.scene.objects.active = None
|
||||
|
||||
|
||||
def addMaterialAreaObject():
|
||||
s = bpy.context.scene
|
||||
operation = s.cam_operations[s.cam_active_operation]
|
||||
|
@ -1670,8 +1715,8 @@ def reload_pathss(o):
|
|||
# print('sleep')
|
||||
# time.sleep(1)
|
||||
|
||||
o.warnings = d['warnings']
|
||||
o.duration = d['duration']
|
||||
o.info.warnings = d['warnings']
|
||||
o.info.duration = d['duration']
|
||||
verts = d['path']
|
||||
|
||||
edges = []
|
||||
|
|
Ładowanie…
Reference in New Issue