kopia lustrzana https://github.com/vilemduha/blendercam
				
				
				
			Merge branch 'master' of https://github.com/vilemnovak/blendercam
						commit
						7c4882d90c
					
				|  | @ -6,8 +6,13 @@ config/bookmarks.txt | |||
| /scripts/startup/ | ||||
| /scripts/templates_osl/ | ||||
| /scripts/templates_py/ | ||||
| /scripts/addons/ | ||||
| /scripts/addons_contrib/ | ||||
| *.spi1d | ||||
| *.pyc | ||||
| *.ocio | ||||
| *.spi3d | ||||
| *.py | ||||
| config/recent-files.txt | ||||
| scripts/addons_contrib/add_mesh_rocks/add_mesh_rocks.xml | ||||
| scripts/addons_contrib/online_mat_lib/material-library/bundled/cycles/wood/rough_pine.bcm | ||||
|  |  | |||
|  | @ -219,8 +219,9 @@ def updateStrategy(o,context): | |||
| 	updateExact(o,context) | ||||
| 
 | ||||
| def updateCutout(o,context): | ||||
| 	if o.outlines_count>1: | ||||
| 		o.use_bridges=False | ||||
| 	pass; | ||||
| 	#if o.outlines_count>1: | ||||
| 	#	o.use_bridges=False | ||||
| 		 | ||||
| 	 | ||||
| def updateExact(o,context): | ||||
|  | @ -481,6 +482,9 @@ 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_group_name = bpy.props.StringProperty(name='Bridges Group', description='Group of curves used as bridges', update=operationValid) | ||||
| 
 | ||||
| 	'''commented this - auto bridges will be generated, but not as a setting of the operation | ||||
| 	bridges_placement = bpy.props.EnumProperty(name='Bridge placement', | ||||
| 		items=( | ||||
| 			('AUTO','Automatic', 'Automatic bridges with a set distance'), | ||||
|  | @ -492,6 +496,9 @@ class camOperation(bpy.types.PropertyGroup): | |||
| 	 | ||||
| 	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) | ||||
| 	''' | ||||
| 	group_name = bpy.props.StringProperty(name='Group', description='Object group handled by this operation', update=operationValid) | ||||
| 
 | ||||
| 	#optimisation panel | ||||
| 	 | ||||
| 	#material settings | ||||
|  | @ -706,7 +713,7 @@ def get_panels():#convenience function for bot register and unregister functions | |||
| 	ops.CamOperationRemove, | ||||
| 	ops.CamOperationMove, | ||||
| 	#bridges related | ||||
| 	ops.CamBridgeAdd, | ||||
| 	ops.CamBridgesAdd, | ||||
| 	#5 axis ops | ||||
| 	ops.CamOrientationAdd, | ||||
| 	#shape packing | ||||
|  |  | |||
|  | @ -3,8 +3,8 @@ import Polygon | |||
| import shapely | ||||
| from shapely.geometry import polygon as spolygon | ||||
| from shapely import ops | ||||
| from shapely import geometry | ||||
| 
 | ||||
| from shapely import geometry as sgeometry | ||||
| from cam import polygon_utils_cam | ||||
| from cam import simple | ||||
| from cam.simple import *  | ||||
| 
 | ||||
|  | @ -130,7 +130,7 @@ class camPathChunk: | |||
| 		#self.unsortedchildren=False		 | ||||
| 	#	return self | ||||
| 	 | ||||
| 	def getNextClosest(self,o,pos):#this should be deprecated after reworking sortchunks a bit | ||||
| 	def getNextClosest(self,o,pos): | ||||
| 		mind=100000000000 | ||||
| 		 | ||||
| 		self.cango=False | ||||
|  | @ -155,10 +155,10 @@ class camPathChunk: | |||
| 						ch=chtest | ||||
| 						mind=d | ||||
| 		if ch!=None: | ||||
| 			print('found some') | ||||
| 			#print('found some') | ||||
| 			return ch | ||||
| 		#self.unsortedchildren=False		 | ||||
| 		print('returning none') | ||||
| 		#print('returning none') | ||||
| 		return None	 | ||||
| 	 | ||||
| 		 | ||||
|  | @ -295,9 +295,8 @@ class camPathChunk: | |||
| 				z=znew | ||||
| 				i+=1 | ||||
| 					 | ||||
| 				 | ||||
| 		self.points = chunk.points | ||||
| 		 | ||||
| 		return chunk | ||||
| 
 | ||||
| 	def rampZigZag(self,zstart,zend,o): | ||||
| 		chunk=camPathChunk([]) | ||||
|  | @ -428,8 +427,7 @@ class camPathChunk: | |||
| 								ratio=1-(traveled/ramplength) | ||||
| 								znew=zstart-stepdown*ratio | ||||
| 								chunk.points.append((p2[0],p2[1],max(p2[2],znew)))#max value here is so that it doesn't go below surface in the case of 3d paths | ||||
| 		 | ||||
| 		return chunk | ||||
| 		self.points=chunk.points | ||||
| #def appendChunk(sorted,ch,o,pos)  | ||||
| 
 | ||||
| def chunksCoherency(chunks): | ||||
|  | @ -542,7 +540,7 @@ def limitChunks(chunks,o, force=False):#TODO: this should at least add point on | |||
| 			nch1=nch | ||||
| 			closed=True | ||||
| 			for s in ch.points: | ||||
| 				sampled=o.ambient.isInside(s[0],s[1]) | ||||
| 				sampled=o.ambient.contains(sgeometry.Point(s[0],s[1])) | ||||
| 				if not sampled and len(nch.points)>0: | ||||
| 					nch.closed=False | ||||
| 					closed=False | ||||
|  | @ -571,8 +569,8 @@ def parentChildPoly(parents,children,o): | |||
| 		#print(parent.poly) | ||||
| 		for child in children: | ||||
| 			#print(child.poly) | ||||
| 			if child!=parent and len(child.poly)>0: | ||||
| 				if parent.poly.isInside(child.poly[0][0][0],child.poly[0][0][1]): | ||||
| 			if child!=parent:# and len(child.poly)>0 | ||||
| 				if parent.poly.contains(sgeometry.Point(child.poly.boundary.coords[0])): | ||||
| 					parent.children.append(child) | ||||
| 					child.parents.append(parent) | ||||
| 
 | ||||
|  | @ -612,7 +610,7 @@ def parentChild(parents, children, o): | |||
| 				if parent!=child: | ||||
| 					parent.children.append(child) | ||||
| 					child.parents.append(parent)	 | ||||
| 					 | ||||
| '''					 | ||||
| def chunksToShapely(chunks):#this does more cleve chunks to Poly with hierarchies... ;) | ||||
| 	#print ('analyzing paths') | ||||
| 	#verts=[] | ||||
|  | @ -633,6 +631,73 @@ def chunksToShapely(chunks):#this does more cleve chunks to Poly with hierarchie | |||
| 		returnpolys.append(ch.poly) | ||||
| 	#print(len(returnpolys)) | ||||
| 	return returnpolys   | ||||
| ''' | ||||
| 	 | ||||
| def chunksToShapely(chunks):#this does more cleve chunks to Poly with hierarchies... ;) | ||||
| 	#print ('analyzing paths') | ||||
| 	#verts=[] | ||||
| 	#pverts=[] | ||||
| 	polys=[] | ||||
| 	for ch in chunks:#first convert chunk to poly | ||||
| 		if len(ch.points)>2: | ||||
| 			pchunk=[] | ||||
| 			ch.poly=sgeometry.Polygon(ch.points) | ||||
| 			 | ||||
| 	for ppart in chunks:#then add hierarchy relations | ||||
| 		for ptest in chunks: | ||||
| 				 | ||||
| 			#if ppart!=ptest and len(ptest.poly)>0 and len(ppart.poly)>0 and ptest.poly.nPoints(0)>0 and ppart.poly.nPoints(0)>0: | ||||
| 			if ppart!=ptest : | ||||
| 				if ptest.poly.contains(ppart.poly): | ||||
| 					#hierarchy works like this: - children get milled first.  | ||||
| 					#ptest.children.append(ppart) | ||||
| 					ppart.parents.append(ptest) | ||||
|   | ||||
| 	 | ||||
| 	for ch in chunks:#now make only simple polygons with holes, not more polys inside others | ||||
| 		#print(len(chunks[polyi].parents)) | ||||
| 		found=False | ||||
| 		if len(ch.parents)%2==1: | ||||
| 			 | ||||
| 			for parent in ch.parents: | ||||
| 				if len(parent.parents)+1==len(ch.parents): | ||||
| 					ch.nparents=[parent]#nparents serves as temporary storage for parents, not to get mixed with the first parenting during the check | ||||
| 					found=True | ||||
| 					break | ||||
| 				 | ||||
| 		if not found: | ||||
| 			ch.nparents=[] | ||||
| 
 | ||||
| 	for ch in chunks:#then subtract the 1st level holes | ||||
| 		ch.parents=ch.nparents | ||||
| 		ch.nparents=None | ||||
| 		if len(ch.parents)>0: | ||||
| 			#print(len(ch.parents)) | ||||
| 			#ch.parents[0].poly=ch.parents[0].poly-ch.poly | ||||
| 			#print(ch.parents[0].poly,[ch.poly]) | ||||
| 			print('addparent') | ||||
| 			#polygon_utils_cam.shapelyToCurve('crust',ch.parents[0].poly,0) | ||||
| 			#polygon_utils_cam.shapelyToCurve('hole',ch.poly,0) | ||||
| 			ch.parents[0].poly = ch.parents[0].poly.difference(ch.poly)#sgeometry.Polygon( ch.parents[0].poly, ch.poly) | ||||
| 			 | ||||
| 			 | ||||
| 	returnpolys=[] | ||||
| 
 | ||||
| 	for polyi in range(0,len(chunks)):#export only the booleaned polygons | ||||
| 		ch=chunks[polyi] | ||||
| 		if len(ch.parents)==0: | ||||
| 			#ch.poly.simplify()#TODO:THIS CHECK | ||||
| 			returnpolys.append(ch.poly) | ||||
| 			#if len(ch.poly.interiors)>0: | ||||
| 			#	print(ch.poly.interiors[0].coords[0]) | ||||
| 			#polygon_utils_cam.shapelyToCurve('test',ch.poly,0) | ||||
| 			#print(ch.poly.boundary) | ||||
| 	print('shapely hierarchies') | ||||
| 	#print(len(returnpolys)) | ||||
| 	 | ||||
| 	 | ||||
| 	return returnpolys   | ||||
| 		 | ||||
| 	 | ||||
| def chunksToPolys(chunks):#this does more cleve chunks to Poly with hierarchies... ;) | ||||
| 	#print ('analyzing paths') | ||||
|  | @ -736,6 +801,7 @@ def meshFromCurveToChunk(object): | |||
| 		chunk.points.append((mesh.vertices[lastvi].co.x+x,mesh.vertices[lastvi].co.y+y,mesh.vertices[lastvi].co.z+z)) | ||||
| 	#else: | ||||
| 		#   print('itisnot') | ||||
| 		 | ||||
| 	chunks.append(chunk) | ||||
| 	return chunks | ||||
| 
 | ||||
|  | @ -818,6 +884,32 @@ def polyToChunks(p,zlevel):# | |||
| 	# | ||||
| 	return chunks | ||||
| 
 | ||||
| def shapelyToChunks(p,zlevel):# | ||||
| 	chunks=[] | ||||
| 	#p=sortContours(p) | ||||
| 	seq=polygon_utils_cam.shapelyToCoords(p) | ||||
| 	i=0 | ||||
| 	for s in seq: | ||||
| 		#progress(p[i]) | ||||
| 		if len(s)>2: | ||||
| 			chunk=camPathChunk([]) | ||||
| 			chunk.poly=spolygon.Polygon(s)#this should maybe be LineString? but for sorting, we need polygon inside functions. | ||||
| 			for v in s: | ||||
| 				#progress (v) | ||||
| 				 | ||||
| 				if len(v)>2: | ||||
| 					chunk.points.append((v[0],v[1],v[2]))   | ||||
| 				else: | ||||
| 					chunk.points.append((v[0],v[1],zlevel))   | ||||
| 			 | ||||
| 			chunk.points.append((chunk.points[0][0],chunk.points[0][1],chunk.points[0][2]))#last point =first point | ||||
| 			chunk.closed=True | ||||
| 			chunks.append(chunk) | ||||
| 		i+=1 | ||||
| 	chunks.reverse()#this is for smaller shapes first. | ||||
| 	# | ||||
| 	return chunks | ||||
| 	 | ||||
| def chunkToPoly(chunk): | ||||
| 	pverts=[] | ||||
| 	 | ||||
|  | @ -828,6 +920,16 @@ def chunkToPoly(chunk): | |||
| 	p=Polygon.Polygon(pverts) | ||||
| 	return p | ||||
| 
 | ||||
| def chunkToShapely(chunk): | ||||
| 	#pverts=[] | ||||
| 	 | ||||
| 	#for v in chunk.points: | ||||
| 		  | ||||
| 	#	pverts.append((v[0],v[1])) | ||||
| 	  | ||||
| 	p=spolygon.Polygon(chunk.points) | ||||
| 	return p	 | ||||
| 	 | ||||
| def chunksRefine(chunks,o): | ||||
| 	'''add extra points in between for chunks''' | ||||
| 	for ch in chunks: | ||||
|  |  | |||
|  | @ -1446,9 +1446,9 @@ def imageToChunks(o,image, with_border=False): | |||
| 	else: | ||||
| 		return [] | ||||
| 	 | ||||
| def imageToPoly(o,i, with_border=False): | ||||
| def imageToShapely(o,i, with_border=False): | ||||
| 	polychunks=imageToChunks(o,i, with_border) | ||||
| 	polys=chunksToPolys(polychunks) | ||||
| 	polys=chunksToShapely(polychunks) | ||||
| 	 | ||||
| 	#polys=orderPoly(polys) | ||||
| 	t=time.time() | ||||
|  |  | |||
|  | @ -664,10 +664,10 @@ class CamOrientationAdd(bpy.types.Operator): | |||
| 		return {'FINISHED'} | ||||
| 		 | ||||
| 
 | ||||
| class CamBridgeAdd(bpy.types.Operator): | ||||
| class CamBridgesAdd(bpy.types.Operator): | ||||
| 	'''Add orientation to cam operation, for multiaxis operations''' | ||||
| 	bl_idname = "scene.cam_bridge_add" | ||||
| 	bl_label = "Add bridge" | ||||
| 	bl_idname = "scene.cam_bridges_add" | ||||
| 	bl_label = "Add bridges" | ||||
| 	bl_options = {'REGISTER', 'UNDO'} | ||||
| 	 | ||||
| 		 | ||||
|  | @ -680,7 +680,7 @@ class CamBridgeAdd(bpy.types.Operator): | |||
| 		s=bpy.context.scene | ||||
| 		a=s.cam_active_operation | ||||
| 		o=s.cam_operations[a] | ||||
| 		utils.addBridge(o) | ||||
| 		utils.addAutoBridges(o) | ||||
| 		return {'FINISHED'} | ||||
| 		 | ||||
| 		 | ||||
|  | @ -789,13 +789,13 @@ class CamObjectSilhouete(bpy.types.Operator): | |||
| 	def execute(self, context):#this is almost same as getobjectoutline, just without the need of operation data | ||||
| 		ob=bpy.context.active_object | ||||
| 		self.silh=utils.getObjectSilhouete('OBJECTS', objects=bpy.context.selected_objects) | ||||
| 		poly=Polygon.Polygon() | ||||
| 		for p in self.silh: | ||||
| 			for ci in range(0,len(p)): | ||||
| 				poly.addContour(p[ci]) | ||||
| 		#poly=Polygon.Polygon() | ||||
| 		#for p in self.silh: | ||||
| 		#	for ci in range(0,len(p)): | ||||
| 		#		poly.addContour(p[ci]) | ||||
| 		bpy.context.scene.cursor_location=(0,0,0) | ||||
| 		polygon_utils_cam.polyToMesh(ob.name+'_silhouette',poly,0)# | ||||
| 		bpy.ops.object.convert(target='CURVE') | ||||
| 		polygon_utils_cam.shapelyToCurve(ob.name+'_silhouette',self.silh,0)# | ||||
| 		#bpy.ops.object.convert(target='CURVE') | ||||
| 		bpy.context.scene.cursor_location=ob.location | ||||
| 		bpy.ops.object.origin_set(type='ORIGIN_CURSOR') | ||||
| 		return {'FINISHED'} | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ from cam.simple import * | |||
| from cam.chunk import *  | ||||
| from cam import polygon_utils_cam | ||||
| from cam.polygon_utils_cam import * | ||||
| import shapely | ||||
| from shapely import geometry as sgeometry | ||||
| 
 | ||||
| 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 | ||||
|  | @ -324,8 +326,9 @@ def getPathPattern(operation): | |||
| 		pathchunks=[] | ||||
| 		chunks=[] | ||||
| 		for p in polys: | ||||
| 			p=outlinePoly(p,o.dist_between_paths/3,o.circle_detail,o.optimize,o.optimize_threshold,False)#first, move a bit inside, because otherwise the border samples go crazy very often changin between hit/non hit and making too many jumps in the path. | ||||
| 			chunks.extend(polyToChunks(p,0)) | ||||
| 			#p=outlinePoly(p,o.dist_between_paths/3,o.circle_detail,o.optimize,o.optimize_threshold,False)#first, move a bit inside, because otherwise the border samples go crazy very often changin between hit/non hit and making too many jumps in the path. | ||||
| 			p=p.buffer(-o.dist_between_paths/3,o.circle_detail)#first, move a bit inside, because otherwise the border samples go crazy very often changin between hit/non hit and making too many jumps in the path. | ||||
| 			chunks.extend(shapelyToChunks(p,0)) | ||||
| 		 | ||||
| 		pathchunks.extend(chunks) | ||||
| 		lastchunks=chunks | ||||
|  | @ -340,10 +343,11 @@ def getPathPattern(operation): | |||
| 		 | ||||
| 		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) | ||||
| 			while not p.is_empty:#:p.nPoints()>0: | ||||
| 				#p=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,False) | ||||
| 				p=p.buffer(-o.dist_between_paths,o.circle_detail) | ||||
| 				if not p.is_empty: | ||||
| 					nchunks=shapelyToChunks(p,zlevel) | ||||
| 					#parentChildPoly(lastchunks,nchunks,o) | ||||
| 					pathchunks.extend(nchunks) | ||||
| 					lastchunks=nchunks | ||||
|  | @ -362,9 +366,10 @@ def getPathPattern(operation): | |||
| 							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) | ||||
| 					p=p.buffer(dist,o.circle_detail) | ||||
| 					#p=outlinePoly(p,dist,o.circle_detail,o.optimize,o.optimize_threshold,True) | ||||
| 					if not p.is_empty: | ||||
| 						chunks=shapelyToChunks(p,zlevel) | ||||
| 						pathchunks.extend(chunks) | ||||
| 					lastchunks=chunks | ||||
| 		 | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ import Polygon | |||
| import shapely | ||||
| from shapely.geometry import polygon as spolygon | ||||
| from shapely import ops | ||||
| from shapely import geometry | ||||
| from shapely import geometry as sgeometry | ||||
| SHAPELY=True | ||||
| #except: | ||||
| #	SHAPELY=False | ||||
|  | @ -17,7 +17,7 @@ SHAPELY=True | |||
| 
 | ||||
| def Polygon2Shapely(p): | ||||
| 	conts=[] | ||||
| 	sp=geometry.Polygon() | ||||
| 	sp=sgeometry.Polygon() | ||||
| 	holes=[] | ||||
| 	contours=[] | ||||
| 	#print(len(p)) | ||||
|  | @ -39,7 +39,7 @@ def Polygon2Shapely(p): | |||
| 	for h in holes: | ||||
| 		sp=sp.difference(h) | ||||
| 		 | ||||
| 	#sp=geometry.asMultiPolygon(conts) | ||||
| 	#sp=sgeometry.asMultiPolygon(conts) | ||||
| 	#sp=ops.cascaded_union(sp) | ||||
| 	return sp | ||||
| 	 | ||||
|  | @ -69,7 +69,7 @@ def Circle(r,np): | |||
| 		c.append((v.x,v.y)) | ||||
| 		v.rotate(e) | ||||
| 		 | ||||
| 	p=Polygon.Polygon(c) | ||||
| 	p=spolygon.Polygon(c) | ||||
| 	return p | ||||
| 
 | ||||
| def nRect(l,r): | ||||
|  | @ -264,12 +264,85 @@ def polyToMesh(name,p,z): | |||
| 	 | ||||
| 	return bpy.context.active_object | ||||
| 
 | ||||
| def shapelyToMesh(name,p,z): | ||||
| 	p = Shapely2Polygon(p) | ||||
| 	ob = polyToMesh(name,p,z) | ||||
| 	return ob | ||||
| 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=='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: | ||||
| 			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)   | ||||
| 	 | ||||
| 	return objectdata#bpy.context.active_object | ||||
| 	 | ||||
| '''#outdated? | ||||
| def orderPoly(polys):	#sor poly, do holes e.t.c. | ||||
| 	p=Polygon.Polygon() | ||||
| 	levels=[[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]  | ||||
|  | @ -302,4 +375,5 @@ def orderPoly(polys):	#sor poly, do holes e.t.c. | |||
| 			p.simplify() | ||||
| 		li+=1 | ||||
| 	   | ||||
| 	return p | ||||
| 	return p | ||||
| ''' | ||||
|  | @ -408,13 +408,16 @@ 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_placement') | ||||
| 						layout.prop(ao,'bridges_width') | ||||
| 						layout.prop(ao,'bridges_height') | ||||
| 						if ao.bridges_placement == 'AUTO': | ||||
| 							layout.prop(ao,'bridges_per_curve') | ||||
| 							layout.prop(ao,'bridges_max_distance') | ||||
| 					 | ||||
| 						 | ||||
| 						layout.prop_search(ao, "bridges_group_name", bpy.data, "groups") | ||||
| 						#layout.prop(ao,'bridges_group_name') | ||||
| 						#if ao.bridges_placement == 'AUTO': | ||||
| 						#	layout.prop(ao,'bridges_per_curve') | ||||
| 						#	layout.prop(ao,'bridges_max_distance') | ||||
| 					layout.operator("scene.cam_bridges_add", text="Autogenerate bridges") | ||||
| 				elif ao.strategy=='WATERLINE': | ||||
| 					layout.prop(ao,'slice_detail')	 | ||||
| 					layout.prop(ao,'waterline_fill')   | ||||
|  |  | |||
|  | @ -53,15 +53,15 @@ from cam.polygon_utils_cam import * | |||
| from cam import image_utils | ||||
| from cam.image_utils import * | ||||
| from . import nc | ||||
| from cam.opencamlib.opencamlib import oclSample, oclSamplePoints, oclResampleChunks, oclGetWaterline | ||||
| from cam.opencamlib.opencamlib import oclSample, oclSamplePoints, oclResampleChunks, oclGetWaterline | ||||
| 
 | ||||
| try: | ||||
| 	from shapely.geometry import polygon as spolygon | ||||
| 	from shapely import ops as sops | ||||
| 	from shapely import geometry as sgeometry | ||||
| 	SHAPELY=True | ||||
| except: | ||||
| 	SHAPELY=False | ||||
| 
 | ||||
| from shapely.geometry import polygon as spolygon | ||||
| from shapely import ops as sops | ||||
| from shapely import geometry as sgeometry | ||||
| from shapely import affinity | ||||
| #from shapely.geometry import * not possible until Polygon libs gets out finally.. | ||||
| SHAPELY=True | ||||
| 	 | ||||
| def positionObject(operation): | ||||
| 	ob=bpy.data.objects[operation.object_name] | ||||
|  | @ -90,21 +90,65 @@ def getBoundsWorldspace(obs): | |||
| 				maxy=max(maxy,worldCoord.y) | ||||
| 				maxz=max(maxz,worldCoord.z) | ||||
| 		else: | ||||
| 			 | ||||
| 			for coord in bb: | ||||
| 				#this can work badly with some imported curves, don't know why... | ||||
| 				#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z)) | ||||
| 				worldCoord =mw * Vector((coord[0], coord[1], coord[2])) | ||||
| 				minx=min(minx,worldCoord.x) | ||||
| 				miny=min(miny,worldCoord.y) | ||||
| 				minz=min(minz,worldCoord.z) | ||||
| 				maxx=max(maxx,worldCoord.x) | ||||
| 				maxy=max(maxy,worldCoord.y) | ||||
| 				maxz=max(maxz,worldCoord.z) | ||||
| 			 | ||||
| 			  | ||||
| 			#for coord in bb: | ||||
| 			for c in ob.data.splines: | ||||
| 				for p in c.bezier_points: | ||||
| 					coord=p.co | ||||
| 					#this can work badly with some imported curves, don't know why... | ||||
| 					#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z)) | ||||
| 					worldCoord =mw * Vector((coord[0], coord[1], coord[2])) | ||||
| 					minx=min(minx,worldCoord.x) | ||||
| 					miny=min(miny,worldCoord.y) | ||||
| 					minz=min(minz,worldCoord.z) | ||||
| 					maxx=max(maxx,worldCoord.x) | ||||
| 					maxy=max(maxy,worldCoord.y) | ||||
| 					maxz=max(maxz,worldCoord.z) | ||||
| 				for p in c.points: | ||||
| 					coord=p.co | ||||
| 					#this can work badly with some imported curves, don't know why... | ||||
| 					#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z)) | ||||
| 					worldCoord =mw * Vector((coord[0], coord[1], coord[2])) | ||||
| 					minx=min(minx,worldCoord.x) | ||||
| 					miny=min(miny,worldCoord.y) | ||||
| 					minz=min(minz,worldCoord.z) | ||||
| 					maxx=max(maxx,worldCoord.x) | ||||
| 					maxy=max(maxy,worldCoord.y) | ||||
| 					maxz=max(maxz,worldCoord.z) | ||||
| 	#progress(time.time()-t) | ||||
| 	return minx,miny,minz,maxx,maxy,maxz | ||||
| 
 | ||||
| def getSplineBounds(ob,curve): | ||||
| 	#progress('getting bounds of object(s)') | ||||
| 	maxx=maxy=maxz=-10000000 | ||||
| 	minx=miny=minz=10000000 | ||||
| 	mw=ob.matrix_world | ||||
| 		 | ||||
| 	for p in curve.bezier_points: | ||||
| 		coord=p.co | ||||
| 		#this can work badly with some imported curves, don't know why... | ||||
| 		#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z)) | ||||
| 		worldCoord =mw * Vector((coord[0], coord[1], coord[2])) | ||||
| 		minx=min(minx,worldCoord.x) | ||||
| 		miny=min(miny,worldCoord.y) | ||||
| 		minz=min(minz,worldCoord.z) | ||||
| 		maxx=max(maxx,worldCoord.x) | ||||
| 		maxy=max(maxy,worldCoord.y) | ||||
| 		maxz=max(maxz,worldCoord.z) | ||||
| 	for p in curve.points: | ||||
| 		coord=p.co | ||||
| 		#this can work badly with some imported curves, don't know why... | ||||
| 		#worldCoord = mw * Vector((coord[0]/ob.scale.x, coord[1]/ob.scale.y, coord[2]/ob.scale.z)) | ||||
| 		worldCoord =mw * Vector((coord[0], coord[1], coord[2])) | ||||
| 		minx=min(minx,worldCoord.x) | ||||
| 		miny=min(miny,worldCoord.y) | ||||
| 		minz=min(minz,worldCoord.z) | ||||
| 		maxx=max(maxx,worldCoord.x) | ||||
| 		maxy=max(maxy,worldCoord.y) | ||||
| 		maxz=max(maxz,worldCoord.z) | ||||
| 	#progress(time.time()-t) | ||||
| 	return minx,miny,minz,maxx,maxy,maxz | ||||
| 	 | ||||
| def getOperationSources(o): | ||||
| 	if o.geometry_source=='OBJECT': | ||||
| 		#bpy.ops.object.select_all(action='DESELECT') | ||||
|  | @ -254,7 +298,7 @@ def samplePathLow(o,ch1,ch2,dosample): | |||
| 	#print(len(bpath)) | ||||
| 	pixsize=o.pixsize | ||||
| 	if dosample: | ||||
| 		if not (o.use_opencamlib and o.use_exact): | ||||
| 		if not (o.use_opencamlib and o.use_exact): | ||||
| 			if o.use_exact: | ||||
| 				cutterdepth=o.cutter_shape.dimensions.z/2 | ||||
| 				for p in bpath.points: | ||||
|  | @ -279,10 +323,10 @@ def sampleChunks(o,pathSamples,layers): | |||
| 	getAmbient(o)   | ||||
| 
 | ||||
| 	if o.use_exact:#prepare collision world | ||||
| 		if o.use_opencamlib: | ||||
| 			oclSample(o, pathSamples) | ||||
| 			cutterdepth=0 | ||||
| 		else: | ||||
| 		if o.use_opencamlib: | ||||
| 			oclSample(o, pathSamples) | ||||
| 			cutterdepth=0 | ||||
| 		else: | ||||
| 			if o.update_bullet_collision_tag: | ||||
| 				prepareBulletCollision(o) | ||||
| 				 | ||||
|  | @ -349,14 +393,14 @@ def sampleChunks(o,pathSamples,layers): | |||
| 			n+=1 | ||||
| 			x=s[0] | ||||
| 			y=s[1] | ||||
| 			if not o.ambient.isInside(x,y): | ||||
| 			if not o.ambient.contains(sgeometry.Point(x,y)): | ||||
| 				newsample=(x,y,1) | ||||
| 			else: | ||||
| 				if o.use_opencamlib and o.use_exact: | ||||
| 					z=s[2] | ||||
| 					if minz>z: | ||||
| 						z=minz | ||||
| 					newsample=(x,y,z) | ||||
| 				if o.use_opencamlib and o.use_exact: | ||||
| 					z=s[2] | ||||
| 					if minz>z: | ||||
| 						z=minz | ||||
| 					newsample=(x,y,z) | ||||
| 				####sampling | ||||
| 				elif o.use_exact and not o.use_opencamlib: | ||||
| 					 | ||||
|  | @ -817,20 +861,20 @@ def doSimulation(name,operations): | |||
| 	numpysave(i,iname) | ||||
| 	i=bpy.data.images.load(iname) | ||||
| 	createSimulationObject(name,operations,i) | ||||
| 
 | ||||
| 
 | ||||
| def extendChunks5axis(chunks,o): | ||||
| 
 | ||||
| 	s=bpy.context.scene | ||||
| 	m=s.cam_machine | ||||
| 	m=s.cam_machine | ||||
| 	s=bpy.context.scene | ||||
| 	free_movement_height = o.free_movement_height# o.max.z +  | ||||
| 	if m.use_position_definitions:# dhull | ||||
| 		cutterstart=Vector((m.starting_position.x, m.starting_position.y ,max(o.max.z, m.starting_position.z)))#start point for casting | ||||
| 	else: | ||||
| 		cutterstart=Vector((0,0,max(o.max.z,free_movement_height)))#start point for casting | ||||
| 	cutterend=Vector((0,0,o.min.z)) | ||||
| 	oriname=o.name+' orientation' | ||||
| 	ori=s.objects[oriname] | ||||
| 		cutterstart=Vector((0,0,max(o.max.z,free_movement_height)))#start point for casting | ||||
| 	cutterend=Vector((0,0,o.min.z)) | ||||
| 	oriname=o.name+' orientation' | ||||
| 	ori=s.objects[oriname] | ||||
| 	#rotationaxes = rotTo2axes(ori.rotation_euler,'CA')#warning-here it allready is reset to 0!! | ||||
| 	print('rot',o.rotationaxes) | ||||
| 	a,b=o.rotationaxes#this is all nonsense by now. | ||||
|  | @ -846,23 +890,23 @@ def extendChunks5axis(chunks,o): | |||
| 			 | ||||
| 			 | ||||
| def chunksToMesh(chunks,o): | ||||
| 	'''convert sampled chunks to path, optimization of paths''' | ||||
| 	t=time.time() | ||||
| 	s=bpy.context.scene | ||||
| 	m=s.cam_machine | ||||
| 	'''convert sampled chunks to path, optimization of paths''' | ||||
| 	t=time.time() | ||||
| 	s=bpy.context.scene | ||||
| 	m=s.cam_machine | ||||
| 	verts=[] | ||||
| 	 | ||||
| 	free_movement_height =  o.free_movement_height#o.max.z + | ||||
| 	 | ||||
| 	 | ||||
| 	if o.machine_axes=='3': | ||||
| 		if m.use_position_definitions: | ||||
| 			origin=(m.starting_position.x, m.starting_position.y, m.starting_position.z)# dhull | ||||
| 			origin=(m.starting_position.x, m.starting_position.y, m.starting_position.z)# dhull | ||||
| 		else: | ||||
| 			origin=(0,0,free_movement_height)	  | ||||
| 		 | ||||
| 		verts = [origin] | ||||
| 	if o.machine_axes!='3': | ||||
| 		verts_rotations=[]#(0,0,0) | ||||
| 			origin=(0,0,free_movement_height)	  | ||||
| 		 | ||||
| 		verts = [origin] | ||||
| 	if o.machine_axes!='3': | ||||
| 		verts_rotations=[]#(0,0,0) | ||||
| 	if (o.machine_axes == '5' and o.strategy5axis=='INDEXED') or (o.machine_axes=='4' and o.strategy4axis=='INDEXED'): | ||||
| 		extendChunks5axis(chunks,o) | ||||
| 	 | ||||
|  | @ -1035,27 +1079,27 @@ def exportGcodePath(filename,vertslist,operations): | |||
| 	elif m.post_processor=='GRAVOS': | ||||
| 		extension = '.nc' | ||||
| 		from .nc import gravos as postprocessor | ||||
| 	elif m.post_processor=='WIN-PC' : | ||||
| 		extension='.din' | ||||
| 		from .nc import winpc as postprocessor | ||||
| 	elif m.post_processor=='WIN-PC' : | ||||
| 		extension='.din' | ||||
| 		from .nc import winpc as postprocessor | ||||
| 	elif m.post_processor=='SHOPBOT MTC': | ||||
| 		extension='.sbp' | ||||
| 		from .nc import shopbot_mtc as postprocessor | ||||
| 	elif m.post_processor=='LYNX_OTTER_O': | ||||
| 		extension='.nc' | ||||
| 		from .nc import lynx_otter_o as postprocessor | ||||
| 	 | ||||
| 	if s.unit_settings.system=='METRIC': | ||||
| 		unitcorr=1000.0 | ||||
| 	elif s.unit_settings.system=='IMPERIAL': | ||||
| 		unitcorr=1/0.0254; | ||||
| 	else: | ||||
| 		unitcorr=1; | ||||
| 	rotcorr=180.0/pi | ||||
| 	 | ||||
| 	if s.unit_settings.system=='METRIC': | ||||
| 		unitcorr=1000.0 | ||||
| 	elif s.unit_settings.system=='IMPERIAL': | ||||
| 		unitcorr=1/0.0254; | ||||
| 	else: | ||||
| 		unitcorr=1; | ||||
| 	rotcorr=180.0/pi | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	def startNewFile(): | ||||
| 	 | ||||
| 	def startNewFile(): | ||||
| 		fileindex='' | ||||
| 		if split: | ||||
| 			fileindex='_'+str(findex) | ||||
|  | @ -1064,15 +1108,15 @@ def exportGcodePath(filename,vertslist,operations): | |||
| 		c.file_open(filename) | ||||
| 	 | ||||
| 		#unit system correction | ||||
| 		############### | ||||
| 		if s.unit_settings.system=='METRIC': | ||||
| 			c.metric() | ||||
| 		elif s.unit_settings.system=='IMPERIAL': | ||||
| 		############### | ||||
| 		if s.unit_settings.system=='METRIC': | ||||
| 			c.metric() | ||||
| 		elif s.unit_settings.system=='IMPERIAL': | ||||
| 			c.imperial() | ||||
| 		 | ||||
| 		#start program | ||||
| 		 | ||||
| 		#start program | ||||
| 		c.program_begin(0,filename) | ||||
| 		c.flush_nc() | ||||
| 		c.flush_nc() | ||||
| 		c.comment('G-code generated with BlenderCAM and NC library') | ||||
| 		#absolute coordinates | ||||
| 		c.absolute() | ||||
|  | @ -1117,35 +1161,35 @@ def exportGcodePath(filename,vertslist,operations): | |||
| 		c.flush_nc() | ||||
| 		if m.spindle_start_time>0: | ||||
| 			c.dwell(m.spindle_start_time) | ||||
| 			c.flush_nc() | ||||
| 		 | ||||
| 		 | ||||
| 		# dhull c.feedrate(unitcorr*o.feedrate) | ||||
| 		 | ||||
| 		 | ||||
| 		 | ||||
| 			c.flush_nc() | ||||
| 		 | ||||
| 		 | ||||
| 		# dhull c.feedrate(unitcorr*o.feedrate) | ||||
| 		 | ||||
| 		 | ||||
| 		 | ||||
| 		#commands=[] | ||||
| 		m=bpy.context.scene.cam_machine | ||||
| 		 | ||||
| 		millfeedrate=min(o.feedrate,m.feedrate_max) | ||||
| 		 | ||||
| 		millfeedrate=unitcorr*max(millfeedrate,m.feedrate_min) | ||||
| 		plungefeedrate= millfeedrate*o.plunge_feedrate/100 | ||||
| 		plungefeedrate= millfeedrate*o.plunge_feedrate/100 | ||||
| 		freefeedrate=m.feedrate_max*unitcorr | ||||
| 		fadjust=False | ||||
| 		fadjust=False | ||||
| 		if o.do_simulation_feedrate and mesh.shape_keys!= None and  mesh.shape_keys.key_blocks.find('feedrates')!=-1: | ||||
| 			shapek =  mesh.shape_keys.key_blocks['feedrates'] | ||||
| 			fadjust=True | ||||
| 		 | ||||
| 		 | ||||
| 		if m.use_position_definitions:# dhull  | ||||
| 			last=Vector((m.starting_position.x, m.starting_position.y, m.starting_position.z)) | ||||
| 		else:		 | ||||
| 			last=Vector((0.0,0.0,free_movement_height))#nonsense values so first step of the operation gets written for sure | ||||
| 		lastrot=Euler((0,0,0)) | ||||
| 		duration=0.0 | ||||
| 		else:		 | ||||
| 			last=Vector((0.0,0.0,free_movement_height))#nonsense values so first step of the operation gets written for sure | ||||
| 		lastrot=Euler((0,0,0)) | ||||
| 		duration=0.0 | ||||
| 		f=millfeedrate  | ||||
| 		fadjustval = 1 # if simulation load data is Not present | ||||
| 		 | ||||
| 		 | ||||
| 		downvector= Vector((0,0,-1)) | ||||
| 		plungelimit=(pi/2-o.plunge_angle) | ||||
| 		 | ||||
|  | @ -1293,16 +1337,23 @@ def silhoueteOffset(context,offset): | |||
| 	bpy.context.scene.cursor_location=(0,0,0) | ||||
| 	ob=bpy.context.active_object | ||||
| 	if ob.type=='CURVE': | ||||
| 		plist=curveToPolys(ob) | ||||
| 		silhs=curveToShapely(ob) | ||||
| 	else: | ||||
| 		plist=getObjectSilhouete('OBJECTS',[ob]) | ||||
| 	p=Polygon.Polygon() | ||||
| 	for p1 in plist: | ||||
| 		p+=p1 | ||||
| 	p=outlinePoly(p,abs(offset),64,True,abs(offset)*0.002,offset>0) | ||||
| 		silhs=getObjectSilhouete('OBJECTS',[ob]) | ||||
| 	#for p1 in plist: | ||||
| 	#	p+=p1 | ||||
| 	print(silhs) | ||||
| 	polys = [] | ||||
| 	mp = sgeometry.MultiPolygon([silhs[0]],silhs[1:]) | ||||
| 	for p in silhs: | ||||
| 		polys.append(p.buffer(offset, resolution = 64)) | ||||
| 	#mp = mp.buffer(offset,resolution = 64) | ||||
| 	#p=outlinePoly(p,abs(offset),64,True,abs(offset)*0.002,offset>0) | ||||
| 	#print(p[0]) | ||||
| 	#p.shift(ob.location.x,ob.location.y) | ||||
| 	polyToMesh('offset curve',p,ob.location.z) | ||||
| 	#for p in polys: | ||||
| 	for s in polys: | ||||
| 		shapelyToCurve('offset curve',s,ob.location.z) | ||||
| 	 | ||||
| 	 | ||||
| 	return {'FINISHED'} | ||||
|  | @ -1486,7 +1537,7 @@ def sortChunks(chunks,o): | |||
| 		progress('sorting paths') | ||||
| 	sys.setrecursionlimit(100000)# the getNext() function of CamPathChunk was running out of recursion limits. | ||||
| 	sortedchunks=[] | ||||
| 	chunks_to_resample=[] | ||||
| 	chunks_to_resample=[] | ||||
| 	 | ||||
| 	lastch=None | ||||
| 	i=len(chunks) | ||||
|  | @ -1530,7 +1581,7 @@ def sortChunks(chunks,o): | |||
| 				print(len(ch.points)) | ||||
| 		''' | ||||
| 		 | ||||
| 	 | ||||
| 	 | ||||
| 	sys.setrecursionlimit(1000) | ||||
| 	if o.strategy!='DRILL': | ||||
| 		sortedchunks = connectChunksLow(sortedchunks,o) | ||||
|  | @ -1632,7 +1683,7 @@ def getOperationSilhouete(operation): | |||
| 				i = samples > numpy.min(operation.zbuffer_image)#this fixes another numeric imprecision. | ||||
| 				 | ||||
| 			chunks=	imageToChunks(operation,i) | ||||
| 			operation.silhouete=chunksToPolys(chunks) | ||||
| 			operation.silhouete=chunksToShapely(chunks) | ||||
| 			#print(operation.silhouete) | ||||
| 			#this conversion happens because we need the silh to be oriented, for milling directions. | ||||
| 		else: | ||||
|  | @ -1649,7 +1700,7 @@ def getObjectSilhouete(stype, objects=None): | |||
| 		for ob in objects: | ||||
| 			chunks=curveToChunks(ob) | ||||
| 			allchunks.extend(chunks) | ||||
| 		silhouete=chunksToPolys(allchunks) | ||||
| 		silhouete=chunksToShapely(allchunks) | ||||
| 		 | ||||
| 	elif stype=='OBJECTS': | ||||
| 		totfaces=0 | ||||
|  | @ -1699,7 +1750,7 @@ def getObjectSilhouete(stype, objects=None): | |||
| 			print(time.time()-t) | ||||
| 			 | ||||
| 			t=time.time() | ||||
| 			silhouete = [polygon_utils_cam.Shapely2Polygon(p)] | ||||
| 			silhouete = [p]#[polygon_utils_cam.Shapely2Polygon(p)] | ||||
| 			''' | ||||
| 			e=0.00001#one hunderth of a millimeter, should be ok. | ||||
| 			origtol=Polygon.getTolerance() | ||||
|  | @ -1751,41 +1802,58 @@ def getAmbient(o): | |||
| 			r=o.ambient_radius - m | ||||
| 			o.ambient = getObjectOutline( r , o , True)# in this method we need ambient from silhouete | ||||
| 		else: | ||||
| 			o.ambient=Polygon.Polygon(((o.min.x + m ,o.min.y + m ) , (o.min.x + m ,o.max.y - m ),(o.max.x - m ,o.max.y - m ),(o.max.x - m , o.min.y + m ))) | ||||
| 			#o.ambient=Polygon.Polygon(((o.min.x + m ,o.min.y + m ) , (o.min.x + m ,o.max.y - m ),(o.max.x - m ,o.max.y - m ),(o.max.x - m , o.min.y + m ))) | ||||
| 			#SHAPELY stuff! | ||||
| 			o.ambient=spolygon.Polygon(((o.min.x + m ,o.min.y + m ) , (o.min.x + m ,o.max.y - m ),(o.max.x - m ,o.max.y - m ),(o.max.x - m , o.min.y + m ))) | ||||
| 		 | ||||
| 		if o.use_limit_curve: | ||||
| 			if o.limit_curve!='': | ||||
| 				limit_curve=bpy.data.objects[o.limit_curve] | ||||
| 				polys=curveToPolys(limit_curve) | ||||
| 				o.limit_poly=Polygon.Polygon() | ||||
| 				for p in polys: | ||||
| 					o.limit_poly+=p | ||||
| 				#polys=curveToPolys(limit_curve) | ||||
| 				polys = curveToShapely(limit_curve) | ||||
| 				o.limit_poly=shapely.ops.unary_union(polys) | ||||
| 				#for p in polys: | ||||
| 				#	o.limit_poly+=p | ||||
| 				if o.ambient_cutter_restrict: | ||||
| 					o.limit_poly = outlinePoly(o.limit_poly,o.cutter_diameter/2,o.circle_detail,o.optimize,o.optimize_threshold,offset = False) | ||||
| 			o.ambient = o.ambient & o.limit_poly | ||||
| 					#o.limit_poly = outlinePoly(o.limit_poly,o.cutter_diameter/2,o.circle_detail,o.optimize,o.optimize_threshold,offset = False) | ||||
| 					o.limit_poly = o.limit_poly.buffer(o.cutter_diameter/2,resolution = o.circle_detail) | ||||
| 			o.ambient = o.ambient.intersection(o.limit_poly) | ||||
| 	o.update_ambient_tag=False | ||||
| 	 | ||||
| def getObjectOutline(radius,o,Offset):#FIXME: make this one operation independent | ||||
| #circle detail, optimize, optimize thresold. | ||||
| 	 | ||||
| 	polygons=getOperationSilhouete(o) | ||||
| 	outline=Polygon.Polygon() | ||||
| 	 | ||||
| 	i=0 | ||||
| 	#print('offseting polygons') | ||||
| 		 | ||||
| 	if Offset: | ||||
| 		offset=1 | ||||
| 	else: | ||||
| 		offset=-1 | ||||
| 		 | ||||
| 	outlines=[] | ||||
| 	for p in polygons:#sort by size before this??? | ||||
| 		 | ||||
| 		 | ||||
| 	i=0 | ||||
| 	#print(polygons, polygons.type) | ||||
| 	for p1 in polygons:#sort by size before this??? | ||||
| 		print(p1.type,len(polygons)) | ||||
| 		i+=1 | ||||
| 		if radius>0: | ||||
| 			p=outlinePoly(p,radius,o.circle_detail,o.optimize,o.optimize_threshold*0.000001,Offset) | ||||
| 					 | ||||
| 		if o.dont_merge: | ||||
| 			for ci in range(0,len(p)): | ||||
| 				outline.addContour(p[ci],p.isHole(ci)) | ||||
| 		else: | ||||
| 			#print(p) | ||||
| 			outline=outline+p | ||||
| 			#p=outlinePoly(p,radius,o.circle_detail,o.optimize,o.optimize_threshold*0.000001,Offset) | ||||
| 			p1 = p1.buffer(radius*offset,resolution = o.circle_detail) | ||||
| 		outlines.append(p1) | ||||
| 	 | ||||
| 	print(outlines) | ||||
| 	if o.dont_merge: | ||||
| 		outline=sgeometry.MultiPolygon(outlines) | ||||
| 		#for ci in range(0,len(p)): | ||||
| 		#	outline.addContour(p[ci],p.isHole(ci)) | ||||
| 	else: | ||||
| 		#print(p) | ||||
| 		outline=shapely.ops.unary_union(outlines) | ||||
| 		#outline = sgeometry.MultiPolygon([outline]) | ||||
| 	shapelyToCurve('oboutline',outline,0) | ||||
| 	return outline | ||||
| 	 | ||||
| def addOrientationObject(o): | ||||
|  | @ -1926,7 +1994,7 @@ def getContainer(): | |||
| 		container=s.objects['CAM_OBJECTS'] | ||||
| 	 | ||||
| 	return container | ||||
| 
 | ||||
| ''' | ||||
| 
 | ||||
| def getSnappingObject(o): | ||||
| 	s=bpy.context.scene | ||||
|  | @ -1980,8 +2048,167 @@ def getBridges(p,o): | |||
| 			pos=pos[0],pos[1] | ||||
| 			bridges.append(pos) | ||||
| 	return bridges | ||||
| ''' | ||||
| 
 | ||||
| def addAutoBridges(o): | ||||
| 	'''attempt to add auto bridges as set of curves''' | ||||
| 	getOperationSources(o) | ||||
| 	if not o.onlycurves: | ||||
| 		o.warnings.append('not curves') | ||||
| 		return; | ||||
| 	bridgegroupname=o.bridges_group_name | ||||
| 	if bridgegroupname == '' or bpy.data.groups.get(bridgegroupname) == None: | ||||
| 		bridgegroupname = 'bridges_'+o.name | ||||
| 		bpy.data.groups.new(bridgegroupname) | ||||
| 	g= bpy.data.groups[bridgegroupname] | ||||
| 	for ob in o.objects: | ||||
| 		 | ||||
| 		if ob.type=='CURVE': | ||||
| 			sply = curveToShapely(ob) | ||||
| 			 | ||||
| 			mw=ob.matrix_world | ||||
| 			for c in ob.data.splines: | ||||
| 				blength = o.cutter_diameter*1 | ||||
| 				 | ||||
| 				minx,miny,minz,maxx,maxy,maxz = getSplineBounds(ob,c) | ||||
| 				bpy.ops.mesh.primitive_plane_add(radius=blength, view_align=False, enter_editmode=False, location=(0, 0, 0)) | ||||
| 				b=bpy.context.active_object | ||||
| 				b.name = 'bridge' | ||||
| 				b.show_name=True | ||||
| 				b.dimensions.x=o.bridges_width | ||||
| 				bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) | ||||
| 				 | ||||
| 				bpy.ops.object.editmode_toggle() | ||||
| 				bpy.ops.transform.translate(value=(0, blength/2, 0), constraint_axis=(False, True, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1) | ||||
| 				bpy.ops.object.editmode_toggle() | ||||
| 				bpy.ops.object.convert(target='CURVE') | ||||
| 
 | ||||
| 				b.location = (minx+maxx)/2, miny, 0 | ||||
| 				b.rotation_euler.z=pi | ||||
| 				g.objects.link(b) | ||||
| 				bpy.ops.object.duplicate(linked=True) | ||||
| 				b=bpy.context.active_object | ||||
| 				b.location = (minx+maxx)/2, maxy, 0 | ||||
| 				b.rotation_euler.z=0 | ||||
| 				bpy.ops.object.duplicate(linked=True) | ||||
| 				b=bpy.context.active_object | ||||
| 				b.location = minx, (miny+maxy)/2, 0 | ||||
| 				b.rotation_euler.z=pi/2 | ||||
| 				bpy.ops.object.duplicate(linked=True) | ||||
| 				b=bpy.context.active_object | ||||
| 				b.location = maxx, (miny+maxy)/2, 0 | ||||
| 				b.rotation_euler.z=-pi/2 | ||||
| 				 | ||||
| 
 | ||||
| 				 | ||||
| def addBridges(ch,o): | ||||
| 	'''this adds bridges to chunks, takes the bridge-objects group and uses the curves inside it as bridges.''' | ||||
| 	bridgegroupname=o.bridges_group_name | ||||
| 	bridgegroup=bpy.data.groups[bridgegroupname] | ||||
| 	 | ||||
| 	 | ||||
| 
 | ||||
| 	#get bridgepoly | ||||
| 	shapes=[] | ||||
| 	for ob in bridgegroup.objects: | ||||
| 		if ob.type == 'CURVE': | ||||
| 			shapes.extend(curveToShapely(ob)) | ||||
| 	bridgespoly=sops.unary_union(shapes) | ||||
| 	#buffer the poly, so the bridges are not actually milled... | ||||
| 	bridgespoly = bridgespoly.buffer(distance = o.cutter_diameter/2.0) | ||||
| 	#### | ||||
| 	bridgeheight=min(0,o.min.z+o.bridges_height) | ||||
| 	vi=0 | ||||
| 	#shapelyToCurve('test',bridgespoly,0) | ||||
| 	newpoints=[] | ||||
| 	while vi<len(ch.points): | ||||
| 		i1=vi | ||||
| 		i2=vi | ||||
| 		chp1=ch.points[i1] | ||||
| 		chp2=ch.points[i1]#Vector(v1)#this is for case of last point and not closed chunk.. | ||||
| 		if vi+1<len(ch.points): | ||||
| 			i2 = vi+1 | ||||
| 			chp2=ch.points[vi+1]#Vector(ch.points[vi+1]) | ||||
| 		v1=Vector(chp1) | ||||
| 		v2=Vector(chp2) | ||||
| 		if v1.z<bridgeheight or v2.z<bridgeheight: | ||||
| 			v=v2-v1 | ||||
| 			#dist+=v.length | ||||
| 			p1=sgeometry.Point(chp1) | ||||
| 			p2=sgeometry.Point(chp1) | ||||
| 			 | ||||
| 			startinside = bridgespoly.contains(p1) | ||||
| 			endinside = bridgespoly.contains(p2) | ||||
| 			l=sgeometry.LineString([chp1,chp2]) | ||||
| 			intersections = bridgespoly.boundary.intersection(l) | ||||
| 			 | ||||
| 			itempty = intersections.type == 'GeometryCollection' | ||||
| 			itpoint = intersections.type == 'Point' | ||||
| 			itmpoint = intersections.type == 'MultiPoint' | ||||
| 			 | ||||
| 			#print(startinside, endinside,intersections, intersections.type) | ||||
| 			#print(l,bridgespoly) | ||||
| 			if not startinside: | ||||
| 				#print('nothing found') | ||||
| 				 | ||||
| 				newpoints.append(chp1) | ||||
| 			#elif startinside and endinside and itempty: | ||||
| 			#	newpoints.append((chp1[0],chp1[1],max(chp1[2],bridgeheight))) | ||||
| 			elif startinside: | ||||
| 				newpoints.append((chp1[0],chp1[1],max(chp1[2],bridgeheight))) | ||||
| 			#elif not startinside: | ||||
| 			#	newpoints.append(chp1) | ||||
| 			cpoints=[] | ||||
| 			if itpoint: | ||||
| 				cpoints= [Vector((intersections.x,intersections.y,intersections.z))] | ||||
| 			elif itmpoint: | ||||
| 				cpoints=[] | ||||
| 				for p in intersections: | ||||
| 					cpoints.append(Vector((p.x,p.y,p.z))) | ||||
| 			#####sort collisions here :( | ||||
| 			ncpoints=[] | ||||
| 			while len(cpoints)>0: | ||||
| 				mind=10000000 | ||||
| 				mini=-1 | ||||
| 				for i,p in enumerate(cpoints): | ||||
| 					if min(mind, (p-v1).length)<mind: | ||||
| 						mini=i | ||||
| 						mind= (p-v1).length | ||||
| 				ncpoints.append(cpoints.pop(mini)) | ||||
| 			cpoints = ncpoints | ||||
| 			#endsorting | ||||
| 			 | ||||
| 			 | ||||
| 			if startinside: | ||||
| 				isinside=True | ||||
| 			else:	 | ||||
| 				isinside=False | ||||
| 			for cp in cpoints: | ||||
| 				v3= cp | ||||
| 				#print(v3) | ||||
| 				if v.length==0: | ||||
| 					ratio=1 | ||||
| 				else: | ||||
| 					fractvect = v3 - v1 | ||||
| 					ratio = fractvect.length/v.length | ||||
| 					 | ||||
| 				collisionz=v1.z+v.z*ratio | ||||
| 				np1 = (v3.x, v3.y, collisionz) | ||||
| 				np2	= (v3.x, v3.y, max(collisionz,bridgeheight)) | ||||
| 				if not isinside: | ||||
| 					newpoints.extend((np1, np2)) | ||||
| 				else: | ||||
| 					newpoints.extend((np2, np1)) | ||||
| 				isinside = not isinside | ||||
| 			vi+=1 | ||||
| 		else: | ||||
| 			newpoints.append(chp1) | ||||
| 			vi+=1 | ||||
| 	ch.points=newpoints | ||||
| 
 | ||||
| 
 | ||||
| ''' | ||||
| 	 | ||||
| def addBridges(ch,o): | ||||
| 	#this functions adds Bridges to the finished chunks. AUTOMATIC ONLY NOW! | ||||
| 	if o.bridges_placement == 'AUTO': | ||||
|  | @ -2063,6 +2290,8 @@ def addBridges(ch,o): | |||
| 			for pi in range(len(insertpoints)-1,-1,-1): | ||||
| 				ch.points.insert(insertpoints[pi][0],insertpoints[pi][1]) | ||||
| 
 | ||||
| ''' | ||||
| 
 | ||||
| ###########cutout strategy is completely here: | ||||
| def strategy_cutout( o ): | ||||
| 	#ob=bpy.context.active_object | ||||
|  | @ -2078,7 +2307,7 @@ def strategy_cutout( o ): | |||
| 			#print(ch.points) | ||||
| 			 | ||||
| 			if len(ch.points)>2: | ||||
| 				ch.poly=chunkToPoly(ch) | ||||
| 				ch.poly=chunkToShapely(ch) | ||||
| 				#p.addContour(ch.poly) | ||||
| 	else: | ||||
| 		chunksFromCurve=[] | ||||
|  | @ -2092,11 +2321,12 @@ def strategy_cutout( o ): | |||
| 			p=getObjectOutline(o.cutter_diameter/2,o,offset) | ||||
| 			if o.outlines_count>1: | ||||
| 				for i in range(1,o.outlines_count): | ||||
| 					chunksFromCurve.extend(polyToChunks(p,-1)) | ||||
| 					p=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offset) | ||||
| 					chunksFromCurve.extend(shapelyToChunks(p,-1)) | ||||
| 					p = p.buffer(distance = o.dist_between_paths * offset, resolution = o.circle_detail) | ||||
| 					#p=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offset) | ||||
| 			 | ||||
| 				 | ||||
| 		chunksFromCurve.extend(polyToChunks(p,-1)) | ||||
| 		chunksFromCurve.extend(shapelyToChunks(p,-1)) | ||||
| 		if o.outlines_count>1 and o.movement_insideout=='OUTSIDEIN': | ||||
| 			chunksFromCurve.reverse() | ||||
| 	#parentChildPoly(chunksFromCurve,chunksFromCurve,o) | ||||
|  | @ -2130,6 +2360,7 @@ def strategy_cutout( o ): | |||
| 			layers=[[o.maxz,o.min.z]] | ||||
| 		 | ||||
| 	print(layers) | ||||
| 	 | ||||
| 	extendorder=[] | ||||
| 	if o.first_down:#each shape gets either cut all the way to bottom, or every shape gets cut 1 layer, then all again. has to create copies, because same chunks are worked with on more layers usually | ||||
| 		for chunk in chunksFromCurve: | ||||
|  | @ -2148,15 +2379,6 @@ def strategy_cutout( o ): | |||
| 	 | ||||
| 	chunks=[] | ||||
| 	 | ||||
| 	if o.use_bridges:#add bridges to chunks | ||||
| 		#bridges=getBridges(p,o) | ||||
| 		bridgeheight=min(0,o.min.z+o.bridges_height) | ||||
| 		for chl in extendorder: | ||||
| 			chunk=chl[0] | ||||
| 			layer=chl[1] | ||||
| 			if layer[1]<bridgeheight: | ||||
| 				addBridges(chunk,o) | ||||
| 			 | ||||
| 	if o.ramp:#add ramps or simply add chunks | ||||
| 		for chl in extendorder: | ||||
| 			chunk=chl[0] | ||||
|  | @ -2165,9 +2387,19 @@ def strategy_cutout( o ): | |||
| 				chunks.append(chunk.rampContour(layer[0],layer[1],o)) | ||||
| 			else: | ||||
| 				chunks.append(chunk.rampZigZag(layer[0],layer[1],o)) | ||||
| 	else: | ||||
| 
 | ||||
| 	if o.use_bridges:#add bridges to chunks | ||||
| 		#bridges=getBridges(p,o) | ||||
| 		bridgeheight=min(0,o.min.z+o.bridges_height) | ||||
| 		for chl in extendorder: | ||||
| 			chunks.append(chl[0]) | ||||
| 			chunk=chl[0] | ||||
| 			layer=chl[1] | ||||
| 			if layer[1]<bridgeheight: | ||||
| 				addBridges(chunk,o) | ||||
| 
 | ||||
| 	for chl in extendorder: | ||||
| 		chunks.append(chl[0]) | ||||
| 			 | ||||
| 
 | ||||
| 	chunksToMesh(chunks,o) | ||||
| 
 | ||||
|  | @ -2269,8 +2501,6 @@ def strategy_proj_curve( s, o ): | |||
| 	#	ch.points=ch.endpoints | ||||
| 	chunksToMesh(chunks,o) | ||||
| 
 | ||||
| #def strategy_pocket( o ): | ||||
| 	 | ||||
| 	 | ||||
| #this is the main function. | ||||
| #FIXME: split strategies into separate file! | ||||
|  | @ -2292,45 +2522,43 @@ def getPath3axis(context, operation): | |||
| 		 | ||||
| 	elif o.strategy=='POCKET':	 | ||||
| 		p=getObjectOutline(o.cutter_diameter/2,o,False) | ||||
| 		all=Polygon.Polygon(p) | ||||
| 		#all=Polygon.Polygon(p) | ||||
| 		approxn=(min(o.max.x-o.min.x,o.max.y-o.min.y)/o.dist_between_paths)/2 | ||||
| 		i=0 | ||||
| 		chunks=[] | ||||
| 		chunksFromCurve=[] | ||||
| 		lastchunks=[] | ||||
| 		centers=None | ||||
| 		checkCenters=False | ||||
| 		 | ||||
| 		if o.dist_between_paths>o.cutter_diameter/2.0: | ||||
| 			checkCenters=True | ||||
| 			o.warnings=o.warnings+'Distance between paths larger\n	than cutter radius can result in uncut areas!\n ' | ||||
| 
 | ||||
| 		while len(p)>0: | ||||
| 			nchunks=polyToChunks(p,o.min.z) | ||||
| 		#shapelyToCurve('testik',p,0) | ||||
| 		while not p.is_empty: | ||||
| 			nchunks=shapelyToChunks(p,o.min.z) | ||||
| 			nchunks=limitChunks(nchunks,o) | ||||
| 			chunksFromCurve.extend(nchunks) | ||||
| 			parentChildDist(lastchunks,nchunks,o) | ||||
| 			lastchunks=nchunks | ||||
| 			 | ||||
| 			pnew=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,False) | ||||
| 			pnew=p.buffer(-o.dist_between_paths,o.circle_detail) | ||||
| 			#pnew=outlinePoly(p,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,False) | ||||
| 			 | ||||
| 			if checkCenters: | ||||
| 				contours_before=len(p) | ||||
| 			if o.dist_between_paths>o.cutter_diameter/2.0:#this mess under this IF condition is here ONLY because of the ability to have stepover> than cutter radius. Other CAM softwares don't allow this at all, maybe because of this mathematical problem and performance cost, but into soft materials, this is good to have. | ||||
| 				o.warnings=o.warnings+'Distance between paths larger\n	than cutter radius can result in uncut areas!\n ' | ||||
| 
 | ||||
| 				contours_before=len(p.boundary) | ||||
| 				 | ||||
| 				if centers==None: | ||||
| 					centers=[] | ||||
| 					for ci in range(0,len(p)): | ||||
| 						centers.append(p.center(ci)) | ||||
| 				contours_after=len(pnew) | ||||
| 					for p in range(0,len(p)): | ||||
| 						centers.append(p.centroid()) | ||||
| 				contours_after=len(pnew.boundary) | ||||
| 				newcenters=[] | ||||
| 				 | ||||
| 				do_test=False | ||||
| 				for ci in range(0,len(pnew)): | ||||
| 					newcenters.append(pnew.center(ci)) | ||||
| 					 | ||||
| 					newcenters.append(pnew.centroid()) | ||||
| 					dodelat | ||||
| 					if len(p)>ci:#comparing polygons to detect larger changes in shape | ||||
| 						#print(ci,len(p)) | ||||
| 						bb1=p.boundingBox(ci) | ||||
| 						bb1=p.bounds(ci) | ||||
| 						bb2=pnew.boundingBox(ci) | ||||
| 						d1=dist2d(newcenters[ci],centers[ci]) | ||||
| 						d2=0 | ||||
|  | @ -2423,10 +2651,10 @@ def getPath3axis(context, operation): | |||
| 						p=ch.points[0]#TODO:intercept closest next point when it should stay low  | ||||
| 						#first thing to do is to check if helix enter can really enter. | ||||
| 						checkc=Circle(helix_radius+o.cutter_diameter/2,o.circle_detail) | ||||
| 						checkc.shift(p[0],p[1]) | ||||
| 						checkc = affinity.translate(checkc,p[0],p[1]) | ||||
| 						covers=False | ||||
| 						for poly in o.silhouete: | ||||
| 							if poly.covers(checkc): | ||||
| 							if poly.contains(checkc): | ||||
| 								covers=True | ||||
| 								break; | ||||
| 						 | ||||
|  | @ -2487,10 +2715,11 @@ def getPath3axis(context, operation): | |||
| 							rothelix.append(p) | ||||
| 							c.append((p[0],p[1])) | ||||
| 							 | ||||
| 						c=Polygon.Polygon(c) | ||||
| 						c=sgeometry.Polygon(c) | ||||
| 						#print('çoutline') | ||||
| 						#print(c) | ||||
| 						coutline = outlinePoly(c,o.cutter_diameter/2,o.circle_detail,o.optimize,o.optimize_threshold,offset = True) | ||||
| 						coutline = c.buffer(o.cutter_diameter/2,o.circle_detail) | ||||
| 						#coutline = outlinePoly(c,o.cutter_diameter/2,o.circle_detail,o.optimize,o.optimize_threshold,offset = True) | ||||
| 						#print(h) | ||||
| 						#print('çoutline') | ||||
| 						#print(coutline) | ||||
|  | @ -2499,7 +2728,7 @@ def getPath3axis(context, operation): | |||
| 						 | ||||
| 						covers=False | ||||
| 						for poly in o.silhouete: | ||||
| 							if poly.covers(coutline): | ||||
| 							if poly.contains(coutline): | ||||
| 								covers=True | ||||
| 								break; | ||||
| 						 | ||||
|  | @ -2592,16 +2821,16 @@ def getPath3axis(context, operation): | |||
| 		 | ||||
| 		 | ||||
| 	elif o.strategy=='WATERLINE' and o.use_opencamlib: | ||||
| 		getAmbient(o) | ||||
| 		chunks=[] | ||||
| 		oclGetWaterline(o, chunks) | ||||
| 		chunks=limitChunks(chunks,o) | ||||
| 		getAmbient(o) | ||||
| 		chunks=[] | ||||
| 		oclGetWaterline(o, chunks) | ||||
| 		chunks=limitChunks(chunks,o) | ||||
| 		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 chunks: | ||||
| 				ch.points.reverse() | ||||
| 		chunksToMesh(chunks,o) | ||||
| 		 | ||||
| 		 | ||||
| 		chunksToMesh(chunks,o) | ||||
| 		 | ||||
| 		 | ||||
| 	elif o.strategy=='WATERLINE' and not o.use_opencamlib: | ||||
| 		topdown=True | ||||
| 		tw=time.time() | ||||
|  | @ -2621,7 +2850,7 @@ def getPath3axis(context, operation): | |||
| 		#######################	  | ||||
| 		nslices=ceil(abs(o.minz/o.slice_detail)) | ||||
| 		lastislice=numpy.array([]) | ||||
| 		lastslice=Polygon.Polygon()#polyversion | ||||
| 		lastslice=spolygon.Polygon()#polyversion | ||||
| 		layerstepinc=0 | ||||
| 		 | ||||
| 		slicesfilled=0 | ||||
|  | @ -2636,10 +2865,10 @@ def getPath3axis(context, operation): | |||
| 			#print(z) | ||||
| 			#sliceimage=o.offset_image>z | ||||
| 			islice=o.offset_image>z | ||||
| 			slicepolys=imageToPoly(o,islice,with_border=True) | ||||
| 			slicepolys=imageToShapely(o,islice,with_border=True) | ||||
| 			#for pviz in slicepolys: | ||||
| 			#	polyToMesh('slice',pviz,z) | ||||
| 			poly=Polygon.Polygon()#polygversion | ||||
| 			poly=spolygon.Polygon()#polygversion | ||||
| 			lastchunks=[] | ||||
| 			#imagechunks=imageToChunks(o,islice) | ||||
| 			#for ch in imagechunks: | ||||
|  | @ -2651,10 +2880,10 @@ def getPath3axis(context, operation): | |||
| 			#print('found polys',layerstepinc,len(slicepolys)) | ||||
| 			for p in slicepolys: | ||||
| 				#print('polypoints',p.nPoints(0)) | ||||
| 				poly+=p#polygversion TODO: why is this added? | ||||
| 				poly=poly.union(p)#polygversion TODO: why is this added? | ||||
| 				#print() | ||||
| 				#polyToMesh(p,z) | ||||
| 				nchunks=polyToChunks(p,z) | ||||
| 				nchunks=shapelyToChunks(p,z) | ||||
| 				nchunks=limitChunks(nchunks,o, force=True) | ||||
| 				#print('chunksnum',len(nchunks)) | ||||
| 				#if len(nchunks)>0: | ||||
|  | @ -2678,25 +2907,27 @@ def getPath3axis(context, operation): | |||
| 				layers=[[layerstart,layerend]] | ||||
| 				##################################### | ||||
| 				#fill top slice for normal and first for inverse, fill between polys | ||||
| 				if len(lastslice)>0 or (o.inverse and len(poly)>0 and slicesfilled==1): | ||||
| 					offs=False | ||||
| 					if len(lastslice)>0:#between polys | ||||
| 				if not lastslice.is_empty or (o.inverse and not poly.is_empty and slicesfilled==1): | ||||
| 					#offs=False | ||||
| 					if not lastslice.is_empty:#between polys | ||||
| 						if o.inverse: | ||||
| 							restpoly=poly-lastslice | ||||
| 							restpoly=poly.difference(lastslice) | ||||
| 						else: | ||||
| 							restpoly=lastslice-poly#Polygon.Polygon(lastslice) | ||||
| 							restpoly=lastslice.difference(poly)#Polygon.Polygon(lastslice) | ||||
| 						#print('filling between') | ||||
| 					if (not o.inverse and len(poly)==0 and slicesfilled>0) or (o.inverse and len(poly)>0 and slicesfilled==1):#first slice fill | ||||
| 					if (not o.inverse and poly.is_empty and slicesfilled>0) or (o.inverse and not poly.is_empty and slicesfilled==1):#first slice fill | ||||
| 						restpoly=lastslice | ||||
| 						#print('filling first') | ||||
| 					 | ||||
| 					#print(len(restpoly)) | ||||
| 					#polyToMesh('fillrest',restpoly,z) | ||||
| 					restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs) | ||||
| 						 | ||||
| 					restpoly=restpoly.buffer(-o.dist_between_paths, resolution = o.circle_detail) | ||||
| 					#outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs) | ||||
| 					fillz = z  | ||||
| 					i=0 | ||||
| 					while len(restpoly)>0: | ||||
| 						nchunks=polyToChunks(restpoly,fillz) | ||||
| 					while not restpoly.is_empty: | ||||
| 						nchunks=shapelyToChunks(restpoly,fillz) | ||||
| 						#project paths TODO: path projection during waterline is not working | ||||
| 						if o.waterline_project: | ||||
| 							nchunks=chunksRefine(nchunks,o) | ||||
|  | @ -2708,38 +2939,41 @@ def getPath3axis(context, operation): | |||
| 						parentChildDist(lastchunks,nchunks,o) | ||||
| 						lastchunks=nchunks | ||||
| 						#slicechunks.extend(polyToChunks(restpoly,z)) | ||||
| 						restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs) | ||||
| 						restpoly=restpoly.buffer(-o.dist_between_paths, resolution = o.circle_detail) | ||||
| 						#restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs) | ||||
| 						i+=1 | ||||
| 						#print(i) | ||||
| 				i=0 | ||||
| 				#''' | ||||
| 				##################################### | ||||
| 				# fill layers and last slice, last slice with inverse is not working yet - inverse millings end now always on 0 so filling ambient does have no sense. | ||||
| 				if (slicesfilled>0 and layerstepinc==layerstep) or (not o.inverse and len(poly)>0 and slicesfilled==1) or (o.inverse and len(poly)==0 and slicesfilled>0): | ||||
| 				if (slicesfilled>0 and layerstepinc==layerstep) or (not o.inverse and not poly.is_empty and slicesfilled==1) or (o.inverse and poly.is_empty and slicesfilled>0): | ||||
| 					fillz=z | ||||
| 					layerstepinc=0 | ||||
| 					 | ||||
| 					#ilim=1000#TODO:this should be replaced... no limit, just check if the shape grows over limits. | ||||
| 					 | ||||
| 					offs=False | ||||
| 					#offs=False | ||||
| 					boundrect=o.ambient#Polygon.Polygon(((o.min.x,o.min.y),(o.min.x,o.max.y),(o.max.x,o.max.y),(o.max.x,o.min.y))) | ||||
| 					 | ||||
| 					restpoly=boundrect-poly | ||||
| 					if (o.inverse and len(poly)==0 and slicesfilled>0): | ||||
| 						restpoly=boundrect-lastslice | ||||
| 					restpoly=boundrect.difference(poly) | ||||
| 					if (o.inverse and poly.is_empty and slicesfilled>0): | ||||
| 						restpoly=boundrect.difference(lastslice) | ||||
| 					 | ||||
| 					restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs) | ||||
| 					restpoly=restpoly.buffer(-o.dist_between_paths, resolution = o.circle_detail) | ||||
| 					#restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs) | ||||
| 					i=0 | ||||
| 					while len(restpoly)>0: | ||||
| 						print(i) | ||||
| 						nchunks=polyToChunks(restpoly,fillz) | ||||
| 					while not restpoly.is_empty: #'GeometryCollection':#len(restpoly.boundary.coords)>0: | ||||
| 						#print(i) | ||||
| 						nchunks=shapelyToChunks(restpoly,fillz) | ||||
| 						######################### | ||||
| 						nchunks=limitChunks(nchunks,o, force=True) | ||||
| 						slicechunks.extend(nchunks) | ||||
| 						parentChildDist(lastchunks,nchunks,o) | ||||
| 						lastchunks=nchunks | ||||
| 						#slicechunks.extend(polyToChunks(restpoly,z)) | ||||
| 						restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs) | ||||
| 						restpoly=restpoly.buffer(-o.dist_between_paths, resolution = o.circle_detail) | ||||
| 						#restpoly=outlinePoly(restpoly,o.dist_between_paths,o.circle_detail,o.optimize,o.optimize_threshold,offs) | ||||
| 						i+=1 | ||||
| 				 | ||||
| 				 | ||||
|  | @ -2757,7 +2991,7 @@ def getPath3axis(context, operation): | |||
| 				n=0 | ||||
| 				while i.sum()>0 and n<10000: | ||||
| 					i=outlineImageBinary(o,o.dist_between_paths,i,False) | ||||
| 					polys=imageToPoly(o,i) | ||||
| 					polys=imageToShapely(o,i) | ||||
| 					for poly in polys: | ||||
| 						chunks.extend(polyToChunks(poly,z)) | ||||
| 					n+=1 | ||||
|  | @ -2861,7 +3095,7 @@ def getPath3axis(context, operation): | |||
| 		for ob in o.objects: | ||||
| 			polys=getOperationSilhouete(o) | ||||
| 			for poly in polys: | ||||
| 				chunks=polyToChunks(poly,-1) | ||||
| 				chunks=shapelyToChunks(poly,-1) | ||||
| 				chunks = chunksRefine(chunks,o) | ||||
| 				 | ||||
| 				''' | ||||
|  | @ -2916,7 +3150,7 @@ def getPath3axis(context, operation): | |||
| 				filteredPts=[] | ||||
| 				print('filter points') | ||||
| 				for p in pts: | ||||
| 					if not poly.isInside(p[0],p[1]): | ||||
| 					if not poly.contains(sgeometry.Point(p)): | ||||
| 						vertr.append((True,-1)) | ||||
| 					else: | ||||
| 						vertr.append((False,newIdx)) | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Jeff Doyle (nfz)
						Jeff Doyle (nfz)