pull/117/head
TurBoss 2019-01-25 23:48:11 +01:00
rodzic edcd11f13f
commit 9b24469cfb
14 zmienionych plików z 10929 dodań i 10391 usunięć

2
.gitignore vendored
Wyświetl plik

@ -19,3 +19,5 @@ scripts/addons_contrib/online_mat_lib/material-library/bundled/cycles/wood/rough
acp
syncWithUpstream
forceSyncWithUpstream
\.idea/

Wyświetl plik

@ -25,217 +25,252 @@ import time
from cam import simple
from cam.simple import *
BULLET_SCALE=10000 # this is a constant for scaling the rigidbody collision world for higher precision from bullet library
CUTTER_OFFSET = (-5*BULLET_SCALE,-5*BULLET_SCALE,-5*BULLET_SCALE)# the cutter object has to be present in the scene , so we need to put it aside for sweep collisions, otherwise it collides itself.
BULLET_SCALE = 10000 # this is a constant for scaling the rigidbody collision world for higher precision from bullet library
CUTTER_OFFSET = (-5 * BULLET_SCALE, -5 * BULLET_SCALE,
-5 * BULLET_SCALE) # the cutter object has to be present in the scene , so we need to put it aside for sweep collisions, otherwise it collides itself.
#
def getCutterBullet(o):
'''cutter for rigidbody simulation collisions
note that everything is 100x bigger for simulation precision.'''
s=bpy.context.scene
if s.objects.get('cutter')!= None:
c=s.objects['cutter']
activate(c)
'''cutter for rigidbody simulation collisions
note that everything is 100x bigger for simulation precision.'''
s = bpy.context.scene
if s.objects.get('cutter') is not None:
c = s.objects['cutter']
activate(c)
type = o.cutter_type
if type == 'END':
bpy.ops.mesh.primitive_cylinder_add(vertices=32, radius=BULLET_SCALE * o.cutter_diameter / 2,
depth=BULLET_SCALE * o.cutter_diameter, end_fill_type='NGON',
view_align=False, enter_editmode=False, location=CUTTER_OFFSET,
rotation=(0, 0, 0))
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter = bpy.context.active_object
cutter.rigid_body.collision_shape = 'CYLINDER'
elif type == 'BALL' or type == 'BALLNOSE':
if o.strategy != 'PROJECTED_CURVE' or type == 'BALL': # only sphere, good for 3 axis and real ball cutters for undercuts and projected curve
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=2, radius=BULLET_SCALE * o.cutter_diameter / 2,
view_align=False, enter_editmode=False, location=CUTTER_OFFSET,
rotation=(0, 0, 0))
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter = bpy.context.active_object
cutter.rigid_body.collision_shape = 'SPHERE'
else: # ballnose ending used mainly when projecting from sides. the actual collision shape is capsule in this case.
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=2, raius=BULLET_SCALE * o.cutter_diameter / 2,
view_align=False, enter_editmode=False, location=CUTTER_OFFSET,
rotation=(0, 0, 0))
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.
cutter.rigid_body.collision_shape = 'CAPSULE'
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
elif type == 'VCARVE':
angle = o.cutter_tip_angle
s = math.tan(math.pi * (90 - angle / 2) / 180) / 2
bpy.ops.mesh.primitive_cone_add(vertices=32, radius1=BULLET_SCALE * o.cutter_diameter / 2, radius2=0,
depth=BULLET_SCALE * o.cutter_diameter * s, end_fill_type='NGON',
view_align=False, enter_editmode=False, location=CUTTER_OFFSET,
rotation=(math.pi, 0, 0))
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter = bpy.context.active_object
cutter.rigid_body.collision_shape = 'CONE'
elif type == 'CUSTOM':
cutob = bpy.data.objects[o.cutter_object_name]
activate(cutob)
bpy.ops.object.duplicate()
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter = bpy.context.active_object
scale = o.cutter_diameter / cutob.dimensions.x
cutter.scale *= BULLET_SCALE * scale
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN', center='BOUNDS')
# print(cutter.dimensions,scale)
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter.rigid_body.collision_shape = 'CONVEX_HULL'
cutter.location = CUTTER_OFFSET
cutter.name = 'cam_cutter'
o.cutter_shape = cutter
return cutter
type=o.cutter_type
if type=='END':
bpy.ops.mesh.primitive_cylinder_add(vertices=32, radius=BULLET_SCALE*o.cutter_diameter/2, depth=BULLET_SCALE*o.cutter_diameter, end_fill_type='NGON', view_align=False, enter_editmode=False, location=CUTTER_OFFSET, rotation=(0, 0, 0))
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter=bpy.context.active_object
cutter.rigid_body.collision_shape = 'CYLINDER'
elif type=='BALL' or type=='BALLNOSE':
if o.strategy!='PROJECTED_CURVE' or type=='BALL':#only sphere, good for 3 axis and real ball cutters for undercuts and projected curve
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=2, size=BULLET_SCALE*o.cutter_diameter/2, view_align=False, enter_editmode=False, location=CUTTER_OFFSET, rotation=(0, 0, 0))
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter=bpy.context.active_object
cutter.rigid_body.collision_shape = 'SPHERE'
else:#ballnose ending used mainly when projecting from sides. the actual collision shape is capsule in this case.
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=2, size=BULLET_SCALE*o.cutter_diameter/2, view_align=False, enter_editmode=False, location=CUTTER_OFFSET, rotation=(0, 0, 0))
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.
cutter.rigid_body.collision_shape = 'CAPSULE'
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
elif type=='VCARVE':
angle=o.cutter_tip_angle
s=math.tan(math.pi*(90-angle/2)/180)/2
bpy.ops.mesh.primitive_cone_add(vertices=32, radius1=BULLET_SCALE*o.cutter_diameter/2, radius2=0, depth = BULLET_SCALE*o.cutter_diameter*s, end_fill_type='NGON', view_align=False, enter_editmode=False, location=CUTTER_OFFSET, rotation=(math.pi, 0, 0))
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter=bpy.context.active_object
cutter.rigid_body.collision_shape = 'CONE'
elif type=='CUSTOM':
cutob=bpy.data.objects[o.cutter_object_name]
activate(cutob)
bpy.ops.object.duplicate()
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter=bpy.context.active_object
scale=o.cutter_diameter/cutob.dimensions.x
cutter.scale*=BULLET_SCALE*scale
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN',center = 'BOUNDS')
#print(cutter.dimensions,scale)
bpy.ops.rigidbody.object_add(type='ACTIVE')
cutter.rigid_body.collision_shape = 'CONVEX_HULL'
cutter.location=CUTTER_OFFSET
cutter.name='cam_cutter'
o.cutter_shape=cutter
return cutter
def subdivideLongEdges(ob, threshold):
print('subdividing long edges')
m=ob.data
scale=(ob.scale.x+ob.scale.y+ob.scale.z)/3
subdivides=[]
n=1
iter=0
while n>0:
n=0
for i,e in enumerate(m.edges):
v1=m.vertices[e.vertices[0]].co
v2=m.vertices[e.vertices[1]].co
vec=v2-v1
l=vec.length
if l*scale>threshold:
n+=1
subdivides.append(i)
if n>0:
print(len(subdivides))
bpy.ops.object.editmode_toggle()
print('subdividing long edges')
m = ob.data
scale = (ob.scale.x + ob.scale.y + ob.scale.z) / 3
subdivides = []
n = 1
iter = 0
while n > 0:
n = 0
for i, e in enumerate(m.edges):
v1 = m.vertices[e.vertices[0]].co
v2 = m.vertices[e.vertices[1]].co
vec = v2 - v1
l = vec.length
if l * scale > threshold:
n += 1
subdivides.append(i)
if n > 0:
print(len(subdivides))
bpy.ops.object.editmode_toggle()
#bpy.ops.mesh.quads_convert_to_tris(quad_method='BEAUTY', ngon_method='BEAUTY')
#bpy.ops.mesh.tris_convert_to_quads()
# bpy.ops.mesh.quads_convert_to_tris(quad_method='BEAUTY', ngon_method='BEAUTY')
# bpy.ops.mesh.tris_convert_to_quads()
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bpy.ops.object.editmode_toggle()
for i in subdivides:
m.edges[i].select = True
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.subdivide(smoothness=0)
if iter == 0:
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.quads_convert_to_tris(quad_method='SHORTEST_DIAGONAL', ngon_method='BEAUTY')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.editmode_toggle()
ob.update_from_editmode()
iter += 1
# n=0
#
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bpy.ops.object.editmode_toggle()
for i in subdivides:
m.edges[i].select=True
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.subdivide(smoothness=0)
if iter==0:
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.quads_convert_to_tris(quad_method='SHORTEST_DIAGONAL', ngon_method='BEAUTY')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.editmode_toggle()
ob.update_from_editmode()
iter+=1
#n=0
#
def prepareBulletCollision(o):
'''prepares all objects needed for sampling with bullet collision'''
progress('preparing collisions')
t=time.time()
s=bpy.context.scene
s.gravity=(0,0,0)
#cleanup rigidbodies wrongly placed somewhere in the scene
for ob in bpy.context.scene.objects:
if ob.rigid_body != None and (bpy.data.groups.find('machine')>-1 and ob.name not in bpy.data.groups['machine'].objects):
activate(ob)
bpy.ops.rigidbody.object_remove()
for collisionob in o.objects:
activate(collisionob)
bpy.ops.object.duplicate(linked=False)
collisionob=bpy.context.active_object
if collisionob.type=='CURVE' or collisionob.type=='FONT':#support for curve objects collision
if collisionob.type=='CURVE':
odata=collisionob.data.dimensions
collisionob.data.dimensions='2D'
bpy.ops.object.convert(target='MESH', keep_original=False)
'''prepares all objects needed for sampling with bullet collision'''
progress('preparing collisions')
print(o.name)
t = time.time()
s = bpy.context.scene
s.gravity = (0, 0, 0)
# cleanup rigidbodies wrongly placed somewhere in the scene
for ob in bpy.context.scene.objects:
if ob.rigid_body is not None and (bpy.data.objects.find('machine') > -1 and ob.name not in bpy.data.objects['machine'].objects):
activate(ob)
bpy.ops.rigidbody.object_remove()
for collisionob in o.objects:
activate(collisionob)
bpy.ops.object.duplicate(linked=False)
collisionob = bpy.context.active_object
if collisionob.type == 'CURVE' or collisionob.type == 'FONT': # support for curve objects collision
if collisionob.type == 'CURVE':
odata = collisionob.data.dimensions
collisionob.data.dimensions = '2D'
bpy.ops.object.convert(target='MESH', keep_original=False)
if o.use_modifiers:
newmesh = collisionob.to_mesh(bpy.context.depsgraph, True, calc_undeformed=False)
oldmesh = collisionob.data
collisionob.modifiers.clear()
collisionob.data = newmesh
bpy.data.meshes.remove(oldmesh)
# subdivide long edges here:
if o.exact_subdivide_edges:
subdivideLongEdges(collisionob, o.cutter_diameter * 2)
bpy.ops.rigidbody.object_add(type='ACTIVE') # using active instead of passive because of performance.TODO: check if this works also with 4axis...
collisionob.rigid_body.collision_shape = 'MESH'
collisionob.rigid_body.kinematic = True # this fixed a serious bug and gave big speedup, rbs could move since they are now active...
collisionob.rigid_body.collision_margin = o.skin * BULLET_SCALE
bpy.ops.transform.resize(value=(BULLET_SCALE, BULLET_SCALE, BULLET_SCALE),
constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False,
proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1,
snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False,
snap_normal=(0, 0, 0), texture_space=False, release_confirm=False)
collisionob.location = collisionob.location * BULLET_SCALE
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
getCutterBullet(o)
# machine objects scaling up to simulation scale
if bpy.data.objects.find('machine') > -1:
for ob in bpy.data.objects['machine'].objects:
activate(ob)
bpy.ops.transform.resize(value=(BULLET_SCALE, BULLET_SCALE, BULLET_SCALE),
constraint_axis=(False, False, False), constraint_orientation='GLOBAL',
mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH',
proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0),
snap_align=False, snap_normal=(0, 0, 0), texture_space=False,
release_confirm=False)
ob.location = ob.location * BULLET_SCALE
# stepping simulation so that objects are up to date
bpy.context.scene.frame_set(0)
bpy.context.scene.frame_set(1)
bpy.context.scene.frame_set(2)
progress(time.time() - t)
if o.use_modifiers:
newmesh = collisionob.to_mesh(bpy.context.scene, True, 'RENDER', False)
oldmesh = collisionob.data
collisionob.modifiers.clear()
collisionob.data = newmesh
bpy.data.meshes.remove(oldmesh)
#subdivide long edges here:
if o.exact_subdivide_edges:
subdivideLongEdges(collisionob, o.cutter_diameter*2)
bpy.ops.rigidbody.object_add(type='ACTIVE')#using active instead of passive because of performance.TODO: check if this works also with 4axis...
collisionob.rigid_body.collision_shape = 'MESH'
collisionob.rigid_body.kinematic=True#this fixed a serious bug and gave big speedup, rbs could move since they are now active...
collisionob.rigid_body.collision_margin = o.skin*BULLET_SCALE
bpy.ops.transform.resize(value=(BULLET_SCALE, BULLET_SCALE, BULLET_SCALE), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), texture_space=False, release_confirm=False)
collisionob.location=collisionob.location*BULLET_SCALE
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
getCutterBullet(o)
#machine objects scaling up to simulation scale
if bpy.data.groups.find('machine')>-1:
for ob in bpy.data.groups['machine'].objects:
activate(ob)
bpy.ops.transform.resize(value=(BULLET_SCALE, BULLET_SCALE, BULLET_SCALE), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), texture_space=False, release_confirm=False)
ob.location=ob.location*BULLET_SCALE
#stepping simulation so that objects are up to date
bpy.context.scene.frame_set(0)
bpy.context.scene.frame_set(1)
bpy.context.scene.frame_set(2)
progress(time.time()-t)
def cleanupBulletCollision(o):
if bpy.data.groups.find('machine')>-1:
machinepresent=True
else:
machinepresent=False
for ob in bpy.context.scene.objects:
if ob.rigid_body != None and not (machinepresent and ob.name in bpy.data.groups['machine'].objects):
delob(ob)
#machine objects scaling up to simulation scale
if machinepresent:
for ob in bpy.data.groups['machine'].objects:
activate(ob)
bpy.ops.transform.resize(value=(1.0/BULLET_SCALE, 1.0/BULLET_SCALE, 1.0/BULLET_SCALE), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), texture_space=False, release_confirm=False)
ob.location=ob.location/BULLET_SCALE
if bpy.data.objects.find('machine') > -1:
machinepresent = True
else:
machinepresent = False
for ob in bpy.context.scene.objects:
if ob.rigid_body is not None and not (machinepresent and ob.name in bpy.data.objects['machine'].objects):
delob(ob)
# machine objects scaling up to simulation scale
if machinepresent:
for ob in bpy.data.objects['machine'].objects:
activate(ob)
bpy.ops.transform.resize(value=(1.0 / BULLET_SCALE, 1.0 / BULLET_SCALE, 1.0 / BULLET_SCALE),
constraint_axis=(False, False, False), constraint_orientation='GLOBAL',
mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH',
proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0),
snap_align=False, snap_normal=(0, 0, 0), texture_space=False,
release_confirm=False)
ob.location = ob.location / BULLET_SCALE
def getSampleBullet(cutter, x,y, radius, startz, endz):
'''collision test for 3 axis milling. Is simplified compared to the full 3d test'''
pos=bpy.context.scene.rigidbody_world.convex_sweep_test(cutter, (x*BULLET_SCALE, y*BULLET_SCALE, startz*BULLET_SCALE), (x*BULLET_SCALE, y*BULLET_SCALE, endz*BULLET_SCALE))
#radius is subtracted because we are interested in cutter tip position, this gets collision object center
if pos[3]==1:
return (pos[0][2]-radius)/BULLET_SCALE
else:
return endz-10;
def getSampleBulletNAxis(cutter, startpoint,endpoint,rotation, cutter_compensation):
'''fully 3d collision test for NAxis milling'''
cutterVec=Vector((0,0,1))*cutter_compensation#cutter compensation vector - cutter physics object has center in the middle, while cam needs the tip position.
cutterVec.rotate(Euler(rotation))
#print(rotation)
#print(cutterVec)
#cutterVec=Vector((0,0,0))
#cutterVec = startpoint-endpoint
#cutterVec.normalize()
#cutterVec*=cutter_compensation
#cutterVec=Vector((0,0,0))
start=(startpoint*BULLET_SCALE+cutterVec).to_tuple()
end=((endpoint)*BULLET_SCALE+cutterVec).to_tuple()
#cutter.rotation_euler=rotation
pos=bpy.context.scene.rigidbody_world.convex_sweep_test(cutter, start, end)
if pos[3]==1:
pos=Vector(pos[0])
#rescale and compensate from center to tip.
res=pos/BULLET_SCALE-cutterVec/BULLET_SCALE
#this is a debug loop that duplicates the cutter on sampling positions, to see where it was moving...
#if random.random()<0.01:
# dupliob(cutter,res)
return res
else:
return None;
def getSampleBullet(cutter, x, y, radius, startz, endz):
'''collision test for 3 axis milling. Is simplified compared to the full 3d test'''
pos = bpy.context.scene.rigidbody_world.convex_sweep_test(cutter, (
x * BULLET_SCALE, y * BULLET_SCALE, startz * BULLET_SCALE),
(x * BULLET_SCALE, y * BULLET_SCALE, endz * BULLET_SCALE))
# radius is subtracted because we are interested in cutter tip position, this gets collision object center
if pos[3] == 1:
return (pos[0][2] - radius) / BULLET_SCALE
else:
return endz - 10
def getSampleBulletNAxis(cutter, startpoint, endpoint, rotation, cutter_compensation):
'''fully 3d collision test for NAxis milling'''
cutterVec = Vector((0, 0,
1)) * cutter_compensation # cutter compensation vector - cutter physics object has center in the middle, while cam needs the tip position.
cutterVec.rotate(Euler(rotation))
# print(rotation)
# print(cutterVec)
# cutterVec=Vector((0,0,0))
# cutterVec = startpoint-endpoint
# cutterVec.normalize()
# cutterVec*=cutter_compensation
# cutterVec=Vector((0,0,0))
start = (startpoint * BULLET_SCALE + cutterVec).to_tuple()
end = ((endpoint) * BULLET_SCALE + cutterVec).to_tuple()
# cutter.rotation_euler=rotation
pos = bpy.context.scene.rigidbody_world.convex_sweep_test(cutter, start, end)
if pos[3] == 1:
pos = Vector(pos[0])
# rescale and compensate from center to tip.
res = pos / BULLET_SCALE - cutterVec / BULLET_SCALE
# this is a debug loop that duplicates the cutter on sampling positions, to see where it was moving...
# if random.random()<0.01:
# dupliob(cutter,res)
return res
else:
return None

Plik diff jest za duży Load Diff

Wyświetl plik

@ -20,7 +20,7 @@
# ***** END GPL LICENCE BLOCK *****
import bpy
from cam import utils, simple,polygon_utils_cam
from cam import utils, simple, polygon_utils_cam
import shapely
from shapely import geometry as sgeometry
from shapely import affinity, prepared
@ -28,198 +28,198 @@ from shapely import speedups
import random, time
import mathutils
from mathutils import Vector
#this algorithm takes all selected curves,
#converts them to polygons,
# this algorithm takes all selected curves,
# converts them to polygons,
# offsets them by the pre-set margin
#then chooses a starting location possibly inside the allready occupied area and moves and rotates the polygon out of the occupied area
#if one or more positions are found where the poly doesn't overlap, it is placed and added to the occupied area - allpoly
#this algorithm is very slow and STUPID, a collision algorithm would be much much faster...
def translate(s,x,y):
ncoords=[]
for p in s.exterior.coords:
ncoords.append((p[0]+x,p[1]+y))
return sgeometry.Polygon(ncoords)
# then chooses a starting location possibly inside the allready occupied area and moves and rotates the polygon out of the occupied area
# if one or more positions are found where the poly doesn't overlap, it is placed and added to the occupied area - allpoly
# this algorithm is very slow and STUPID, a collision algorithm would be much much faster...
def translate(s, x, y):
ncoords = []
for p in s.exterior.coords:
ncoords.append((p[0] + x, p[1] + y))
return sgeometry.Polygon(ncoords)
def srotate(s, r, x, y):
ncoords = []
e = mathutils.Euler((0, 0, r))
for p in s.exterior.coords:
v1 = Vector((p[0], p[1], 0))
v2 = Vector((x, y, 0))
v = v1 - v2
v.rotate(e)
ncoords.append((v[0], v[1]))
return sgeometry.Polygon(ncoords)
def srotate(s,r,x,y):
ncoords=[]
e=mathutils.Euler((0,0,r))
for p in s.exterior.coords:
v1=Vector((p[0],p[1],0))
v2=Vector((x,y,0))
v=v1-v2
v.rotate(e)
ncoords.append((v[0],v[1]))
return sgeometry.Polygon(ncoords)
def packCurves():
if speedups.available:
speedups.enable()
t=time.time()
packsettings=bpy.context.scene.cam_pack
sheetsizex=packsettings.sheet_x
sheetsizey=packsettings.sheet_y
direction=packsettings.sheet_fill_direction
distance=packsettings.distance
rotate = packsettings.rotate
polyfield=[]#in this, position, rotation, and actual poly will be stored.
for ob in bpy.context.selected_objects:
allchunks=[]
simple.activate(ob)
bpy.ops.object.make_single_user(type='SELECTED_OBJECTS')
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
z=ob.location.z
bpy.ops.object.location_clear()
bpy.ops.object.rotation_clear()
if speedups.available:
speedups.enable()
t = time.time()
packsettings = bpy.context.scene.cam_pack
chunks=utils.curveToChunks(ob)
npolys=utils.chunksToShapely(chunks)
#add all polys in silh to one poly
poly=shapely.ops.unary_union(npolys)
poly=poly.buffer(distance/1.5,8)
poly=poly.simplify(0.0003)
polyfield.append([[0,0],0.0,poly,ob,z])
random.shuffle(polyfield)
#primitive layout here:
allpoly=prepared.prep(sgeometry.Polygon())#main collision poly.
#allpoly=sgeometry.Polygon()#main collision poly.
shift=0.0015#one milimeter by now.
rotchange=.3123456#in radians
xmin,ymin,xmax,ymax=polyfield[0][2].bounds
if direction=='X':
mindist=-xmin
else:
mindist=-ymin
i=0
p=polyfield[0][2]
placedpolys=[]
rotcenter=sgeometry.Point(0,0)
for pf in polyfield:
print(i)
rot=0
porig=pf[2]
placed=False
xmin,ymin,xmax,ymax=p.bounds
#p.shift(-xmin,-ymin)
if direction=='X':
x=mindist
y=-ymin
if direction=='Y':
x=-xmin
y=mindist
iter=0
best=None
hits=0
besthit=None
while not placed:
#swap x and y, and add to x
#print(x,y)
p=porig
if rotate:
#ptrans=srotate(p,rot,0,0)
ptrans=affinity.rotate(p,rot,origin = rotcenter, use_radians=True)
#ptrans = translate(ptrans,x,y)
ptrans = affinity.translate(ptrans,x,y)
else:
#ptrans = translate(p,x,y)
ptrans = affinity.translate(p,x,y)
xmin,ymin,xmax,ymax=ptrans.bounds
#print(iter,p.bounds)
if xmin>0 and ymin>0 and ((direction=='Y' and xmax<sheetsizex) or (direction=='X' and ymax<sheetsizey)):
if not allpoly.intersects(ptrans):
#if allpoly.disjoint(ptrans):
#print('gothit')
#we do more good solutions, choose best out of them:
hits+=1
if best==None:
best=[x,y,rot,xmax,ymax]
besthit=hits
if direction=='X':
if xmax<best[3]:
best=[x,y,rot,xmax,ymax]
besthit=hits
elif ymax<best[4]:
best=[x,y,rot,xmax,ymax]
besthit=hits
sheetsizex = packsettings.sheet_x
sheetsizey = packsettings.sheet_y
direction = packsettings.sheet_fill_direction
distance = packsettings.distance
rotate = packsettings.rotate
polyfield = [] # in this, position, rotation, and actual poly will be stored.
for ob in bpy.context.selected_objects:
allchunks = []
simple.activate(ob)
bpy.ops.object.make_single_user(type='SELECTED_OBJECTS')
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
z = ob.location.z
bpy.ops.object.location_clear()
bpy.ops.object.rotation_clear()
if hits>=15 or (iter>10000 and hits>0):#here was originally more, but 90% of best solutions are still 1
placed=True
pf[3].location.x=best[0]
pf[3].location.y=best[1]
pf[3].location.z=pf[4]
pf[3].rotation_euler.z=best[2]
pf[3].select=True
#print(mindist)
mindist=mindist-0.5*(xmax-xmin)
#print(mindist)
#print(iter)
#reset polygon to best position here:
ptrans=affinity.rotate(porig,best[2],rotcenter, use_radians = True)
#ptrans=srotate(porig,best[2],0,0)
ptrans = affinity.translate(ptrans,best[0],best[1])
#ptrans = translate(ptrans,best[0],best[1])
#polygon_utils_cam.polyToMesh(p,0.1)#debug visualisation
keep=[]
print(best[0],best[1])
#print(len(ptrans.exterior))
#npoly=allpoly.union(ptrans)
'''
for ci in range(0,len(allpoly)):
cminx,cmaxx,cminy,cmaxy=allpoly.boundingBox(ci)
if direction=='X' and cmaxx>mindist-.1:
npoly.addContour(allpoly[ci])
if direction=='Y' and cmaxy>mindist-.1:
npoly.addContour(allpoly[ci])
'''
#allpoly=npoly
placedpolys.append(ptrans)
allpoly=prepared.prep(sgeometry.MultiPolygon(placedpolys))
#*** temporary fix until prepared geometry code is setup properly
#allpoly=sgeometry.MultiPolygon(placedpolys)
#polygon_utils_cam.polyToMesh(allpoly,0.1)#debug visualisation
#for c in p:
# allpoly.addContour(c)
#cleanup allpoly
print(iter,hits,besthit)
if not placed:
if direction=='Y':
x+=shift
mindist=y
if (xmax+shift>sheetsizex):
x=x-xmin
y+=shift
if direction=='X':
y+=shift
mindist=x
if (ymax+shift>sheetsizey):
y=y-ymin
x+=shift
if rotate: rot+=rotchange
iter+=1
i+=1
t=time.time()-t
chunks = utils.curveToChunks(ob)
npolys = utils.chunksToShapely(chunks)
# add all polys in silh to one poly
poly = shapely.ops.unary_union(npolys)
polygon_utils_cam.shapelyToCurve('test',sgeometry.MultiPolygon(placedpolys),0)
print(t)
poly = poly.buffer(distance / 1.5, 8)
poly = poly.simplify(0.0003)
polyfield.append([[0, 0], 0.0, poly, ob, z])
random.shuffle(polyfield)
# primitive layout here:
allpoly = prepared.prep(sgeometry.Polygon()) # main collision poly.
# allpoly=sgeometry.Polygon()#main collision poly.
shift = 0.0015 # one milimeter by now.
rotchange = .3123456 # in radians
xmin, ymin, xmax, ymax = polyfield[0][2].bounds
if direction == 'X':
mindist = -xmin
else:
mindist = -ymin
i = 0
p = polyfield[0][2]
placedpolys = []
rotcenter = sgeometry.Point(0, 0)
for pf in polyfield:
print(i)
rot = 0
porig = pf[2]
placed = False
xmin, ymin, xmax, ymax = p.bounds
# p.shift(-xmin,-ymin)
if direction == 'X':
x = mindist
y = -ymin
if direction == 'Y':
x = -xmin
y = mindist
iter = 0
best = None
hits = 0
besthit = None
while not placed:
# swap x and y, and add to x
# print(x,y)
p = porig
if rotate:
# ptrans=srotate(p,rot,0,0)
ptrans = affinity.rotate(p, rot, origin=rotcenter, use_radians=True)
# ptrans = translate(ptrans,x,y)
ptrans = affinity.translate(ptrans, x, y)
else:
# ptrans = translate(p,x,y)
ptrans = affinity.translate(p, x, y)
xmin, ymin, xmax, ymax = ptrans.bounds
# print(iter,p.bounds)
if xmin > 0 and ymin > 0 and (
(direction == 'Y' and xmax < sheetsizex) or (direction == 'X' and ymax < sheetsizey)):
if not allpoly.intersects(ptrans):
# if allpoly.disjoint(ptrans):
# print('gothit')
# we do more good solutions, choose best out of them:
hits += 1
if best == None:
best = [x, y, rot, xmax, ymax]
besthit = hits
if direction == 'X':
if xmax < best[3]:
best = [x, y, rot, xmax, ymax]
besthit = hits
elif ymax < best[4]:
best = [x, y, rot, xmax, ymax]
besthit = hits
if hits >= 15 or (
iter > 10000 and hits > 0): # here was originally more, but 90% of best solutions are still 1
placed = True
pf[3].location.x = best[0]
pf[3].location.y = best[1]
pf[3].location.z = pf[4]
pf[3].rotation_euler.z = best[2]
pf[3].select = True
# print(mindist)
mindist = mindist - 0.5 * (xmax - xmin)
# print(mindist)
# print(iter)
# reset polygon to best position here:
ptrans = affinity.rotate(porig, best[2], rotcenter, use_radians=True)
# ptrans=srotate(porig,best[2],0,0)
ptrans = affinity.translate(ptrans, best[0], best[1])
# ptrans = translate(ptrans,best[0],best[1])
# polygon_utils_cam.polyToMesh(p,0.1)#debug visualisation
keep = []
print(best[0], best[1])
# print(len(ptrans.exterior))
# npoly=allpoly.union(ptrans)
'''
for ci in range(0,len(allpoly)):
cminx,cmaxx,cminy,cmaxy=allpoly.boundingBox(ci)
if direction=='X' and cmaxx>mindist-.1:
npoly.addContour(allpoly[ci])
if direction=='Y' and cmaxy>mindist-.1:
npoly.addContour(allpoly[ci])
'''
# allpoly=npoly
placedpolys.append(ptrans)
allpoly = prepared.prep(sgeometry.MultiPolygon(placedpolys))
# *** temporary fix until prepared geometry code is setup properly
# allpoly=sgeometry.MultiPolygon(placedpolys)
# polygon_utils_cam.polyToMesh(allpoly,0.1)#debug visualisation
# for c in p:
# allpoly.addContour(c)
# cleanup allpoly
print(iter, hits, besthit)
if not placed:
if direction == 'Y':
x += shift
mindist = y
if (xmax + shift > sheetsizex):
x = x - xmin
y += shift
if direction == 'X':
y += shift
mindist = x
if (ymax + shift > sheetsizey):
y = y - ymin
x += shift
if rotate: rot += rotchange
iter += 1
i += 1
t = time.time() - t
polygon_utils_cam.shapelyToCurve('test', sgeometry.MultiPolygon(placedpolys), 0)
print(t)

Wyświetl plik

@ -29,144 +29,150 @@ import shapely
from shapely.geometry import polygon as spolygon
from shapely import ops
from shapely import geometry as sgeometry
SHAPELY=True
#except:
SHAPELY = True
# except:
# SHAPELY=False
def Circle(r,np):
c=[]
pi=math.pi
v=mathutils.Vector((r,0,0))
e=mathutils.Euler((0,0,2.0*pi/np))
for a in range(0,np):
c.append((v.x,v.y))
v.rotate(e)
p=spolygon.Polygon(c)
return p
def Circle(r, np):
c = []
pi = math.pi
v = mathutils.Vector((r, 0, 0))
e = mathutils.Euler((0, 0, 2.0 * pi / np))
for a in range(0, np):
c.append((v.x, v.y))
v.rotate(e)
p = spolygon.Polygon(c)
return p
def shapelyRemoveDoubles(p, optimize_threshold):
optimize_threshold *= 0.000001
# vecs=[]
soptions = ['distance', 'distance', 0.0, 5, optimize_threshold, 5, optimize_threshold]
for ci, c in enumerate(p.boundary): # in range(0,len(p)):
veclist = []
for v in c:
veclist.append(Vector((v[0], v[1])))
# progress(len(veclist))
s = curve_simplify.simplify_RDP(veclist, soptions)
# progress(len(s))
nc = []
for i in range(0, len(s)):
nc.append(c[s[i]])
if len(nc) > 2:
pnew.addContour(nc, p.isHole(ci))
else:
pnew.addContour(p[ci], p.isHole(ci))
# progress(time.time()-t)
return pnew
def shapelyRemoveDoubles(p,optimize_threshold):
optimize_threshold*=0.000001
#vecs=[]
soptions=['distance','distance',0.0,5,optimize_threshold,5,optimize_threshold]
for ci,c in enumerate(p.boundary):# in range(0,len(p)):
veclist=[]
for v in c:
veclist.append(Vector((v[0],v[1])))
#progress(len(veclist))
s=curve_simplify.simplify_RDP(veclist, soptions)
#progress(len(s))
nc=[]
for i in range(0,len(s)):
nc.append(c[s[i]])
if len(nc)>2:
pnew.addContour(nc,p.isHole(ci))
else:
pnew.addContour(p[ci],p.isHole(ci))
#progress(time.time()-t)
return pnew
def shapelyToMultipolygon(anydata):
if anydata.type == 'MultiPolygon':
return anydata
elif anydata.type == 'Polygon':
if not anydata.is_empty:
return shapely.geometry.MultiPolygon([anydata])
else:
return sgeometry.MultiPolygon()
else:
print(anydata.type, 'shapely conversion aborted')
return sgeometry.MultiPolygon()
if anydata.type == 'MultiPolygon':
return anydata
elif anydata.type == 'Polygon':
if not anydata.is_empty:
return shapely.geometry.MultiPolygon([anydata])
else:
return sgeometry.MultiPolygon()
else:
print(anydata.type, 'shapely conversion aborted')
return sgeometry.MultiPolygon()
def shapelyToCoords(anydata):
p=anydata
seq=[]
#print(p.type)
#print(p.geom_type)
if p.is_empty:
return seq
elif p.type=='Polygon':
#print('polygon')
clen=len(p.exterior.coords)
#seq = sgeometry.asMultiLineString(p)
seq=[p.exterior.coords]
#print(len(p.interiors))
for interior in p.interiors:
seq.append(interior.coords)
elif p.type=='MultiPolygon':
clen=0
seq=[]
for sp in p:
clen+=len(sp.exterior.coords)
seq.append(sp.exterior.coords)
for interior in sp.interiors:
seq.append(interior.coords)
elif p.type=='MultiLineString':
seq=[]
for linestring in p:
seq.append(linestring.coords)
elif p.type=='LineString':
seq=[]
seq.append(p.coords)
elif p.type=='MultiPoint':
return;
elif p.type=='GeometryCollection':
#print(dir(p))
#print(p.geometryType, p.geom_type)
clen=0
seq=[]
#print(p.boundary.coordsd)
for sp in p:#TODO
#seq.append(shapelyToCoords(sp))
clen+=len(sp.exterior.coords)
seq.append(sp.exterior.coords)
for interior in sp.interiors:
seq.extend(interior.coords)
p = anydata
seq = []
# print(p.type)
# print(p.geom_type)
if p.is_empty:
return seq
elif p.type == 'Polygon':
#for g in p.geom:
# print(g.type)
return seq
def shapelyToCurve(name,p,z):
import bpy,bmesh
from bpy_extras import object_utils
verts=[]
edges=[]
vi=0
ci=0
#for c in p.exterior.coords:
#print(p.type)
seq = shapelyToCoords(p)
w = 1 # weight
# print('polygon')
clen = len(p.exterior.coords)
# seq = sgeometry.asMultiLineString(p)
seq = [p.exterior.coords]
# print(len(p.interiors))
for interior in p.interiors:
seq.append(interior.coords)
elif p.type == 'MultiPolygon':
clen = 0
seq = []
for sp in p:
clen += len(sp.exterior.coords)
seq.append(sp.exterior.coords)
for interior in sp.interiors:
seq.append(interior.coords)
curvedata = bpy.data.curves.new(name=name, type='CURVE')
curvedata.dimensions = '3D'
objectdata = bpy.data.objects.new(name, curvedata)
objectdata.location = (0,0,0) #object origin
bpy.context.scene.objects.link(objectdata)
for c in seq:
polyline = curvedata.splines.new('POLY')
polyline.points.add(len(c)-1)
for num in range(len(c)):
x, y = c[num][0],c[num][1]
polyline.points[num].co = (x, y, z, w)
objectdata.select = True
bpy.context.scene.objects.active = objectdata
for c in objectdata.data.splines:
c.use_cyclic_u=True
objectdata.data.show_handles=False
objectdata.data.show_normal_face=False
return objectdata#bpy.context.active_object
elif p.type == 'MultiLineString':
seq = []
for linestring in p:
seq.append(linestring.coords)
elif p.type == 'LineString':
seq = []
seq.append(p.coords)
elif p.type == 'MultiPoint':
return;
elif p.type == 'GeometryCollection':
# print(dir(p))
# print(p.geometryType, p.geom_type)
clen = 0
seq = []
# print(p.boundary.coordsd)
for sp in p: # TODO
# seq.append(shapelyToCoords(sp))
clen += len(sp.exterior.coords)
seq.append(sp.exterior.coords)
for interior in sp.interiors:
seq.extend(interior.coords)
# for g in p.geom:
# print(g.type)
return seq
def shapelyToCurve(name, p, z):
import bpy, bmesh
from bpy_extras import object_utils
verts = []
edges = []
vi = 0
ci = 0
# for c in p.exterior.coords:
# print(p.type)
seq = shapelyToCoords(p)
w = 1 # weight
curvedata = bpy.data.curves.new(name=name, type='CURVE')
curvedata.dimensions = '3D'
objectdata = bpy.data.objects.new(name, curvedata)
objectdata.location = (0, 0, 0) # object origin
bpy.context.scene.objects.link(objectdata)
for c in seq:
polyline = curvedata.splines.new('POLY')
polyline.points.add(len(c) - 1)
for num in range(len(c)):
x, y = c[num][0], c[num][1]
polyline.points[num].co = (x, y, z, w)
objectdata.select = True
bpy.context.scene.objects.active = objectdata
for c in objectdata.data.splines:
c.use_cyclic_u = True
objectdata.data.show_handles = False
objectdata.data.show_normal_face = False
return objectdata # bpy.context.active_object

Wyświetl plik

@ -19,152 +19,171 @@
#
# ***** END GPL LICENCE BLOCK *****
import math,sys,os,string
import math, sys, os, string
import time
import bpy
import mathutils
import mathutils
from mathutils import *
from math import *
def tuple_add(t,t1):#add two tuples as Vectors
return (t[0]+t1[0],t[1]+t1[1],t[2]+t1[2])
def tuple_sub(t,t1):#sub two tuples as Vectors
return (t[0]-t1[0],t[1]-t1[1],t[2]-t1[2])
def tuple_add(t, t1): # add two tuples as Vectors
return (t[0] + t1[0], t[1] + t1[1], t[2] + t1[2])
def tuple_mul(t,c):#multiply two tuples with a number
return (t[0]*c,t[1]*c,t[2]*c)
def tuple_length(t):#get length of vector, but passed in as tuple.
return (Vector(t).length)
#timing functions for optimisation purposes...
def tuple_sub(t, t1): # sub two tuples as Vectors
return (t[0] - t1[0], t[1] - t1[1], t[2] - t1[2])
def tuple_mul(t, c): # multiply two tuples with a number
return (t[0] * c, t[1] * c, t[2] * c)
def tuple_length(t): # get length of vector, but passed in as tuple.
return (Vector(t).length)
# timing functions for optimisation purposes...
def timinginit():
return[0,0]
return [0, 0]
def timingstart(tinf):
t=time.time()
tinf[1]=t
t = time.time()
tinf[1] = t
def timingadd(tinf):
t=time.time()
tinf[0]+=t-tinf[1]
t = time.time()
tinf[0] += t - tinf[1]
def timingprint(tinf):
print('time '+str(tinf[0])+'seconds')
def progress(text,n=None):
'''function for reporting during the script, works for background operations in the header.'''
#for i in range(n+1):
#sys.stdout.flush()
text=str(text)
if n== None:
n=''
else:
n=' ' + str(int(n*1000)/1000) + '%'
#d=int(n/2)
spaces=' '*(len(text)+55)
sys.stdout.write('progress{%s%s}\n' % (text,n))
sys.stdout.flush()
#bpy.data.window_managers['WinMan'].progress_update(n)
#if bpy.context.scene.o
#bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
#time.sleep(0.5)
print('time ' + str(tinf[0]) + 'seconds')
def progress(text, n=None):
'''function for reporting during the script, works for background operations in the header.'''
# for i in range(n+1):
# sys.stdout.flush()
text = str(text)
if n == None:
n = ''
else:
n = ' ' + str(int(n * 1000) / 1000) + '%'
# d=int(n/2)
spaces = ' ' * (len(text) + 55)
sys.stdout.write('progress{%s%s}\n' % (text, n))
sys.stdout.flush()
# bpy.data.window_managers['WinMan'].progress_update(n)
# if bpy.context.scene.o
# bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
# time.sleep(0.5)
#
def activate(o):
'''makes an object active, used many times in blender'''
s=bpy.context.scene
bpy.ops.object.select_all(action='DESELECT')
o.select=True
s.objects.active=o
'''makes an object active, used many times in blender'''
s = bpy.context.scene
bpy.ops.object.select_all(action='DESELECT')
o.select_set(state=True, view_layer=None)
s.objects[o.name].select_set(state=True, view_layer=None)
def dist2d(v1, v2):
'''distance between two points in 2d'''
return math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]))
def dist2d(v1,v2):
'''distance between two points in 2d'''
return math.sqrt((v1[0]-v2[0])*(v1[0]-v2[0])+(v1[1]-v2[1])*(v1[1]-v2[1]))
def delob(ob):
'''object deletion for multiple uses'''
activate(ob)
bpy.ops.object.delete(use_global=False)
'''object deletion for multiple uses'''
activate(ob)
bpy.ops.object.delete(use_global=False)
def dupliob(o,pos):
'''helper function for visualising cutter positions in bullet simulation'''
activate(o)
bpy.ops.object.duplicate()
s=1.0/BULLET_SCALE
bpy.ops.transform.resize(value=(s, s, s), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1)
o=bpy.context.active_object
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 dupliob(o, pos):
'''helper function for visualising cutter positions in bullet simulation'''
activate(o)
bpy.ops.object.duplicate()
s = 1.0 / BULLET_SCALE
bpy.ops.transform.resize(value=(s, s, s), constraint_axis=(False, False, False), constraint_orientation='GLOBAL',
mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH',
proportional_size=1)
o = bpy.context.active_object
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
v1 = Vector(v1)
v2 = Vector(v2)
vmiddle = Vector(vmiddle)
vect1 = v2 - v1
vect2 = vmiddle - v1
vect1.normalize()
vect1 *= vect2.length
v = vect2 - vect1
if v.length < e:
return True
return False
def isVerticalLimit(v1, v2, limit):
'''test path segment on verticality threshold, for protect_vertical option'''
z = abs(v1[2] - v2[2])
# verticality=0.05
# this will be better.
#
# print(a)
if z > 0:
v2d = Vector((0, 0, -1))
v3d = Vector((v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]))
a = v3d.angle(v2d)
if a > pi / 2:
a = abs(a - pi)
# print(a)
if a < limit:
# print(abs(v1[0]-v2[0])/z)
# print(abs(v1[1]-v2[1])/z)
if v1[2] > v2[2]:
v1 = (v2[0], v2[1], v1[2])
return v1, v2
else:
v2 = (v1[0], v1[1], v2[2])
return v1, v2
return v1, v2
def compare(v1,v2,vmiddle,e):
'''comparison for optimisation of paths'''
#e=0.0001
v1=Vector(v1)
v2=Vector(v2)
vmiddle=Vector(vmiddle)
vect1=v2-v1
vect2=vmiddle-v1
vect1.normalize()
vect1*=vect2.length
v=vect2-vect1
if v.length<e:
return True
return False
def isVerticalLimit(v1,v2,limit):
'''test path segment on verticality threshold, for protect_vertical option'''
z=abs(v1[2]-v2[2])
#verticality=0.05
#this will be better.
#
#print(a)
if z>0:
v2d=Vector((0,0,-1))
v3d=Vector((v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]))
a=v3d.angle(v2d)
if a>pi/2:
a=abs(a-pi)
#print(a)
if a<limit:
#print(abs(v1[0]-v2[0])/z)
#print(abs(v1[1]-v2[1])/z)
if v1[2]>v2[2]:
v1=(v2[0],v2[1],v1[2])
return v1,v2
else:
v2=(v1[0],v1[1],v2[2])
return v1,v2
return v1,v2
def getCachePath(o):
fn=bpy.data.filepath
l=len(bpy.path.basename(fn))
bn=bpy.path.basename(fn)[:-6]
iname=fn[:-l]+'temp_cam'+os.sep+bn+'_'+o.name
return iname
fn = bpy.data.filepath
l = len(bpy.path.basename(fn))
bn = bpy.path.basename(fn)[:-6]
def safeFileName(name):#for export gcode
valid_chars = "-_.()%s%s" % (string.ascii_letters, string.digits)
filename=''.join(c for c in name if c in valid_chars)
return filename
iname = fn[:-l] + 'temp_cam' + os.sep + bn + '_' + o.name
return iname
def strInUnits(x,precision=5):
if bpy.context.scene.unit_settings.system == 'METRIC':
return str( round(x * 1000,precision) )+' mm '
elif bpy.context.scene.unit_settings.system == 'IMPERIAL':
return str( round(x * 1000/25.4,precision) )+"'' "
else:
return str(x)
def safeFileName(name): # for export gcode
valid_chars = "-_.()%s%s" % (string.ascii_letters, string.digits)
filename = ''.join(c for c in name if c in valid_chars)
return filename
def strInUnits(x, precision=5):
if bpy.context.scene.unit_settings.system == 'METRIC':
return str(round(x * 1000, precision)) + ' mm '
elif bpy.context.scene.unit_settings.system == 'IMPERIAL':
return str(round(x * 1000 / 25.4, precision)) + "'' "
else:
return str(x)

Wyświetl plik

@ -19,257 +19,249 @@
#
# ***** END GPL LICENCE BLOCK *****
#very simple slicing for 3d meshes, usefull for plywood cutting.
# very simple slicing for 3d meshes, usefull for plywood cutting.
from cam import chunk, polygon_utils_cam
import bpy
def getSlices(ob,slice_distance):
'''function for slicing a mesh. It is now not used, but can be used for e.g. lasercutting from sheets a 3d model in the future.'''
layer_thickness=slice_distance
edges=[]
verts = []
i=0
slices=[]#slice format is [length, minx,miny, maxx, maxy,verts,z]
firstslice=None
lastslice=None
maxzt = -100000000000000000000000000
minzt = 1000000000000000000000000000
#progress('slicing object')
m=ob.to_mesh(scene=bpy.context.scene, apply_modifiers=True, settings='PREVIEW')
#d={}#!
for p in m.polygons:
#a=i*50+12
v1=m.vertices[p.vertices[0]].co
v2=m.vertices[p.vertices[1]].co
v3=m.vertices[p.vertices[2]].co
if len(p.vertices)==3:
tris=[[v1,v2,v3]]
else:
v4=m.vertices[p.vertices[3]].co
tris=[[v1,v2,v3],[v3,v4,v1]]
for v in tris:
#print(v)
minz=min(v[0].z,v[1].z,v[2].z)
maxz=max(v[0].z,v[1].z,v[2].z)
t=layer_thickness
start=int(minz // t)
end=int(maxz // t +2)
if firstslice==None:
firstslice = start
lastslice = end
#print start, end
for s in range(firstslice,lastslice):
sz= s*t
slices.append([0.0,100000000000.0,100000000000.0,-100000000000.0,-100000000000.0,[],sz])
if start<firstslice:
ns=[]
ind=0
for s in range(start, firstslice):
sz=s*t
slices.insert(ind,[0.0,100000000000.0,100000000000.0,-100000000000.0,-100000000000.0,[],sz])
ind+=1
firstslice=start
if end>lastslice:
for s in range(lastslice,end):
sz=s*t
slices.append([0.0,100000000000.0,100000000000.0,-100000000000.0,-100000000000.0,[],sz])
#i+=1
lastslice=end
for s in range(start,end):
si=s-firstslice
sc=slices[si]
sz = sc[6]#s * t
over=[]
under=[]
onslice=[]
iv=[]
for vert in v:
if vert[2]>sz:
over.append(vert)
elif vert[2]<sz:
under.append(vert)
elif vert[2]==sz:
onslice.append(vert)
if len(onslice)==1:
#pass
iv.append((onslice[0][0],onslice[0][1],sz))
#iv[-1]=(int(1000000000*iv[-1][0])/1000000000,int(1000000000*iv[-1][1])/1000000000,int(1000000000*iv[-1][2])/1000000000)
elif len(onslice)==2:
#if p.normal.z<1.0:
#iv.extend([onslice[0],onslice[1]])
iv.append((onslice[0][0],onslice[0][1],sz))
iv.append((onslice[1][0],onslice[1][1],sz))
#iv[-2]=(int(1000000000*iv[-2][0])/1000000000,int(1000000000*iv[-2][1])/1000000000,int(1000000000*iv[-2][2])/1000000000)
#iv[-1]=(int(1000000000*iv[-1][0])/1000000000,int(1000000000*iv[-1][1])/1000000000,int(1000000000*iv[-1][2])/1000000000)
elif len(onslice)==3:
print('flat face')#,v)
for v1 in under:
for v2 in over:
coef=(sz-v1[2])/(v2[2]-v1[2])
x=v1[0]+(v2[0]-v1[0])*coef
y=v1[1]+(v2[1]-v1[1])*coef
z=sz#!
#iv.append((int(100000000*x)/100000000,int(100000000*y)/100000000,int(100000000*z)/100000000))#! z not needed!
iv.append((x,y,sz))
if len(iv)==2:
#d{iv[0]}
#sc=slices[si]
#print(iv)
sc[5].append(iv[0])
sc[5].append(iv[1])
else:
pass
# print('strange count of layer faces',iv)
if i % 10000 == 0:
print ('parsed faces', i, firstslice, lastslice, len(slices))
i+=1
#sliceobs=[]
print('sorting slices')
slicechunks=[]
obs=[]
for sc in slices:
if len(sc[5])>0:
i=0
chi=0
edges=[]
z=sc[5][0][2]
slicechunks.append([])
d={}
for i in range(0,len(sc[5])):
d[sc[5][i]]=[]
for i in range(0,int(len(sc[5])/2)):
verts1=d[sc[5][i*2]]
verts2=d[sc[5][i*2+1]]
if len(verts1)==2:
if verts1[0]==verts1[1]:
verts1.pop()
if len(verts1)<2:
verts1.append(sc[5][i*2+1])
if len(verts2)==2:
if verts2[0]==verts2[1]:
verts2.pop()
if len(verts2)<2:
verts2.append(sc[5][i*2])
ch=[sc[5][0],sc[5][1]]#first and his reference
d.pop(ch[0])
i=0
verts=[123]
while len(d)>0 and i<200000:# and verts!=[]:
verts=d.get(ch[-1],[])
if len(verts)<=1:
if len(ch)>2:
slicechunks[-1].append(ch)
v1=d.popitem()
ch=[v1[0],v1[1][0]]
elif len(verts)>2:
pass;
i+=1
else:
done=False
for v in verts:
if not done:
if v[0]==ch[-2][0] and v[1]==ch[-2][1]:# and v[2]==ch[-2][2]:
pass
else:
#print(v,ch[-2])
ch.append(v)
d.pop(ch[-2])
done=True
if v[0]==ch[0][0] and v[1]==ch[0][1]:# and v[2]==ch[0][2]:
slicechunks[-1].append(ch)
print('closed')
#d.pop(ch[-1])
if len(d)>0:
v1=d.popitem()
ch=[v1[0],v1[1][0]]
i+=1
slicechunks[-1].append(ch)################3this might be a bug!!!!
#print(len(slicechunks))
return slicechunks
def getSlices(ob, slice_distance):
'''function for slicing a mesh. It is now not used, but can be used for e.g. lasercutting from sheets a 3d model in the future.'''
layer_thickness = slice_distance
edges = []
verts = []
i = 0
slices = [] # slice format is [length, minx,miny, maxx, maxy,verts,z]
firstslice = None
lastslice = None
maxzt = -100000000000000000000000000
minzt = 1000000000000000000000000000
# progress('slicing object')
m = ob.to_mesh(bpy.context.depsgraph, True, calc_undeformed=False)
# d={}#!
for p in m.polygons:
# a=i*50+12
v1 = m.vertices[p.vertices[0]].co
v2 = m.vertices[p.vertices[1]].co
v3 = m.vertices[p.vertices[2]].co
if len(p.vertices) == 3:
tris = [[v1, v2, v3]]
else:
v4 = m.vertices[p.vertices[3]].co
tris = [[v1, v2, v3], [v3, v4, v1]]
for v in tris:
# print(v)
minz = min(v[0].z, v[1].z, v[2].z)
maxz = max(v[0].z, v[1].z, v[2].z)
t = layer_thickness
start = int(minz // t)
end = int(maxz // t + 2)
if firstslice == None:
firstslice = start
lastslice = end
# print start, end
for s in range(firstslice, lastslice):
sz = s * t
slices.append([0.0, 100000000000.0, 100000000000.0, -100000000000.0, -100000000000.0, [], sz])
if start < firstslice:
ns = []
ind = 0
for s in range(start, firstslice):
sz = s * t
slices.insert(ind, [0.0, 100000000000.0, 100000000000.0, -100000000000.0, -100000000000.0, [], sz])
ind += 1
firstslice = start
if end > lastslice:
for s in range(lastslice, end):
sz = s * t
slices.append([0.0, 100000000000.0, 100000000000.0, -100000000000.0, -100000000000.0, [], sz])
# i+=1
lastslice = end
for s in range(start, end):
si = s - firstslice
sc = slices[si]
sz = sc[6] # s * t
over = []
under = []
onslice = []
iv = []
for vert in v:
if vert[2] > sz:
over.append(vert)
elif vert[2] < sz:
under.append(vert)
elif vert[2] == sz:
onslice.append(vert)
if len(onslice) == 1:
# pass
iv.append((onslice[0][0], onslice[0][1], sz))
# iv[-1]=(int(1000000000*iv[-1][0])/1000000000,int(1000000000*iv[-1][1])/1000000000,int(1000000000*iv[-1][2])/1000000000)
elif len(onslice) == 2:
# if p.normal.z<1.0:
# iv.extend([onslice[0],onslice[1]])
iv.append((onslice[0][0], onslice[0][1], sz))
iv.append((onslice[1][0], onslice[1][1], sz))
# iv[-2]=(int(1000000000*iv[-2][0])/1000000000,int(1000000000*iv[-2][1])/1000000000,int(1000000000*iv[-2][2])/1000000000)
# iv[-1]=(int(1000000000*iv[-1][0])/1000000000,int(1000000000*iv[-1][1])/1000000000,int(1000000000*iv[-1][2])/1000000000)
elif len(onslice) == 3:
print('flat face') # ,v)
for v1 in under:
for v2 in over:
coef = (sz - v1[2]) / (v2[2] - v1[2])
x = v1[0] + (v2[0] - v1[0]) * coef
y = v1[1] + (v2[1] - v1[1]) * coef
z = sz # !
# iv.append((int(100000000*x)/100000000,int(100000000*y)/100000000,int(100000000*z)/100000000))#! z not needed!
iv.append((x, y, sz))
if len(iv) == 2:
# d{iv[0]}
# sc=slices[si]
# print(iv)
sc[5].append(iv[0])
sc[5].append(iv[1])
else:
pass
# print('strange count of layer faces',iv)
if i % 10000 == 0:
print('parsed faces', i, firstslice, lastslice, len(slices))
i += 1
# sliceobs=[]
print('sorting slices')
slicechunks = []
obs = []
for sc in slices:
if len(sc[5]) > 0:
i = 0
chi = 0
edges = []
z = sc[5][0][2]
slicechunks.append([])
d = {}
for i in range(0, len(sc[5])):
d[sc[5][i]] = []
for i in range(0, int(len(sc[5]) / 2)):
verts1 = d[sc[5][i * 2]]
verts2 = d[sc[5][i * 2 + 1]]
if len(verts1) == 2:
if verts1[0] == verts1[1]:
verts1.pop()
if len(verts1) < 2:
verts1.append(sc[5][i * 2 + 1])
if len(verts2) == 2:
if verts2[0] == verts2[1]:
verts2.pop()
if len(verts2) < 2:
verts2.append(sc[5][i * 2])
ch = [sc[5][0], sc[5][1]] # first and his reference
d.pop(ch[0])
i = 0
verts = [123]
while len(d) > 0 and i < 200000: # and verts!=[]:
verts = d.get(ch[-1], [])
if len(verts) <= 1:
if len(ch) > 2:
slicechunks[-1].append(ch)
v1 = d.popitem()
ch = [v1[0], v1[1][0]]
elif len(verts) > 2:
pass;
i += 1
else:
done = False
for v in verts:
if not done:
if v[0] == ch[-2][0] and v[1] == ch[-2][1]: # and v[2]==ch[-2][2]:
pass
else:
# print(v,ch[-2])
ch.append(v)
d.pop(ch[-2])
done = True
if v[0] == ch[0][0] and v[1] == ch[0][1]: # and v[2]==ch[0][2]:
slicechunks[-1].append(ch)
print('closed')
# d.pop(ch[-1])
if len(d) > 0:
v1 = d.popitem()
ch = [v1[0], v1[1][0]]
i += 1
slicechunks[-1].append(ch) ################3this might be a bug!!!!
# print(len(slicechunks))
return slicechunks
def sliceObject(ob):
settings=bpy.context.scene.cam_slice
layers = getSlices(ob, settings.slice_distance)
#print(layers)
sliceobjects=[]
i=1
for layer in layers:
pi=1
layerpolys=[]
for slicechunk in layer:
#these functions here are totally useless conversions, could generate slices more directly, just lazy to write new functions
#print (slicechunk)
nchp=[]
for p in slicechunk:
nchp.append((p[0],p[1]))
#print(slicechunk)
ch = chunk.camPathChunk(nchp)
settings = bpy.context.scene.cam_slice
#print(ch)
pslices=chunk.chunksToShapely([ch])
#print(pslices)
for pslice in pslices:
p = pslice#-p1
#print(p)
text = '%i - %i' % (i,pi)
bpy.ops.object.text_add()
textob = bpy.context.active_object
textob.data.size = 0.0035
textob.data.body = text
textob.data.align = 'CENTER'
#print(len(ch.points))
sliceobject = polygon_utils_cam.shapelyToCurve('slice',p,slicechunk[0][2])
textob.location=(0,0,0)
textob.parent=sliceobject
sliceobject.data.extrude = settings.slice_distance/2
sliceobject.data.dimensions = '2D'
sliceobjects.append(sliceobject)
pi+=1
#FIXME: the polys on same layer which are hollow are not joined by now, this prevents doing hollow surfaces :(
#for p in layerpolys:
#for p1 in layerpolys:
i+=1
for o in sliceobjects:
o.select=True
bpy.ops.group.create(name='slices')
layers = getSlices(ob, settings.slice_distance)
# print(layers)
sliceobjects = []
i = 1
for layer in layers:
pi = 1
layerpolys = []
for slicechunk in layer:
# these functions here are totally useless conversions, could generate slices more directly, just lazy to write new functions
# print (slicechunk)
nchp = []
for p in slicechunk:
nchp.append((p[0], p[1]))
# print(slicechunk)
ch = chunk.camPathChunk(nchp)
# print(ch)
pslices = chunk.chunksToShapely([ch])
# print(pslices)
for pslice in pslices:
p = pslice # -p1
# print(p)
text = '%i - %i' % (i, pi)
bpy.ops.object.text_add()
textob = bpy.context.active_object
textob.data.size = 0.0035
textob.data.body = text
textob.data.align = 'CENTER'
# print(len(ch.points))
sliceobject = polygon_utils_cam.shapelyToCurve('slice', p, slicechunk[0][2])
textob.location = (0, 0, 0)
textob.parent = sliceobject
sliceobject.data.extrude = settings.slice_distance / 2
sliceobject.data.dimensions = '2D'
sliceobjects.append(sliceobject)
pi += 1
# FIXME: the polys on same layer which are hollow are not joined by now, this prevents doing hollow surfaces :(
# for p in layerpolys:
# for p1 in layerpolys:
i += 1
for o in sliceobjects:
o.select = True
bpy.ops.group.create(name='slices')

Wyświetl plik

@ -1,180 +1,197 @@
# blender CAM testing.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 *****
import bpy
from cam import simple, utils
from cam.simple import *
def addTestCurve(loc):
bpy.ops.curve.primitive_bezier_circle_add(radius=.05, view_align=False, enter_editmode=False, location=loc)
bpy.ops.object.editmode_toggle()
bpy.ops.curve.duplicate()
bpy.ops.transform.resize(value=(0.5, 0.5, 0.5), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1)
bpy.ops.curve.duplicate()
bpy.ops.transform.resize(value=(0.5, 0.5, 0.5), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1)
bpy.ops.object.editmode_toggle()
def addTestMesh(loc):
bpy.ops.mesh.primitive_monkey_add(radius=.01, view_align=False, enter_editmode=False, location=loc)
bpy.ops.transform.rotate(value=-1.5708, axis=(1, 0, 0), constraint_axis=(True, False, False), constraint_orientation='GLOBAL')
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.primitive_plane_add(radius=1, view_align=False, enter_editmode=False, location=loc)
bpy.ops.transform.resize(value=(0.01, 0.01, 0.01), constraint_axis=(False, False, False), constraint_orientation='GLOBAL')
bpy.ops.transform.translate(value=(-0.01, 0, 0), constraint_axis=(True, False, False), constraint_orientation='GLOBAL')
bpy.ops.object.editmode_toggle()
def deleteFirstVert(ob):
activate(ob)
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.editmode_toggle()
for i,v in enumerate(ob.data.vertices):
v.select=False
if i==0:
v.select=True
ob.data.update()
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.delete(type='VERT')
bpy.ops.object.editmode_toggle()
def testCalc(o):
bpy.ops.object.calculate_cam_path()
deleteFirstVert(bpy.data.objects[o.path_object_name])
def testCutout(pos):
addTestCurve((pos[0],pos[1],-.05))
bpy.ops.scene.cam_operation_add()
o=bpy.context.scene.cam_operations[-1]
o.strategy = 'CUTOUT'
testCalc(o)
def testPocket(pos):
addTestCurve((pos[0],pos[1],-.01))
bpy.ops.scene.cam_operation_add()
o=bpy.context.scene.cam_operations[-1]
o.strategy = 'POCKET'
o.helix_enter = True
o.retract_tangential=True
testCalc(o)
def testParallel(pos):
addTestMesh((pos[0],pos[1],-.02))
bpy.ops.scene.cam_operation_add()
o=bpy.context.scene.cam_operations[-1]
o.ambient_behaviour='AROUND'
o.material_radius_around_model=0.01
bpy.ops.object.calculate_cam_path()
def testWaterline(pos):
addTestMesh((pos[0],pos[1],-.02))
bpy.ops.scene.cam_operation_add()
o=bpy.context.scene.cam_operations[-1]
o.strategy='WATERLINE'
o.pixsize=.0002
#o.ambient_behaviour='AROUND'
#o.material_radius_around_model=0.01
testCalc(o)
#bpy.ops.object.cam_simulate()
def testSimulation():
pass;
def cleanUp():
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
while len(bpy.context.scene.cam_operations)>0:
bpy.ops.scene.cam_operation_remove()
def testOperation(i):
s=bpy.context.scene
o = s.cam_operations[i]
report=''
report+='testing operation '+ o.name+ '\n'
utils.getPath(bpy.context,o)
newresult=bpy.data.objects[o.path_object_name]
origname="test_cam_path_"+o.name
if origname not in s.objects:
report+='operation test has nothing to compare with, making the new result as comparable result.\n\n'
newresult.name = origname
else:
testresult = bpy.data.objects[origname]
m1 = testresult.data
m2 = newresult.data
test_ok=True
if len(m1.vertices) != len(m2.vertices):
report += "vertex counts don't match\n\n"
test_ok = False
else:
different_co_count=0
for i in range(0,len(m1.vertices)):
v1=m1.vertices[i]
v2=m2.vertices[i]
if v1.co != v2.co:
different_co_count+=1
if different_co_count>0:
report += 'vertex position is different on %i vertices \n\n' % (different_co_count)
test_ok = False
if test_ok:
report += 'test ok\n\n'
else:
report += 'test result is different\n \n '
print(report)
return report
def testAll():
s=bpy.context.scene
report=''
for i in range(0, len(s.cam_operations)):
report+=testOperation(i)
print(report)
''''
tests=[
testCutout,
testParallel,
testWaterline,
testPocket,
]
cleanUp()
#deleteFirstVert(bpy.context.active_object)
for i,t in enumerate(tests):
p=i*.2
t((p,0,0))
# cleanUp()
#cleanUp()
'''
# blender CAM testing.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 *****
import sys
import bpy
from cam import simple, utils
from cam.simple import *
def addTestCurve(loc):
bpy.ops.curve.primitive_bezier_circle_add(radius=.05, view_align=False, enter_editmode=False, location=loc)
bpy.ops.object.editmode_toggle()
bpy.ops.curve.duplicate()
bpy.ops.transform.resize(value=(0.5, 0.5, 0.5), constraint_axis=(False, False, False),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1)
bpy.ops.curve.duplicate()
bpy.ops.transform.resize(value=(0.5, 0.5, 0.5), constraint_axis=(False, False, False),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1)
bpy.ops.object.editmode_toggle()
def addTestMesh(loc):
bpy.ops.mesh.primitive_monkey_add(radius=.01, view_align=False, enter_editmode=False, location=loc)
bpy.ops.transform.rotate(value=-1.5708, axis=(1, 0, 0), constraint_axis=(True, False, False),
constraint_orientation='GLOBAL')
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.primitive_plane_add(radius=1, view_align=False, enter_editmode=False, location=loc)
bpy.ops.transform.resize(value=(0.01, 0.01, 0.01), constraint_axis=(False, False, False),
constraint_orientation='GLOBAL')
bpy.ops.transform.translate(value=(-0.01, 0, 0), constraint_axis=(True, False, False),
constraint_orientation='GLOBAL')
bpy.ops.object.editmode_toggle()
def deleteFirstVert(ob):
activate(ob)
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.editmode_toggle()
for i, v in enumerate(ob.data.vertices):
v.select = False
if i == 0:
v.select = True
ob.data.update()
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.delete(type='VERT')
bpy.ops.object.editmode_toggle()
def testCalc(o):
bpy.ops.object.calculate_cam_path()
deleteFirstVert(bpy.data.objects[o.name])
def testCutout(pos):
addTestCurve((pos[0], pos[1], -.05))
bpy.ops.scene.cam_operation_add()
o = bpy.context.scene.cam_operations[-1]
o.strategy = 'CUTOUT'
testCalc(o)
def testPocket(pos):
addTestCurve((pos[0], pos[1], -.01))
bpy.ops.scene.cam_operation_add()
o = bpy.context.scene.cam_operations[-1]
o.strategy = 'POCKET'
o.helix_enter = True
o.retract_tangential = True
testCalc(o)
def testParallel(pos):
addTestMesh((pos[0], pos[1], -.02))
bpy.ops.scene.cam_operation_add()
o = bpy.context.scene.cam_operations[-1]
o.ambient_behaviour = 'AROUND'
o.material_radius_around_model = 0.01
bpy.ops.object.calculate_cam_path()
def testWaterline(pos):
addTestMesh((pos[0], pos[1], -.02))
bpy.ops.scene.cam_operation_add()
o = bpy.context.scene.cam_operations[-1]
o.strategy = 'WATERLINE'
o.pixsize = .0002
# o.ambient_behaviour='AROUND'
# o.material_radius_around_model=0.01
testCalc(o)
# bpy.ops.object.cam_simulate()
def testSimulation():
pass;
def cleanUp():
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
while len(bpy.context.scene.cam_operations):
bpy.ops.scene.cam_operation_remove()
def testOperation(i):
s = bpy.context.scene
o = s.cam_operations[i]
report = ''
report += 'testing operation ' + o.name + '\n'
utils.getPath(bpy.context, o)
newresult = bpy.data.objects[o.path_object_name]
origname = "test_cam_path_" + o.name
if origname not in s.objects:
report += 'operation test has nothing to compare with, making the new result as comparable result.\n\n'
newresult.name = origname
else:
testresult = bpy.data.objects[origname]
m1 = testresult.data
m2 = newresult.data
test_ok = True
if len(m1.vertices) != len(m2.vertices):
report += "vertex counts don't match\n\n"
test_ok = False
else:
different_co_count = 0
for i in range(0, len(m1.vertices)):
v1 = m1.vertices[i]
v2 = m2.vertices[i]
if v1.co != v2.co:
different_co_count += 1
if different_co_count > 0:
report += 'vertex position is different on %i vertices \n\n' % (different_co_count)
test_ok = False
if test_ok:
report += 'test ok\n\n'
else:
report += 'test result is different\n \n '
print(report)
return report
def testAll():
s = bpy.context.scene
report = ''
for i in range(0, len(s.cam_operations)):
report += testOperation(i)
print(report)
tests = [
testCutout,
testParallel,
testWaterline,
testPocket,
]
cleanUp()
# deleteFirstVert(bpy.context.active_object)
for i, t in enumerate(tests):
p = i * .2
t((p, 0, 0))
# cleanUp()
# cleanUp()

Plik diff jest za duży Load Diff