kopia lustrzana https://github.com/vilemduha/blendercam
802 wiersze
24 KiB
Python
802 wiersze
24 KiB
Python
# blender CAM ops.py (c) 2012 Vilem Novak
|
|
#
|
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
|
#
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# ***** END GPL LICENCE BLOCK *****
|
|
|
|
#blender operators definitions are in this file. They mostly call the functions from utils.py
|
|
|
|
import bpy
|
|
import subprocess,os, sys, threading
|
|
from cam import utils, pack,polygon_utils_cam,chunk,simple
|
|
from bpy.props import *
|
|
import Polygon
|
|
|
|
|
|
|
|
|
|
class threadCom:#object passed to threads to read background process stdout info
|
|
def __init__(self,o,proc):
|
|
self.opname=o.name
|
|
self.outtext=''
|
|
self.proc=proc
|
|
self.lasttext=''
|
|
|
|
def threadread( tcom):
|
|
'''reads stdout of background process, done this way to have it non-blocking'''
|
|
inline = tcom.proc.stdout.readline()
|
|
inline=str(inline)
|
|
s=inline.find('progress{')
|
|
if s>-1:
|
|
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'''
|
|
text=''
|
|
s=bpy.context.scene
|
|
if hasattr(bpy.ops.object.calculate_cam_paths_background.__class__,'cam_processes'):
|
|
processes=bpy.ops.object.calculate_cam_paths_background.__class__.cam_processes
|
|
for p in processes:
|
|
#proc=p[1].proc
|
|
readthread=p[0]
|
|
tcom=p[1]
|
|
if not readthread.is_alive():
|
|
readthread.join()
|
|
#readthread.
|
|
tcom.lasttext=tcom.outtext
|
|
if tcom.outtext!='':
|
|
print(tcom.opname,tcom.outtext)
|
|
tcom.outtext=''
|
|
|
|
if 'finished' in tcom.lasttext:
|
|
processes.remove(p)
|
|
|
|
o=s.cam_operations[tcom.opname]
|
|
o.computing=False;
|
|
utils.reload_paths(o)
|
|
update_zbufferimage_tag = False
|
|
update_offsetimage_tag = False
|
|
else:
|
|
readthread=threading.Thread(target=threadread, args = ([tcom]), daemon=True)
|
|
readthread.start()
|
|
p[0]=readthread
|
|
o=s.cam_operations[tcom.opname]#changes
|
|
o.outtext=tcom.lasttext#changes
|
|
#text=text+('# %s %s #' % (tcom.opname,tcom.lasttext))#CHANGES
|
|
#s.cam_text=text#changes
|
|
|
|
# commented out by NFZ: asking every property area to redraw
|
|
# causes my netbook to come to a crawl and cpu overheats
|
|
# need to find a better way of doing this
|
|
# doesn't effect normal path calculation when commented out
|
|
# maybe this should only be enabled when when background calc selected
|
|
#if bpy.context.screen!=None:
|
|
# for area in bpy.context.screen.areas:
|
|
# if area.type == 'PROPERTIES':
|
|
# area.tag_redraw()
|
|
|
|
class PathsBackground(bpy.types.Operator):
|
|
'''calculate CAM paths in background. File has to be saved before.'''
|
|
bl_idname = "object.calculate_cam_paths_background"
|
|
bl_label = "Calculate CAM paths in background"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
#processes=[]
|
|
|
|
#@classmethod
|
|
#def poll(cls, context):
|
|
# return context.active_object is not None
|
|
|
|
def execute(self, context):
|
|
s=bpy.context.scene
|
|
o=s.cam_operations[s.cam_active_operation]
|
|
self.operation=o
|
|
o.computing=True
|
|
#if bpy.data.is_dirty:
|
|
#bpy.ops.wm.save_mainfile()#this has to be replaced with passing argument or pickle stuff..
|
|
#picklepath=getCachePath(o)+'init.pickle'
|
|
|
|
bpath=bpy.app.binary_path
|
|
fpath=bpy.data.filepath
|
|
scriptpath=bpy.utils.script_paths()[0]+os.sep+'addons'+os.sep+'cam'+os.sep+'backgroundop.py_'
|
|
|
|
proc= subprocess.Popen([bpath, '-b', fpath,'-P',scriptpath,'--', '-o='+str(s.cam_active_operation) ],bufsize=1, stdout=subprocess.PIPE,stdin=subprocess.PIPE)
|
|
|
|
tcom=threadCom(o,proc)
|
|
readthread=threading.Thread(target=threadread, args = ([tcom]), daemon=True)
|
|
readthread.start()
|
|
#self.__class__.cam_processes=[]
|
|
if not hasattr(bpy.ops.object.calculate_cam_paths_background.__class__,'cam_processes'):
|
|
bpy.ops.object.calculate_cam_paths_background.__class__.cam_processes=[]
|
|
bpy.ops.object.calculate_cam_paths_background.__class__.cam_processes.append([readthread,tcom])
|
|
return {'FINISHED'}
|
|
|
|
class KillPathsBackground(bpy.types.Operator):
|
|
'''Remove CAM path processes in background.'''
|
|
bl_idname = "object.kill_calculate_cam_paths_background"
|
|
bl_label = "Kill background computation of an operation"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
#processes=[]
|
|
|
|
#@classmethod
|
|
#def poll(cls, context):
|
|
# return context.active_object is not None
|
|
|
|
def execute(self, context):
|
|
s=bpy.context.scene
|
|
o=s.cam_operations[s.cam_active_operation]
|
|
self.operation=o
|
|
|
|
|
|
if hasattr(bpy.ops.object.calculate_cam_paths_background.__class__,'cam_processes'):
|
|
processes=bpy.ops.object.calculate_cam_paths_background.__class__.cam_processes
|
|
for p in processes:
|
|
#proc=p[1].proc
|
|
#readthread=p[0]
|
|
tcom=p[1]
|
|
if tcom.opname==o.name:
|
|
processes.remove(p)
|
|
tcom.proc.kill()
|
|
o.computing=False
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
|
|
class CalculatePath(bpy.types.Operator):
|
|
'''calculate CAM paths'''
|
|
bl_idname = "object.calculate_cam_path"
|
|
bl_label = "Calculate CAM paths"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
#this property was actually ignored, so removing it in 0.3
|
|
#operation= StringProperty(name="Operation",
|
|
# description="Specify the operation to calculate",default='Operation')
|
|
|
|
def execute(self, context):
|
|
#getIslands(context.object)
|
|
s=bpy.context.scene
|
|
o = s.cam_operations[s.cam_active_operation]
|
|
|
|
if not o.valid:
|
|
self.report({'ERROR_INVALID_INPUT'}, "Operation can't be performed, see warnings for info")
|
|
#print("Operation can't be performed, see warnings for info")
|
|
return {'FINISHED'}
|
|
if o.computing:
|
|
return {'FINISHED'}
|
|
|
|
o.operator=self
|
|
|
|
if o.use_layers:
|
|
o.parallel_step_back = False
|
|
|
|
utils.getPath(context,o)
|
|
|
|
return {'FINISHED'}
|
|
|
|
class PathsAll(bpy.types.Operator):
|
|
'''calculate all CAM paths'''
|
|
bl_idname = "object.calculate_cam_paths_all"
|
|
bl_label = "Calculate all CAM paths"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
import bpy
|
|
i=0
|
|
for o in bpy.context.scene.cam_operations:
|
|
bpy.context.scene.cam_active_operation=i
|
|
print('\nCalculating path :'+o.name)
|
|
print('\n')
|
|
bpy.ops.object.calculate_cam_paths_background()
|
|
i+=1
|
|
|
|
return {'FINISHED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.prop_search(self, "operation", bpy.context.scene, "cam_operations")
|
|
|
|
class CamPackObjects(bpy.types.Operator):
|
|
'''calculate all CAM paths'''
|
|
bl_idname = "object.cam_pack_objects"
|
|
bl_label = "Pack curves on sheet"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
|
|
obs=bpy.context.selected_objects
|
|
pack.packCurves()
|
|
#layout.
|
|
return {'FINISHED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
class CamSliceObjects(bpy.types.Operator):
|
|
'''Slice a mesh object horizontally'''
|
|
#warning, this is a separate and neglected feature, it's a mess - by now it just slices up the object.
|
|
bl_idname = "object.cam_slice_objects"
|
|
bl_label = "Slice object - usefull for lasercut puzzles e.t.c."
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
from cam import slice
|
|
ob=bpy.context.active_object
|
|
slice.sliceObject(ob)
|
|
return {'FINISHED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
|
|
|
|
def getChainOperations(chain):
|
|
'''return chain operations, currently chain object can't store operations directly due to blender limitations'''
|
|
chop=[]
|
|
for cho in chain.operations:
|
|
for so in bpy.context.scene.cam_operations:
|
|
if so.name==cho.name:
|
|
chop.append(so)
|
|
return chop
|
|
|
|
class PathsChain(bpy.types.Operator):
|
|
'''calculate a chain and export the gcode alltogether. '''
|
|
bl_idname = "object.calculate_cam_paths_chain"
|
|
bl_label = "Calculate CAM paths in current chain and export chain gcode"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
import bpy
|
|
s=bpy.context.scene
|
|
|
|
chain=s.cam_chains[s.cam_active_chain]
|
|
chainops=getChainOperations(chain)
|
|
meshes=[]
|
|
for o in chainops:
|
|
#bpy.ops.object.calculate_cam_paths_background()
|
|
meshes.append(bpy.data.objects[o.path_object_name].data)
|
|
utils.exportGcodePath(chain.filename,meshes,chainops)
|
|
return {'FINISHED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.prop_search(self, "operation", bpy.context.scene, "cam_operations")
|
|
|
|
class PathExport(bpy.types.Operator):
|
|
'''Export gcode. Can be used only when the path object is present'''
|
|
bl_idname = "object.cam_export"
|
|
bl_label = "Export operation gcode"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
import bpy
|
|
s=bpy.context.scene
|
|
operation = s.cam_operations[s.cam_active_operation]
|
|
utils.exportGcodePath( operation.filename , [bpy.data.objects[operation.path_object_name].data] , [operation])
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CAMSimulate(bpy.types.Operator):
|
|
'''simulate CAM operation
|
|
this is performed by: creating an image, painting Z depth of the brush substractively. Works only for some operations, can not be used for 4-5 axis.'''
|
|
bl_idname = "object.cam_simulate"
|
|
bl_label = "CAM simulation"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
operation = StringProperty(name="Operation",
|
|
description="Specify the operation to calculate",default='Operation')
|
|
|
|
def execute(self, context):
|
|
s=bpy.context.scene
|
|
operation = s.cam_operations[s.cam_active_operation]
|
|
|
|
#if operation.geometry_source=='OBJECT' and operation.object_name in bpy.data.objects and #bpy.data.objects[operation.object_name].type=='CURVE':
|
|
# print('simulation of curve operations is not available')
|
|
# return {'FINISHED'}
|
|
if operation.path_object_name in bpy.data.objects:
|
|
utils.doSimulation(operation.name,[operation])
|
|
else:
|
|
print('no computed path to simulate')
|
|
return {'FINISHED'}
|
|
return {'FINISHED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.prop_search(self, "operation", bpy.context.scene, "cam_operations")
|
|
|
|
|
|
class CAMSimulateChain(bpy.types.Operator):
|
|
'''simulate CAM chain, compared to single op simulation just writes into one image and thus enables to see how ops work together.'''
|
|
bl_idname = "object.cam_simulate_chain"
|
|
bl_label = "CAM simulation"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
operation = StringProperty(name="Operation",
|
|
description="Specify the operation to calculate",default='Operation')
|
|
|
|
def execute(self, context):
|
|
s=bpy.context.scene
|
|
chain=s.cam_chains[s.cam_active_chain]
|
|
chainops=getChainOperations(chain)
|
|
|
|
canSimulate=True
|
|
for operation in chainops:
|
|
if not operation.path_object_name in bpy.data.objects:
|
|
canSimulate=False
|
|
if canSimulate:
|
|
utils.doSimulation(chain.name,chainops)
|
|
else:
|
|
print('no computed path to simulate')
|
|
return {'FINISHED'}
|
|
return {'FINISHED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.prop_search(self, "operation", bpy.context.scene, "cam_operations")
|
|
|
|
|
|
class CamChainAdd(bpy.types.Operator):
|
|
'''Add new CAM chain'''
|
|
bl_idname = "scene.cam_chain_add"
|
|
bl_label = "Add new CAM chain"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
#main(context)
|
|
s=bpy.context.scene
|
|
s.cam_chains.add()
|
|
chain=s.cam_chains[-1]
|
|
s.cam_active_chain=len(s.cam_chains)-1
|
|
chain.name='Chain_'+str(s.cam_active_chain+1)
|
|
chain.filename=chain.name
|
|
chain.index=s.cam_active_chain
|
|
|
|
return {'FINISHED'}
|
|
|
|
class CamChainRemove(bpy.types.Operator):
|
|
'''Remove CAM chain'''
|
|
bl_idname = "scene.cam_chain_remove"
|
|
bl_label = "Remove CAM chain"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
bpy.context.scene.cam_chains.remove(bpy.context.scene.cam_active_chain)
|
|
if bpy.context.scene.cam_active_chain>0:
|
|
bpy.context.scene.cam_active_chain-=1
|
|
|
|
return {'FINISHED'}
|
|
|
|
class CamChainOperationAdd(bpy.types.Operator):
|
|
'''Add operation to chain'''
|
|
bl_idname = "scene.cam_chain_operation_add"
|
|
bl_label = "Add operation to chain"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
s=bpy.context.scene
|
|
chain=s.cam_chains[s.cam_active_chain]
|
|
s=bpy.context.scene
|
|
#s.chaindata[chain.index].remove(chain.active_operation+1,s.cam_operations[s.cam_active_operation])
|
|
chain.operations.add()
|
|
chain.active_operation+=1
|
|
chain.operations[-1].name=s.cam_operations[s.cam_active_operation].name
|
|
return {'FINISHED'}
|
|
|
|
class CamChainOperationUp(bpy.types.Operator):
|
|
'''Add operation to chain'''
|
|
bl_idname = "scene.cam_chain_operation_up"
|
|
bl_label = "Add operation to chain"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
s=bpy.context.scene
|
|
chain=s.cam_chains[s.cam_active_chain]
|
|
a=chain.active_operation
|
|
if a>0:
|
|
chain.operations.move(a,a-1)
|
|
chain.active_operation-=1
|
|
return {'FINISHED'}
|
|
|
|
class CamChainOperationDown(bpy.types.Operator):
|
|
'''Add operation to chain'''
|
|
bl_idname = "scene.cam_chain_operation_down"
|
|
bl_label = "Add operation to chain"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
s=bpy.context.scene
|
|
chain=s.cam_chains[s.cam_active_chain]
|
|
a=chain.active_operation
|
|
if a<len(chain.operations)-1:
|
|
chain.operations.move(a,a+1)
|
|
chain.active_operation+=1
|
|
return {'FINISHED'}
|
|
|
|
class CamChainOperationRemove(bpy.types.Operator):
|
|
'''Remove operation from chain'''
|
|
bl_idname = "scene.cam_chain_operation_remove"
|
|
bl_label = "Remove operation from chain"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
#main(context)
|
|
s=bpy.context.scene
|
|
chain=s.cam_chains[s.cam_active_chain]
|
|
s=bpy.context.scene
|
|
#s.chaindata[chain.index].append(s.cam_operations[s.cam_active_operation])
|
|
chain.operations.remove(chain.active_operation)
|
|
chain.active_operation-=1
|
|
if chain.active_operation<0:
|
|
chain.active_operation = 0
|
|
return {'FINISHED'}
|
|
|
|
def fixUnits():
|
|
'''Sets up units for blender CAM'''
|
|
s=bpy.context.scene
|
|
# dhull: leave unit settings alone - may also need to comment out scale_length below
|
|
#if s.unit_settings.system=='NONE':#metric is hereby default
|
|
# s.unit_settings.system='METRIC'
|
|
|
|
s.unit_settings.system_rotation='DEGREES'
|
|
|
|
s.unit_settings.scale_length=1.0 # Blender CAM doesn't respect this property and there were users reporting problems, not seeing this was changed.
|
|
|
|
class CamOperationAdd(bpy.types.Operator):
|
|
'''Add new CAM operation'''
|
|
bl_idname = "scene.cam_operation_add"
|
|
bl_label = "Add new CAM operation"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
#main(context)
|
|
s=bpy.context.scene
|
|
|
|
fixUnits()
|
|
|
|
if s.objects.get('CAM_machine')==None:
|
|
utils.addMachineAreaObject()
|
|
#if len(s.cam_material)==0:
|
|
# s.cam_material.add()
|
|
|
|
s.cam_operations.add()
|
|
o=s.cam_operations[-1]
|
|
s.cam_active_operation=len(s.cam_operations)-1
|
|
o.name='Operation_'+str(s.cam_active_operation+1)
|
|
o.filename=o.name
|
|
ob=bpy.context.active_object
|
|
if ob!=None:
|
|
o.object_name=ob.name
|
|
minx,miny,minz,maxx,maxy,maxz=utils.getBoundsWorldspace([ob])
|
|
o.minz=minz
|
|
|
|
return {'FINISHED'}
|
|
|
|
class CamOperationCopy(bpy.types.Operator):
|
|
'''Copy CAM operation'''
|
|
bl_idname = "scene.cam_operation_copy"
|
|
bl_label = "Copy active CAM operation"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
#main(context)
|
|
s=bpy.context.scene
|
|
|
|
fixUnits()
|
|
|
|
s=bpy.context.scene
|
|
s.cam_operations.add()
|
|
copyop=s.cam_operations[s.cam_active_operation]
|
|
s.cam_active_operation+=1
|
|
l=len(s.cam_operations)-1
|
|
s.cam_operations.move(l,s.cam_active_operation)
|
|
o=s.cam_operations[s.cam_active_operation]
|
|
|
|
for k in copyop.keys():
|
|
o[k]=copyop[k]
|
|
o.computing=False
|
|
|
|
####get digits in the end
|
|
|
|
isdigit=True
|
|
numdigits=0
|
|
num=0
|
|
if o.name[-1].isdigit():
|
|
numdigits=1
|
|
while isdigit:
|
|
numdigits+=1
|
|
isdigit=o.name[-numdigits].isdigit()
|
|
numdigits-=1
|
|
o.name=o.name[:-numdigits]+str(int(o.name[-numdigits:])+1).zfill(numdigits)
|
|
o.filename=o.name
|
|
else:
|
|
o.name=o.name+'_copy'
|
|
o.filename=o.filename+'_copy'
|
|
|
|
return {'FINISHED'}
|
|
|
|
class CamOperationRemove(bpy.types.Operator):
|
|
'''Remove CAM operation'''
|
|
bl_idname = "scene.cam_operation_remove"
|
|
bl_label = "Remove CAM operation"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
#main(context)
|
|
bpy.context.scene.cam_operations.remove(bpy.context.scene.cam_active_operation)
|
|
if bpy.context.scene.cam_active_operation>0:
|
|
bpy.context.scene.cam_active_operation-=1
|
|
|
|
return {'FINISHED'}
|
|
|
|
#move cam operation in the list up or down
|
|
class CamOperationMove(bpy.types.Operator):
|
|
'''Move CAM operation'''
|
|
bl_idname = "scene.cam_operation_move"
|
|
bl_label = "Move CAM operation in list"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
direction = EnumProperty(name='direction',
|
|
items=(('UP','Up',''),('DOWN','Down','')),
|
|
description='direction',
|
|
default='DOWN')
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
#main(context)
|
|
a=bpy.context.scene.cam_active_operation
|
|
cops=bpy.context.scene.cam_operations
|
|
if self.direction=='UP':
|
|
if a>0:
|
|
cops.move(a,a-1)
|
|
bpy.context.scene.cam_active_operation -= 1
|
|
|
|
else:
|
|
if a<len(cops)-1:
|
|
cops.move(a,a+1)
|
|
bpy.context.scene.cam_active_operation += 1
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
|
|
class CamOrientationAdd(bpy.types.Operator):
|
|
'''Add orientation to cam operation, for multiaxis operations'''
|
|
bl_idname = "scene.cam_orientation_add"
|
|
bl_label = "Add orientation"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
#main(context)
|
|
s=bpy.context.scene
|
|
a=s.cam_active_operation
|
|
o=s.cam_operations[a]
|
|
gname=o.name+'_orientations'
|
|
bpy.ops.object.empty_add(type='ARROWS')
|
|
|
|
oriob=bpy.context.active_object
|
|
oriob.empty_draw_size=0.02 # 2 cm
|
|
|
|
simple.addToGroup(oriob,gname)
|
|
oriob.name='ori_'+o.name+'.'+str(len(bpy.data.groups[gname].objects)).zfill(3)
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class CamBridgeAdd(bpy.types.Operator):
|
|
'''Add orientation to cam operation, for multiaxis operations'''
|
|
bl_idname = "scene.cam_bridge_add"
|
|
bl_label = "Add bridge"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene is not None
|
|
|
|
def execute(self, context):
|
|
#main(context)
|
|
s=bpy.context.scene
|
|
a=s.cam_active_operation
|
|
o=s.cam_operations[a]
|
|
utils.addBridge(o)
|
|
return {'FINISHED'}
|
|
|
|
|
|
#boolean operations for curve objects
|
|
class CamCurveBoolean(bpy.types.Operator):
|
|
'''Boolean operation on two curves'''
|
|
bl_idname = "object.curve_boolean"
|
|
bl_label = "Curve Boolean"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
boolean_type = EnumProperty(name='type',
|
|
items=(('UNION','Union',''),('DIFFERENCE','Difference',''),('INTERSECT','Intersect','')),
|
|
description='boolean type',
|
|
default='UNION')
|
|
|
|
#@classmethod
|
|
#def poll(cls, context):
|
|
# return context.active_object is not None and context.active_object.type=='CURVE' and len(bpy.context.selected_objects)==2
|
|
|
|
def execute(self, context):
|
|
utils.polygonBoolean(context,self.boolean_type)
|
|
return {'FINISHED'}
|
|
|
|
#intarsion or joints
|
|
class CamCurveIntarsion(bpy.types.Operator):
|
|
'''makes curve cuttable both inside and outside, for intarsion and joints'''
|
|
bl_idname = "object.curve_intarsion"
|
|
bl_label = "Intarsion"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
radius = bpy.props.FloatProperty(name="offset", default=.003, min=0, max=100,precision=4, unit="LENGTH")
|
|
|
|
#@classmethod
|
|
#def poll(cls, context):
|
|
# return context.active_object is not None and context.active_object.type=='CURVE' and len(bpy.context.selected_objects)==2
|
|
|
|
def execute(self, context):
|
|
utils.silhoueteOffset(context,-self.radius)
|
|
o1=bpy.context.active_object
|
|
|
|
utils.silhoueteOffset(context,2*self.radius)
|
|
o2=bpy.context.active_object
|
|
utils.silhoueteOffset(context,-self.radius)
|
|
o3=bpy.context.active_object
|
|
o1.select=True
|
|
o2.select=True
|
|
o3.select=False
|
|
bpy.ops.object.delete(use_global=False)
|
|
o3.select=True
|
|
return {'FINISHED'}
|
|
|
|
class CamCurveRemoveDoubles(bpy.types.Operator):
|
|
'''curve remove doubles - warning, removes beziers!'''
|
|
bl_idname = "object.curve_remove_doubles"
|
|
bl_label = "C-Remove doubles"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
mode=False
|
|
if bpy.context.mode=='EDIT_CURVE':
|
|
bpy.ops.object.editmode_toggle()
|
|
mode=True
|
|
bpy.ops.object.convert(target='MESH')
|
|
bpy.ops.object.editmode_toggle()
|
|
bpy.ops.mesh.select_all(action='TOGGLE')
|
|
bpy.ops.mesh.remove_doubles()
|
|
bpy.ops.object.editmode_toggle()
|
|
bpy.ops.object.convert(target='CURVE')
|
|
|
|
if mode:
|
|
bpy.ops.object.editmode_toggle()
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
#this operator finds the silhouette of objects(meshes, curves just get converted) and offsets it.
|
|
class CamOffsetSilhouete(bpy.types.Operator):
|
|
'''Curve offset operation '''
|
|
bl_idname = "object.silhouete_offset"
|
|
bl_label = "Silhouete offset"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
offset = bpy.props.FloatProperty(name="offset", default=.003, min=-100, max=100,precision=4, unit="LENGTH")
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.active_object is not None and (context.active_object.type=='CURVE' or context.active_object.type=='MESH')
|
|
|
|
def execute(self, context):#this is almost same as getobjectoutline, just without the need of operation data
|
|
utils.silhoueteOffset(context,self.offset)
|
|
return {'FINISHED'}
|
|
|
|
#Finds object silhouette, usefull for meshes, since with curves it's not needed.
|
|
class CamObjectSilhouete(bpy.types.Operator):
|
|
'''Object silhouete '''
|
|
bl_idname = "object.silhouete"
|
|
bl_label = "Object silhouete"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.active_object is not None and (context.active_object.type=='CURVE' or context.active_object.type=='MESH')
|
|
|
|
|
|
|
|
def execute(self, context):#this is almost same as getobjectoutline, just without the need of operation data
|
|
ob=bpy.context.active_object
|
|
self.silh=utils.getObjectSilhouete('OBJECTS', objects=bpy.context.selected_objects)
|
|
poly=Polygon.Polygon()
|
|
for p in self.silh:
|
|
for ci in range(0,len(p)):
|
|
poly.addContour(p[ci])
|
|
bpy.context.scene.cursor_location=(0,0,0)
|
|
polygon_utils_cam.polyToMesh(ob.name+'_silhouette',poly,0)#
|
|
bpy.ops.object.convert(target='CURVE')
|
|
bpy.context.scene.cursor_location=ob.location
|
|
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
|
|
return {'FINISHED'}
|