kopia lustrzana https://github.com/vilemduha/blendercam
Merge branch 'master' of https://github.com/vilemnovak/blendercam
commit
f8be77852c
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
|
|
@ -453,6 +453,7 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
movement_insideout = EnumProperty(name='Direction', items=(('INSIDEOUT','Inside out', 'a'),('OUTSIDEIN', 'Outside in', 'a')),description='approach to the piece',default='INSIDEOUT', update = updateRest)
|
||||
parallel_step_back = bpy.props.BoolProperty(name="Parallel step back", description='For roughing and finishing in one pass: mills material in climb mode, then steps back and goes between 2 last chunks back', 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)
|
||||
#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)
|
||||
|
|
@ -481,6 +482,15 @@ class camOperation(bpy.types.PropertyGroup):
|
|||
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, 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)
|
||||
bridges_placement = bpy.props.EnumProperty(name='Bridge placement',
|
||||
items=(
|
||||
('AUTO','Automatic', 'Automatic bridges with a set distance'),
|
||||
('MANUAL','Manual', 'Manual placement of bridges'),
|
||||
),
|
||||
description='Bridge placement',
|
||||
default='AUTO',
|
||||
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)
|
||||
#optimisation panel
|
||||
|
|
@ -696,6 +706,8 @@ def get_panels():#convenience function for bot register and unregister functions
|
|||
ops.CamOperationCopy,
|
||||
ops.CamOperationRemove,
|
||||
ops.CamOperationMove,
|
||||
#bridges related
|
||||
ops.CamBridgeAdd,
|
||||
#5 axis ops
|
||||
ops.CamOrientationAdd,
|
||||
#shape packing
|
||||
|
|
|
|||
|
|
@ -152,8 +152,8 @@ class camPathChunk:
|
|||
print('found some')
|
||||
return ch
|
||||
#self.unsortedchildren=False
|
||||
print('returning orig')
|
||||
return self
|
||||
print('returning none')
|
||||
return None
|
||||
|
||||
|
||||
def getLength(self):
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
import bpy
|
||||
import subprocess,os, sys, threading
|
||||
from cam import utils, pack,polygon_utils_cam,chunk
|
||||
from cam import utils, pack,polygon_utils_cam,chunk,simple
|
||||
from bpy.props import *
|
||||
import Polygon
|
||||
|
||||
|
|
@ -635,9 +635,9 @@ class CamOperationMove(bpy.types.Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
#move cam operation in the list up or down
|
||||
|
||||
class CamOrientationAdd(bpy.types.Operator):
|
||||
'''Add orientation to cam operation'''
|
||||
'''Add orientation to cam operation, for multiaxis operations'''
|
||||
bl_idname = "scene.cam_orientation_add"
|
||||
bl_label = "Add orientation"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
|
@ -652,20 +652,35 @@ class CamOrientationAdd(bpy.types.Operator):
|
|||
s=bpy.context.scene
|
||||
a=s.cam_active_operation
|
||||
o=s.cam_operations[a]
|
||||
cops=bpy.context.scene.cam_operations
|
||||
gname=o.name+'_orientations'
|
||||
bpy.ops.object.empty_add(type='ARROWS')
|
||||
|
||||
oriob=bpy.context.active_object
|
||||
oriob.empty_draw_size=0.02 # 2 cm
|
||||
|
||||
|
||||
if not gname in bpy.data.groups:
|
||||
bpy.ops.group.create(name=gname)
|
||||
else:
|
||||
bpy.data.groups[gname].objects.link(oriob)
|
||||
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'}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,14 @@ def dupliob(o,pos):
|
|||
bpy.ops.rigidbody.object_remove()
|
||||
o.location=pos
|
||||
|
||||
def addToGroup(ob,groupname):
|
||||
activate(ob)
|
||||
if bpy.data.groups.get(groupname)==None:
|
||||
bpy.ops.group.create(name = groupname)
|
||||
else:
|
||||
bpy.ops.object.group_link(group=groupname)
|
||||
|
||||
|
||||
def compare(v1,v2,vmiddle,e):
|
||||
'''comparison for optimisation of paths'''
|
||||
#e=0.0001
|
||||
|
|
|
|||
|
|
@ -405,10 +405,12 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
layout.prop(ao,'dont_merge')
|
||||
layout.prop(ao,'use_bridges')
|
||||
if ao.use_bridges:
|
||||
layout.prop(ao,'bridges_placement')
|
||||
layout.prop(ao,'bridges_width')
|
||||
layout.prop(ao,'bridges_height')
|
||||
layout.prop(ao,'bridges_per_curve')
|
||||
layout.prop(ao,'bridges_max_distance')
|
||||
if ao.bridges_placement == 'AUTO':
|
||||
layout.prop(ao,'bridges_per_curve')
|
||||
layout.prop(ao,'bridges_max_distance')
|
||||
|
||||
elif ao.strategy=='WATERLINE':
|
||||
layout.prop(ao,'slice_detail')
|
||||
|
|
@ -442,8 +444,7 @@ class CAM_OPERATION_PROPERTIES_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
layout.prop(ao,'dist_along_paths')
|
||||
if ao.strategy=='PARALLEL' or ao.strategy=='CROSS':
|
||||
layout.prop(ao,'parallel_angle')
|
||||
if not ao.ramp:
|
||||
layout.prop(ao,'parallel_step_back')
|
||||
|
||||
|
||||
layout.prop(ao,'skin')
|
||||
layout.prop(ao,'inverse')
|
||||
|
|
@ -485,11 +486,15 @@ class CAM_MOVEMENT_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
ao=scene.cam_operations[scene.cam_active_operation]
|
||||
if ao.valid:
|
||||
layout.prop(ao,'movement_type')
|
||||
|
||||
if ao.movement_type=='BLOCK' or ao.movement_type=='SPIRAL' or ao.movement_type=='CIRCLES':
|
||||
layout.prop(ao,'movement_insideout')
|
||||
|
||||
layout.prop(ao,'spindle_rotation_direction')
|
||||
layout.prop(ao,'free_movement_height')
|
||||
if ao.strategy=='PARALLEL' or ao.strategy=='CROSS':
|
||||
if not ao.ramp:
|
||||
layout.prop(ao,'parallel_step_back')
|
||||
if ao.strategy=='CUTOUT':
|
||||
layout.prop(ao,'first_down')
|
||||
#if ao.first_down:
|
||||
|
|
@ -513,6 +518,8 @@ class CAM_MOVEMENT_Panel(CAMButtonsPanel, bpy.types.Panel):
|
|||
layout.prop(ao,'ramp_out_angle')
|
||||
|
||||
layout.prop(ao,'stay_low')
|
||||
if ao.stay_low:
|
||||
layout.prop(ao,'merge_dist')
|
||||
layout.prop(ao,'protect_vertical')
|
||||
if ao.protect_vertical:
|
||||
layout.prop(ao,'protect_vertical_limit')
|
||||
|
|
|
|||
|
|
@ -1423,7 +1423,9 @@ def connectChunksLow(chunks,o):
|
|||
|
||||
if o.parallel_step_back:
|
||||
mergedist*=2
|
||||
|
||||
if o.merge_dist>0:
|
||||
mergedist=o.merge_dist
|
||||
#mergedist=10
|
||||
lastch=None
|
||||
i=len(chunks)
|
||||
pos=(0,0,0)
|
||||
|
|
@ -1904,88 +1906,155 @@ def addMaterialAreaObject():
|
|||
else:
|
||||
bpy.context.scene.objects.active=None
|
||||
|
||||
|
||||
def getContainer():
|
||||
s=bpy.context.scene
|
||||
if s.objects.get('CAM_OBJECTS')==None:
|
||||
bpy.ops.object.empty_add(type='PLAIN_AXES', view_align=False)
|
||||
container=bpy.context.active_object
|
||||
container.name='CAM_OBJECTS'
|
||||
container.location=[0,0,0]
|
||||
container.hide=True
|
||||
else:
|
||||
container=s.objects['CAM_OBJECTS']
|
||||
|
||||
return container
|
||||
|
||||
|
||||
def getSnappingObject(o):
|
||||
s=bpy.context.scene
|
||||
|
||||
bproj_name='cam_snap_object_'+o.name
|
||||
|
||||
if s.objects.get(bproj_name)!=None:
|
||||
ob=s.objects[bproj_name]
|
||||
else:
|
||||
getOperationSources(o)
|
||||
ob=o.objects[0]
|
||||
activate(ob)
|
||||
bpy.ops.object.duplicate()
|
||||
ob=bpy.context.active_object
|
||||
#should do with ALL objects from the operation sources, and join them!
|
||||
ob.name=bproj_name
|
||||
#ensure the object is 'flat'
|
||||
ob.data.dimensions = '2D'
|
||||
ob.data.dimensions = '3D'
|
||||
ob.location.z=0
|
||||
ob.data.extrude=0.01
|
||||
bpy.ops.object.convert(target='MESH')
|
||||
bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM')
|
||||
ob.parent=getContainer()
|
||||
ob.hide=True
|
||||
return ob
|
||||
|
||||
def addBridge(o):
|
||||
container=getContainer()
|
||||
bpy.ops.object.empty_add(type='CUBE',location=[0,0,0], view_align=False)
|
||||
b=bpy.context.active_object
|
||||
b.name='bridge_'+o.name
|
||||
b.rotation_euler.x=math.pi/2
|
||||
b.empty_draw_size=0.01
|
||||
b.lock_location[2]=True
|
||||
b.parent=container
|
||||
ob=getSnappingObject(o)
|
||||
activate(b)
|
||||
bpy.ops.object.constraint_add(type='SHRINKWRAP')
|
||||
b.constraints[-1].target=ob
|
||||
addToGroup(b,'cam_bridges_' + o.name )
|
||||
|
||||
|
||||
def getBridges(p,o):
|
||||
# this function finds positions of the bridges, and returns these.
|
||||
pass;
|
||||
def addBridges(ch,o,z):
|
||||
#this functions adds Bridges to the finished chunks.
|
||||
ch.getLength()
|
||||
n=int(ch.length/o.bridges_max_distance)
|
||||
bpc=o.bridges_per_curve
|
||||
if o.bridges_width*bpc>ch.length/2:
|
||||
bpc=math.floor(ch.length/(2*o.bridges_width))
|
||||
n = max(n,bpc)
|
||||
if n>0:
|
||||
dist=ch.length/n
|
||||
pos=[]
|
||||
for i in range(0,n):
|
||||
pos.append([i*dist+0.00001+dist/2.0,i*dist+0.00001+dist/2.0+o.bridges_width+o.cutter_diameter])
|
||||
dist=0
|
||||
bridgeheight=min(0,o.min.z+o.bridges_height)
|
||||
inbridge=False
|
||||
posi=0
|
||||
insertpoints=[]
|
||||
changepoints=[]
|
||||
vi=0
|
||||
while vi<len(ch.points):
|
||||
v1=ch.points[vi]
|
||||
v2=Vector(v1)#this is for case of last point and not closed chunk..
|
||||
if ch.closed and vi==len(ch.points)-1:
|
||||
v2=Vector(ch.points[0])
|
||||
elif vi+1<len(ch.points):
|
||||
v2=Vector(ch.points[vi+1])
|
||||
v1=Vector(v1)
|
||||
#if v1.z<bridgeheight or v2.z<bridgeheight:
|
||||
v=v2-v1
|
||||
dist+=v.length
|
||||
|
||||
wasinbridge=inbridge
|
||||
if not inbridge and posi<len(pos) and pos[posi][0]<dist:#detect start of bridge
|
||||
g=bpy.data.groups.get('cam_bridges_'+o.name)
|
||||
bridges=[]
|
||||
if g!=None:
|
||||
for o in g.objects:
|
||||
pos=o.matrix_world.to_translation()
|
||||
pos=pos[0],pos[1]
|
||||
bridges.append(pos)
|
||||
return bridges
|
||||
|
||||
|
||||
def addBridges(ch,o):
|
||||
#this functions adds Bridges to the finished chunks. AUTOMATIC ONLY NOW!
|
||||
if o.bridges_placement == 'AUTO':
|
||||
ch.getLength()
|
||||
n=int(ch.length/o.bridges_max_distance)
|
||||
bpc=o.bridges_per_curve
|
||||
if o.bridges_width*bpc>ch.length/2:
|
||||
bpc=math.floor(ch.length/(2*o.bridges_width))
|
||||
n = max(n,bpc)
|
||||
if n>0:
|
||||
dist=ch.length/n
|
||||
pos=[]
|
||||
for i in range(0,n):
|
||||
pos.append([i*dist+0.00001+dist/2.0,i*dist+0.00001+dist/2.0+o.bridges_width+o.cutter_diameter])
|
||||
dist=0
|
||||
bridgeheight=min(0,o.min.z+o.bridges_height)
|
||||
inbridge=False
|
||||
posi=0
|
||||
insertpoints=[]
|
||||
changepoints=[]
|
||||
vi=0
|
||||
while vi<len(ch.points):
|
||||
v1=ch.points[vi]
|
||||
v2=Vector(v1)#this is for case of last point and not closed chunk..
|
||||
if ch.closed and vi==len(ch.points)-1:
|
||||
v2=Vector(ch.points[0])
|
||||
elif vi+1<len(ch.points):
|
||||
v2=Vector(ch.points[vi+1])
|
||||
v1=Vector(v1)
|
||||
#if v1.z<bridgeheight or v2.z<bridgeheight:
|
||||
v=v2-v1
|
||||
dist+=v.length
|
||||
|
||||
ratio=(dist-pos[posi][0])/v.length
|
||||
point1=v2-v*ratio#TODO: optimize this : how? what was meant by the initial comment?
|
||||
point2=v2-v*ratio
|
||||
if bridgeheight>point1.z:
|
||||
point1.z=min(point1.z,bridgeheight)
|
||||
point2.z=max(point2.z,bridgeheight)
|
||||
#ch.points.insert(vi-1,point1)
|
||||
#ch.points.insert(vi,point2)
|
||||
insertpoints.append([vi+1,point1.to_tuple()])
|
||||
insertpoints.append([vi+1,point2.to_tuple()])
|
||||
inbridge=True
|
||||
wasinbridge=inbridge
|
||||
if not inbridge and posi<len(pos) and pos[posi][0]<dist:#detect start of bridge
|
||||
|
||||
ratio=(dist-pos[posi][0])/v.length
|
||||
point1=v2-v*ratio
|
||||
point2=point1.copy()
|
||||
if bridgeheight>point1.z:
|
||||
point1.z=min(point1.z,bridgeheight)
|
||||
point2.z=max(point2.z,bridgeheight)
|
||||
#ch.points.insert(vi-1,point1)
|
||||
#ch.points.insert(vi,point2)
|
||||
insertpoints.append([vi+1,point1.to_tuple()])
|
||||
insertpoints.append([vi+1,point2.to_tuple()])
|
||||
inbridge=True
|
||||
|
||||
if wasinbridge and inbridge:#still in bridge, raise the point up.#
|
||||
changepoints.append([vi,(v1.x,v1.y,max(v1.z,bridgeheight))])
|
||||
#ch.points[vi]=(v1.x,v1.y,max(v1.z,bridgeheight))
|
||||
|
||||
if inbridge and pos[posi][1]<dist:#detect end of bridge
|
||||
ratio=(dist-pos[posi][1])/v.length
|
||||
point1=v2-v*ratio
|
||||
point2=v2-v*ratio
|
||||
if bridgeheight>point1.z:
|
||||
point1.z=max(point1.z,bridgeheight)
|
||||
point2.z=min(point2.z,bridgeheight)
|
||||
#ch.points.insert(vi,point1)
|
||||
#ch.points.insert(vi+1,point2)
|
||||
#vi+=2
|
||||
insertpoints.append([vi+1,point1.to_tuple()])
|
||||
insertpoints.append([vi+1,point2.to_tuple()])
|
||||
inbridge=False
|
||||
posi+=1
|
||||
vi-=1
|
||||
dist-=v.length
|
||||
vi+=1
|
||||
|
||||
|
||||
if wasinbridge and inbridge:#still in bridge, raise the point up.#
|
||||
changepoints.append([vi,(v1.x,v1.y,max(v1.z,bridgeheight))])
|
||||
#ch.points[vi]=(v1.x,v1.y,max(v1.z,bridgeheight))
|
||||
|
||||
if inbridge and pos[posi][1]<dist:#detect end of bridge
|
||||
ratio=(dist-pos[posi][1])/v.length
|
||||
point1=v2-v*ratio
|
||||
point2=v2-v*ratio
|
||||
if bridgeheight>point1.z:
|
||||
point1.z=max(point1.z,bridgeheight)
|
||||
point2.z=min(point2.z,bridgeheight)
|
||||
#ch.points.insert(vi,point1)
|
||||
#ch.points.insert(vi+1,point2)
|
||||
#vi+=2
|
||||
insertpoints.append([vi+1,point1.to_tuple()])
|
||||
insertpoints.append([vi+1,point2.to_tuple()])
|
||||
inbridge=False
|
||||
posi+=1
|
||||
vi-=1
|
||||
dist-=v.length
|
||||
vi+=1
|
||||
|
||||
|
||||
|
||||
|
||||
if posi>=len(pos):
|
||||
#print('added bridges')
|
||||
break;
|
||||
for p in changepoints:
|
||||
ch.points[p[0]]=p[1]
|
||||
for pi in range(len(insertpoints)-1,-1,-1):
|
||||
ch.points.insert(insertpoints[pi][0],insertpoints[pi][1])
|
||||
if posi>=len(pos):
|
||||
#print('added bridges')
|
||||
break;
|
||||
for p in changepoints:
|
||||
ch.points[p[0]]=p[1]
|
||||
for pi in range(len(insertpoints)-1,-1,-1):
|
||||
ch.points.insert(insertpoints[pi][0],insertpoints[pi][1])
|
||||
#this is the main function.
|
||||
#FIXME: split strategies into separate file!
|
||||
#def cutoutStrategy(o):
|
||||
|
|
@ -2088,7 +2157,7 @@ def getPath3axis(context,operation):
|
|||
chunk=chl[0]
|
||||
layer=chl[1]
|
||||
if layer[1]<bridgeheight:
|
||||
addBridges(chunk,o,0)
|
||||
addBridges(chunk,o)
|
||||
|
||||
if o.ramp:#add ramps or simply add chunks
|
||||
for chl in extendorder:
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue