kopia lustrzana https://github.com/vilemduha/blendercam
518 wiersze
14 KiB
Python
518 wiersze
14 KiB
Python
import time
|
|
import mathutils
|
|
from mathutils import *
|
|
|
|
|
|
from cam import simple, chunk
|
|
from cam.simple import *
|
|
from cam.chunk import *
|
|
from cam import polygon_utils_cam
|
|
from cam.polygon_utils_cam import *
|
|
|
|
def getPathPatternParallel(o,angle):
|
|
#minx,miny,minz,maxx,maxy,maxz=o.min.x,o.min.y,o.min.z,o.max.x,o.max.y,o.max.z
|
|
#ob=o.object
|
|
zlevel=1
|
|
pathd=o.dist_between_paths
|
|
pathstep=o.dist_along_paths
|
|
pathchunks=[]
|
|
#progress(o.max.x,stepx)
|
|
#progress(o.max.y,stepy)
|
|
|
|
#angle=(angle/360)*2*math.pi
|
|
xm=(o.max.x+o.min.x)/2
|
|
ym=(o.max.y+o.min.y)/2
|
|
vm=Vector((xm,ym,0))
|
|
xdim=o.max.x-o.min.x
|
|
ydim=o.max.y-o.min.y
|
|
dim=(xdim+ydim)/2.0
|
|
e=Euler((0,0,angle))
|
|
v=Vector((1,0,0))
|
|
reverse=False
|
|
#if o.movement_type=='CONVENTIONAL'
|
|
#ar=numpy.array((1.1,1.1))
|
|
#ar.resize()
|
|
#if bpy.app.debug_value==0:
|
|
dirvect=Vector((0,1,0))
|
|
dirvect.rotate(e)
|
|
dirvect.normalize()
|
|
dirvect*=pathstep
|
|
for a in range(int(-dim/pathd), int(dim/pathd)):#this is highly ineffective, computes path2x the area needed...
|
|
chunk=camPathChunk([])
|
|
v=Vector((a*pathd,int(-dim/pathstep)*pathstep,0))
|
|
v.rotate(e)
|
|
v+=vm#shifting for the rotation, so pattern rotates around middle...
|
|
for b in range(int(-dim/pathstep),int(dim/pathstep)):
|
|
v+=dirvect
|
|
|
|
if v.x>o.min.x and v.x<o.max.x and v.y>o.min.y and v.y<o.max.y:
|
|
chunk.points.append((v.x,v.y,zlevel))
|
|
if (reverse and o.movement_type=='MEANDER') or (o.movement_type=='CONVENTIONAL' and o.spindle_rotation_direction=='CW') or (o.movement_type=='CLIMB' and o.spindle_rotation_direction=='CCW') :
|
|
chunk.points.reverse()
|
|
|
|
|
|
#elif
|
|
if len(chunk.points)>0:
|
|
pathchunks.append(chunk)
|
|
if len(pathchunks)>1 and reverse and o.parallel_step_back and not o.use_layers:
|
|
#parallel step back - for finishing, best with climb movement, saves cutter life by going into material with climb, while using move back on the surface to improve finish(which would otherwise be a conventional move in the material)
|
|
|
|
if o.movement_type=='CONVENTIONAL' or o.movement_type=='CLIMB':
|
|
pathchunks[-2].points.reverse()
|
|
changechunk=pathchunks[-1]
|
|
pathchunks[-1]=pathchunks[-2]
|
|
pathchunks[-2]=changechunk
|
|
|
|
reverse = not reverse
|
|
|
|
#else:#alternative algorithm with numpy, didn't work as should so blocked now...
|
|
'''
|
|
v=Vector((1,0,0))
|
|
v.rotate(e)
|
|
a1res=int(dim/pathd)-int(-dim/pathd)
|
|
a2res=int(dim/pathstep)-int(-dim/pathstep)
|
|
|
|
axis_across_paths=numpy.array((numpy.arange(int(-dim/pathd), int(dim/pathd))*pathd*v.y+xm,
|
|
numpy.arange(int(-dim/pathd), int(dim/pathd))*pathd*v.x+ym,
|
|
numpy.arange(int(-dim/pathd), int(dim/pathd))*0))
|
|
#axis_across_paths=axis_across_paths.swapaxes(0,1)
|
|
#progress(axis_across_paths)
|
|
|
|
axis_along_paths=numpy.array((numpy.arange(int(-dim/pathstep),int(dim/pathstep))*pathstep*v.x,
|
|
numpy.arange(int(-dim/pathstep),int(dim/pathstep))*pathstep*v.y,
|
|
numpy.arange(int(-dim/pathstep),int(dim/pathstep))*0+zlevel))#rotate this first
|
|
progress(axis_along_paths)
|
|
#axis_along_paths = axis_along_paths.swapaxes(0,1)
|
|
#progress(axis_along_paths)
|
|
|
|
chunks=numpy.array((1.0))
|
|
chunks.resize(3,a1res,a2res)
|
|
|
|
for a in range(0,len(axis_across_paths[0])):
|
|
#progress(chunks[a,...,...].shape)
|
|
#progress(axis_along_paths.shape)
|
|
nax=axis_along_paths.copy()
|
|
#progress(nax.shape)
|
|
nax[0]+=axis_across_paths[0][a]
|
|
nax[1]+=axis_across_paths[1][a]
|
|
#progress(a)
|
|
#progress(nax.shape)
|
|
#progress(chunks.shape)
|
|
#progress(chunks[...,a,...].shape)
|
|
chunks[...,a,...]=nax
|
|
'''
|
|
'''
|
|
for a in range(0,a1res):
|
|
chunks[a,...,1]=axis2
|
|
|
|
for a in range(0,a1res):
|
|
for b in range(0,a2res):
|
|
v.x=chunks.item(a,b,0)
|
|
v.y=chunks.item(a,b,1)
|
|
v.rotate(e)
|
|
v.x+=xm
|
|
v.y+=ym
|
|
if v.x>o.min.x and v.x<o.max.x and v.y>o.min.y and v.y<o.max.y:
|
|
chunks.itemset(a,b,0,v.x)
|
|
chunks.itemset(a,b,1,v.y)
|
|
else:
|
|
chunks.itemset(a,b,0,-10)
|
|
chunks.itemset(a,b,1,-10)
|
|
chunks.itemset(a,b,2,-10)
|
|
|
|
|
|
chunks[...,...,2]=zlevel
|
|
|
|
pathchunks=chunks
|
|
'''
|
|
|
|
return pathchunks
|
|
|
|
|
|
|
|
def getPathPattern(operation):
|
|
o=operation
|
|
t=time.time()
|
|
progress('building path pattern')
|
|
minx,miny,minz,maxx,maxy,maxz=o.min.x,o.min.y,o.min.z,o.max.x,o.max.y,o.max.z
|
|
|
|
pathchunks=[]
|
|
|
|
zlevel=1#minz#this should do layers...
|
|
if o.strategy=='PARALLEL':
|
|
pathchunks= getPathPatternParallel(o,o.parallel_angle)
|
|
elif o.strategy=='CROSS':
|
|
|
|
pathchunks.extend(getPathPatternParallel(o,o.parallel_angle))
|
|
pathchunks.extend(getPathPatternParallel(o,o.parallel_angle-math.pi/2.0))
|
|
|
|
elif o.strategy=='BLOCK':
|
|
|
|
pathd=o.dist_between_paths
|
|
pathstep=o.dist_along_paths
|
|
maxxp=maxx
|
|
maxyp=maxy
|
|
minxp=minx
|
|
minyp=miny
|
|
x=0.0
|
|
y=0.0
|
|
incx=1
|
|
incy=0
|
|
chunk=camPathChunk([])
|
|
i=0
|
|
while maxxp-minxp>0 and maxyp-minyp>0:
|
|
|
|
y=minyp
|
|
for a in range(ceil(minxp/pathstep),ceil(maxxp/pathstep),1):
|
|
x=a*pathstep
|
|
chunk.points.append((x,y,zlevel))
|
|
|
|
if i>0:
|
|
minxp+=pathd
|
|
chunk.points.append((maxxp,minyp,zlevel))
|
|
|
|
|
|
x=maxxp
|
|
|
|
for a in range(ceil(minyp/pathstep),ceil(maxyp/pathstep),1):
|
|
|
|
y=a*pathstep
|
|
chunk.points.append((x,y,zlevel))
|
|
|
|
minyp+=pathd
|
|
chunk.points.append((maxxp,maxyp,zlevel))
|
|
|
|
|
|
y=maxyp
|
|
for a in range(floor(maxxp/pathstep),ceil(minxp/pathstep),-1):
|
|
x=a*pathstep
|
|
chunk.points.append((x,y,zlevel))
|
|
|
|
|
|
|
|
|
|
maxxp-=pathd
|
|
chunk.points.append((minxp,maxyp,zlevel))
|
|
|
|
x=minxp
|
|
for a in range(floor(maxyp/pathstep),ceil(minyp/pathstep),-1):
|
|
y=a*pathstep
|
|
chunk.points.append((x,y,zlevel))
|
|
chunk.points.append((minxp,minyp,zlevel))
|
|
|
|
|
|
maxyp-=pathd
|
|
|
|
i+=1
|
|
if o.movement_insideout=='INSIDEOUT':
|
|
chunk.points.reverse()
|
|
if (o.movement_type=='CLIMB' and o.spindle_rotation_direction=='CW') or (o.movement_type=='CONVENTIONAL' and o.spindle_rotation_direction=='CCW'):
|
|
for si in range(0,len(chunk.points)):
|
|
s=chunk.points[si]
|
|
chunk.points[si]=(o.max.x+o.min.x-s[0],s[1],s[2])
|
|
#if insideout:
|
|
# chunk.reverse()
|
|
pathchunks=[chunk]
|
|
|
|
elif o.strategy=='SPIRAL':
|
|
chunk=camPathChunk([])
|
|
pathd=o.dist_between_paths
|
|
pathstep=o.dist_along_paths
|
|
midx=(o.max.x+o.min.x)/2
|
|
midy=(o.max.y+o.min.y)/2
|
|
x=pathd/4
|
|
y=pathd/4
|
|
v=Vector((pathd/4,0,0))
|
|
|
|
#progress(x,y,midx,midy)
|
|
e=Euler((0,0,0))
|
|
pi=math.pi
|
|
chunk.points.append((midx+v.x,midy+v.y,zlevel))
|
|
while midx+v.x>o.min.x or midy+v.y>o.min.y:
|
|
#v.x=x-midx
|
|
#v.y=y-midy
|
|
offset=2*v.length*pi
|
|
e.z=2*pi*(pathstep/offset)
|
|
v.rotate(e)
|
|
|
|
v.length=(v.length+pathd/(offset/pathstep))
|
|
#progress(v.x,v.y)
|
|
if o.max.x>midx+v.x>o.min.x and o.max.y>midy+v.y>o.min.y:
|
|
chunk.points.append((midx+v.x,midy+v.y,zlevel))
|
|
else:
|
|
pathchunks.append(chunk)
|
|
chunk=camPathChunk([])
|
|
if len(chunk.points)>0:
|
|
pathchunks.append(chunk)
|
|
if o.movement_insideout=='OUTSIDEIN':
|
|
pathchunks.reverse()
|
|
for chunk in pathchunks:
|
|
if o.movement_insideout=='OUTSIDEIN':
|
|
chunk.points.reverse()
|
|
|
|
if (o.movement_type=='CONVENTIONAL' and o.spindle_rotation_direction=='CW') or (o.movement_type=='CLIMB' and o.spindle_rotation_direction=='CCW'):
|
|
for si in range(0,len(chunk.points)):
|
|
s=chunk.points[si]
|
|
chunk.points[si]=(o.max.x+o.min.x-s[0],s[1],s[2])
|
|
|
|
|
|
elif o.strategy=='CIRCLES':
|
|
|
|
pathd=o.dist_between_paths
|
|
pathstep=o.dist_along_paths
|
|
midx=(o.max.x+o.min.x)/2
|
|
midy=(o.max.y+o.min.y)/2
|
|
rx=o.max.x-o.min.x
|
|
ry=o.max.y-o.min.y
|
|
maxr=math.sqrt(rx*rx+ry*ry)
|
|
#x=pathd/4
|
|
#y=pathd/4
|
|
v=Vector((1,0,0))
|
|
|
|
#progress(x,y,midx,midy)
|
|
e=Euler((0,0,0))
|
|
pi=math.pi
|
|
chunk=camPathChunk([])
|
|
chunk.points.append((midx,midy,zlevel))
|
|
pathchunks.append(chunk)
|
|
r=0
|
|
|
|
while r<maxr:
|
|
#v.x=x-midx
|
|
#v.y=y-midy
|
|
r+=pathd
|
|
chunk=camPathChunk([])
|
|
firstchunk=chunk
|
|
v=Vector((-r,0,0))
|
|
steps=2*pi*r/pathstep
|
|
e.z=2*pi/steps
|
|
for a in range(0,int(steps)):
|
|
|
|
|
|
if o.max.x>midx+v.x>o.min.x and o.max.y>midy+v.y>o.min.y:
|
|
chunk.points.append((midx+v.x,midy+v.y,zlevel))
|
|
else:
|
|
if len(chunk.points)>0:
|
|
chunk.closed=False
|
|
pathchunks.append(chunk)
|
|
|
|
chunk=camPathChunk([])
|
|
v.rotate(e)
|
|
|
|
|
|
if len(chunk.points)>0:
|
|
chunk.points.append(firstchunk.points[0])
|
|
if chunk==firstchunk:
|
|
chunk.closed=True
|
|
pathchunks.append(chunk)
|
|
chunk=camPathChunk([])
|
|
if o.movement_insideout=='OUTSIDEIN':
|
|
pathchunks.reverse()
|
|
for chunk in pathchunks:
|
|
if o.movement_insideout=='OUTSIDEIN':
|
|
chunk.points.reverse()
|
|
if (o.movement_type=='CONVENTIONAL' and o.spindle_rotation_direction=='CW') or (o.movement_type=='CLIMB' and o.spindle_rotation_direction=='CCW'):
|
|
chunk.points.reverse()
|
|
#for si in range(0,len(chunk.points)):
|
|
#s=chunk.points[si]
|
|
#chunk.points[si]=(o.max.x+o.min.x-s[0],s[1],s[2])
|
|
#pathchunks=sortChunks(pathchunks,o)not until they get hierarchy parents!
|
|
elif o.strategy=='OUTLINEFILL':
|
|
|
|
|
|
polys=operation.silhouete
|
|
pathchunks=[]
|
|
chunks=[]
|
|
for p in polys:
|
|
chunks.extend(polyToChunks(p,0))
|
|
|
|
pathchunks.extend(chunks)
|
|
lastchunks=chunks
|
|
firstchunks=chunks
|
|
|
|
#for ch in chunks:
|
|
# if len(ch.points)>2:
|
|
# polys.extend()
|
|
|
|
approxn=(min(maxx-minx,maxy-miny)/o.dist_between_paths)/2
|
|
i=0
|
|
|
|
for porig in polys:
|
|
p=porig
|
|
while p.nPoints()>0:
|
|
p=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,False)
|
|
if p.nPoints()>0:
|
|
nchunks=polyToChunks(p,zlevel)
|
|
#parentChildPoly(lastchunks,nchunks,o)
|
|
pathchunks.extend(nchunks)
|
|
lastchunks=nchunks
|
|
percent=int(i/approxn*100)
|
|
progress('outlining polygons ',percent)
|
|
i+=1
|
|
if not(o.inverse):#dont do ambient for inverse milling
|
|
lastchunks=firstchunks
|
|
for p in polys:
|
|
d=o.dist_between_paths
|
|
steps=o.ambient_radius/o.dist_between_paths
|
|
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# 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=outlinePoly(p,dist,o.circle_detail,o.optimize,o.optimize_threshold,True)
|
|
if p.nPoints()>0:
|
|
chunks=polyToChunks(p,zlevel)
|
|
pathchunks.extend(chunks)
|
|
lastchunks=chunks
|
|
|
|
if (o.movement_type=='CLIMB' and o.spindle_rotation_direction=='CW') or (o.movement_type=='CONVENTIONAL' and o.spindle_rotation_direction=='CCW'):
|
|
for ch in pathchunks:
|
|
ch.points.reverse()
|
|
parentChildPoly(pathchunks,pathchunks,o)
|
|
pathchunks=chunksRefine(pathchunks,o)
|
|
progress(time.time()-t)
|
|
return pathchunks
|
|
|
|
def getPathPattern4axis(operation):
|
|
o=operation
|
|
t=time.time()
|
|
progress('building path pattern')
|
|
minx,miny,minz,maxx,maxy,maxz=o.min.x,o.min.y,o.min.z,o.max.x,o.max.y,o.max.z
|
|
pathchunks=[]
|
|
zlevel=1#minz#this should do layers...
|
|
|
|
|
|
#set axes for various options, Z option is obvious nonsense now.
|
|
if o.rotary_axis_1=='X':
|
|
a1=0
|
|
a2=1
|
|
a3=2
|
|
if o.rotary_axis_1=='Y':
|
|
a1=1
|
|
a2=0
|
|
a3=2
|
|
if o.rotary_axis_1=='Z':
|
|
a1=2
|
|
a2=0
|
|
a3=1
|
|
|
|
#set radius for all types of operation
|
|
m1=max(abs(o.min[a2]),abs(o.max[a2]))
|
|
m2=max(abs(o.min[a3]),abs(o.max[a3]))
|
|
|
|
radius=math.sqrt(m1*m1+m2*m2)#max radius estimation
|
|
|
|
circlesteps=(radius*pi*2)/o.dist_along_paths
|
|
anglestep = 2*pi/circlesteps
|
|
#generalized rotation
|
|
e=Euler((0,0,0))
|
|
e[a1]=anglestep
|
|
|
|
#generalized length of the operation
|
|
maxl=o.max[a1]
|
|
minl=o.min[a1]
|
|
steps=(maxl-minl)/o.dist_between_paths
|
|
|
|
#set starting positions for cutter e.t.c.
|
|
cutterstart=Vector((0,0,0))
|
|
cutterend=Vector((0,0,0))#end point for casting
|
|
|
|
|
|
|
|
if o.strategy4axis=='PARALLELR':
|
|
|
|
for a in range(0,floor(steps)+1):
|
|
chunk=camPathChunk([])
|
|
|
|
cutterstart[a1]=o[a1]+a*o.dist_between_paths
|
|
cutterend[a1]=cutterstart[a1]
|
|
|
|
cutterstart[a2]=radius
|
|
|
|
for b in range(0,floor(circlesteps)+1):
|
|
#print(cutterstart,cutterend)
|
|
chunk.startpoints.append(cutterstart.to_tuple())
|
|
chunk.endpoints.append(cutterend.to_tuple())
|
|
rot=[0,0,0]
|
|
rot[a1]=b*anglestep
|
|
chunk.rotations.append(rot)
|
|
cutterstart.rotate(e)
|
|
|
|
chunk.depth=-radius
|
|
#last point = first
|
|
chunk.startpoints.append(chunk.startpoints[0])
|
|
chunk.endpoints.append(chunk.endpoints[0])
|
|
chunk.rotations.append(chunk.rotations[0])
|
|
|
|
pathchunks.append(chunk)
|
|
|
|
if o.strategy4axis=='PARALLEL':
|
|
|
|
reverse=False
|
|
|
|
for b in range(0,floor(circlesteps)+1):
|
|
chunk=camPathChunk([])
|
|
cutterstart[a2]=0
|
|
cutterstart[a3]=radius
|
|
e[a1]=anglestep*b
|
|
cutterstart.rotate(e)
|
|
for a in range(0,floor(steps)+1):
|
|
cutterstart[a1]=o.min[a1]+a*o.dist_between_paths
|
|
cutterend[a1]=cutterstart[a1]
|
|
chunk.startpoints.append(cutterstart.to_tuple())
|
|
chunk.endpoints.append(cutterend.to_tuple())
|
|
rot=[0,0,0]
|
|
rot[a1]=b*anglestep
|
|
chunk.rotations.append(rot)
|
|
|
|
chunk.depth=-radius
|
|
#last point = first
|
|
|
|
pathchunks.append(chunk)
|
|
|
|
if (reverse and o.movement_type=='MEANDER') or (o.movement_type=='CONVENTIONAL' and o.spindle_rotation_direction=='CW') or (o.movement_type=='CLIMB' and o.spindle_rotation_direction=='CCW') :
|
|
chunk.reverse()
|
|
|
|
reverse=not reverse
|
|
|
|
if o.strategy4axis=='HELIX':
|
|
print('helix')
|
|
|
|
a1step=o.dist_between_paths / circlesteps
|
|
|
|
chunk=camPathChunk([])#only one chunk, init here
|
|
|
|
for a in range(0,floor(steps)+1):
|
|
|
|
cutterstart[a1]=o.min[a1]+a*o.dist_between_paths
|
|
cutterend[a1]=cutterstart[a1]
|
|
cutterstart[a2]=0
|
|
cutterstart[a3]=radius
|
|
|
|
for b in range(0,floor(circlesteps)+1):
|
|
#print(cutterstart,cutterend)
|
|
cutterstart[a1]+=a1step
|
|
cutterend[a1]+=a1step
|
|
chunk.startpoints.append(cutterstart.to_tuple())
|
|
chunk.endpoints.append(cutterend.to_tuple())
|
|
|
|
rot=[0,0,0]
|
|
rot[a1]=b*anglestep
|
|
chunk.rotations.append(rot)
|
|
|
|
cutterstart.rotate(e)
|
|
|
|
chunk.depth=-radius
|
|
#last point = first
|
|
|
|
|
|
|
|
pathchunks.append(chunk)
|
|
#print(chunk.startpoints)
|
|
#print(pathchunks)
|
|
#sprint(len(pathchunks))
|
|
#print(o.strategy4axis)
|
|
return pathchunks
|
|
|